@praxisjs/decorators 1.7.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +41 -0
- package/dist/component/component.d.ts +1 -1
- package/dist/component/component.d.ts.map +1 -1
- package/dist/component/component.js +8 -15
- package/dist/component/component.js.map +1 -1
- package/dist/component/lazy.d.ts +1 -1
- package/dist/component/lazy.d.ts.map +1 -1
- package/dist/component/lazy.js +44 -36
- package/dist/component/lazy.js.map +1 -1
- package/dist/create-class-decorator.d.ts +27 -5
- package/dist/create-class-decorator.d.ts.map +1 -1
- package/dist/create-class-decorator.js +53 -18
- package/dist/create-class-decorator.js.map +1 -1
- package/dist/create-field-decorator.d.ts +42 -3
- package/dist/create-field-decorator.d.ts.map +1 -1
- package/dist/create-field-decorator.js +63 -27
- package/dist/create-field-decorator.js.map +1 -1
- package/dist/create-getter-decorator.d.ts +81 -16
- package/dist/create-getter-decorator.d.ts.map +1 -1
- package/dist/create-getter-decorator.js +127 -15
- package/dist/create-getter-decorator.js.map +1 -1
- package/dist/create-lifecycle-method-decorator.d.ts +21 -3
- package/dist/create-lifecycle-method-decorator.d.ts.map +1 -1
- package/dist/create-lifecycle-method-decorator.js +25 -18
- package/dist/create-lifecycle-method-decorator.js.map +1 -1
- package/dist/create-method-decorator.d.ts +43 -3
- package/dist/create-method-decorator.d.ts.map +1 -1
- package/dist/create-method-decorator.js +49 -8
- package/dist/create-method-decorator.js.map +1 -1
- package/dist/events/command.d.ts +2 -1
- package/dist/events/command.d.ts.map +1 -1
- package/dist/events/command.js +10 -8
- package/dist/events/command.js.map +1 -1
- package/dist/events/emit.d.ts +2 -2
- package/dist/events/emit.d.ts.map +1 -1
- package/dist/events/emit.js +18 -24
- package/dist/events/emit.js.map +1 -1
- package/dist/events/on-command.d.ts +2 -1
- package/dist/events/on-command.d.ts.map +1 -1
- package/dist/events/on-command.js +12 -14
- package/dist/events/on-command.js.map +1 -1
- package/dist/field.d.ts +51 -0
- package/dist/field.d.ts.map +1 -0
- package/dist/field.js +82 -0
- package/dist/field.js.map +1 -0
- package/dist/functions/bind.d.ts +2 -1
- package/dist/functions/bind.d.ts.map +1 -1
- package/dist/functions/bind.js +4 -4
- package/dist/functions/bind.js.map +1 -1
- package/dist/functions/debounce.d.ts +2 -2
- package/dist/functions/debounce.d.ts.map +1 -1
- package/dist/functions/debounce.js +25 -23
- package/dist/functions/debounce.js.map +1 -1
- package/dist/functions/log.d.ts +2 -1
- package/dist/functions/log.d.ts.map +1 -1
- package/dist/functions/log.js +38 -40
- package/dist/functions/log.js.map +1 -1
- package/dist/functions/memo.d.ts +2 -1
- package/dist/functions/memo.d.ts.map +1 -1
- package/dist/functions/memo.js +41 -40
- package/dist/functions/memo.js.map +1 -1
- package/dist/functions/once.d.ts +2 -1
- package/dist/functions/once.d.ts.map +1 -1
- package/dist/functions/once.js +10 -14
- package/dist/functions/once.js.map +1 -1
- package/dist/functions/retry.d.ts +2 -1
- package/dist/functions/retry.d.ts.map +1 -1
- package/dist/functions/retry.js +21 -23
- package/dist/functions/retry.js.map +1 -1
- package/dist/functions/throttle.d.ts +2 -1
- package/dist/functions/throttle.d.ts.map +1 -1
- package/dist/functions/throttle.js +12 -14
- package/dist/functions/throttle.js.map +1 -1
- package/dist/functions/until.d.ts +2 -1
- package/dist/functions/until.d.ts.map +1 -1
- package/dist/functions/until.js +13 -14
- package/dist/functions/until.js.map +1 -1
- package/dist/functions/watch.d.ts +1 -1
- package/dist/functions/watch.d.ts.map +1 -1
- package/dist/functions/watch.js +36 -34
- package/dist/functions/watch.js.map +1 -1
- package/dist/functions/when.d.ts +1 -1
- package/dist/functions/when.d.ts.map +1 -1
- package/dist/functions/when.js +19 -21
- package/dist/functions/when.js.map +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/lifecycle.d.ts +24 -0
- package/dist/lifecycle.d.ts.map +1 -0
- package/dist/lifecycle.js +55 -0
- package/dist/lifecycle.js.map +1 -0
- package/dist/properties/compose.d.ts +3 -2
- package/dist/properties/compose.d.ts.map +1 -1
- package/dist/properties/compose.js +33 -19
- package/dist/properties/compose.js.map +1 -1
- package/dist/properties/computed.d.ts +12 -10
- package/dist/properties/computed.d.ts.map +1 -1
- package/dist/properties/computed.js +26 -21
- package/dist/properties/computed.js.map +1 -1
- package/dist/properties/deep-state.d.ts +2 -1
- package/dist/properties/deep-state.d.ts.map +1 -1
- package/dist/properties/deep-state.js +66 -60
- package/dist/properties/deep-state.js.map +1 -1
- package/dist/properties/function-prop.d.ts +2 -1
- package/dist/properties/function-prop.d.ts.map +1 -1
- package/dist/properties/function-prop.js +20 -22
- package/dist/properties/function-prop.js.map +1 -1
- package/dist/properties/history.d.ts +2 -2
- package/dist/properties/history.d.ts.map +1 -1
- package/dist/properties/history.js +34 -33
- package/dist/properties/history.js.map +1 -1
- package/dist/properties/index.d.ts +1 -0
- package/dist/properties/index.d.ts.map +1 -1
- package/dist/properties/index.js +1 -0
- package/dist/properties/index.js.map +1 -1
- package/dist/properties/persisted.d.ts +2 -1
- package/dist/properties/persisted.d.ts.map +1 -1
- package/dist/properties/persisted.js +24 -18
- package/dist/properties/persisted.js.map +1 -1
- package/dist/properties/prop.d.ts +2 -1
- package/dist/properties/prop.d.ts.map +1 -1
- package/dist/properties/prop.js +26 -22
- package/dist/properties/prop.js.map +1 -1
- package/dist/properties/ref.d.ts +2 -1
- package/dist/properties/ref.d.ts.map +1 -1
- package/dist/properties/ref.js +11 -8
- package/dist/properties/ref.js.map +1 -1
- package/dist/properties/resource.d.ts.map +1 -1
- package/dist/properties/resource.js +21 -16
- package/dist/properties/resource.js.map +1 -1
- package/dist/properties/selector.d.ts +12 -0
- package/dist/properties/selector.d.ts.map +1 -0
- package/dist/properties/selector.js +25 -0
- package/dist/properties/selector.js.map +1 -0
- package/dist/properties/slot.d.ts +2 -1
- package/dist/properties/slot.d.ts.map +1 -1
- package/dist/properties/slot.js +22 -20
- package/dist/properties/slot.js.map +1 -1
- package/dist/properties/state.d.ts.map +1 -1
- package/dist/properties/state.js +27 -16
- package/dist/properties/state.js.map +1 -1
- package/dist/properties/synced.d.ts +2 -1
- package/dist/properties/synced.d.ts.map +1 -1
- package/dist/properties/synced.js +27 -19
- package/dist/properties/synced.js.map +1 -1
- package/dist/shared-method.d.ts +14 -0
- package/dist/shared-method.d.ts.map +1 -0
- package/dist/shared-method.js +87 -0
- package/dist/shared-method.js.map +1 -0
- package/package.json +14 -5
- package/src/component/component.ts +8 -27
- package/src/component/lazy.ts +51 -41
- package/src/create-class-decorator.ts +90 -31
- package/src/create-field-decorator.ts +120 -43
- package/src/create-getter-decorator.ts +263 -66
- package/src/create-lifecycle-method-decorator.ts +50 -28
- package/src/create-method-decorator.ts +119 -13
- package/src/events/command.ts +11 -9
- package/src/events/emit.ts +16 -22
- package/src/events/on-command.ts +17 -18
- package/src/field.ts +116 -0
- package/src/functions/bind.ts +4 -4
- package/src/functions/debounce.ts +25 -23
- package/src/functions/log.ts +44 -46
- package/src/functions/memo.ts +39 -37
- package/src/functions/once.ts +10 -13
- package/src/functions/retry.ts +19 -21
- package/src/functions/throttle.ts +12 -13
- package/src/functions/until.ts +14 -14
- package/src/functions/watch.ts +37 -36
- package/src/functions/when.ts +18 -20
- package/src/index.ts +12 -5
- package/src/lifecycle.ts +74 -0
- package/src/properties/compose.ts +33 -20
- package/src/properties/computed.ts +35 -45
- package/src/properties/deep-state.ts +66 -64
- package/src/properties/function-prop.ts +25 -27
- package/src/properties/history.ts +34 -35
- package/src/properties/index.ts +1 -0
- package/src/properties/persisted.ts +30 -20
- package/src/properties/prop.ts +30 -22
- package/src/properties/ref.ts +12 -10
- package/src/properties/resource.ts +22 -17
- package/src/properties/selector.ts +45 -0
- package/src/properties/slot.ts +28 -22
- package/src/properties/state.ts +32 -16
- package/src/properties/synced.ts +31 -19
- package/src/shared-method.ts +101 -0
- package/dist/__tests__/component.test.d.ts +0 -2
- package/dist/__tests__/component.test.d.ts.map +0 -1
- package/dist/__tests__/component.test.js +0 -147
- package/dist/__tests__/component.test.js.map +0 -1
- package/dist/__tests__/compose.test.d.ts +0 -2
- package/dist/__tests__/compose.test.d.ts.map +0 -1
- package/dist/__tests__/compose.test.js +0 -164
- package/dist/__tests__/compose.test.js.map +0 -1
- package/dist/__tests__/deep-state.test.d.ts +0 -2
- package/dist/__tests__/deep-state.test.d.ts.map +0 -1
- package/dist/__tests__/deep-state.test.js +0 -221
- package/dist/__tests__/deep-state.test.js.map +0 -1
- package/dist/__tests__/events.test.d.ts +0 -2
- package/dist/__tests__/events.test.d.ts.map +0 -1
- package/dist/__tests__/events.test.js +0 -295
- package/dist/__tests__/events.test.js.map +0 -1
- package/dist/__tests__/functions.test.d.ts +0 -2
- package/dist/__tests__/functions.test.d.ts.map +0 -1
- package/dist/__tests__/functions.test.js +0 -618
- package/dist/__tests__/functions.test.js.map +0 -1
- package/dist/__tests__/lazy.test.d.ts +0 -2
- package/dist/__tests__/lazy.test.d.ts.map +0 -1
- package/dist/__tests__/lazy.test.js +0 -227
- package/dist/__tests__/lazy.test.js.map +0 -1
- package/dist/__tests__/memo.test.d.ts +0 -2
- package/dist/__tests__/memo.test.d.ts.map +0 -1
- package/dist/__tests__/memo.test.js +0 -249
- package/dist/__tests__/memo.test.js.map +0 -1
- package/dist/__tests__/properties-browser.test.d.ts +0 -2
- package/dist/__tests__/properties-browser.test.d.ts.map +0 -1
- package/dist/__tests__/properties-browser.test.js +0 -227
- package/dist/__tests__/properties-browser.test.js.map +0 -1
- package/dist/__tests__/properties.test.d.ts +0 -2
- package/dist/__tests__/properties.test.d.ts.map +0 -1
- package/dist/__tests__/properties.test.js +0 -1253
- package/dist/__tests__/properties.test.js.map +0 -1
- package/dist/__tests__/ref.test.d.ts +0 -2
- package/dist/__tests__/ref.test.d.ts.map +0 -1
- package/dist/__tests__/ref.test.js +0 -106
- package/dist/__tests__/ref.test.js.map +0 -1
- package/dist/__tests__/resource.test.d.ts +0 -2
- package/dist/__tests__/resource.test.d.ts.map +0 -1
- package/dist/__tests__/resource.test.js +0 -217
- package/dist/__tests__/resource.test.js.map +0 -1
- package/dist/__tests__/slot.test.d.ts +0 -2
- package/dist/__tests__/slot.test.d.ts.map +0 -1
- package/dist/__tests__/slot.test.js +0 -147
- package/dist/__tests__/slot.test.js.map +0 -1
- package/dist/__tests__/synced.test.d.ts +0 -2
- package/dist/__tests__/synced.test.d.ts.map +0 -1
- package/dist/__tests__/synced.test.js +0 -161
- package/dist/__tests__/synced.test.js.map +0 -1
- package/dist/__tests__/until.test.d.ts +0 -2
- package/dist/__tests__/until.test.d.ts.map +0 -1
- package/dist/__tests__/until.test.js +0 -88
- package/dist/__tests__/until.test.js.map +0 -1
- package/dist/create-accessor-decorator.d.ts +0 -14
- package/dist/create-accessor-decorator.d.ts.map +0 -1
- package/dist/create-accessor-decorator.js +0 -27
- package/dist/create-accessor-decorator.js.map +0 -1
- package/src/__tests__/component.test.ts +0 -167
- package/src/__tests__/compose.test.ts +0 -202
- package/src/__tests__/deep-state.test.ts +0 -265
- package/src/__tests__/events.test.ts +0 -366
- package/src/__tests__/functions.test.ts +0 -803
- package/src/__tests__/lazy.test.ts +0 -296
- package/src/__tests__/memo.test.ts +0 -293
- package/src/__tests__/properties-browser.test.ts +0 -288
- package/src/__tests__/properties.test.ts +0 -1556
- package/src/__tests__/ref.test.ts +0 -131
- package/src/__tests__/resource.test.ts +0 -246
- package/src/__tests__/slot.test.ts +0 -179
- package/src/__tests__/synced.test.ts +0 -193
- package/src/__tests__/until.test.ts +0 -113
- package/src/create-accessor-decorator.ts +0 -45
- package/tsconfig.json +0 -9
|
@@ -1,288 +0,0 @@
|
|
|
1
|
-
// @vitest-environment jsdom
|
|
2
|
-
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
3
|
-
|
|
4
|
-
import { StatefulComponent } from "@praxisjs/core";
|
|
5
|
-
|
|
6
|
-
import { Persisted } from "../properties/persisted";
|
|
7
|
-
import { Slot, initSlots, getSlot } from "../properties/slot";
|
|
8
|
-
|
|
9
|
-
beforeEach(() => {
|
|
10
|
-
localStorage.clear();
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
// Helper: creates a ClassFieldDecoratorContext mock
|
|
14
|
-
function fieldCtx(name: string) {
|
|
15
|
-
const initializers: Array<(this: unknown) => void> = [];
|
|
16
|
-
return {
|
|
17
|
-
ctx: {
|
|
18
|
-
name,
|
|
19
|
-
kind: "field" as const,
|
|
20
|
-
addInitializer(fn: (this: unknown) => void) {
|
|
21
|
-
initializers.push(fn);
|
|
22
|
-
},
|
|
23
|
-
} as ClassFieldDecoratorContext,
|
|
24
|
-
run(instance: unknown) {
|
|
25
|
-
initializers.forEach((fn) => { fn.call(instance); });
|
|
26
|
-
},
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// Minimal concrete component
|
|
31
|
-
class TestComponent extends StatefulComponent {
|
|
32
|
-
render() { return null; }
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// ── Persisted ─────────────────────────────────────────────────────────────────
|
|
36
|
-
|
|
37
|
-
describe("Persisted decorator", () => {
|
|
38
|
-
it("reads back the initial value when nothing is stored", () => {
|
|
39
|
-
const { ctx, run } = fieldCtx("theme");
|
|
40
|
-
Persisted<string>("theme")(undefined, ctx);
|
|
41
|
-
|
|
42
|
-
const instance = new TestComponent();
|
|
43
|
-
(instance as unknown as Record<string, unknown>).theme = "light";
|
|
44
|
-
run(instance);
|
|
45
|
-
|
|
46
|
-
expect((instance as unknown as Record<string, unknown>).theme).toBe("light");
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it("persists set value to localStorage", () => {
|
|
50
|
-
const { ctx, run } = fieldCtx("lang");
|
|
51
|
-
Persisted<string>("lang")(undefined, ctx);
|
|
52
|
-
|
|
53
|
-
const instance = new TestComponent();
|
|
54
|
-
(instance as unknown as Record<string, unknown>).lang = "en";
|
|
55
|
-
run(instance);
|
|
56
|
-
|
|
57
|
-
(instance as unknown as Record<string, unknown>).lang = "pt";
|
|
58
|
-
expect(localStorage.getItem("lang")).toBe('"pt"');
|
|
59
|
-
expect((instance as unknown as Record<string, unknown>).lang).toBe("pt");
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it("reads existing localStorage value over the initialValue", () => {
|
|
63
|
-
localStorage.setItem("color", '"red"');
|
|
64
|
-
const { ctx, run } = fieldCtx("color");
|
|
65
|
-
Persisted<string>("color")(undefined, ctx);
|
|
66
|
-
|
|
67
|
-
const instance = new TestComponent();
|
|
68
|
-
(instance as unknown as Record<string, unknown>).color = "blue";
|
|
69
|
-
run(instance);
|
|
70
|
-
|
|
71
|
-
expect((instance as unknown as Record<string, unknown>).color).toBe("red");
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
it("uses the property name as storage key when no explicit key given", () => {
|
|
75
|
-
const { ctx, run } = fieldCtx("count");
|
|
76
|
-
Persisted<number>()(undefined, ctx);
|
|
77
|
-
|
|
78
|
-
const instance = new TestComponent();
|
|
79
|
-
(instance as unknown as Record<string, unknown>).count = 0;
|
|
80
|
-
run(instance);
|
|
81
|
-
|
|
82
|
-
(instance as unknown as Record<string, unknown>).count = 7;
|
|
83
|
-
expect(localStorage.getItem("count")).toBe("7");
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
it("returns separate values per instance", () => {
|
|
87
|
-
const { ctx: ctxA, run: runA } = fieldCtx("val");
|
|
88
|
-
Persisted<number>("valA")(undefined, ctxA);
|
|
89
|
-
|
|
90
|
-
const { ctx: ctxB, run: runB } = fieldCtx("val");
|
|
91
|
-
Persisted<number>("valB")(undefined, ctxB);
|
|
92
|
-
|
|
93
|
-
const a = new TestComponent();
|
|
94
|
-
(a as unknown as Record<string, unknown>).val = 1;
|
|
95
|
-
runA(a);
|
|
96
|
-
|
|
97
|
-
const b = new TestComponent();
|
|
98
|
-
(b as unknown as Record<string, unknown>).val = 2;
|
|
99
|
-
runB(b);
|
|
100
|
-
|
|
101
|
-
(a as unknown as Record<string, unknown>).val = 10;
|
|
102
|
-
(b as unknown as Record<string, unknown>).val = 20;
|
|
103
|
-
|
|
104
|
-
expect((a as unknown as Record<string, unknown>).val).toBe(10);
|
|
105
|
-
expect((b as unknown as Record<string, unknown>).val).toBe(20);
|
|
106
|
-
});
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
// ── Slot ──────────────────────────────────────────────────────────────────────
|
|
110
|
-
|
|
111
|
-
describe("Slot decorator", () => {
|
|
112
|
-
it("returns an empty array before initSlots is called", () => {
|
|
113
|
-
const { ctx, run } = fieldCtx("default");
|
|
114
|
-
Slot()(undefined, ctx);
|
|
115
|
-
|
|
116
|
-
const instance = new TestComponent();
|
|
117
|
-
run(instance);
|
|
118
|
-
|
|
119
|
-
expect((instance as unknown as Record<string, unknown>).default).toEqual([]);
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
it("returns default slot children after initSlots", () => {
|
|
123
|
-
const { ctx, run } = fieldCtx("default");
|
|
124
|
-
Slot()(undefined, ctx);
|
|
125
|
-
|
|
126
|
-
const instance = new TestComponent();
|
|
127
|
-
run(instance);
|
|
128
|
-
|
|
129
|
-
const el = document.createElement("span");
|
|
130
|
-
initSlots(instance, [el]);
|
|
131
|
-
|
|
132
|
-
expect((instance as unknown as Record<string, unknown>).default).toContain(el);
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
it("resolves named slot children", () => {
|
|
136
|
-
const { ctx, run } = fieldCtx("header");
|
|
137
|
-
Slot("header")(undefined, ctx);
|
|
138
|
-
|
|
139
|
-
const instance = new TestComponent();
|
|
140
|
-
run(instance);
|
|
141
|
-
|
|
142
|
-
const el = document.createElement("div");
|
|
143
|
-
el.setAttribute("slot", "header");
|
|
144
|
-
initSlots(instance, [el]);
|
|
145
|
-
|
|
146
|
-
const result = (instance as unknown as Record<string, unknown>).header as unknown[];
|
|
147
|
-
expect(result).toHaveLength(1);
|
|
148
|
-
expect(result[0]).toBe(el);
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
it("named slot element has slot attribute removed", () => {
|
|
152
|
-
const { ctx, run } = fieldCtx("footer");
|
|
153
|
-
Slot("footer")(undefined, ctx);
|
|
154
|
-
|
|
155
|
-
const instance = new TestComponent();
|
|
156
|
-
run(instance);
|
|
157
|
-
|
|
158
|
-
const el = document.createElement("div");
|
|
159
|
-
el.setAttribute("slot", "footer");
|
|
160
|
-
initSlots(instance, [el]);
|
|
161
|
-
|
|
162
|
-
expect(el.getAttribute("slot")).toBeNull();
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
it("warns when attempting to set a slot directly (dev mode)", () => {
|
|
166
|
-
const originalEnv = process.env.NODE_ENV;
|
|
167
|
-
process.env.NODE_ENV = "development";
|
|
168
|
-
|
|
169
|
-
const { ctx, run } = fieldCtx("content");
|
|
170
|
-
Slot("content")(undefined, ctx);
|
|
171
|
-
|
|
172
|
-
const instance = new TestComponent();
|
|
173
|
-
run(instance);
|
|
174
|
-
|
|
175
|
-
const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
176
|
-
(instance as unknown as Record<string, unknown>).content = ["something"];
|
|
177
|
-
expect(warn).toHaveBeenCalledWith(expect.stringContaining("[Slot]"));
|
|
178
|
-
warn.mockRestore();
|
|
179
|
-
|
|
180
|
-
process.env.NODE_ENV = originalEnv;
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
it("uses property name as slot name when no name given and prop is not 'default'", () => {
|
|
184
|
-
const { ctx, run } = fieldCtx("sidebar");
|
|
185
|
-
Slot()(undefined, ctx);
|
|
186
|
-
|
|
187
|
-
const instance = new TestComponent();
|
|
188
|
-
run(instance);
|
|
189
|
-
|
|
190
|
-
const el = document.createElement("aside");
|
|
191
|
-
el.setAttribute("slot", "sidebar");
|
|
192
|
-
initSlots(instance, [el]);
|
|
193
|
-
|
|
194
|
-
const result = (instance as unknown as Record<string, unknown>).sidebar as unknown[];
|
|
195
|
-
expect(result).toHaveLength(1);
|
|
196
|
-
});
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
// ── initSlots / getSlot helpers ───────────────────────────────────────────────
|
|
200
|
-
|
|
201
|
-
describe("initSlots / getSlot", () => {
|
|
202
|
-
it("splits children into named and default slots", () => {
|
|
203
|
-
const named = document.createElement("div");
|
|
204
|
-
named.setAttribute("slot", "header");
|
|
205
|
-
|
|
206
|
-
const plain = document.createElement("p");
|
|
207
|
-
|
|
208
|
-
const instance = {};
|
|
209
|
-
initSlots(instance, [named, plain]);
|
|
210
|
-
|
|
211
|
-
expect(getSlot(instance, "header")).toContain(named);
|
|
212
|
-
expect(getSlot(instance, "default")).toContain(plain);
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
it("handles null children gracefully", () => {
|
|
216
|
-
const instance = {};
|
|
217
|
-
initSlots(instance, null);
|
|
218
|
-
expect(getSlot(instance, "default")).toEqual([]);
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
it("flattens nested arrays", () => {
|
|
222
|
-
const a = document.createElement("span");
|
|
223
|
-
const b = document.createElement("span");
|
|
224
|
-
const instance = {};
|
|
225
|
-
initSlots(instance, [[a, b]]);
|
|
226
|
-
expect(getSlot(instance, "default")).toHaveLength(2);
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
it("returns empty array for unknown slot", () => {
|
|
230
|
-
const instance = {};
|
|
231
|
-
initSlots(instance, []);
|
|
232
|
-
expect(getSlot(instance, "nonexistent")).toEqual([]);
|
|
233
|
-
});
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
describe("Persisted decorator — unmount cleanup", () => {
|
|
237
|
-
function mountPersisted(name: string, key: string) {
|
|
238
|
-
const { ctx, run } = fieldCtx(name);
|
|
239
|
-
Persisted<string>(key)(undefined, ctx);
|
|
240
|
-
const instance = new TestComponent();
|
|
241
|
-
(instance as unknown as Record<string, unknown>)[name] = "initial";
|
|
242
|
-
run(instance);
|
|
243
|
-
return instance as unknown as Record<string, unknown> & { onUnmount?: () => void };
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
function storageEvent(key: string, newValue: string) {
|
|
247
|
-
window.dispatchEvent(new StorageEvent("storage", { key, newValue, storageArea: localStorage }));
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
it("keeps syncing other tabs while mounted", () => {
|
|
251
|
-
const instance = mountPersisted("a", "sync-key");
|
|
252
|
-
storageEvent("sync-key", '"remote"');
|
|
253
|
-
expect(instance.a).toBe("remote");
|
|
254
|
-
});
|
|
255
|
-
|
|
256
|
-
it("stops listening for storage events after unmount", () => {
|
|
257
|
-
const instance = mountPersisted("a", "gone-key");
|
|
258
|
-
instance.onUnmount?.();
|
|
259
|
-
storageEvent("gone-key", '"remote"');
|
|
260
|
-
expect(instance.a).toBe("initial");
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
it("repeated mount/unmount cycles do not accumulate window listeners", () => {
|
|
264
|
-
const add = vi.spyOn(window, "addEventListener");
|
|
265
|
-
const remove = vi.spyOn(window, "removeEventListener");
|
|
266
|
-
for (let i = 0; i < 5; i++) mountPersisted("a", "cycle-key").onUnmount?.();
|
|
267
|
-
const added = add.mock.calls.filter(([type]) => type === "storage").length;
|
|
268
|
-
const removed = remove.mock.calls.filter(([type]) => type === "storage").length;
|
|
269
|
-
expect(added).toBe(5);
|
|
270
|
-
expect(removed).toBe(5);
|
|
271
|
-
add.mockRestore();
|
|
272
|
-
remove.mockRestore();
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
it("two fields sharing a key on one instance share one signal", () => {
|
|
276
|
-
const first = fieldCtx("a");
|
|
277
|
-
const second = fieldCtx("b");
|
|
278
|
-
Persisted<string>("shared-key")(undefined, first.ctx);
|
|
279
|
-
Persisted<string>("shared-key")(undefined, second.ctx);
|
|
280
|
-
const instance = new TestComponent() as unknown as Record<string, unknown>;
|
|
281
|
-
instance.a = "x";
|
|
282
|
-
instance.b = "y";
|
|
283
|
-
first.run(instance);
|
|
284
|
-
second.run(instance);
|
|
285
|
-
instance.a = "changed";
|
|
286
|
-
expect(instance.b).toBe("changed");
|
|
287
|
-
});
|
|
288
|
-
});
|