create-elit 3.3.2 → 3.3.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/dist/templates/README.md +1 -0
- package/dist/templates/elit.config.ts +16 -0
- package/dist/templates/package.json +4 -1
- package/dist/templates/src/client.test.ts +292 -0
- package/dist/templates/src/components/Footer.test.ts +226 -0
- package/dist/templates/src/components/Header.test.ts +493 -0
- package/dist/templates/src/pages/ChatListPage.test.ts +603 -0
- package/dist/templates/src/pages/ChatPage.test.ts +530 -0
- package/dist/templates/src/pages/ForgotPasswordPage.test.ts +484 -0
- package/dist/templates/src/pages/HomePage.test.ts +601 -0
- package/dist/templates/src/pages/LoginPage.test.ts +619 -0
- package/dist/templates/src/pages/PrivateChatPage.test.ts +556 -0
- package/dist/templates/src/pages/ProfilePage.test.ts +628 -0
- package/dist/templates/src/pages/RegisterPage.test.ts +661 -0
- package/package.json +1 -1
|
@@ -0,0 +1,661 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RegisterPage Component Unit Tests
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// CRITICAL: Set up ALL mocks BEFORE importing RegisterPage component
|
|
6
|
+
// The component reads localStorage during import, so mocks must be set up first
|
|
7
|
+
|
|
8
|
+
// Simple mock function to track calls
|
|
9
|
+
function mockFn() {
|
|
10
|
+
const calls: any[] = [];
|
|
11
|
+
const fn = (...args: any[]) => {
|
|
12
|
+
calls.push(args);
|
|
13
|
+
return undefined;
|
|
14
|
+
};
|
|
15
|
+
fn.calls = calls;
|
|
16
|
+
fn.mockClear = () => {
|
|
17
|
+
calls.length = 0;
|
|
18
|
+
};
|
|
19
|
+
return fn;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Mock localStorage
|
|
23
|
+
const localStorageMock = (() => {
|
|
24
|
+
let store: Record<string, string> = {};
|
|
25
|
+
return {
|
|
26
|
+
getItem: (key: string): string | null => store[key] || null,
|
|
27
|
+
setItem: (key: string, value: string): void => {
|
|
28
|
+
store[key] = value;
|
|
29
|
+
},
|
|
30
|
+
removeItem: (key: string): void => {
|
|
31
|
+
delete store[key];
|
|
32
|
+
},
|
|
33
|
+
clear: (): void => {
|
|
34
|
+
store = {};
|
|
35
|
+
},
|
|
36
|
+
get length(): number {
|
|
37
|
+
return Object.keys(store).length;
|
|
38
|
+
},
|
|
39
|
+
key: (index: number): string | null => {
|
|
40
|
+
return Object.keys(store)[index] || null;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
})();
|
|
44
|
+
|
|
45
|
+
// Mock fetch
|
|
46
|
+
let mockFetchResponse: any = {
|
|
47
|
+
ok: true,
|
|
48
|
+
json: async () => ({ token: 'fake-token', user: { id: '123', name: 'Test User' } })
|
|
49
|
+
};
|
|
50
|
+
const mockFetch = async () => mockFetchResponse;
|
|
51
|
+
|
|
52
|
+
// Mock window.addEventListener and dispatchEvent
|
|
53
|
+
const eventListeners: Record<string, Function[]> = {};
|
|
54
|
+
const addEventListenerMock = (event: string, handler: Function) => {
|
|
55
|
+
if (!eventListeners[event]) {
|
|
56
|
+
eventListeners[event] = [];
|
|
57
|
+
}
|
|
58
|
+
eventListeners[event].push(handler);
|
|
59
|
+
};
|
|
60
|
+
const dispatchEventMock = (event: Event) => {
|
|
61
|
+
const listeners = eventListeners[event.type];
|
|
62
|
+
if (listeners) {
|
|
63
|
+
listeners.forEach((listener: Function) => listener(event));
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// Mock requestAnimationFrame
|
|
68
|
+
let rafId = 0;
|
|
69
|
+
const rafCallbacks: Map<number, FrameRequestCallback> = new Map();
|
|
70
|
+
const mockRequestAnimationFrame = (callback: FrameRequestCallback) => {
|
|
71
|
+
const id = ++rafId;
|
|
72
|
+
rafCallbacks.set(id, callback);
|
|
73
|
+
return id;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const mockCancelAnimationFrame = (id: number) => {
|
|
77
|
+
rafCallbacks.delete(id);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
// Mock router
|
|
81
|
+
const mockRouter = {
|
|
82
|
+
push: mockFn() as any,
|
|
83
|
+
replace: mockFn() as any,
|
|
84
|
+
go: mockFn() as any,
|
|
85
|
+
back: mockFn() as any,
|
|
86
|
+
forward: mockFn() as any,
|
|
87
|
+
currentPath: '/',
|
|
88
|
+
currentState: null
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// SETUP GLOBALS BEFORE IMPORT
|
|
92
|
+
// Clear real localStorage if it exists
|
|
93
|
+
if (typeof localStorage !== 'undefined') {
|
|
94
|
+
localStorage.clear();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Set up global mocks
|
|
98
|
+
(global as any).localStorage = localStorageMock;
|
|
99
|
+
(globalThis as any).localStorage = localStorageMock;
|
|
100
|
+
(global as any).fetch = mockFetch;
|
|
101
|
+
(globalThis as any).fetch = mockFetch;
|
|
102
|
+
(global as any).window = {
|
|
103
|
+
addEventListener: addEventListenerMock,
|
|
104
|
+
removeEventListener: mockFn(),
|
|
105
|
+
dispatchEvent: dispatchEventMock,
|
|
106
|
+
localStorage: localStorageMock
|
|
107
|
+
};
|
|
108
|
+
(globalThis as any).window = (global as any).window;
|
|
109
|
+
(global as any).requestAnimationFrame = mockRequestAnimationFrame;
|
|
110
|
+
(global as any).cancelAnimationFrame = mockCancelAnimationFrame;
|
|
111
|
+
(globalThis as any).requestAnimationFrame = mockRequestAnimationFrame;
|
|
112
|
+
(globalThis as any).cancelAnimationFrame = mockCancelAnimationFrame;
|
|
113
|
+
|
|
114
|
+
// NOW import the component (after mocks are set up)
|
|
115
|
+
import { RegisterPage } from './RegisterPage';
|
|
116
|
+
import type { VNode } from 'elit/types';
|
|
117
|
+
|
|
118
|
+
// Helper function to render VNode to HTML string
|
|
119
|
+
function renderToString(vNode: VNode | string | number | undefined | null): string {
|
|
120
|
+
if (vNode == null || vNode === false) return '';
|
|
121
|
+
if (typeof vNode !== 'object') return String(vNode);
|
|
122
|
+
|
|
123
|
+
const { tagName, props, children } = vNode;
|
|
124
|
+
const attrs = props ? Object.entries(props)
|
|
125
|
+
.filter(([k, v]) => v != null && v !== false && k !== 'children' && k !== 'ref' && !k.startsWith('on'))
|
|
126
|
+
.map(([k, v]) => {
|
|
127
|
+
if (k === 'className' || k === 'class') return `class="${Array.isArray(v) ? v.join(' ') : v}"`;
|
|
128
|
+
if (k === 'style') return `style="${typeof v === 'string' ? v : Object.entries(v).map(([sk, sv]) => `${sk.replace(/([A-Z])/g, '-$1').toLowerCase()}:${sv}`).join(';')}"`;
|
|
129
|
+
if (v === true) return k;
|
|
130
|
+
return `${k}="${v}"`;
|
|
131
|
+
})
|
|
132
|
+
.join(' ') : '';
|
|
133
|
+
|
|
134
|
+
const childrenStr = children && children.length > 0
|
|
135
|
+
? children.map(c => renderToString(c as any)).join('')
|
|
136
|
+
: '';
|
|
137
|
+
|
|
138
|
+
return `<${tagName}${attrs ? ' ' + attrs : ''}>${childrenStr}</${tagName}>`;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Helper function to find children by tag name
|
|
142
|
+
function findChildrenByTagName(vNode: VNode, tagName: string): VNode[] {
|
|
143
|
+
const results: VNode[] = [];
|
|
144
|
+
|
|
145
|
+
function search(node: VNode | string | number | null | undefined) {
|
|
146
|
+
if (node && typeof node === 'object' && 'tagName' in node) {
|
|
147
|
+
if (node.tagName === tagName) {
|
|
148
|
+
results.push(node);
|
|
149
|
+
}
|
|
150
|
+
if (node.children) {
|
|
151
|
+
for (const child of node.children) {
|
|
152
|
+
search(child as any);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
search(vNode);
|
|
159
|
+
return results;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
describe('RegisterPage Component', () => {
|
|
163
|
+
// Clear REAL browser localStorage before any tests run
|
|
164
|
+
beforeAll(() => {
|
|
165
|
+
if (typeof localStorage !== 'undefined') {
|
|
166
|
+
localStorage.clear();
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
beforeEach(() => {
|
|
171
|
+
// Clear RAF callbacks FIRST
|
|
172
|
+
rafCallbacks.clear();
|
|
173
|
+
rafId = 0;
|
|
174
|
+
|
|
175
|
+
// Clear localStorage before each test
|
|
176
|
+
localStorageMock.clear();
|
|
177
|
+
|
|
178
|
+
// Also clear REAL browser localStorage
|
|
179
|
+
if (typeof localStorage !== 'undefined') {
|
|
180
|
+
localStorage.clear();
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Reset mock router
|
|
184
|
+
(mockRouter.push as any).mockClear();
|
|
185
|
+
(mockRouter.replace as any).mockClear();
|
|
186
|
+
|
|
187
|
+
// Reset fetch mock
|
|
188
|
+
mockFetchResponse = {
|
|
189
|
+
ok: true,
|
|
190
|
+
json: async () => ({ token: 'fake-token', user: { id: '123', name: 'Test User' } })
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
// Clear event listeners
|
|
194
|
+
Object.keys(eventListeners).forEach(key => {
|
|
195
|
+
delete eventListeners[key];
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
afterEach(() => {
|
|
200
|
+
// Clean up event listeners after each test
|
|
201
|
+
Object.keys(eventListeners).forEach(key => {
|
|
202
|
+
delete eventListeners[key];
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
// Clear RAF callbacks after each test
|
|
206
|
+
rafCallbacks.clear();
|
|
207
|
+
rafId = 0;
|
|
208
|
+
|
|
209
|
+
// Clear REAL browser localStorage after each test
|
|
210
|
+
if (typeof localStorage !== 'undefined') {
|
|
211
|
+
localStorage.clear();
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
describe('authentication redirect', () => {
|
|
216
|
+
it('should redirect to profile if already logged in', () => {
|
|
217
|
+
localStorageMock.setItem('token', 'existing-token');
|
|
218
|
+
RegisterPage(mockRouter as any);
|
|
219
|
+
|
|
220
|
+
expect(mockRouter.push.calls.length).toBeGreaterThan(0);
|
|
221
|
+
expect(mockRouter.push.calls[0][0]).toBe('/profile');
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
it('should not redirect if not logged in', () => {
|
|
225
|
+
RegisterPage(mockRouter as any);
|
|
226
|
+
|
|
227
|
+
expect(mockRouter.push.calls.length).toBe(0);
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
describe('page structure', () => {
|
|
232
|
+
it('should render auth-page', () => {
|
|
233
|
+
const page = RegisterPage(mockRouter as any);
|
|
234
|
+
|
|
235
|
+
expect(page).toBeDefined();
|
|
236
|
+
expect(page.tagName).toBe('div');
|
|
237
|
+
expect(page.props?.className).toBe('auth-page');
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it('should render auth-container', () => {
|
|
241
|
+
const page = RegisterPage(mockRouter as any);
|
|
242
|
+
const html = renderToString(page);
|
|
243
|
+
|
|
244
|
+
expect(html).toContain('auth-container');
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
it('should render auth-branding', () => {
|
|
248
|
+
const page = RegisterPage(mockRouter as any);
|
|
249
|
+
const html = renderToString(page);
|
|
250
|
+
|
|
251
|
+
expect(html).toContain('auth-branding');
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
it('should render auth-form-wrapper', () => {
|
|
255
|
+
const page = RegisterPage(mockRouter as any);
|
|
256
|
+
const html = renderToString(page);
|
|
257
|
+
|
|
258
|
+
expect(html).toContain('auth-form-wrapper');
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
it('should render auth-form-card', () => {
|
|
262
|
+
const page = RegisterPage(mockRouter as any);
|
|
263
|
+
const html = renderToString(page);
|
|
264
|
+
|
|
265
|
+
expect(html).toContain('auth-form-card');
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
describe('branding section', () => {
|
|
270
|
+
it('should render branding title', () => {
|
|
271
|
+
const page = RegisterPage(mockRouter as any);
|
|
272
|
+
const html = renderToString(page);
|
|
273
|
+
|
|
274
|
+
expect(html).toContain('Join Us Today');
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
it('should render branding description', () => {
|
|
278
|
+
const page = RegisterPage(mockRouter as any);
|
|
279
|
+
const html = renderToString(page);
|
|
280
|
+
|
|
281
|
+
expect(html).toContain('Create your account and start building amazing applications in minutes.');
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
it('should render branding features', () => {
|
|
285
|
+
const page = RegisterPage(mockRouter as any);
|
|
286
|
+
const html = renderToString(page);
|
|
287
|
+
|
|
288
|
+
expect(html).toContain('branding-features');
|
|
289
|
+
expect(html).toContain('Free forever for personal projects');
|
|
290
|
+
expect(html).toContain('No credit card required');
|
|
291
|
+
expect(html).toContain('Instant setup & deployment');
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
it('should render feature icons', () => {
|
|
295
|
+
const page = RegisterPage(mockRouter as any);
|
|
296
|
+
const html = renderToString(page);
|
|
297
|
+
|
|
298
|
+
expect(html).toContain('feature-icon');
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
describe('form header', () => {
|
|
303
|
+
it('should render auth header', () => {
|
|
304
|
+
const page = RegisterPage(mockRouter as any);
|
|
305
|
+
const html = renderToString(page);
|
|
306
|
+
|
|
307
|
+
expect(html).toContain('auth-header');
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
it('should render auth title', () => {
|
|
311
|
+
const page = RegisterPage(mockRouter as any);
|
|
312
|
+
const html = renderToString(page);
|
|
313
|
+
|
|
314
|
+
expect(html).toContain('Create Account');
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
it('should render auth subtitle', () => {
|
|
318
|
+
const page = RegisterPage(mockRouter as any);
|
|
319
|
+
const html = renderToString(page);
|
|
320
|
+
|
|
321
|
+
expect(html).toContain('Sign up to get started with your free account');
|
|
322
|
+
});
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
describe('error handling', () => {
|
|
326
|
+
it('should have error state capability', () => {
|
|
327
|
+
const page = RegisterPage(mockRouter as any);
|
|
328
|
+
// Error state is reactive
|
|
329
|
+
expect(page).toBeDefined();
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
it('should render auth-error when error exists', () => {
|
|
333
|
+
const page = RegisterPage(mockRouter as any);
|
|
334
|
+
// Error is reactive and only shows when error.value is set
|
|
335
|
+
expect(page).toBeDefined();
|
|
336
|
+
});
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
describe('form elements', () => {
|
|
340
|
+
it('should render form element', () => {
|
|
341
|
+
const page = RegisterPage(mockRouter as any);
|
|
342
|
+
const html = renderToString(page);
|
|
343
|
+
|
|
344
|
+
expect(html).toContain('<form');
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
it('should render name input', () => {
|
|
348
|
+
const page = RegisterPage(mockRouter as any);
|
|
349
|
+
const html = renderToString(page);
|
|
350
|
+
|
|
351
|
+
expect(html).toContain('type="text"');
|
|
352
|
+
expect(html).toContain('id="name"');
|
|
353
|
+
expect(html).toContain('form-input');
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
it('should render name label', () => {
|
|
357
|
+
const page = RegisterPage(mockRouter as any);
|
|
358
|
+
const html = renderToString(page);
|
|
359
|
+
|
|
360
|
+
expect(html).toContain('Full Name');
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
it('should render name icon', () => {
|
|
364
|
+
const page = RegisterPage(mockRouter as any);
|
|
365
|
+
const html = renderToString(page);
|
|
366
|
+
|
|
367
|
+
expect(html).toContain('👤');
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
it('should render email input', () => {
|
|
371
|
+
const page = RegisterPage(mockRouter as any);
|
|
372
|
+
const html = renderToString(page);
|
|
373
|
+
|
|
374
|
+
expect(html).toContain('type="email"');
|
|
375
|
+
expect(html).toContain('id="email"');
|
|
376
|
+
expect(html).toContain('form-input');
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
it('should render email label', () => {
|
|
380
|
+
const page = RegisterPage(mockRouter as any);
|
|
381
|
+
const html = renderToString(page);
|
|
382
|
+
|
|
383
|
+
expect(html).toContain('Email Address');
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
it('should render email icon', () => {
|
|
387
|
+
const page = RegisterPage(mockRouter as any);
|
|
388
|
+
const html = renderToString(page);
|
|
389
|
+
|
|
390
|
+
expect(html).toContain('📧');
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
it('should render password input', () => {
|
|
394
|
+
const page = RegisterPage(mockRouter as any);
|
|
395
|
+
const html = renderToString(page);
|
|
396
|
+
|
|
397
|
+
expect(html).toContain('type="password"');
|
|
398
|
+
expect(html).toContain('id="password"');
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
it('should render password label', () => {
|
|
402
|
+
const page = RegisterPage(mockRouter as any);
|
|
403
|
+
const html = renderToString(page);
|
|
404
|
+
|
|
405
|
+
expect(html).toContain('Password');
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
it('should render password icon', () => {
|
|
409
|
+
const page = RegisterPage(mockRouter as any);
|
|
410
|
+
const html = renderToString(page);
|
|
411
|
+
|
|
412
|
+
expect(html).toContain('🔒');
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
it('should render confirm password input', () => {
|
|
416
|
+
const page = RegisterPage(mockRouter as any);
|
|
417
|
+
const html = renderToString(page);
|
|
418
|
+
|
|
419
|
+
expect(html).toContain('type="password"');
|
|
420
|
+
expect(html).toContain('id="confirmPassword"');
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
it('should render confirm password label', () => {
|
|
424
|
+
const page = RegisterPage(mockRouter as any);
|
|
425
|
+
const html = renderToString(page);
|
|
426
|
+
|
|
427
|
+
expect(html).toContain('Confirm Password');
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
it('should have correct placeholders', () => {
|
|
431
|
+
const page = RegisterPage(mockRouter as any);
|
|
432
|
+
const html = renderToString(page);
|
|
433
|
+
|
|
434
|
+
expect(html).toContain('John Doe');
|
|
435
|
+
expect(html).toContain('your@email.com');
|
|
436
|
+
expect(html).toContain('••••••••');
|
|
437
|
+
});
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
describe('form options', () => {
|
|
441
|
+
it('should render terms checkbox', () => {
|
|
442
|
+
const page = RegisterPage(mockRouter as any);
|
|
443
|
+
const html = renderToString(page);
|
|
444
|
+
|
|
445
|
+
expect(html).toContain('I agree to the Terms of Service and Privacy Policy');
|
|
446
|
+
expect(html).toContain('checkbox');
|
|
447
|
+
});
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
describe('submit button', () => {
|
|
451
|
+
it('should render submit button', () => {
|
|
452
|
+
const page = RegisterPage(mockRouter as any);
|
|
453
|
+
const html = renderToString(page);
|
|
454
|
+
|
|
455
|
+
expect(html).toContain('Create Account');
|
|
456
|
+
expect(html).toContain('btn-primary');
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
it('should have loading state capability', () => {
|
|
460
|
+
const page = RegisterPage(mockRouter as any);
|
|
461
|
+
// Submit button text is reactive based on isLoading state
|
|
462
|
+
expect(page).toBeDefined();
|
|
463
|
+
});
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
describe('social login', () => {
|
|
467
|
+
it('should render auth divider', () => {
|
|
468
|
+
const page = RegisterPage(mockRouter as any);
|
|
469
|
+
const html = renderToString(page);
|
|
470
|
+
|
|
471
|
+
expect(html).toContain('auth-divider');
|
|
472
|
+
expect(html).toContain('OR');
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
it('should render social login section', () => {
|
|
476
|
+
const page = RegisterPage(mockRouter as any);
|
|
477
|
+
const html = renderToString(page);
|
|
478
|
+
|
|
479
|
+
expect(html).toContain('social-login');
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
it('should render Google button', () => {
|
|
483
|
+
const page = RegisterPage(mockRouter as any);
|
|
484
|
+
const html = renderToString(page);
|
|
485
|
+
|
|
486
|
+
expect(html).toContain('Sign up with Google');
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
it('should render GitHub button', () => {
|
|
490
|
+
const page = RegisterPage(mockRouter as any);
|
|
491
|
+
const html = renderToString(page);
|
|
492
|
+
|
|
493
|
+
expect(html).toContain('Sign up with GitHub');
|
|
494
|
+
});
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
describe('footer section', () => {
|
|
498
|
+
it('should render auth footer', () => {
|
|
499
|
+
const page = RegisterPage(mockRouter as any);
|
|
500
|
+
const html = renderToString(page);
|
|
501
|
+
|
|
502
|
+
expect(html).toContain('auth-footer');
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
it('should render footer text', () => {
|
|
506
|
+
const page = RegisterPage(mockRouter as any);
|
|
507
|
+
const html = renderToString(page);
|
|
508
|
+
|
|
509
|
+
expect(html).toContain('Already have an account?');
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
it('should render sign in button', () => {
|
|
513
|
+
const page = RegisterPage(mockRouter as any);
|
|
514
|
+
const html = renderToString(page);
|
|
515
|
+
|
|
516
|
+
expect(html).toContain('Sign in');
|
|
517
|
+
});
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
describe('CSS classes', () => {
|
|
521
|
+
it('should have correct CSS classes', () => {
|
|
522
|
+
const page = RegisterPage(mockRouter as any);
|
|
523
|
+
const html = renderToString(page);
|
|
524
|
+
|
|
525
|
+
expect(html).toContain('auth-page');
|
|
526
|
+
expect(html).toContain('auth-container');
|
|
527
|
+
expect(html).toContain('auth-branding');
|
|
528
|
+
expect(html).toContain('branding-content');
|
|
529
|
+
expect(html).toContain('branding-title');
|
|
530
|
+
expect(html).toContain('branding-description');
|
|
531
|
+
});
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
describe('form structure', () => {
|
|
535
|
+
it('should have form-group', () => {
|
|
536
|
+
const page = RegisterPage(mockRouter as any);
|
|
537
|
+
const html = renderToString(page);
|
|
538
|
+
|
|
539
|
+
expect(html).toContain('form-group');
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
it('should have input-wrapper', () => {
|
|
543
|
+
const page = RegisterPage(mockRouter as any);
|
|
544
|
+
const html = renderToString(page);
|
|
545
|
+
|
|
546
|
+
expect(html).toContain('input-wrapper');
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
it('should have input-icon', () => {
|
|
550
|
+
const page = RegisterPage(mockRouter as any);
|
|
551
|
+
const html = renderToString(page);
|
|
552
|
+
|
|
553
|
+
expect(html).toContain('input-icon');
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
it('should have form-options', () => {
|
|
557
|
+
const page = RegisterPage(mockRouter as any);
|
|
558
|
+
const html = renderToString(page);
|
|
559
|
+
|
|
560
|
+
expect(html).toContain('form-options');
|
|
561
|
+
});
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
describe('component consistency', () => {
|
|
565
|
+
it('should always return the same structure', () => {
|
|
566
|
+
const page1 = RegisterPage(mockRouter as any);
|
|
567
|
+
const page2 = RegisterPage(mockRouter as any);
|
|
568
|
+
|
|
569
|
+
expect(page1.tagName).toBe(page2.tagName);
|
|
570
|
+
expect(page1.props?.className).toBe(page2.props?.className);
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
it('should render without errors', () => {
|
|
574
|
+
expect(() => {
|
|
575
|
+
const page = RegisterPage(mockRouter as any);
|
|
576
|
+
renderToString(page);
|
|
577
|
+
}).not.toThrow();
|
|
578
|
+
});
|
|
579
|
+
|
|
580
|
+
it('should have h1 element', () => {
|
|
581
|
+
const page = RegisterPage(mockRouter as any);
|
|
582
|
+
const h1Elements = findChildrenByTagName(page, 'h1');
|
|
583
|
+
|
|
584
|
+
expect(h1Elements.length).toBeGreaterThan(0);
|
|
585
|
+
});
|
|
586
|
+
|
|
587
|
+
it('should have h2 element', () => {
|
|
588
|
+
const page = RegisterPage(mockRouter as any);
|
|
589
|
+
const h2Elements = findChildrenByTagName(page, 'h2');
|
|
590
|
+
|
|
591
|
+
expect(h2Elements.length).toBeGreaterThan(0);
|
|
592
|
+
});
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
describe('reactive state', () => {
|
|
596
|
+
it('should have name state', () => {
|
|
597
|
+
const page = RegisterPage(mockRouter as any);
|
|
598
|
+
expect(page).toBeDefined();
|
|
599
|
+
});
|
|
600
|
+
|
|
601
|
+
it('should have email state', () => {
|
|
602
|
+
const page = RegisterPage(mockRouter as any);
|
|
603
|
+
expect(page).toBeDefined();
|
|
604
|
+
});
|
|
605
|
+
|
|
606
|
+
it('should have password state', () => {
|
|
607
|
+
const page = RegisterPage(mockRouter as any);
|
|
608
|
+
expect(page).toBeDefined();
|
|
609
|
+
});
|
|
610
|
+
|
|
611
|
+
it('should have confirmPassword state', () => {
|
|
612
|
+
const page = RegisterPage(mockRouter as any);
|
|
613
|
+
expect(page).toBeDefined();
|
|
614
|
+
});
|
|
615
|
+
|
|
616
|
+
it('should have error state', () => {
|
|
617
|
+
const page = RegisterPage(mockRouter as any);
|
|
618
|
+
expect(page).toBeDefined();
|
|
619
|
+
});
|
|
620
|
+
|
|
621
|
+
it('should have isLoading state', () => {
|
|
622
|
+
const page = RegisterPage(mockRouter as any);
|
|
623
|
+
expect(page).toBeDefined();
|
|
624
|
+
});
|
|
625
|
+
});
|
|
626
|
+
|
|
627
|
+
describe('navigation', () => {
|
|
628
|
+
it('should have sign in link', () => {
|
|
629
|
+
const page = RegisterPage(mockRouter as any);
|
|
630
|
+
const html = renderToString(page);
|
|
631
|
+
|
|
632
|
+
expect(html).toContain('Sign in');
|
|
633
|
+
});
|
|
634
|
+
});
|
|
635
|
+
|
|
636
|
+
describe('form validation capabilities', () => {
|
|
637
|
+
it('should have name validation capability', () => {
|
|
638
|
+
const page = RegisterPage(mockRouter as any);
|
|
639
|
+
// Component has name validation logic in handleRegister
|
|
640
|
+
expect(page).toBeDefined();
|
|
641
|
+
});
|
|
642
|
+
|
|
643
|
+
it('should have email validation capability', () => {
|
|
644
|
+
const page = RegisterPage(mockRouter as any);
|
|
645
|
+
// Component has email validation logic in handleRegister
|
|
646
|
+
expect(page).toBeDefined();
|
|
647
|
+
});
|
|
648
|
+
|
|
649
|
+
it('should have password length validation capability', () => {
|
|
650
|
+
const page = RegisterPage(mockRouter as any);
|
|
651
|
+
// Component has password length validation in handleRegister
|
|
652
|
+
expect(page).toBeDefined();
|
|
653
|
+
});
|
|
654
|
+
|
|
655
|
+
it('should have password match validation capability', () => {
|
|
656
|
+
const page = RegisterPage(mockRouter as any);
|
|
657
|
+
// Component has password match validation in handleRegister
|
|
658
|
+
expect(page).toBeDefined();
|
|
659
|
+
});
|
|
660
|
+
});
|
|
661
|
+
});
|