local Charm = require("../../Charm") local client = require("../client") local test = require("../../../../tests/test") test.afterEach(function() client.removeAllSignals() end) test("should hydrate atom", function() local a = Charm.atom(1) client.addSignals({ a = a }) client.patch({ { type = "init", data = { a = 2 } }, }) assert(a() == 2, "should set a to the initial value") end) test("should merge patch", function() local a = Charm.atom({ b = 1, c = 2 }) local previous = a() client.addSignals({ a = a }) client.patch({ { type = "init", data = { a = a() } }, }) assert(a() == previous, "should set a to the initial value") client.patch({ { type = "patch", data = { a = { b = 3 } } }, }) assert(a() ~= previous, "should apply patch") assert(a().b == 3, "should set b to the new value") assert(a().c == 2, "should not change c") end) test("should merge patch (reactive)", function() local a = Charm.reactive({ b = 1, c = 2 }) local runs = 0 Charm.effect(function() local _ = a.b + a.c runs += 1 end) client.addSignals({ a = a }) client.patch({ { type = "init", data = { a = { b = a.b, c = a.c } } }, }) assert(runs == 1, "should not trigger effect for redundant init") client.patch({ { type = "patch", data = { a = { b = 3 } } }, }) assert(a.b == 3, "should set b to the new value") assert(a.c == 2, "should not change c") assert(runs == 2, "should trigger effect for patch") end) test("should fix sparse array patches", function() local a = Charm.atom({ 1 }) client.addSignals({ a = a }) client.patch({ { type = "init", data = { a = a() } }, }) -- This patch would be the result of a diff between { 1 } and { 1, 2 } that -- was JSON-serialized and deserialized. The client should be able to catch -- this and convert the string key back to a number. client.patch({ { type = "patch", data = { a = { ["2"] = 2 } } }, }) assert(a()["2" :: any] == nil, "should convert serialized arrays to use numbers") assert(a()[2] == 2, "should convert serialized arrays to use numbers") end) test("should merge multiple patches", function() local a = Charm.atom(1) local calls = {} client.addSignals({ a = a }) Charm.subscribe(a, function(value) table.insert(calls, value) end) client.patch({ { type = "init", data = { a = a() } }, }) client.patch({ { type = "patch", data = { a = 2 } }, { type = "patch", data = { a = 3 } }, }) assert(a() == 3, "should apply the last patch") assert(table.concat(calls) == "23", `wrong order: {table.concat(calls)}`) end) test("should batch patches", function() local a = Charm.atom(0) local b = Charm.atom(0) local states = {} client.addSignals({ a = a, b = b }) Charm.subscribe(a, function() states.b = b() end) Charm.subscribe(b, function() states.a = a() end) client.patch({ { type = "init", data = { a = a(), b = b() } }, }) client.patch({ { type = "patch", data = { a = 1, b = 2 } }, }) assert(a() == 1, "should set a to the new value") assert(b() == 2, "should set b to the new value") assert(states.a == 1, "sub to a should run after b updates") assert(states.b == 2, "sub to b should run after a updates") end) return {}