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.
- package/{src/components/index.ts → dist/components/index.d.ts} +0 -2
- package/dist/components/vlist/config.d.ts +86 -0
- package/{src/components/vlist/constants.ts → dist/components/vlist/constants.d.ts} +10 -11
- package/dist/components/vlist/features/api.d.ts +7 -0
- package/{src/components/vlist/features/index.ts → dist/components/vlist/features/index.d.ts} +0 -2
- package/dist/components/vlist/features/selection.d.ts +6 -0
- package/dist/components/vlist/features/viewport.d.ts +9 -0
- package/dist/components/vlist/features.d.ts +31 -0
- package/{src/components/vlist/index.ts → dist/components/vlist/index.d.ts} +1 -10
- package/dist/components/vlist/types.d.ts +596 -0
- package/dist/components/vlist/vlist.d.ts +29 -0
- package/dist/core/compose/features/gestures/index.d.ts +86 -0
- package/dist/core/compose/features/gestures/longpress.d.ts +85 -0
- package/dist/core/compose/features/gestures/pan.d.ts +108 -0
- package/dist/core/compose/features/gestures/pinch.d.ts +111 -0
- package/dist/core/compose/features/gestures/rotate.d.ts +111 -0
- package/dist/core/compose/features/gestures/swipe.d.ts +149 -0
- package/dist/core/compose/features/gestures/tap.d.ts +79 -0
- package/{src/core/compose/features/index.ts → dist/core/compose/features/index.d.ts} +1 -2
- package/{src/core/compose/index.ts → dist/core/compose/index.d.ts} +2 -11
- package/{src/core/gestures/index.ts → dist/core/gestures/index.d.ts} +1 -20
- package/dist/core/gestures/longpress.d.ts +23 -0
- package/dist/core/gestures/manager.d.ts +14 -0
- package/dist/core/gestures/pan.d.ts +12 -0
- package/dist/core/gestures/pinch.d.ts +14 -0
- package/dist/core/gestures/rotate.d.ts +14 -0
- package/dist/core/gestures/swipe.d.ts +20 -0
- package/dist/core/gestures/tap.d.ts +12 -0
- package/dist/core/gestures/types.d.ts +320 -0
- package/dist/core/gestures/utils.d.ts +57 -0
- package/dist/core/index.d.ts +13 -0
- package/dist/core/layout/config.d.ts +33 -0
- package/dist/core/layout/index.d.ts +51 -0
- package/dist/core/layout/jsx.d.ts +65 -0
- package/dist/core/layout/schema.d.ts +112 -0
- package/dist/core/layout/types.d.ts +69 -0
- package/dist/core/viewport/constants.d.ts +105 -0
- package/dist/core/viewport/features/base.d.ts +14 -0
- package/dist/core/viewport/features/collection.d.ts +41 -0
- package/dist/core/viewport/features/events.d.ts +13 -0
- package/{src/core/viewport/features/index.ts → dist/core/viewport/features/index.d.ts} +0 -7
- package/dist/core/viewport/features/item-size.d.ts +30 -0
- package/dist/core/viewport/features/loading.d.ts +34 -0
- package/dist/core/viewport/features/momentum.d.ts +17 -0
- package/dist/core/viewport/features/performance.d.ts +53 -0
- package/dist/core/viewport/features/placeholders.d.ts +38 -0
- package/dist/core/viewport/features/rendering.d.ts +16 -0
- package/dist/core/viewport/features/scrollbar.d.ts +26 -0
- package/dist/core/viewport/features/scrolling.d.ts +16 -0
- package/dist/core/viewport/features/utils.d.ts +43 -0
- package/dist/core/viewport/features/virtual.d.ts +18 -0
- package/{src/core/viewport/index.ts → dist/core/viewport/index.d.ts} +1 -17
- package/dist/core/viewport/types.d.ts +96 -0
- package/dist/core/viewport/utils/speed-tracker.d.ts +22 -0
- package/dist/core/viewport/viewport.d.ts +11 -0
- package/{src/index.ts → dist/index.d.ts} +0 -4
- package/dist/index.js +5143 -0
- package/dist/index.mjs +5111 -0
- package/dist/styles.css +254 -0
- package/dist/styles.css.map +1 -0
- package/package.json +16 -2
- package/.cursorrules +0 -117
- package/AI.md +0 -39
- package/CLAUDE.md +0 -882
- package/build.js +0 -377
- package/index.ts +0 -7
- package/scripts/analyze-orphaned-functions.ts +0 -387
- package/scripts/debug/vlist-selection.ts +0 -121
- package/src/components/vlist/config.ts +0 -323
- package/src/components/vlist/features/api.ts +0 -626
- package/src/components/vlist/features/selection.ts +0 -436
- package/src/components/vlist/features/viewport.ts +0 -59
- package/src/components/vlist/features.ts +0 -112
- package/src/components/vlist/types.ts +0 -723
- package/src/components/vlist/vlist.ts +0 -92
- package/src/core/compose/features/gestures/index.ts +0 -227
- package/src/core/compose/features/gestures/longpress.ts +0 -383
- package/src/core/compose/features/gestures/pan.ts +0 -424
- package/src/core/compose/features/gestures/pinch.ts +0 -475
- package/src/core/compose/features/gestures/rotate.ts +0 -485
- package/src/core/compose/features/gestures/swipe.ts +0 -492
- package/src/core/compose/features/gestures/tap.ts +0 -334
- package/src/core/gestures/longpress.ts +0 -68
- package/src/core/gestures/manager.ts +0 -418
- package/src/core/gestures/pan.ts +0 -48
- package/src/core/gestures/pinch.ts +0 -58
- package/src/core/gestures/rotate.ts +0 -58
- package/src/core/gestures/swipe.ts +0 -66
- package/src/core/gestures/tap.ts +0 -45
- package/src/core/gestures/types.ts +0 -387
- package/src/core/gestures/utils.ts +0 -128
- package/src/core/index.ts +0 -43
- package/src/core/layout/config.ts +0 -102
- package/src/core/layout/index.ts +0 -168
- package/src/core/layout/jsx.ts +0 -174
- package/src/core/layout/schema.ts +0 -1044
- package/src/core/layout/types.ts +0 -95
- package/src/core/viewport/constants.ts +0 -145
- package/src/core/viewport/features/base.ts +0 -73
- package/src/core/viewport/features/collection.ts +0 -1182
- package/src/core/viewport/features/events.ts +0 -130
- package/src/core/viewport/features/item-size.ts +0 -271
- package/src/core/viewport/features/loading.ts +0 -263
- package/src/core/viewport/features/momentum.ts +0 -269
- package/src/core/viewport/features/performance.ts +0 -161
- package/src/core/viewport/features/placeholders.ts +0 -335
- package/src/core/viewport/features/rendering.ts +0 -962
- package/src/core/viewport/features/scrollbar.ts +0 -434
- package/src/core/viewport/features/scrolling.ts +0 -634
- package/src/core/viewport/features/utils.ts +0 -94
- package/src/core/viewport/features/virtual.ts +0 -525
- package/src/core/viewport/types.ts +0 -133
- package/src/core/viewport/utils/speed-tracker.ts +0 -79
- package/src/core/viewport/viewport.ts +0 -265
- package/test/benchmarks/layout/advanced.test.ts +0 -656
- package/test/benchmarks/layout/comparison.test.ts +0 -519
- package/test/benchmarks/layout/performance-comparison.test.ts +0 -274
- package/test/benchmarks/layout/real-components.test.ts +0 -733
- package/test/benchmarks/layout/simple.test.ts +0 -321
- package/test/benchmarks/layout/stress.test.ts +0 -990
- package/test/collection/basic.test.ts +0 -304
- package/test/components/vlist-selection.test.ts +0 -240
- package/test/components/vlist.test.ts +0 -63
- package/test/core/collection/adapter.test.ts +0 -161
- package/test/core/collection/collection.test.ts +0 -394
- package/test/core/layout/layout.test.ts +0 -201
- package/test/utils/dom-helpers.ts +0 -275
- package/test/utils/performance-helpers.ts +0 -392
- 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 };
|