@excom/renderable-element 0.1.0

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.
Files changed (40) hide show
  1. package/.rush/temp/chunked-rush-logs/renderable-element.apply-exports.chunks.jsonl +1 -0
  2. package/.rush/temp/chunked-rush-logs/renderable-element.build_docs.chunks.jsonl +1 -0
  3. package/.rush/temp/chunked-rush-logs/renderable-element.build_package-metas.chunks.jsonl +1 -0
  4. package/.rush/temp/operation/apply-exports/all.log +1 -0
  5. package/.rush/temp/operation/apply-exports/log-chunks.jsonl +1 -0
  6. package/.rush/temp/operation/apply-exports/state.json +3 -0
  7. package/.rush/temp/operation/build_docs/all.log +1 -0
  8. package/.rush/temp/operation/build_docs/log-chunks.jsonl +1 -0
  9. package/.rush/temp/operation/build_docs/state.json +3 -0
  10. package/.rush/temp/operation/build_package-metas/all.log +1 -0
  11. package/.rush/temp/operation/build_package-metas/log-chunks.jsonl +1 -0
  12. package/.rush/temp/operation/build_package-metas/state.json +3 -0
  13. package/.rush/temp/shrinkwrap-deps.json +3 -0
  14. package/config/rig.json +6 -0
  15. package/index.ts +638 -0
  16. package/package.json +48 -0
  17. package/rush-logs/renderable-element.apply-exports.cache.log +1 -0
  18. package/rush-logs/renderable-element.apply-exports.log +1 -0
  19. package/rush-logs/renderable-element.build_docs.cache.log +1 -0
  20. package/rush-logs/renderable-element.build_docs.log +1 -0
  21. package/rush-logs/renderable-element.build_package-metas.cache.log +1 -0
  22. package/rush-logs/renderable-element.build_package-metas.log +1 -0
  23. package/src/index.css +11 -0
  24. package/support/custom-elements.json +371 -0
  25. package/support/demos/host-iframe.html +26 -0
  26. package/support/demos/host-selector.html +29 -0
  27. package/support/demos/host-shadow.html +31 -0
  28. package/support/demos/persist-content.html +57 -0
  29. package/support/demos/render-event.html +66 -0
  30. package/support/dist-docs/renderable-element.md +499 -0
  31. package/support/docs/README.md +146 -0
  32. package/support/package-meta.json +206 -0
  33. package/support/tests/host-iframe.view.test.ts +22 -0
  34. package/support/tests/host-selector.view.test.ts +19 -0
  35. package/support/tests/host-shadow.view.test.ts +19 -0
  36. package/support/tests/persist-content.view.test.ts +31 -0
  37. package/support/tests/render-event.view.test.ts +24 -0
  38. package/support/tests/render-lifecycle.test.ts +961 -0
  39. package/support/tests/renderable-element.test.ts +222 -0
  40. package/tsconfig.json +5 -0
