@rakeyshgidwani/roger-ui-bank-theme-stan-design 0.1.6 โ 0.1.7
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/CHANGELOG.md +1 -1
- package/dist/index.d.ts +7 -0
- package/dist/index.esm.js +18 -1
- package/dist/index.js +18 -1
- package/dist/setupTests.d.ts +124 -0
- package/dist/setupTests.esm.js +122 -0
- package/dist/setupTests.js +122 -0
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/src/index.css +1046 -0
- package/src/index.ts +18 -0
- package/src/plugins/theme-css-generator.ts +354 -0
- package/src/setupTests.ts +124 -0
- package/src/stories/README.md +39 -0
- package/src/stories/components/ThemeDebugger.tsx +143 -0
- package/src/stories/index.ts +29 -0
- package/src/stories/storybook-theme-imports.css +51 -0
- package/src/styles/base/fonts.css +30 -0
- package/src/styles/base/generated-theme-variables.css +573 -0
- package/src/styles/base/index.css +7 -0
- package/src/styles/base/reset.css +48 -0
- package/src/styles/base/theme.css +1068 -0
- package/src/styles/base/typography.css +68 -0
- package/src/styles/base/variables.css +5 -0
- package/src/styles/components/CLAUDE.md +62 -0
- package/src/styles/components/base/badge.css +428 -0
- package/src/styles/components/base/button.css +774 -0
- package/src/styles/components/base/card.css +601 -0
- package/src/styles/components/base/checkbox.css +442 -0
- package/src/styles/components/base/index.css +9 -0
- package/src/styles/components/base/input.css +887 -0
- package/src/styles/components/base/label.css +296 -0
- package/src/styles/components/data-display/chart.css +353 -0
- package/src/styles/components/data-display/data-grid.css +619 -0
- package/src/styles/components/data-display/index.css +9 -0
- package/src/styles/components/data-display/list.css +560 -0
- package/src/styles/components/data-display/table.css +498 -0
- package/src/styles/components/data-display/timeline.css +764 -0
- package/src/styles/components/data-display/tree.css +881 -0
- package/src/styles/components/feedback/alert.css +358 -0
- package/src/styles/components/feedback/index.css +7 -0
- package/src/styles/components/feedback/progress.css +435 -0
- package/src/styles/components/feedback/skeleton.css +337 -0
- package/src/styles/components/feedback/toast.css +564 -0
- package/src/styles/components/index.css +17 -0
- package/src/styles/components/navigation/breadcrumb.css +465 -0
- package/src/styles/components/navigation/index.css +9 -0
- package/src/styles/components/navigation/menu.css +572 -0
- package/src/styles/components/navigation/pagination.css +635 -0
- package/src/styles/components/navigation/sidebar.css +807 -0
- package/src/styles/components/navigation/stepper.css +519 -0
- package/src/styles/components/navigation/tabs.css +404 -0
- package/src/styles/components/overlay/backdrop.css +243 -0
- package/src/styles/components/overlay/index.css +8 -0
- package/src/styles/components/overlay/modal.css +482 -0
- package/src/styles/components/overlay/popover.css +607 -0
- package/src/styles/components/overlay/portal.css +213 -0
- package/src/styles/components/overlay/tooltip.css +488 -0
- package/src/styles/generated-theme-variables.css +573 -0
- package/src/styles/index.css +5 -0
- package/src/styles/layers/index.css +54 -0
- package/src/styles/layers/overrides.css +108 -0
- package/src/styles/layers/validation.css +159 -0
- package/src/styles/layers/validation.js +310 -0
- package/src/styles/themes/default.css +450 -0
- package/src/styles/themes/enterprise.css +370 -0
- package/src/styles/themes/harvey.css +436 -0
- package/src/styles/themes/index.css +4 -0
- package/src/styles/themes/stan-design.css +572 -0
- package/src/styles/utilities/advanced-transition-system.css +467 -0
- package/src/styles/utilities/battery-conscious-animations.css +289 -0
- package/src/styles/utilities/enterprise-mobile-experience.css +817 -0
- package/src/styles/utilities/hardware-acceleration.css +121 -0
- package/src/styles/utilities/index.css +20 -0
- package/src/styles/utilities/mobile-skeleton-loading.css +596 -0
- package/src/styles/utilities/semantic-input-system.css +451 -0
- package/src/styles/utilities/touch-friendly-interface.css +247 -0
- package/src/styles/utilities/touch-optimization.css +165 -0
- package/src/test-utils/index.ts +7 -0
- package/src/test-utils/theme-testing.tsx +219 -0
- package/src/testing/test-automation.ts +627 -0
- package/src/testing/test-utils.tsx +367 -0
|
@@ -0,0 +1,627 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test Automation Scripts
|
|
3
|
+
* Automated testing utilities and scripts for running comprehensive test suites
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { spawn, exec } from 'child_process';
|
|
7
|
+
import { promisify } from 'util';
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
|
|
11
|
+
const execAsync = promisify(exec);
|
|
12
|
+
|
|
13
|
+
export interface TestConfig {
|
|
14
|
+
testTypes: string[];
|
|
15
|
+
browsers?: string[];
|
|
16
|
+
themes?: string[];
|
|
17
|
+
viewports?: string[];
|
|
18
|
+
coverage?: boolean;
|
|
19
|
+
parallel?: boolean;
|
|
20
|
+
timeout?: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface TestResult {
|
|
24
|
+
testType: string;
|
|
25
|
+
passed: number;
|
|
26
|
+
failed: number;
|
|
27
|
+
skipped: number;
|
|
28
|
+
duration: number;
|
|
29
|
+
coverage?: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface TestReport {
|
|
33
|
+
timestamp: string;
|
|
34
|
+
totalTests: number;
|
|
35
|
+
totalPassed: number;
|
|
36
|
+
totalFailed: number;
|
|
37
|
+
totalSkipped: number;
|
|
38
|
+
totalDuration: number;
|
|
39
|
+
results: TestResult[];
|
|
40
|
+
coverageReport?: any;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Main test automation class
|
|
45
|
+
*/
|
|
46
|
+
export class TestAutomation {
|
|
47
|
+
private config: TestConfig;
|
|
48
|
+
private results: TestResult[] = [];
|
|
49
|
+
|
|
50
|
+
constructor(config: TestConfig) {
|
|
51
|
+
this.config = {
|
|
52
|
+
timeout: 30000,
|
|
53
|
+
parallel: true,
|
|
54
|
+
coverage: true,
|
|
55
|
+
...config,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Run all configured tests
|
|
61
|
+
*/
|
|
62
|
+
async runAllTests(): Promise<TestReport> {
|
|
63
|
+
console.log('๐ Starting comprehensive test suite...');
|
|
64
|
+
const startTime = Date.now();
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
// Run tests based on configuration
|
|
68
|
+
if (this.config.testTypes.includes('unit')) {
|
|
69
|
+
await this.runUnitTests();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (this.config.testTypes.includes('visual-regression')) {
|
|
73
|
+
await this.runVisualRegressionTests();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (this.config.testTypes.includes('theme-switching')) {
|
|
77
|
+
await this.runThemeSwitchingTests();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (this.config.testTypes.includes('state-testing')) {
|
|
81
|
+
await this.runStateTests();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (this.config.testTypes.includes('responsive')) {
|
|
85
|
+
await this.runResponsiveTests();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (this.config.testTypes.includes('cross-browser')) {
|
|
89
|
+
await this.runCrossBrowserTests();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (this.config.testTypes.includes('accessibility')) {
|
|
93
|
+
await this.runAccessibilityTests();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (this.config.testTypes.includes('performance')) {
|
|
97
|
+
await this.runPerformanceTests();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (this.config.testTypes.includes('e2e')) {
|
|
101
|
+
await this.runE2ETests();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const endTime = Date.now();
|
|
105
|
+
const totalDuration = endTime - startTime;
|
|
106
|
+
|
|
107
|
+
const report = this.generateReport(totalDuration);
|
|
108
|
+
await this.saveReport(report);
|
|
109
|
+
|
|
110
|
+
console.log('โ
Test suite completed successfully!');
|
|
111
|
+
this.printSummary(report);
|
|
112
|
+
|
|
113
|
+
return report;
|
|
114
|
+
} catch (error) {
|
|
115
|
+
console.error('โ Test suite failed:', error);
|
|
116
|
+
throw error;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Run unit tests
|
|
122
|
+
*/
|
|
123
|
+
private async runUnitTests(): Promise<void> {
|
|
124
|
+
console.log('๐งช Running unit tests...');
|
|
125
|
+
const startTime = Date.now();
|
|
126
|
+
|
|
127
|
+
try {
|
|
128
|
+
const command = this.config.coverage
|
|
129
|
+
? 'npm run test:coverage'
|
|
130
|
+
: 'npm test';
|
|
131
|
+
|
|
132
|
+
const { stdout } = await execAsync(command, {
|
|
133
|
+
timeout: this.config.timeout,
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
const result = this.parseJestOutput(stdout);
|
|
137
|
+
result.testType = 'unit';
|
|
138
|
+
result.duration = Date.now() - startTime;
|
|
139
|
+
|
|
140
|
+
this.results.push(result);
|
|
141
|
+
console.log(`โ
Unit tests completed: ${result.passed} passed, ${result.failed} failed`);
|
|
142
|
+
} catch (error) {
|
|
143
|
+
console.error('โ Unit tests failed:', error);
|
|
144
|
+
this.results.push({
|
|
145
|
+
testType: 'unit',
|
|
146
|
+
passed: 0,
|
|
147
|
+
failed: 1,
|
|
148
|
+
skipped: 0,
|
|
149
|
+
duration: Date.now() - startTime,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Run visual regression tests
|
|
156
|
+
*/
|
|
157
|
+
private async runVisualRegressionTests(): Promise<void> {
|
|
158
|
+
console.log('๐ธ Running visual regression tests...');
|
|
159
|
+
const startTime = Date.now();
|
|
160
|
+
|
|
161
|
+
try {
|
|
162
|
+
const command = 'npm test -- --testPathPatterns=visual-regression';
|
|
163
|
+
const { stdout } = await execAsync(command, {
|
|
164
|
+
timeout: this.config.timeout,
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
const result = this.parseJestOutput(stdout);
|
|
168
|
+
result.testType = 'visual-regression';
|
|
169
|
+
result.duration = Date.now() - startTime;
|
|
170
|
+
|
|
171
|
+
this.results.push(result);
|
|
172
|
+
console.log(`โ
Visual regression tests completed: ${result.passed} passed, ${result.failed} failed`);
|
|
173
|
+
} catch (error) {
|
|
174
|
+
console.error('โ Visual regression tests failed:', error);
|
|
175
|
+
this.results.push({
|
|
176
|
+
testType: 'visual-regression',
|
|
177
|
+
passed: 0,
|
|
178
|
+
failed: 1,
|
|
179
|
+
skipped: 0,
|
|
180
|
+
duration: Date.now() - startTime,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Run theme switching tests
|
|
187
|
+
*/
|
|
188
|
+
private async runThemeSwitchingTests(): Promise<void> {
|
|
189
|
+
console.log('๐จ Running theme switching tests...');
|
|
190
|
+
const startTime = Date.now();
|
|
191
|
+
|
|
192
|
+
try {
|
|
193
|
+
const command = 'npm test -- --testPathPatterns=theme-switching';
|
|
194
|
+
const { stdout } = await execAsync(command, {
|
|
195
|
+
timeout: this.config.timeout,
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
const result = this.parseJestOutput(stdout);
|
|
199
|
+
result.testType = 'theme-switching';
|
|
200
|
+
result.duration = Date.now() - startTime;
|
|
201
|
+
|
|
202
|
+
this.results.push(result);
|
|
203
|
+
console.log(`โ
Theme switching tests completed: ${result.passed} passed, ${result.failed} failed`);
|
|
204
|
+
} catch (error) {
|
|
205
|
+
console.error('โ Theme switching tests failed:', error);
|
|
206
|
+
this.results.push({
|
|
207
|
+
testType: 'theme-switching',
|
|
208
|
+
passed: 0,
|
|
209
|
+
failed: 1,
|
|
210
|
+
skipped: 0,
|
|
211
|
+
duration: Date.now() - startTime,
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Run state tests
|
|
218
|
+
*/
|
|
219
|
+
private async runStateTests(): Promise<void> {
|
|
220
|
+
console.log('๐ Running state tests...');
|
|
221
|
+
const startTime = Date.now();
|
|
222
|
+
|
|
223
|
+
try {
|
|
224
|
+
const command = 'npm test -- --testPathPatterns=state-testing';
|
|
225
|
+
const { stdout } = await execAsync(command, {
|
|
226
|
+
timeout: this.config.timeout,
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
const result = this.parseJestOutput(stdout);
|
|
230
|
+
result.testType = 'state-testing';
|
|
231
|
+
result.duration = Date.now() - startTime;
|
|
232
|
+
|
|
233
|
+
this.results.push(result);
|
|
234
|
+
console.log(`โ
State tests completed: ${result.passed} passed, ${result.failed} failed`);
|
|
235
|
+
} catch (error) {
|
|
236
|
+
console.error('โ State tests failed:', error);
|
|
237
|
+
this.results.push({
|
|
238
|
+
testType: 'state-testing',
|
|
239
|
+
passed: 0,
|
|
240
|
+
failed: 1,
|
|
241
|
+
skipped: 0,
|
|
242
|
+
duration: Date.now() - startTime,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Run responsive tests
|
|
249
|
+
*/
|
|
250
|
+
private async runResponsiveTests(): Promise<void> {
|
|
251
|
+
console.log('๐ฑ Running responsive tests...');
|
|
252
|
+
const startTime = Date.now();
|
|
253
|
+
|
|
254
|
+
try {
|
|
255
|
+
const command = 'npm test -- --testPathPatterns=responsive-testing';
|
|
256
|
+
const { stdout } = await execAsync(command, {
|
|
257
|
+
timeout: this.config.timeout,
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
const result = this.parseJestOutput(stdout);
|
|
261
|
+
result.testType = 'responsive';
|
|
262
|
+
result.duration = Date.now() - startTime;
|
|
263
|
+
|
|
264
|
+
this.results.push(result);
|
|
265
|
+
console.log(`โ
Responsive tests completed: ${result.passed} passed, ${result.failed} failed`);
|
|
266
|
+
} catch (error) {
|
|
267
|
+
console.error('โ Responsive tests failed:', error);
|
|
268
|
+
this.results.push({
|
|
269
|
+
testType: 'responsive',
|
|
270
|
+
passed: 0,
|
|
271
|
+
failed: 1,
|
|
272
|
+
skipped: 0,
|
|
273
|
+
duration: Date.now() - startTime,
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Run cross-browser tests
|
|
280
|
+
*/
|
|
281
|
+
private async runCrossBrowserTests(): Promise<void> {
|
|
282
|
+
console.log('๐ Running cross-browser tests...');
|
|
283
|
+
const startTime = Date.now();
|
|
284
|
+
|
|
285
|
+
try {
|
|
286
|
+
const command = 'npm test -- --testPathPatterns=cross-browser';
|
|
287
|
+
const { stdout } = await execAsync(command, {
|
|
288
|
+
timeout: this.config.timeout,
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
const result = this.parseJestOutput(stdout);
|
|
292
|
+
result.testType = 'cross-browser';
|
|
293
|
+
result.duration = Date.now() - startTime;
|
|
294
|
+
|
|
295
|
+
this.results.push(result);
|
|
296
|
+
console.log(`โ
Cross-browser tests completed: ${result.passed} passed, ${result.failed} failed`);
|
|
297
|
+
} catch (error) {
|
|
298
|
+
console.error('โ Cross-browser tests failed:', error);
|
|
299
|
+
this.results.push({
|
|
300
|
+
testType: 'cross-browser',
|
|
301
|
+
passed: 0,
|
|
302
|
+
failed: 1,
|
|
303
|
+
skipped: 0,
|
|
304
|
+
duration: Date.now() - startTime,
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Run accessibility tests
|
|
311
|
+
*/
|
|
312
|
+
private async runAccessibilityTests(): Promise<void> {
|
|
313
|
+
console.log('โฟ Running accessibility tests...');
|
|
314
|
+
const startTime = Date.now();
|
|
315
|
+
|
|
316
|
+
try {
|
|
317
|
+
const command = 'npm test -- --testPathPatterns=accessibility';
|
|
318
|
+
const { stdout } = await execAsync(command, {
|
|
319
|
+
timeout: this.config.timeout,
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
const result = this.parseJestOutput(stdout);
|
|
323
|
+
result.testType = 'accessibility';
|
|
324
|
+
result.duration = Date.now() - startTime;
|
|
325
|
+
|
|
326
|
+
this.results.push(result);
|
|
327
|
+
console.log(`โ
Accessibility tests completed: ${result.passed} passed, ${result.failed} failed`);
|
|
328
|
+
} catch (error) {
|
|
329
|
+
console.error('โ Accessibility tests failed:', error);
|
|
330
|
+
this.results.push({
|
|
331
|
+
testType: 'accessibility',
|
|
332
|
+
passed: 0,
|
|
333
|
+
failed: 1,
|
|
334
|
+
skipped: 0,
|
|
335
|
+
duration: Date.now() - startTime,
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Run performance tests
|
|
342
|
+
*/
|
|
343
|
+
private async runPerformanceTests(): Promise<void> {
|
|
344
|
+
console.log('โก Running performance tests...');
|
|
345
|
+
const startTime = Date.now();
|
|
346
|
+
|
|
347
|
+
try {
|
|
348
|
+
const command = 'npm test -- --testPathPatterns=performance';
|
|
349
|
+
const { stdout } = await execAsync(command, {
|
|
350
|
+
timeout: this.config.timeout,
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
const result = this.parseJestOutput(stdout);
|
|
354
|
+
result.testType = 'performance';
|
|
355
|
+
result.duration = Date.now() - startTime;
|
|
356
|
+
|
|
357
|
+
this.results.push(result);
|
|
358
|
+
console.log(`โ
Performance tests completed: ${result.passed} passed, ${result.failed} failed`);
|
|
359
|
+
} catch (error) {
|
|
360
|
+
console.error('โ Performance tests failed:', error);
|
|
361
|
+
this.results.push({
|
|
362
|
+
testType: 'performance',
|
|
363
|
+
passed: 0,
|
|
364
|
+
failed: 1,
|
|
365
|
+
skipped: 0,
|
|
366
|
+
duration: Date.now() - startTime,
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Run E2E tests (placeholder for future implementation)
|
|
373
|
+
*/
|
|
374
|
+
private async runE2ETests(): Promise<void> {
|
|
375
|
+
console.log('๐ญ Running E2E tests...');
|
|
376
|
+
const startTime = Date.now();
|
|
377
|
+
|
|
378
|
+
try {
|
|
379
|
+
// Placeholder for E2E tests (Playwright, Cypress, etc.)
|
|
380
|
+
console.log('โน๏ธ E2E tests not yet configured - skipping');
|
|
381
|
+
|
|
382
|
+
this.results.push({
|
|
383
|
+
testType: 'e2e',
|
|
384
|
+
passed: 0,
|
|
385
|
+
failed: 0,
|
|
386
|
+
skipped: 1,
|
|
387
|
+
duration: Date.now() - startTime,
|
|
388
|
+
});
|
|
389
|
+
} catch (error) {
|
|
390
|
+
console.error('โ E2E tests failed:', error);
|
|
391
|
+
this.results.push({
|
|
392
|
+
testType: 'e2e',
|
|
393
|
+
passed: 0,
|
|
394
|
+
failed: 1,
|
|
395
|
+
skipped: 0,
|
|
396
|
+
duration: Date.now() - startTime,
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* Parse Jest output to extract test results
|
|
403
|
+
*/
|
|
404
|
+
private parseJestOutput(output: string): TestResult {
|
|
405
|
+
const result: TestResult = {
|
|
406
|
+
testType: '',
|
|
407
|
+
passed: 0,
|
|
408
|
+
failed: 0,
|
|
409
|
+
skipped: 0,
|
|
410
|
+
duration: 0,
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
// Parse Jest output for test counts
|
|
414
|
+
const passedMatch = output.match(/(\d+) passed/);
|
|
415
|
+
const failedMatch = output.match(/(\d+) failed/);
|
|
416
|
+
const skippedMatch = output.match(/(\d+) skipped/);
|
|
417
|
+
|
|
418
|
+
if (passedMatch) result.passed = parseInt(passedMatch[1], 10);
|
|
419
|
+
if (failedMatch) result.failed = parseInt(failedMatch[1], 10);
|
|
420
|
+
if (skippedMatch) result.skipped = parseInt(skippedMatch[1], 10);
|
|
421
|
+
|
|
422
|
+
return result;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* Generate comprehensive test report
|
|
427
|
+
*/
|
|
428
|
+
private generateReport(totalDuration: number): TestReport {
|
|
429
|
+
const totalPassed = this.results.reduce((sum, r) => sum + r.passed, 0);
|
|
430
|
+
const totalFailed = this.results.reduce((sum, r) => sum + r.failed, 0);
|
|
431
|
+
const totalSkipped = this.results.reduce((sum, r) => sum + r.skipped, 0);
|
|
432
|
+
const totalTests = totalPassed + totalFailed + totalSkipped;
|
|
433
|
+
|
|
434
|
+
return {
|
|
435
|
+
timestamp: new Date().toISOString(),
|
|
436
|
+
totalTests,
|
|
437
|
+
totalPassed,
|
|
438
|
+
totalFailed,
|
|
439
|
+
totalSkipped,
|
|
440
|
+
totalDuration,
|
|
441
|
+
results: this.results,
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Save test report to file
|
|
447
|
+
*/
|
|
448
|
+
private async saveReport(report: TestReport): Promise<void> {
|
|
449
|
+
const reportsDir = path.join(process.cwd(), 'test-reports');
|
|
450
|
+
|
|
451
|
+
if (!fs.existsSync(reportsDir)) {
|
|
452
|
+
fs.mkdirSync(reportsDir, { recursive: true });
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
456
|
+
const reportPath = path.join(reportsDir, `test-report-${timestamp}.json`);
|
|
457
|
+
|
|
458
|
+
fs.writeFileSync(reportPath, JSON.stringify(report, null, 2));
|
|
459
|
+
console.log(`๐ Test report saved to: ${reportPath}`);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Print test summary to console
|
|
464
|
+
*/
|
|
465
|
+
private printSummary(report: TestReport): void {
|
|
466
|
+
console.log('\n๐ Test Summary:');
|
|
467
|
+
console.log('================');
|
|
468
|
+
console.log(`Total Tests: ${report.totalTests}`);
|
|
469
|
+
console.log(`โ
Passed: ${report.totalPassed}`);
|
|
470
|
+
console.log(`โ Failed: ${report.totalFailed}`);
|
|
471
|
+
console.log(`โญ๏ธ Skipped: ${report.totalSkipped}`);
|
|
472
|
+
console.log(`โฑ๏ธ Duration: ${(report.totalDuration / 1000).toFixed(2)}s`);
|
|
473
|
+
console.log(`๐ Success Rate: ${((report.totalPassed / (report.totalPassed + report.totalFailed)) * 100).toFixed(1)}%`);
|
|
474
|
+
|
|
475
|
+
console.log('\n๐ Test Type Results:');
|
|
476
|
+
console.log('=====================');
|
|
477
|
+
report.results.forEach((result) => {
|
|
478
|
+
const icon = result.failed > 0 ? 'โ' : result.passed > 0 ? 'โ
' : 'โญ๏ธ';
|
|
479
|
+
console.log(`${icon} ${result.testType}: ${result.passed} passed, ${result.failed} failed, ${result.skipped} skipped (${(result.duration / 1000).toFixed(2)}s)`);
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* Predefined test configurations
|
|
486
|
+
*/
|
|
487
|
+
export const testConfigurations = {
|
|
488
|
+
quick: {
|
|
489
|
+
testTypes: ['unit', 'visual-regression'],
|
|
490
|
+
parallel: true,
|
|
491
|
+
timeout: 30000,
|
|
492
|
+
},
|
|
493
|
+
comprehensive: {
|
|
494
|
+
testTypes: [
|
|
495
|
+
'unit',
|
|
496
|
+
'visual-regression',
|
|
497
|
+
'theme-switching',
|
|
498
|
+
'state-testing',
|
|
499
|
+
'responsive',
|
|
500
|
+
'cross-browser',
|
|
501
|
+
'accessibility',
|
|
502
|
+
'performance',
|
|
503
|
+
],
|
|
504
|
+
parallel: true,
|
|
505
|
+
coverage: true,
|
|
506
|
+
timeout: 60000,
|
|
507
|
+
},
|
|
508
|
+
ci: {
|
|
509
|
+
testTypes: [
|
|
510
|
+
'unit',
|
|
511
|
+
'visual-regression',
|
|
512
|
+
'theme-switching',
|
|
513
|
+
'state-testing',
|
|
514
|
+
'responsive',
|
|
515
|
+
'accessibility',
|
|
516
|
+
],
|
|
517
|
+
parallel: true,
|
|
518
|
+
coverage: true,
|
|
519
|
+
timeout: 45000,
|
|
520
|
+
},
|
|
521
|
+
accessibility: {
|
|
522
|
+
testTypes: ['accessibility'],
|
|
523
|
+
timeout: 30000,
|
|
524
|
+
},
|
|
525
|
+
performance: {
|
|
526
|
+
testTypes: ['performance'],
|
|
527
|
+
timeout: 45000,
|
|
528
|
+
},
|
|
529
|
+
};
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* CLI utility functions
|
|
533
|
+
*/
|
|
534
|
+
export class TestCLI {
|
|
535
|
+
static async runConfiguration(configName: keyof typeof testConfigurations): Promise<void> {
|
|
536
|
+
const config = testConfigurations[configName];
|
|
537
|
+
if (!config) {
|
|
538
|
+
throw new Error(`Unknown configuration: ${configName}`);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
const automation = new TestAutomation(config);
|
|
542
|
+
await automation.runAllTests();
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
static async runCustom(customConfig: TestConfig): Promise<void> {
|
|
546
|
+
const automation = new TestAutomation(customConfig);
|
|
547
|
+
await automation.runAllTests();
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
static listConfigurations(): void {
|
|
551
|
+
console.log('Available test configurations:');
|
|
552
|
+
console.log('==============================');
|
|
553
|
+
Object.keys(testConfigurations).forEach((name) => {
|
|
554
|
+
const config = testConfigurations[name as keyof typeof testConfigurations];
|
|
555
|
+
console.log(`โข ${name}: ${config.testTypes.join(', ')}`);
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
/**
|
|
561
|
+
* Utility functions for individual test operations
|
|
562
|
+
*/
|
|
563
|
+
export const testUtils = {
|
|
564
|
+
/**
|
|
565
|
+
* Run tests with coverage
|
|
566
|
+
*/
|
|
567
|
+
async runWithCoverage(): Promise<void> {
|
|
568
|
+
console.log('๐ Running tests with coverage...');
|
|
569
|
+
try {
|
|
570
|
+
await execAsync('npm run test:coverage');
|
|
571
|
+
console.log('โ
Coverage report generated');
|
|
572
|
+
} catch (error) {
|
|
573
|
+
console.error('โ Coverage test failed:', error);
|
|
574
|
+
throw error;
|
|
575
|
+
}
|
|
576
|
+
},
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
* Update visual regression snapshots
|
|
580
|
+
*/
|
|
581
|
+
async updateSnapshots(): Promise<void> {
|
|
582
|
+
console.log('๐ธ Updating visual regression snapshots...');
|
|
583
|
+
try {
|
|
584
|
+
await execAsync('npm test -- --updateSnapshot');
|
|
585
|
+
console.log('โ
Snapshots updated');
|
|
586
|
+
} catch (error) {
|
|
587
|
+
console.error('โ Snapshot update failed:', error);
|
|
588
|
+
throw error;
|
|
589
|
+
}
|
|
590
|
+
},
|
|
591
|
+
|
|
592
|
+
/**
|
|
593
|
+
* Run tests in watch mode
|
|
594
|
+
*/
|
|
595
|
+
async runInWatchMode(): Promise<void> {
|
|
596
|
+
console.log('๐ Starting tests in watch mode...');
|
|
597
|
+
try {
|
|
598
|
+
const child = spawn('npm', ['test', '--', '--watch'], {
|
|
599
|
+
stdio: 'inherit',
|
|
600
|
+
});
|
|
601
|
+
|
|
602
|
+
child.on('close', (code) => {
|
|
603
|
+
console.log(`Watch mode exited with code ${code}`);
|
|
604
|
+
});
|
|
605
|
+
} catch (error) {
|
|
606
|
+
console.error('โ Watch mode failed:', error);
|
|
607
|
+
throw error;
|
|
608
|
+
}
|
|
609
|
+
},
|
|
610
|
+
|
|
611
|
+
/**
|
|
612
|
+
* Clean test artifacts
|
|
613
|
+
*/
|
|
614
|
+
async cleanTestArtifacts(): Promise<void> {
|
|
615
|
+
console.log('๐งน Cleaning test artifacts...');
|
|
616
|
+
try {
|
|
617
|
+
await execAsync('rm -rf coverage test-reports __snapshots__');
|
|
618
|
+
console.log('โ
Test artifacts cleaned');
|
|
619
|
+
} catch (error) {
|
|
620
|
+
console.error('โ Cleanup failed:', error);
|
|
621
|
+
throw error;
|
|
622
|
+
}
|
|
623
|
+
},
|
|
624
|
+
};
|
|
625
|
+
|
|
626
|
+
// Export main automation class as default
|
|
627
|
+
export default TestAutomation;
|