mtrl-addons 0.2.2 → 0.2.4

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 (129) hide show
  1. package/{src/components/index.ts → dist/components/index.d.ts} +0 -2
  2. package/dist/components/vlist/config.d.ts +86 -0
  3. package/{src/components/vlist/constants.ts → dist/components/vlist/constants.d.ts} +10 -11
  4. package/dist/components/vlist/features/api.d.ts +7 -0
  5. package/{src/components/vlist/features/index.ts → dist/components/vlist/features/index.d.ts} +0 -2
  6. package/dist/components/vlist/features/selection.d.ts +6 -0
  7. package/dist/components/vlist/features/viewport.d.ts +9 -0
  8. package/dist/components/vlist/features.d.ts +31 -0
  9. package/{src/components/vlist/index.ts → dist/components/vlist/index.d.ts} +1 -10
  10. package/dist/components/vlist/types.d.ts +596 -0
  11. package/dist/components/vlist/vlist.d.ts +29 -0
  12. package/dist/core/compose/features/gestures/index.d.ts +86 -0
  13. package/dist/core/compose/features/gestures/longpress.d.ts +85 -0
  14. package/dist/core/compose/features/gestures/pan.d.ts +108 -0
  15. package/dist/core/compose/features/gestures/pinch.d.ts +111 -0
  16. package/dist/core/compose/features/gestures/rotate.d.ts +111 -0
  17. package/dist/core/compose/features/gestures/swipe.d.ts +149 -0
  18. package/dist/core/compose/features/gestures/tap.d.ts +79 -0
  19. package/{src/core/compose/features/index.ts → dist/core/compose/features/index.d.ts} +1 -2
  20. package/{src/core/compose/index.ts → dist/core/compose/index.d.ts} +2 -11
  21. package/{src/core/gestures/index.ts → dist/core/gestures/index.d.ts} +1 -20
  22. package/dist/core/gestures/longpress.d.ts +23 -0
  23. package/dist/core/gestures/manager.d.ts +14 -0
  24. package/dist/core/gestures/pan.d.ts +12 -0
  25. package/dist/core/gestures/pinch.d.ts +14 -0
  26. package/dist/core/gestures/rotate.d.ts +14 -0
  27. package/dist/core/gestures/swipe.d.ts +20 -0
  28. package/dist/core/gestures/tap.d.ts +12 -0
  29. package/dist/core/gestures/types.d.ts +320 -0
  30. package/dist/core/gestures/utils.d.ts +57 -0
  31. package/dist/core/index.d.ts +13 -0
  32. package/dist/core/layout/config.d.ts +33 -0
  33. package/dist/core/layout/index.d.ts +51 -0
  34. package/dist/core/layout/jsx.d.ts +65 -0
  35. package/dist/core/layout/schema.d.ts +112 -0
  36. package/dist/core/layout/types.d.ts +69 -0
  37. package/dist/core/viewport/constants.d.ts +105 -0
  38. package/dist/core/viewport/features/base.d.ts +14 -0
  39. package/dist/core/viewport/features/collection.d.ts +41 -0
  40. package/dist/core/viewport/features/events.d.ts +13 -0
  41. package/{src/core/viewport/features/index.ts → dist/core/viewport/features/index.d.ts} +0 -7
  42. package/dist/core/viewport/features/item-size.d.ts +30 -0
  43. package/dist/core/viewport/features/loading.d.ts +34 -0
  44. package/dist/core/viewport/features/momentum.d.ts +17 -0
  45. package/dist/core/viewport/features/performance.d.ts +53 -0
  46. package/dist/core/viewport/features/placeholders.d.ts +38 -0
  47. package/dist/core/viewport/features/rendering.d.ts +16 -0
  48. package/dist/core/viewport/features/scrollbar.d.ts +26 -0
  49. package/dist/core/viewport/features/scrolling.d.ts +16 -0
  50. package/dist/core/viewport/features/utils.d.ts +43 -0
  51. package/dist/core/viewport/features/virtual.d.ts +18 -0
  52. package/{src/core/viewport/index.ts → dist/core/viewport/index.d.ts} +1 -17
  53. package/dist/core/viewport/types.d.ts +96 -0
  54. package/dist/core/viewport/utils/speed-tracker.d.ts +22 -0
  55. package/dist/core/viewport/viewport.d.ts +11 -0
  56. package/{src/index.ts → dist/index.d.ts} +0 -4
  57. package/dist/index.js +5143 -0
  58. package/dist/index.mjs +5111 -0
  59. package/dist/styles.css +254 -0
  60. package/dist/styles.css.map +1 -0
  61. package/package.json +16 -2
  62. package/.cursorrules +0 -117
  63. package/AI.md +0 -39
  64. package/CLAUDE.md +0 -882
  65. package/build.js +0 -377
  66. package/index.ts +0 -7
  67. package/scripts/analyze-orphaned-functions.ts +0 -387
  68. package/scripts/debug/vlist-selection.ts +0 -121
  69. package/src/components/vlist/config.ts +0 -323
  70. package/src/components/vlist/features/api.ts +0 -626
  71. package/src/components/vlist/features/selection.ts +0 -436
  72. package/src/components/vlist/features/viewport.ts +0 -59
  73. package/src/components/vlist/features.ts +0 -112
  74. package/src/components/vlist/types.ts +0 -723
  75. package/src/components/vlist/vlist.ts +0 -92
  76. package/src/core/compose/features/gestures/index.ts +0 -227
  77. package/src/core/compose/features/gestures/longpress.ts +0 -383
  78. package/src/core/compose/features/gestures/pan.ts +0 -424
  79. package/src/core/compose/features/gestures/pinch.ts +0 -475
  80. package/src/core/compose/features/gestures/rotate.ts +0 -485
  81. package/src/core/compose/features/gestures/swipe.ts +0 -492
  82. package/src/core/compose/features/gestures/tap.ts +0 -334
  83. package/src/core/gestures/longpress.ts +0 -68
  84. package/src/core/gestures/manager.ts +0 -418
  85. package/src/core/gestures/pan.ts +0 -48
  86. package/src/core/gestures/pinch.ts +0 -58
  87. package/src/core/gestures/rotate.ts +0 -58
  88. package/src/core/gestures/swipe.ts +0 -66
  89. package/src/core/gestures/tap.ts +0 -45
  90. package/src/core/gestures/types.ts +0 -387
  91. package/src/core/gestures/utils.ts +0 -128
  92. package/src/core/index.ts +0 -43
  93. package/src/core/layout/config.ts +0 -102
  94. package/src/core/layout/index.ts +0 -168
  95. package/src/core/layout/jsx.ts +0 -174
  96. package/src/core/layout/schema.ts +0 -1044
  97. package/src/core/layout/types.ts +0 -95
  98. package/src/core/viewport/constants.ts +0 -145
  99. package/src/core/viewport/features/base.ts +0 -73
  100. package/src/core/viewport/features/collection.ts +0 -1182
  101. package/src/core/viewport/features/events.ts +0 -130
  102. package/src/core/viewport/features/item-size.ts +0 -271
  103. package/src/core/viewport/features/loading.ts +0 -263
  104. package/src/core/viewport/features/momentum.ts +0 -269
  105. package/src/core/viewport/features/performance.ts +0 -161
  106. package/src/core/viewport/features/placeholders.ts +0 -335
  107. package/src/core/viewport/features/rendering.ts +0 -962
  108. package/src/core/viewport/features/scrollbar.ts +0 -434
  109. package/src/core/viewport/features/scrolling.ts +0 -634
  110. package/src/core/viewport/features/utils.ts +0 -94
  111. package/src/core/viewport/features/virtual.ts +0 -525
  112. package/src/core/viewport/types.ts +0 -133
  113. package/src/core/viewport/utils/speed-tracker.ts +0 -79
  114. package/src/core/viewport/viewport.ts +0 -265
  115. package/test/benchmarks/layout/advanced.test.ts +0 -656
  116. package/test/benchmarks/layout/comparison.test.ts +0 -519
  117. package/test/benchmarks/layout/performance-comparison.test.ts +0 -274
  118. package/test/benchmarks/layout/real-components.test.ts +0 -733
  119. package/test/benchmarks/layout/simple.test.ts +0 -321
  120. package/test/benchmarks/layout/stress.test.ts +0 -990
  121. package/test/collection/basic.test.ts +0 -304
  122. package/test/components/vlist-selection.test.ts +0 -240
  123. package/test/components/vlist.test.ts +0 -63
  124. package/test/core/collection/adapter.test.ts +0 -161
  125. package/test/core/collection/collection.test.ts +0 -394
  126. package/test/core/layout/layout.test.ts +0 -201
  127. package/test/utils/dom-helpers.ts +0 -275
  128. package/test/utils/performance-helpers.ts +0 -392
  129. package/tsconfig.json +0 -20
