Skip to content

Commit 23c84f2

Browse files
committed
test: add test for sort store host
1 parent 5252c89 commit 23c84f2

1 file changed

Lines changed: 223 additions & 0 deletions

File tree

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
import { attrId } from "@mendix/widget-plugin-test-utils";
2+
import { SortStoreHost } from "../stores/SortStoreHost";
3+
import { ObservableSortStore, SortInstruction } from "../types/store";
4+
5+
describe("SortStoreHost", () => {
6+
let sortStoreHost: SortStoreHost;
7+
let mockStore: ObservableSortStore;
8+
9+
beforeEach(() => {
10+
sortStoreHost = new SortStoreHost();
11+
mockStore = {
12+
sortOrder: [
13+
[attrId("attr1"), "asc"],
14+
[attrId("attr2"), "desc"]
15+
] as SortInstruction[]
16+
};
17+
});
18+
19+
describe("constructor", () => {
20+
it("should initialize with empty state", () => {
21+
expect(sortStoreHost.sortOrder).toEqual([]);
22+
expect(sortStoreHost.usedBy).toBeNull();
23+
});
24+
25+
it("should make properties observable/computed correctly", () => {
26+
// Test that the object is properly observable by checking MobX behavior
27+
expect(sortStoreHost).toBeDefined();
28+
expect(typeof sortStoreHost.sortOrder).toBe("object");
29+
expect(typeof sortStoreHost.usedBy).toBe("object");
30+
});
31+
});
32+
33+
describe("sortOrder", () => {
34+
it("should return empty array when no store is observed", () => {
35+
expect(sortStoreHost.sortOrder).toEqual([]);
36+
});
37+
38+
it("should return sort order from observed store", () => {
39+
sortStoreHost.observe(mockStore);
40+
expect(sortStoreHost.sortOrder).toEqual([
41+
[attrId("attr1"), "asc"],
42+
[attrId("attr2"), "desc"]
43+
]);
44+
});
45+
46+
it("should return empty array after unobserving", () => {
47+
sortStoreHost.observe(mockStore);
48+
sortStoreHost.unobserve();
49+
expect(sortStoreHost.sortOrder).toEqual([]);
50+
});
51+
});
52+
53+
describe("observe", () => {
54+
it("should set the internal store", () => {
55+
sortStoreHost.observe(mockStore);
56+
expect(sortStoreHost.sortOrder).toBe(mockStore.sortOrder);
57+
});
58+
59+
it("should replace previously observed store", () => {
60+
const anotherMockStore: ObservableSortStore = {
61+
sortOrder: [[attrId("attr3"), "asc"]] as SortInstruction[]
62+
};
63+
64+
sortStoreHost.observe(mockStore);
65+
expect(sortStoreHost.sortOrder).toBe(mockStore.sortOrder);
66+
67+
sortStoreHost.observe(anotherMockStore);
68+
expect(sortStoreHost.sortOrder).toBe(anotherMockStore.sortOrder);
69+
});
70+
});
71+
72+
describe("unobserve", () => {
73+
it("should clear the internal store", () => {
74+
sortStoreHost.observe(mockStore);
75+
sortStoreHost.unobserve();
76+
expect(sortStoreHost.sortOrder).toEqual([]);
77+
});
78+
79+
it("should be safe to call when no store is observed", () => {
80+
expect(() => sortStoreHost.unobserve()).not.toThrow();
81+
expect(sortStoreHost.sortOrder).toEqual([]);
82+
});
83+
});
84+
85+
describe("lock", () => {
86+
it("should add id to usedBy list and return unlock function", () => {
87+
const unlock = sortStoreHost.lock("widget1");
88+
89+
expect(sortStoreHost.usedBy).toBe("widget1");
90+
expect(typeof unlock).toBe("function");
91+
});
92+
93+
it("should return unlock function that removes the id", () => {
94+
const unlock = sortStoreHost.lock("widget1");
95+
expect(sortStoreHost.usedBy).toBe("widget1");
96+
97+
unlock();
98+
expect(sortStoreHost.usedBy).toBeNull();
99+
});
100+
101+
it("should handle multiple locks correctly", () => {
102+
const unlock1 = sortStoreHost.lock("widget1");
103+
const unlock2 = sortStoreHost.lock("widget2");
104+
105+
// First widget should be the one returned by usedBy
106+
expect(sortStoreHost.usedBy).toBe("widget1");
107+
108+
unlock1();
109+
expect(sortStoreHost.usedBy).toBe("widget2");
110+
111+
unlock2();
112+
expect(sortStoreHost.usedBy).toBeNull();
113+
});
114+
115+
it("should not add duplicate ids", () => {
116+
sortStoreHost.lock("widget1");
117+
sortStoreHost.lock("widget1");
118+
119+
expect(sortStoreHost.usedBy).toBe("widget1");
120+
// Internal _usedBy array should only have one entry
121+
// We can test this indirectly by checking that unlocking once clears it
122+
const unlock = sortStoreHost.lock("widget1");
123+
unlock();
124+
expect(sortStoreHost.usedBy).toBeNull();
125+
});
126+
});
127+
128+
describe("usedBy", () => {
129+
it("should return null when no widgets are using the store", () => {
130+
expect(sortStoreHost.usedBy).toBeNull();
131+
});
132+
133+
it("should return the first widget id when multiple widgets are using the store", () => {
134+
sortStoreHost.lock("widget1");
135+
sortStoreHost.lock("widget2");
136+
sortStoreHost.lock("widget3");
137+
138+
expect(sortStoreHost.usedBy).toBe("widget1");
139+
});
140+
141+
it("should return the next widget id after the first is removed", () => {
142+
const unlock1 = sortStoreHost.lock("widget1");
143+
const unlock2 = sortStoreHost.lock("widget2");
144+
145+
expect(sortStoreHost.usedBy).toBe("widget1");
146+
147+
unlock1();
148+
expect(sortStoreHost.usedBy).toBe("widget2");
149+
150+
unlock2();
151+
expect(sortStoreHost.usedBy).toBeNull();
152+
});
153+
});
154+
155+
describe("private methods", () => {
156+
it("should handle removing non-existent id gracefully", () => {
157+
// This tests the _remove method indirectly
158+
const unlock = sortStoreHost.lock("widget1");
159+
160+
// Call unlock twice - second call should be safe
161+
unlock();
162+
expect(() => unlock()).not.toThrow();
163+
expect(sortStoreHost.usedBy).toBeNull();
164+
});
165+
166+
it("should maintain correct order when removing from middle", () => {
167+
const unlock1 = sortStoreHost.lock("widget1");
168+
const unlock2 = sortStoreHost.lock("widget2");
169+
const unlock3 = sortStoreHost.lock("widget3");
170+
171+
expect(sortStoreHost.usedBy).toBe("widget1");
172+
173+
// Remove middle item
174+
unlock2();
175+
expect(sortStoreHost.usedBy).toBe("widget1");
176+
177+
unlock1();
178+
expect(sortStoreHost.usedBy).toBe("widget3");
179+
180+
unlock3();
181+
expect(sortStoreHost.usedBy).toBeNull();
182+
});
183+
});
184+
185+
describe("integration scenarios", () => {
186+
it("should work correctly when combining observe and lock", () => {
187+
sortStoreHost.observe(mockStore);
188+
const unlock = sortStoreHost.lock("widget1");
189+
190+
expect(sortStoreHost.sortOrder).toEqual([
191+
[attrId("attr1"), "asc"],
192+
[attrId("attr2"), "desc"]
193+
]);
194+
expect(sortStoreHost.usedBy).toBe("widget1");
195+
196+
sortStoreHost.unobserve();
197+
expect(sortStoreHost.sortOrder).toEqual([]);
198+
expect(sortStoreHost.usedBy).toBe("widget1"); // Lock should remain
199+
200+
unlock();
201+
expect(sortStoreHost.usedBy).toBeNull();
202+
});
203+
204+
it("should handle store changes after observation", () => {
205+
const mutableStore = {
206+
sortOrder: [[attrId("attr1"), "asc"]] as SortInstruction[]
207+
};
208+
209+
sortStoreHost.observe(mutableStore);
210+
expect(sortStoreHost.sortOrder).toEqual([[attrId("attr1"), "asc"]]);
211+
212+
// Simulate store change
213+
mutableStore.sortOrder = [
214+
[attrId("attr2"), "desc"],
215+
[attrId("attr3"), "asc"]
216+
];
217+
expect(sortStoreHost.sortOrder).toEqual([
218+
[attrId("attr2"), "desc"],
219+
[attrId("attr3"), "asc"]
220+
]);
221+
});
222+
});
223+
});

0 commit comments

Comments
 (0)