@useavalon/avalon 0.1.4 → 0.1.6
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/package.json +31 -58
- package/src/vite-plugin/plugin.ts +22 -4
- package/src/build/README.md +0 -310
- package/src/client/tests/css-hmr-handler.test.ts +0 -360
- package/src/client/tests/framework-adapter.test.ts +0 -519
- package/src/client/tests/hmr-coordinator.test.ts +0 -176
- package/src/client/tests/hydration-option-parsing.test.ts +0 -107
- package/src/client/tests/lit-adapter.test.ts +0 -427
- package/src/client/tests/preact-adapter.test.ts +0 -353
- package/src/client/tests/qwik-adapter.test.ts +0 -343
- package/src/client/tests/react-adapter.test.ts +0 -317
- package/src/client/tests/solid-adapter.test.ts +0 -396
- package/src/client/tests/svelte-adapter.test.ts +0 -387
- package/src/client/tests/vue-adapter.test.ts +0 -407
- package/src/components/tests/component-analyzer.test.ts +0 -96
- package/src/components/tests/component-detection.test.ts +0 -347
- package/src/components/tests/persistent-islands.test.ts +0 -398
- package/src/core/components/tests/enhanced-framework-detector.test.ts +0 -577
- package/src/core/components/tests/framework-registry.test.ts +0 -465
- package/src/core/integrations/README.md +0 -282
- package/src/core/layout/tests/enhanced-layout-resolver.test.ts +0 -477
- package/src/core/layout/tests/layout-cache-optimization.test.ts +0 -149
- package/src/core/layout/tests/layout-composer.test.ts +0 -486
- package/src/core/layout/tests/layout-data-loader.test.ts +0 -443
- package/src/core/layout/tests/layout-discovery.test.ts +0 -253
- package/src/core/layout/tests/layout-matcher.test.ts +0 -480
- package/src/core/modules/tests/framework-module-resolver.test.ts +0 -263
- package/src/core/modules/tests/module-resolution-integration.test.ts +0 -117
- package/src/islands/discovery/tests/island-discovery.test.ts +0 -881
- package/src/middleware/__tests__/discovery.test.ts +0 -107
- package/src/types/tests/layout-types.test.ts +0 -197
- package/src/vite-plugin/tests/image-optimization.test.ts +0 -54
|
@@ -1,480 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
-
import { LayoutMatcher, BuiltInLayoutRules } from '../layout-matcher.ts';
|
|
3
|
-
import type { LayoutRule, RouteInfo } from '../layout-types.ts';
|
|
4
|
-
|
|
5
|
-
// Helper function to create mock RouteInfo
|
|
6
|
-
function createMockRoute(path: string, method: string = 'GET', headers: Record<string, string> = {}): RouteInfo {
|
|
7
|
-
const headersObj = new Headers();
|
|
8
|
-
Object.entries(headers).forEach(([key, value]) => {
|
|
9
|
-
headersObj.set(key, value);
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
return {
|
|
13
|
-
path,
|
|
14
|
-
params: {},
|
|
15
|
-
method,
|
|
16
|
-
headers: headersObj,
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
describe('LayoutMatcher', () => {
|
|
21
|
-
let matcher: LayoutMatcher;
|
|
22
|
-
|
|
23
|
-
beforeEach(() => {
|
|
24
|
-
matcher = new LayoutMatcher({ developmentMode: false });
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
describe('Basic functionality', () => {
|
|
28
|
-
it('should apply layouts by default when no rules match', () => {
|
|
29
|
-
const route = createMockRoute('/home');
|
|
30
|
-
const result = matcher.shouldApplyLayout('/layouts/_layout.tsx', route);
|
|
31
|
-
expect(result).toEqual(true);
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it('should add custom rules', () => {
|
|
35
|
-
const customRule: LayoutRule = {
|
|
36
|
-
matches: () => true,
|
|
37
|
-
apply: false,
|
|
38
|
-
priority: 10,
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
matcher.addRule(customRule);
|
|
42
|
-
const rules = matcher.getRules();
|
|
43
|
-
|
|
44
|
-
expect(rules.length > 4).toEqual(true);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it('should remove rules', () => {
|
|
48
|
-
const customRule: LayoutRule = {
|
|
49
|
-
matches: () => true,
|
|
50
|
-
apply: false,
|
|
51
|
-
priority: 10,
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
matcher.addRule(customRule);
|
|
55
|
-
const initialCount = matcher.getRules().length;
|
|
56
|
-
|
|
57
|
-
matcher.removeRule(customRule);
|
|
58
|
-
const finalCount = matcher.getRules().length;
|
|
59
|
-
|
|
60
|
-
expect(finalCount).toEqual(initialCount - 1);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
it('should clear all rules', () => {
|
|
64
|
-
matcher.clearRules();
|
|
65
|
-
expect(matcher.getRules().length).toEqual(0);
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
it('should validate rule structure', () => {
|
|
69
|
-
expect(() => {
|
|
70
|
-
matcher.addRule({
|
|
71
|
-
matches: null as any,
|
|
72
|
-
apply: true,
|
|
73
|
-
priority: 10,
|
|
74
|
-
});
|
|
75
|
-
}).toThrow('Layout rule must have a valid matches function');
|
|
76
|
-
|
|
77
|
-
expect(() => {
|
|
78
|
-
matcher.addRule({
|
|
79
|
-
matches: () => true,
|
|
80
|
-
apply: 'true' as any,
|
|
81
|
-
priority: 10,
|
|
82
|
-
});
|
|
83
|
-
}).toThrow('Layout rule must have a boolean apply property');
|
|
84
|
-
|
|
85
|
-
expect(() => {
|
|
86
|
-
matcher.addRule({
|
|
87
|
-
matches: () => true,
|
|
88
|
-
apply: true,
|
|
89
|
-
priority: 'high' as any,
|
|
90
|
-
});
|
|
91
|
-
}).toThrow('Layout rule must have a numeric priority');
|
|
92
|
-
});
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
describe('Built-in rules', () => {
|
|
96
|
-
describe('API routes skip layouts', () => {
|
|
97
|
-
it('should skip layouts for API routes', () => {
|
|
98
|
-
const apiRoute = createMockRoute('/api/users');
|
|
99
|
-
const result = matcher.shouldApplyLayout('/layouts/_layout.tsx', apiRoute);
|
|
100
|
-
expect(result).toEqual(false);
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
it('should apply layouts for non-API routes', () => {
|
|
104
|
-
const regularRoute = createMockRoute('/users');
|
|
105
|
-
const result = matcher.shouldApplyLayout('/layouts/_layout.tsx', regularRoute);
|
|
106
|
-
expect(result).toEqual(true);
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
it('should skip layouts for nested API routes', () => {
|
|
110
|
-
const nestedApiRoute = createMockRoute('/api/v1/users/123');
|
|
111
|
-
const result = matcher.shouldApplyLayout('/layouts/_layout.tsx', nestedApiRoute);
|
|
112
|
-
expect(result).toEqual(false);
|
|
113
|
-
});
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
describe('Mobile layout detection', () => {
|
|
117
|
-
it('should apply mobile layouts for mobile user agents', () => {
|
|
118
|
-
const mobileRoute = createMockRoute('/home', 'GET', {
|
|
119
|
-
'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15',
|
|
120
|
-
});
|
|
121
|
-
const result = matcher.shouldApplyLayout('/layouts/mobile/_layout.tsx', mobileRoute);
|
|
122
|
-
expect(result).toEqual(true);
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
it('should skip mobile layouts for desktop user agents', () => {
|
|
126
|
-
const desktopRoute = createMockRoute('/home', 'GET', {
|
|
127
|
-
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
|
|
128
|
-
});
|
|
129
|
-
const result = matcher.shouldApplyLayout('/layouts/mobile/_layout.tsx', desktopRoute);
|
|
130
|
-
expect(result).toEqual(false);
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
it('should apply regular layouts for desktop user agents', () => {
|
|
134
|
-
const desktopRoute = createMockRoute('/home', 'GET', {
|
|
135
|
-
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
|
|
136
|
-
});
|
|
137
|
-
const result = matcher.shouldApplyLayout('/layouts/_layout.tsx', desktopRoute);
|
|
138
|
-
expect(result).toEqual(true);
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
it('should handle missing user agent gracefully', () => {
|
|
142
|
-
const route = createMockRoute('/home');
|
|
143
|
-
const result = matcher.shouldApplyLayout('/layouts/_layout.tsx', route);
|
|
144
|
-
expect(result).toEqual(true);
|
|
145
|
-
});
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
describe('Header-based skip', () => {
|
|
149
|
-
it('should skip layouts when X-Skip-Layout header is true', () => {
|
|
150
|
-
const route = createMockRoute('/home', 'GET', {
|
|
151
|
-
'x-skip-layout': 'true',
|
|
152
|
-
});
|
|
153
|
-
const result = matcher.shouldApplyLayout('/layouts/_layout.tsx', route);
|
|
154
|
-
expect(result).toEqual(false);
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
it('should skip layouts when X-Skip-Layout header is 1', () => {
|
|
158
|
-
const route = createMockRoute('/home', 'GET', {
|
|
159
|
-
'x-skip-layout': '1',
|
|
160
|
-
});
|
|
161
|
-
const result = matcher.shouldApplyLayout('/layouts/_layout.tsx', route);
|
|
162
|
-
expect(result).toEqual(false);
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
it('should apply layouts when X-Skip-Layout header is false', () => {
|
|
166
|
-
const route = createMockRoute('/home', 'GET', {
|
|
167
|
-
'x-skip-layout': 'false',
|
|
168
|
-
});
|
|
169
|
-
const result = matcher.shouldApplyLayout('/layouts/_layout.tsx', route);
|
|
170
|
-
expect(result).toEqual(true);
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
it('should apply layouts when X-Skip-Layout header is missing', () => {
|
|
174
|
-
const route = createMockRoute('/home');
|
|
175
|
-
const result = matcher.shouldApplyLayout('/layouts/_layout.tsx', route);
|
|
176
|
-
expect(result).toEqual(true);
|
|
177
|
-
});
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
describe('Admin layout restriction', () => {
|
|
181
|
-
it('should apply admin layouts to admin routes', () => {
|
|
182
|
-
const adminRoute = createMockRoute('/admin/dashboard');
|
|
183
|
-
const result = matcher.shouldApplyLayout('/layouts/admin/_layout.tsx', adminRoute);
|
|
184
|
-
expect(result).toEqual(true);
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
it('should not apply admin layouts to non-admin routes', () => {
|
|
188
|
-
const regularRoute = createMockRoute('/home');
|
|
189
|
-
const result = matcher.shouldApplyLayout('/layouts/admin/_layout.tsx', regularRoute);
|
|
190
|
-
expect(result).toEqual(false);
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
it('should apply regular layouts to any route', () => {
|
|
194
|
-
const adminRoute = createMockRoute('/admin/dashboard');
|
|
195
|
-
const regularRoute = createMockRoute('/home');
|
|
196
|
-
|
|
197
|
-
expect(matcher.shouldApplyLayout('/layouts/_layout.tsx', adminRoute)).toEqual(true);
|
|
198
|
-
expect(matcher.shouldApplyLayout('/layouts/_layout.tsx', regularRoute)).toEqual(true);
|
|
199
|
-
});
|
|
200
|
-
});
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
describe('Priority-based conflict resolution', () => {
|
|
204
|
-
beforeEach(() => {
|
|
205
|
-
matcher.clearRules();
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
it('should apply highest priority rule when rules conflict', () => {
|
|
209
|
-
const lowPriorityRule: LayoutRule = {
|
|
210
|
-
matches: () => true,
|
|
211
|
-
apply: true,
|
|
212
|
-
priority: 10,
|
|
213
|
-
};
|
|
214
|
-
|
|
215
|
-
const highPriorityRule: LayoutRule = {
|
|
216
|
-
matches: () => true,
|
|
217
|
-
apply: false,
|
|
218
|
-
priority: 100,
|
|
219
|
-
};
|
|
220
|
-
|
|
221
|
-
matcher.addRule(lowPriorityRule);
|
|
222
|
-
matcher.addRule(highPriorityRule);
|
|
223
|
-
|
|
224
|
-
const route = createMockRoute('/test');
|
|
225
|
-
const result = matcher.shouldApplyLayout('/layouts/_layout.tsx', route);
|
|
226
|
-
|
|
227
|
-
expect(result).toEqual(false);
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
it('should handle equal priority conflicts by preferring skip', () => {
|
|
231
|
-
const applyRule: LayoutRule = {
|
|
232
|
-
matches: () => true,
|
|
233
|
-
apply: true,
|
|
234
|
-
priority: 50,
|
|
235
|
-
};
|
|
236
|
-
|
|
237
|
-
const skipRule: LayoutRule = {
|
|
238
|
-
matches: () => true,
|
|
239
|
-
apply: false,
|
|
240
|
-
priority: 50,
|
|
241
|
-
};
|
|
242
|
-
|
|
243
|
-
matcher.addRule(applyRule);
|
|
244
|
-
matcher.addRule(skipRule);
|
|
245
|
-
|
|
246
|
-
const route = createMockRoute('/test');
|
|
247
|
-
const result = matcher.shouldApplyLayout('/layouts/_layout.tsx', route);
|
|
248
|
-
|
|
249
|
-
expect(result).toEqual(false);
|
|
250
|
-
});
|
|
251
|
-
|
|
252
|
-
it('should apply majority rule when multiple equal priority rules exist', () => {
|
|
253
|
-
const applyRule1: LayoutRule = {
|
|
254
|
-
matches: () => true,
|
|
255
|
-
apply: true,
|
|
256
|
-
priority: 50,
|
|
257
|
-
};
|
|
258
|
-
|
|
259
|
-
const applyRule2: LayoutRule = {
|
|
260
|
-
matches: () => true,
|
|
261
|
-
apply: true,
|
|
262
|
-
priority: 50,
|
|
263
|
-
};
|
|
264
|
-
|
|
265
|
-
const skipRule: LayoutRule = {
|
|
266
|
-
matches: () => true,
|
|
267
|
-
apply: false,
|
|
268
|
-
priority: 50,
|
|
269
|
-
};
|
|
270
|
-
|
|
271
|
-
matcher.addRule(applyRule1);
|
|
272
|
-
matcher.addRule(applyRule2);
|
|
273
|
-
matcher.addRule(skipRule);
|
|
274
|
-
|
|
275
|
-
const route = createMockRoute('/test');
|
|
276
|
-
const result = matcher.shouldApplyLayout('/layouts/_layout.tsx', route);
|
|
277
|
-
|
|
278
|
-
expect(result).toEqual(true);
|
|
279
|
-
});
|
|
280
|
-
});
|
|
281
|
-
|
|
282
|
-
describe('Custom rule creation helpers', () => {
|
|
283
|
-
it('should create custom rules', () => {
|
|
284
|
-
const rule = LayoutMatcher.createCustomRule(route => route.path === '/test', false, 25);
|
|
285
|
-
|
|
286
|
-
expect(rule.apply).toEqual(false);
|
|
287
|
-
expect(rule.priority).toEqual(25);
|
|
288
|
-
expect(rule.matches(createMockRoute('/test'))).toEqual(true);
|
|
289
|
-
expect(rule.matches(createMockRoute('/other'))).toEqual(false);
|
|
290
|
-
});
|
|
291
|
-
|
|
292
|
-
it('should create path-based rules with string patterns', () => {
|
|
293
|
-
const rule = LayoutMatcher.createPathRule('/admin', false, 30);
|
|
294
|
-
|
|
295
|
-
expect(rule.apply).toEqual(false);
|
|
296
|
-
expect(rule.priority).toEqual(30);
|
|
297
|
-
expect(rule.matches(createMockRoute('/admin/users'))).toEqual(true);
|
|
298
|
-
expect(rule.matches(createMockRoute('/users'))).toEqual(false);
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
it('should create path-based rules with regex patterns', () => {
|
|
302
|
-
const rule = LayoutMatcher.createPathRule(/^\/api\/v\d+/, false, 40);
|
|
303
|
-
|
|
304
|
-
expect(rule.apply).toEqual(false);
|
|
305
|
-
expect(rule.priority).toEqual(40);
|
|
306
|
-
expect(rule.matches(createMockRoute('/api/v1/users'))).toEqual(true);
|
|
307
|
-
expect(rule.matches(createMockRoute('/api/v2/posts'))).toEqual(true);
|
|
308
|
-
expect(rule.matches(createMockRoute('/api/users'))).toEqual(false);
|
|
309
|
-
});
|
|
310
|
-
|
|
311
|
-
it('should create header-based rules with string values', () => {
|
|
312
|
-
const rule = LayoutMatcher.createHeaderRule('x-api-version', 'v2', true, 20);
|
|
313
|
-
|
|
314
|
-
expect(rule.apply).toEqual(true);
|
|
315
|
-
expect(rule.priority).toEqual(20);
|
|
316
|
-
expect(rule.matches(createMockRoute('/test', 'GET', { 'x-api-version': 'v2' }))).toEqual(true);
|
|
317
|
-
expect(rule.matches(createMockRoute('/test', 'GET', { 'x-api-version': 'v1' }))).toEqual(false);
|
|
318
|
-
});
|
|
319
|
-
|
|
320
|
-
it('should create header-based rules with regex values', () => {
|
|
321
|
-
const rule = LayoutMatcher.createHeaderRule('authorization', /^Bearer /, true, 35);
|
|
322
|
-
|
|
323
|
-
expect(rule.apply).toEqual(true);
|
|
324
|
-
expect(rule.priority).toEqual(35);
|
|
325
|
-
expect(rule.matches(createMockRoute('/test', 'GET', { authorization: 'Bearer token123' }))).toEqual(true);
|
|
326
|
-
expect(rule.matches(createMockRoute('/test', 'GET', { authorization: 'Basic dXNlcjpwYXNz' }))).toEqual(false);
|
|
327
|
-
});
|
|
328
|
-
|
|
329
|
-
it('should create method-based rules with single method', () => {
|
|
330
|
-
const rule = LayoutMatcher.createMethodRule('POST', false, 15);
|
|
331
|
-
|
|
332
|
-
expect(rule.apply).toEqual(false);
|
|
333
|
-
expect(rule.priority).toEqual(15);
|
|
334
|
-
expect(rule.matches(createMockRoute('/test', 'POST'))).toEqual(true);
|
|
335
|
-
expect(rule.matches(createMockRoute('/test', 'GET'))).toEqual(false);
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
it('should create method-based rules with multiple methods', () => {
|
|
339
|
-
const rule = LayoutMatcher.createMethodRule(['POST', 'PUT', 'DELETE'], false, 25);
|
|
340
|
-
|
|
341
|
-
expect(rule.apply).toEqual(false);
|
|
342
|
-
expect(rule.priority).toEqual(25);
|
|
343
|
-
expect(rule.matches(createMockRoute('/test', 'POST'))).toEqual(true);
|
|
344
|
-
expect(rule.matches(createMockRoute('/test', 'PUT'))).toEqual(true);
|
|
345
|
-
expect(rule.matches(createMockRoute('/test', 'DELETE'))).toEqual(true);
|
|
346
|
-
expect(rule.matches(createMockRoute('/test', 'GET'))).toEqual(false);
|
|
347
|
-
});
|
|
348
|
-
|
|
349
|
-
it('should handle case-insensitive method matching', () => {
|
|
350
|
-
const rule = LayoutMatcher.createMethodRule('post', false, 15);
|
|
351
|
-
|
|
352
|
-
expect(rule.matches(createMockRoute('/test', 'POST'))).toEqual(true);
|
|
353
|
-
expect(rule.matches(createMockRoute('/test', 'post'))).toEqual(true);
|
|
354
|
-
});
|
|
355
|
-
});
|
|
356
|
-
|
|
357
|
-
describe('Debug information', () => {
|
|
358
|
-
beforeEach(() => {
|
|
359
|
-
matcher.clearRules();
|
|
360
|
-
});
|
|
361
|
-
|
|
362
|
-
it('should provide debug information', () => {
|
|
363
|
-
const rule1: LayoutRule = {
|
|
364
|
-
matches: () => true,
|
|
365
|
-
apply: true,
|
|
366
|
-
priority: 10,
|
|
367
|
-
};
|
|
368
|
-
|
|
369
|
-
const rule2: LayoutRule = {
|
|
370
|
-
matches: () => false,
|
|
371
|
-
apply: false,
|
|
372
|
-
priority: 20,
|
|
373
|
-
};
|
|
374
|
-
|
|
375
|
-
matcher.addRule(rule1);
|
|
376
|
-
matcher.addRule(rule2);
|
|
377
|
-
|
|
378
|
-
const route = createMockRoute('/test');
|
|
379
|
-
const debugInfo = matcher.getDebugInfo('/layout.tsx', route);
|
|
380
|
-
|
|
381
|
-
expect(debugInfo.totalRules).toEqual(2);
|
|
382
|
-
expect(debugInfo.matchingRules.length).toEqual(1);
|
|
383
|
-
expect(debugInfo.matchingRules[0].priority).toEqual(10);
|
|
384
|
-
expect(debugInfo.matchingRules[0].apply).toEqual(true);
|
|
385
|
-
expect(debugInfo.finalDecision).toEqual(true);
|
|
386
|
-
expect(debugInfo.conflictResolution).toEqual('single-rule');
|
|
387
|
-
});
|
|
388
|
-
|
|
389
|
-
it('should indicate conflict resolution when multiple rules match', () => {
|
|
390
|
-
const rule1: LayoutRule = {
|
|
391
|
-
matches: () => true,
|
|
392
|
-
apply: true,
|
|
393
|
-
priority: 10,
|
|
394
|
-
};
|
|
395
|
-
|
|
396
|
-
const rule2: LayoutRule = {
|
|
397
|
-
matches: () => true,
|
|
398
|
-
apply: false,
|
|
399
|
-
priority: 20,
|
|
400
|
-
};
|
|
401
|
-
|
|
402
|
-
matcher.addRule(rule1);
|
|
403
|
-
matcher.addRule(rule2);
|
|
404
|
-
|
|
405
|
-
const route = createMockRoute('/test');
|
|
406
|
-
const debugInfo = matcher.getDebugInfo('/layout.tsx', route);
|
|
407
|
-
|
|
408
|
-
expect(debugInfo.totalRules).toEqual(2);
|
|
409
|
-
expect(debugInfo.matchingRules.length).toEqual(2);
|
|
410
|
-
expect(debugInfo.conflictResolution).toEqual('priority-based');
|
|
411
|
-
});
|
|
412
|
-
});
|
|
413
|
-
|
|
414
|
-
describe('Error handling', () => {
|
|
415
|
-
it('should handle rule evaluation errors gracefully', () => {
|
|
416
|
-
const faultyRule: LayoutRule = {
|
|
417
|
-
matches: () => {
|
|
418
|
-
throw new Error('Rule evaluation failed');
|
|
419
|
-
},
|
|
420
|
-
apply: false,
|
|
421
|
-
priority: 10,
|
|
422
|
-
};
|
|
423
|
-
|
|
424
|
-
matcher.addRule(faultyRule);
|
|
425
|
-
|
|
426
|
-
const route = createMockRoute('/test');
|
|
427
|
-
const result = matcher.shouldApplyLayout('/layout.tsx', route);
|
|
428
|
-
expect(result).toEqual(true);
|
|
429
|
-
});
|
|
430
|
-
|
|
431
|
-
it('should continue with other rules when one fails', () => {
|
|
432
|
-
const faultyRule: LayoutRule = {
|
|
433
|
-
matches: () => {
|
|
434
|
-
throw new Error('Rule evaluation failed');
|
|
435
|
-
},
|
|
436
|
-
apply: false,
|
|
437
|
-
priority: 10,
|
|
438
|
-
};
|
|
439
|
-
|
|
440
|
-
const workingRule: LayoutRule = {
|
|
441
|
-
matches: () => true,
|
|
442
|
-
apply: false,
|
|
443
|
-
priority: 20,
|
|
444
|
-
};
|
|
445
|
-
|
|
446
|
-
matcher.addRule(faultyRule);
|
|
447
|
-
matcher.addRule(workingRule);
|
|
448
|
-
|
|
449
|
-
const route = createMockRoute('/test');
|
|
450
|
-
const result = matcher.shouldApplyLayout('/layout.tsx', route);
|
|
451
|
-
|
|
452
|
-
expect(result).toEqual(false);
|
|
453
|
-
});
|
|
454
|
-
});
|
|
455
|
-
|
|
456
|
-
describe('Built-in rules access', () => {
|
|
457
|
-
it('should provide access to all built-in rules', () => {
|
|
458
|
-
const builtInRules = BuiltInLayoutRules.getAllRules();
|
|
459
|
-
expect(builtInRules.length).toEqual(4);
|
|
460
|
-
|
|
461
|
-
const priorities = builtInRules.map(rule => rule.priority);
|
|
462
|
-
expect(priorities.includes(100)).toEqual(true);
|
|
463
|
-
expect(priorities.includes(90)).toEqual(true);
|
|
464
|
-
expect(priorities.includes(60)).toEqual(true);
|
|
465
|
-
expect(priorities.includes(50)).toEqual(true);
|
|
466
|
-
});
|
|
467
|
-
|
|
468
|
-
it('should have API routes rule with highest priority', () => {
|
|
469
|
-
const apiRule = BuiltInLayoutRules.API_ROUTES_SKIP_LAYOUTS;
|
|
470
|
-
expect(apiRule.priority).toEqual(100);
|
|
471
|
-
expect(apiRule.apply).toEqual(false);
|
|
472
|
-
});
|
|
473
|
-
|
|
474
|
-
it('should have mobile detection rule with medium priority', () => {
|
|
475
|
-
const mobileRule = BuiltInLayoutRules.MOBILE_LAYOUT_DETECTION;
|
|
476
|
-
expect(mobileRule.priority).toEqual(50);
|
|
477
|
-
expect(mobileRule.apply).toEqual(false);
|
|
478
|
-
});
|
|
479
|
-
});
|
|
480
|
-
});
|