@@ -1,161 +0,0 @@
1
- // test/core/collection/adapter.test.ts
2
-
3
- import { describe, test, expect, beforeEach } from "bun:test";
4
- import {
5
- createRouteAdapter,
6
- withRouteAdapter,
7
- } from "../../../src/core/collection/features/adapter";
8
- import { createCollection } from "../../../src/core/collection";
9
-
10
- describe("Route Adapter", () => {
11
- let fetchMock: any;
12
-
13
- beforeEach(() => {
14
- // Mock fetch
15
- fetchMock = {
16
- calls: [] as any[],
17
- response: {
18
- items: [
19
- { id: "1", name: "Item 1" },
20
- { id: "2", name: "Item 2" },
21
- ],
22
- meta: {
23
- total: 100,
24
- hasNext: true,
25
- cursor: "next-cursor",
26
- },
27
- },
28
- };
29
-
30
- global.fetch = async (url: any, options: any) => {
31
- fetchMock.calls.push({ url, options });
32
- return {
33
- ok: true,
34
- headers: {
35
- get: () => "application/json",
36
- },
37
- json: async () => fetchMock.response,
38
- } as any;
39
- };
40
- });
41
-
42
- describe("createRouteAdapter", () => {
43
- test("creates adapter with default config", () => {
44
- const adapter = createRouteAdapter();
45
- expect(adapter).toBeDefined();
46
- expect(adapter.read).toBeDefined();
47
- expect(adapter.disconnect).toBeDefined();
48
- });
49
-
50
- test("makes API request with correct parameters", async () => {
51
- const adapter = createRouteAdapter({
52
- base: "/api",
53
- endpoints: { list: "/users" },
54
- headers: { Authorization: "Bearer token" },
55
- pagination: { strategy: "offset" }, // Use offset strategy for this test
56
- });
57
-
58
- const result = await adapter.read({
59
- offset: 0,
60
- limit: 20,
61
- search: "john",
62
- sort: "name",
63
- });
64
-
65
- expect(fetchMock.calls).toHaveLength(1);
66
- const [call] = fetchMock.calls;
67
- expect(call.url).toContain("/api/users");
68
- expect(call.url).toContain("offset=0");
69
- expect(call.url).toContain("limit=20");
70
- expect(call.url).toContain("search=john");
71
- expect(call.url).toContain("sort=name");
72
- expect(call.options.headers["Authorization"]).toBe("Bearer token");
73
- });
74
-
75
- test("handles different pagination strategies", async () => {
76
- // Cursor pagination
77
- const cursorAdapter = createRouteAdapter({
78
- base: "/api",
79
- endpoints: { list: "/items" },
80
- pagination: { strategy: "cursor" },
81
- });
82
-
83
- await cursorAdapter.read({ cursor: "abc123", limit: 10 });
84
- expect(fetchMock.calls[0].url).toContain("cursor=abc123");
85
-
86
- // Page pagination
87
- const pageAdapter = createRouteAdapter({
88
- base: "/api",
89
- endpoints: { list: "/items" },
90
- pagination: { strategy: "page" },
91
- });
92
-
93
- await pageAdapter.read({ page: 3, limit: 10 });
94
- expect(fetchMock.calls[1].url).toContain("page=3");
95
- });
96
-
97
- test("transforms query operators", async () => {
98
- const adapter = createRouteAdapter({
99
- base: "/api",
100
- endpoints: { list: "/items" },
101
- });
102
-
103
- await adapter.read({
104
- filters: {
105
- age: { GT: 18, LTE: 65 },
106
- status: { EQ: "active" },
107
- tags: { IN: ["premium", "verified"] },
108
- },
109
- });
110
-
111
- const url = fetchMock.calls[0].url;
112
- expect(url).toContain("age_gt=18");
113
- expect(url).toContain("age_lte=65");
114
- expect(url).toContain("status_eq=active");
115
- expect(url).toContain("tags_in=premium");
116
- expect(url).toContain("tags_in=verified");
117
- });
118
-
119
- test("handles caching", async () => {
120
- const adapter = createRouteAdapter({
121
- base: "/api",
122
- endpoints: { list: "/items" },
123
- cache: true,
124
- pagination: { strategy: "offset" }, // Use offset strategy to test offset params
125
- });
126
-
127
- // First call
128
- await adapter.read({ offset: 0, limit: 10 });
129
- expect(fetchMock.calls).toHaveLength(1);
130
-
131
- // Second call with same params - should use cache
132
- await adapter.read({ offset: 0, limit: 10 });
133
- expect(fetchMock.calls).toHaveLength(1);
134
-
135
- // Different params - should make new request
136
- await adapter.read({ offset: 10, limit: 10 });
137
- expect(fetchMock.calls).toHaveLength(2);
138
- });
139
- });
140
-
141
- describe("withRouteAdapter", () => {
142
- test("adds route adapter to collection", async () => {
143
- const collection = createCollection({
144
- pageSize: 20,
145
- });
146
-
147
- const enhancedCollection = withRouteAdapter({
148
- base: "/api",
149
- endpoints: { list: "/users" },
150
- })(collection);
151
-
152
- expect(enhancedCollection.disconnect).toBeDefined();
153
-
154
- // Load data
155
- await enhancedCollection.loadPage(1);
156
-
157
- expect(fetchMock.calls).toHaveLength(1);
158
- expect(fetchMock.calls[0].url).toContain("/api/users");
159
- });
160
- });
161
- });
@@ -1,394 +0,0 @@
1
- // test/core/collection/collection.test.ts - Core Collection Tests
2
- import {
3
- describe,
4
- test,
5
- expect,
6
- mock,
7
- beforeAll,
8
- afterAll,
9
- beforeEach,
10
- afterEach,
11
- } from "bun:test";
12
- import { JSDOM } from "jsdom";
13
-
14
- // Setup for DOM testing environment
15
- let dom: JSDOM;
16
- let window: Window;
17
- let document: Document;
18
- let originalGlobalDocument: any;
19
- let originalGlobalWindow: any;
20
-
21
- // Setup DOM environment before importing modules
22
- beforeAll(() => {
23
- // Create a new JSDOM instance
24
- dom = new JSDOM("<!DOCTYPE html><html><body></body></html>", {
25
- url: "http://localhost/",
26
- pretendToBeVisual: true,
27
- resources: "usable",
28
- });
29
-
30
- // Get window and document from jsdom
31
- window = dom.window as any;
32
- document = window.document;
33
-
34
- // Store original globals
35
- originalGlobalDocument = global.document;
36
- originalGlobalWindow = global.window;
37
-
38
- // Set globals to use jsdom
39
- global.document = document;
40
- global.window = window as any;
41
- global.Element = (window as any).Element;
42
- global.HTMLElement = (window as any).HTMLElement;
43
- global.DocumentFragment = (window as any).DocumentFragment;
44
- global.requestAnimationFrame = (window as any).requestAnimationFrame;
45
- global.cancelAnimationFrame = (window as any).cancelAnimationFrame;
46
-
47
- // Add missing DOM APIs
48
- global.getComputedStyle =
49
- (window as any).getComputedStyle ||
50
- (() => ({
51
- position: "static",
52
- getPropertyValue: () => "",
53
- }));
54
-
55
- // Add IntersectionObserver mock
56
- if (!(window as any).IntersectionObserver) {
57
- const IntersectionObserverMock = class {
58
- constructor() {}
59
- observe() {}
60
- disconnect() {}
61
- unobserve() {}
62
- };
63
- (window as any).IntersectionObserver = IntersectionObserverMock as any;
64
- (global as any).IntersectionObserver = IntersectionObserverMock as any;
65
- }
66
-
67
- // Add ResizeObserver mock
68
- if (!(window as any).ResizeObserver) {
69
- const ResizeObserverMock = class {
70
- constructor() {}
71
- observe() {}
72
- disconnect() {}
73
- unobserve() {}
74
- };
75
- (window as any).ResizeObserver = ResizeObserverMock as any;
76
- (global as any).ResizeObserver = ResizeObserverMock as any;
77
- }
78
- });
79
-
80
- afterAll(() => {
81
- // Restore original globals
82
- global.document = originalGlobalDocument;
83
- global.window = originalGlobalWindow;
84
-
85
- // Clean up jsdom
86
- window.close();
87
- });
88
-
89
- // Import the collection after DOM setup
90
- // TODO: Implement these imports as we build the system
91
- // import { createCollection, pipe, withEvents, withLifecycle } from "../../../src/core/collection";
92
-
93
- // Test data interfaces
94
- interface TestItem {
95
- id: string;
96
- name: string;
97
- email: string;
98
- age: number;
99
- active: boolean;
100
- }
101
-
102
- interface TestProduct {
103
- id: string;
104
- title: string;
105
- price: number;
106
- category: string;
107
- }
108
-
109
- // Helper functions for creating test data
110
- function createTestItem(
111
- id: string,
112
- overrides: Partial<TestItem> = {}
113
- ): TestItem {
114
- return {
115
- id,
116
- name: `User ${id}`,
117
- email: `user${id}@example.com`,
118
- age: 20 + parseInt(id),
119
- active: true,
120
- ...overrides,
121
- };
122
- }
123
-
124
- function createTestProduct(
125
- id: string,
126
- overrides: Partial<TestProduct> = {}
127
- ): TestProduct {
128
- return {
129
- id,
130
- title: `Product ${id}`,
131
- price: parseFloat(id) * 10,
132
- category: "electronics",
133
- ...overrides,
134
- };
135
- }
136
-
137
- // Mock template engine
138
- const mockTemplateEngine = {
139
- render: mock((template: any, data: any) => {
140
- const element = document.createElement("div");
141
- element.className = "test-item";
142
- element.setAttribute("data-id", data.id);
143
- element.innerHTML = `
144
- <div class="item-name">${data.name}</div>
145
- <div class="item-email">${data.email}</div>
146
- `;
147
- return element;
148
- }),
149
-
150
- compile: mock((template: any) => {
151
- return (data: any) => mockTemplateEngine.render(template, data);
152
- }),
153
- };
154
-
155
- // Mock adapter for data loading
156
- const mockAdapter = {
157
- read: mock(async (params: any) => {
158
- const page = params.page || 1;
159
- const limit = params.limit || params.per_page || 20;
160
- const startId = (page - 1) * limit + 1;
161
-
162
- const items: TestItem[] = [];
163
- for (let i = 0; i < limit; i++) {
164
- const id = startId + i;
165
- if (id <= 100) {
166
- items.push(createTestItem(id.toString()));
167
- }
168
- }
169
-
170
- return {
171
- items,
172
- meta: {
173
- total: 100,
174
- page,
175
- hasNext: page * limit < 100,
176
- nextCursor: items.length > 0 ? items[items.length - 1].id : null,
177
- },
178
- };
179
- }),
180
- };
181
-
182
- describe("Collection System", () => {
183
- let container: HTMLElement;
184
-
185
- beforeEach(() => {
186
- // Create fresh container for each test
187
- container = document.createElement("div");
188
- container.style.height = "400px";
189
- container.style.overflow = "auto";
190
- document.body.appendChild(container);
191
-
192
- // Reset mocks
193
- mockTemplateEngine.render.mockClear();
194
- mockTemplateEngine.compile.mockClear();
195
- mockAdapter.read.mockClear();
196
- });
197
-
198
- afterEach(() => {
199
- // Cleanup container
200
- if (container && container.parentNode) {
201
- container.parentNode.removeChild(container);
202
- }
203
- });
204
-
205
- describe("Basic Infrastructure", () => {
206
- test("DOM environment is properly set up", () => {
207
- expect(document).toBeDefined();
208
- expect(document.createElement).toBeDefined();
209
- expect(global.IntersectionObserver).toBeDefined();
210
- expect(global.ResizeObserver).toBeDefined();
211
- });
212
-
213
- test("test container is created correctly", () => {
214
- expect(container).toBeDefined();
215
- expect(container.style.height).toBe("400px");
216
- expect(container.style.overflow).toBe("auto");
217
- expect(container.parentNode).toBe(document.body);
218
- });
219
-
220
- test("test data helpers work correctly", () => {
221
- const item = createTestItem("123");
222
- expect(item.id).toBe("123");
223
- expect(item.name).toBe("User 123");
224
- expect(item.email).toBe("user123@example.com");
225
- expect(item.age).toBe(143);
226
- expect(item.active).toBe(true);
227
-
228
- const customItem = createTestItem("456", { name: "Custom User" });
229
- expect(customItem.name).toBe("Custom User");
230
- expect(customItem.id).toBe("456");
231
- });
232
-
233
- test("mock template engine renders correctly", () => {
234
- const template = { tag: "div", text: "{{name}}" };
235
- const data = { id: "1", name: "John Doe", email: "john@example.com" };
236
-
237
- const element = mockTemplateEngine.render(template, data);
238
-
239
- expect(element.tagName).toBe("DIV");
240
- expect(element.className).toBe("test-item");
241
- expect(element.getAttribute("data-id")).toBe("1");
242
- expect(element.querySelector(".item-name")?.textContent).toBe("John Doe");
243
- });
244
-
245
- test("mock adapter generates test data correctly", async () => {
246
- const result = await mockAdapter.read({ page: 1, per_page: 5 });
247
-
248
- expect(result.items).toHaveLength(5);
249
- expect(result.meta.total).toBe(100);
250
- expect(result.meta.page).toBe(1);
251
- expect(result.meta.hasNext).toBe(true);
252
-
253
- // Check first item
254
- expect(result.items[0].id).toBe("1");
255
- expect(result.items[0].name).toBe("User 1");
256
- });
257
- });
258
-
259
- describe("Collection Core (Placeholder)", () => {
260
- test("placeholder for collection creation", () => {
261
- // TODO: Implement when createCollection is available
262
- // const collection = createCollection({ items: [] });
263
- // expect(collection).toBeDefined();
264
-
265
- // Placeholder assertion
266
- expect(true).toBe(true);
267
- });
268
-
269
- test("placeholder for functional composition", () => {
270
- // TODO: Implement when pipe and features are available
271
- // const collection = pipe(
272
- // createCollection(config),
273
- // withEvents(),
274
- // withLifecycle()
275
- // );
276
- // expect(collection).toBeDefined();
277
-
278
- // Placeholder assertion
279
- expect(true).toBe(true);
280
- });
281
- });
282
-
283
- describe("Template Engine Integration (Placeholder)", () => {
284
- test("placeholder for template compilation", () => {
285
- // TODO: Implement when template engine is available
286
- // const engine = createTemplateEngine('object');
287
- // const template = { tag: 'div', text: '{{name}}' };
288
- // const compiled = engine.compile(template);
289
- // expect(compiled).toBeDefined();
290
-
291
- // Test mock for now
292
- const compiled = mockTemplateEngine.compile({
293
- tag: "div",
294
- text: "{{name}}",
295
- });
296
- expect(compiled).toBeDefined();
297
- expect(mockTemplateEngine.compile).toHaveBeenCalled();
298
- });
299
-
300
- test("placeholder for element recycling", () => {
301
- // TODO: Implement when recycling pool is available
302
- // const pool = createRecyclingPool({ maxSize: 10 });
303
- // const element = pool.getElement();
304
- // expect(element).toBeDefined();
305
-
306
- // Placeholder assertion
307
- expect(true).toBe(true);
308
- });
309
- });
310
-
311
- describe("Performance Testing Framework", () => {
312
- test("measures render time accurately", async () => {
313
- const start = performance.now();
314
-
315
- // Simulate some work
316
- await new Promise((resolve) => setTimeout(resolve, 10));
317
-
318
- const end = performance.now();
319
- const duration = end - start;
320
-
321
- expect(duration).toBeGreaterThan(5);
322
- expect(duration).toBeLessThan(50);
323
- });
324
-
325
- test("creates large datasets for performance testing", () => {
326
- const items = Array.from({ length: 1000 }, (_, i) =>
327
- createTestItem(i.toString())
328
- );
329
-
330
- expect(items).toHaveLength(1000);
331
- expect(items[0].id).toBe("0");
332
- expect(items[999].id).toBe("999");
333
- });
334
-
335
- test("simulates scroll events correctly", () => {
336
- let scrollEventFired = false;
337
-
338
- container.addEventListener("scroll", () => {
339
- scrollEventFired = true;
340
- });
341
-
342
- container.scrollTop = 100;
343
- const scrollEvent = new (window as any).Event("scroll", {
344
- bubbles: true,
345
- });
346
- container.dispatchEvent(scrollEvent);
347
-
348
- expect(scrollEventFired).toBe(true);
349
- expect(container.scrollTop).toBe(100);
350
- });
351
- });
352
-
353
- describe("Memory Management Testing", () => {
354
- test("cleans up event listeners", () => {
355
- const listener = mock(() => {});
356
-
357
- container.addEventListener("scroll", listener);
358
-
359
- // Simulate cleanup
360
- container.removeEventListener("scroll", listener);
361
-
362
- // Fire event - should not call listener
363
- const scrollEvent = new (window as any).Event("scroll", {
364
- bubbles: true,
365
- });
366
- container.dispatchEvent(scrollEvent);
367
-
368
- expect(listener).not.toHaveBeenCalled();
369
- });
370
-
371
- test("handles rapid element creation/destruction", () => {
372
- const elements: HTMLElement[] = [];
373
-
374
- // Create many elements
375
- for (let i = 0; i < 100; i++) {
376
- const element = document.createElement("div");
377
- element.textContent = `Item ${i}`;
378
- elements.push(element);
379
- }
380
-
381
- expect(elements).toHaveLength(100);
382
-
383
- // Clean up
384
- elements.forEach((element) => {
385
- element.remove();
386
- });
387
-
388
- expect(elements[0].isConnected).toBe(false);
389
- });
390
- });
391
- });
392
-
393
- // Export test utilities for use in other test files
394
- export { createTestItem, createTestProduct, mockTemplateEngine, mockAdapter };