@@ -0,0 +1,222 @@
1
+ import { RenderableElement } from "../../index";
2
+ import {
3
+ afterEach,
4
+ describe,
5
+ expect,
6
+ fixture,
7
+ it,
8
+ vi,
9
+ wait,
10
+ waitForEvent,
11
+ } from "@excom/heft-rig/profiles/default/config/test-utils";
12
+ import { KitLogger } from "@excom/kit-logger";
13
+
14
+ const TAG = "renderable-element-test";
15
+ if (!customElements.get(TAG)) {
16
+ RenderableElement.define(TAG);
17
+ }
18
+
19
+ describe("RenderableElement", () => {
20
+ afterEach(() => {
21
+ document.body.innerHTML = "";
22
+ vi.restoreAllMocks();
23
+ KitLogger.unsuppress();
24
+ });
25
+
26
+ it("defines a custom element tag", () => {
27
+ expect(customElements.get(TAG)).toBeTruthy();
28
+ });
29
+
30
+ it("starts with default state", () => {
31
+ const el = fixture<any>(`<${TAG}></${TAG}>`);
32
+ expect(el).dom.to.equalTag(`<${TAG}></${TAG}>`);
33
+ expect(el._persistedTree).toBeFalsy();
34
+ });
35
+
36
+ it("resolves render promise handlers", () => {
37
+ const el = fixture<any>(`<${TAG}></${TAG}>`);
38
+ const resolve = vi.fn();
39
+ const reject = vi.fn();
40
+ el.readyPromiseObject = { resolve, reject, promise: Promise.resolve() };
41
+ el.tryCompleteReady("renderChildren");
42
+ expect(resolve).toHaveBeenCalled();
43
+ expect(reject).not.toHaveBeenCalled();
44
+ expect(el.readyPromiseObject).toBeNull();
45
+ });
46
+
47
+ it("tryCompleteReady is a no-op when no promise object", () => {
48
+ const el = fixture<any>(`<${TAG}></${TAG}>`);
49
+ el.readyPromiseObject = null;
50
+ el.tryCompleteReady("renderChildren");
51
+ expect(el.readyPromiseObject).toBeNull();
52
+ });
53
+
54
+ it("tryCompleteReady is a no-op for a non-responsible caller", () => {
55
+ const el = fixture<any>(`<${TAG}></${TAG}>`);
56
+ const resolve = vi.fn();
57
+ const reject = vi.fn();
58
+ el.readyPromiseObject = { resolve, reject, promise: Promise.resolve() };
59
+ el.tryCompleteReady("doProvision");
60
+ expect(resolve).not.toHaveBeenCalled();
61
+ expect(reject).not.toHaveBeenCalled();
62
+ expect(el.readyPromiseObject).toBeTruthy();
63
+ });
64
+
65
+ it("has default preFetch of lazy", () => {
66
+ const el = fixture<any>(`<${TAG}></${TAG}>`);
67
+ expect(el.preFetch).toBe("lazy");
68
+ });
69
+
70
+ it("accepts eager preFetch", () => {
71
+ KitLogger.suppress();
72
+ const el = fixture<any>(`<${TAG} pre-fetch="eager"></${TAG}>`);
73
+ expect(el.preFetch).toBe("eager");
74
+ });
75
+
76
+ it("renderChildren does nothing when no template content", () => {
77
+ const el = fixture<any>(`<${TAG}></${TAG}>`);
78
+ const result = el.renderChildren();
79
+ expect(result).toBeFalsy();
80
+ });
81
+
82
+ it("renders inline template content when isActive is set", async () => {
83
+ KitLogger.suppress();
84
+ const el = fixture<any>(
85
+ `<${TAG}><template><p>Hello</p></template></${TAG}>`,
86
+ );
87
+ el.isActive = true;
88
+ await wait(50);
89
+ expect(el.querySelector("p")?.textContent).toBe("Hello");
90
+ expect(el).dom.to.equalTag(
91
+ `<${TAG} is-active did-load></${TAG}>`,
92
+ );
93
+ // Without persist-content, the live tree is not retained on the element
94
+ expect(el._persistedTree).toBeFalsy();
95
+ });
96
+
97
+ it("removes rendered content when isActive is unset", async () => {
98
+ KitLogger.suppress();
99
+ const el = fixture<any>(
100
+ `<${TAG}><template><p>Temp</p></template></${TAG}>`,
101
+ );
102
+ el.isActive = true;
103
+ await wait(50);
104
+ expect(el.querySelector("p")).not.toBeNull();
105
+
106
+ el.isActive = false;
107
+ await wait(50);
108
+ expect(el.querySelector("p")).toBeNull();
109
+ // `did-load` stays set (warm re-resolve); no persisted live tree
110
+ expect(el).dom.to.equalTag(`<${TAG} did-load></${TAG}>`);
111
+ expect(el._persistedTree).toBeFalsy();
112
+ });
113
+
114
+ it("keeps didLoad but not _persistedTree when unrendered without persistContent", async () => {
115
+ KitLogger.suppress();
116
+ const el = fixture<any>(
117
+ `<${TAG}><template><span>X</span></template></${TAG}>`,
118
+ );
119
+ el.isActive = true;
120
+ await wait(50);
121
+ expect(el.didLoad).toBe(true);
122
+ expect(el._persistedTree).toBeFalsy();
123
+
124
+ el.isActive = false;
125
+ await wait(50);
126
+ expect(el.didLoad).toBe(true);
127
+ expect(el._persistedTree).toBeFalsy();
128
+
129
+ el.isActive = true;
130
+ await wait(50);
131
+ expect(el.querySelector("span")?.textContent).toBe("X");
132
+ expect(el._persistedTree).toBeFalsy();
133
+ });
134
+
135
+ it("retains live nodes on _persistedTree when persistContent is true", async () => {
136
+ KitLogger.suppress();
137
+ const el = fixture<any>(
138
+ `<${TAG} persist-content><template><span>Keep</span></template></${TAG}>`,
139
+ );
140
+ el.isActive = true;
141
+ await wait(50);
142
+ const live = el.querySelector("span");
143
+ expect(live).not.toBeNull();
144
+ expect(el._persistedTree).toBeTruthy();
145
+
146
+ el.isActive = false;
147
+ await wait(50);
148
+ expect(el.didLoad).toBe(true);
149
+ expect(el._persistedTree).toBeTruthy();
150
+
151
+ el.isActive = true;
152
+ await wait(50);
153
+ expect(el.querySelector("span")).toBe(live);
154
+ });
155
+
156
+ it("bypassCache defaults to false", () => {
157
+ const el = fixture<any>(`<${TAG}></${TAG}>`);
158
+ expect(el.bypassCache).toBeFalsy();
159
+ });
160
+
161
+ it("startReady creates a ready promise and tryCompleteReady resolves it", () => {
162
+ const el = fixture<any>(`<${TAG}></${TAG}>`);
163
+ el.startReady();
164
+ expect(el.readyPromiseObject).toBeTruthy();
165
+ const { promise, resolve, reject } = el.readyPromiseObject;
166
+ const resolveSpy = vi.fn(resolve);
167
+ const rejectSpy = vi.fn(reject);
168
+ el.readyPromiseObject = { promise, resolve: resolveSpy, reject: rejectSpy };
169
+ el.tryCompleteReady("renderChildren");
170
+ expect(resolveSpy).toHaveBeenCalled();
171
+ expect(rejectSpy).not.toHaveBeenCalled();
172
+ expect(el.readyPromiseObject).toBeNull();
173
+ });
174
+
175
+ it("startReady is a no-op when a ready promise already exists", () => {
176
+ const el = fixture<any>(`<${TAG}></${TAG}>`);
177
+ el.startReady();
178
+ const first = el.readyPromiseObject;
179
+ el.startReady();
180
+ expect(el.readyPromiseObject).toBe(first);
181
+ });
182
+
183
+ it("startTeardown rejects ready and emits aborted while loading", async () => {
184
+ KitLogger.suppress();
185
+ const el = fixture<any>(
186
+ `<${TAG}><template><p>X</p></template></${TAG}>`,
187
+ );
188
+ el.isLoading = true;
189
+ el.startReady();
190
+ const readyPromise = el.readyPromiseObject!.promise;
191
+ const aborted = waitForEvent(el, "aborted");
192
+ el.startTeardown();
193
+ await aborted;
194
+ await expect(readyPromise).rejects.toBeUndefined();
195
+ expect(el.isLoading).toBe(false);
196
+ expect(el.readyPromiseObject).toBeNull();
197
+ });
198
+
199
+ it("startTeardown unrenders painted content when idle", async () => {
200
+ KitLogger.suppress();
201
+ const el = fixture<any>(
202
+ `<${TAG}><template><p>Hi</p></template></${TAG}>`,
203
+ );
204
+ el.isActive = true;
205
+ await wait(50);
206
+ expect(el.querySelector("p")).not.toBeNull();
207
+
208
+ el.startTeardown();
209
+ await wait(0);
210
+ expect(el.querySelector("p")).toBeNull();
211
+ });
212
+
213
+ it("tryCompleteReady rejects when passed reject", async () => {
214
+ const el = fixture<any>(`<${TAG}></${TAG}>`);
215
+ el.startReady();
216
+ const readyPromise = el.readyPromiseObject!.promise;
217
+ el.tryCompleteReady("startTeardown", "reject");
218
+ await expect(readyPromise).rejects.toBeUndefined();
219
+ expect(el.readyPromiseObject).toBeNull();
220
+ });
221
+
222
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,5 @@
1
+ {
2
+ "extends": "@excom/heft-rig/profiles/default/config/tsconfig.json",
3
+ "include": ["./*.ts"],
4
+ "exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts"]
5
+ }