@react-native-harness/cli 1.1.0 → 1.2.0
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/__tests__/platform-commands.test.d.ts +2 -0
- package/dist/__tests__/platform-commands.test.d.ts.map +1 -0
- package/dist/__tests__/platform-commands.test.js +207 -0
- package/dist/bundlers/metro.d.ts +5 -0
- package/dist/bundlers/metro.d.ts.map +1 -0
- package/dist/bundlers/metro.js +71 -0
- package/dist/bundlers/webpack.d.ts +2 -0
- package/dist/bundlers/webpack.d.ts.map +1 -0
- package/dist/bundlers/webpack.js +49 -0
- package/dist/commands/test.d.ts +3 -0
- package/dist/commands/test.d.ts.map +1 -0
- package/dist/commands/test.js +140 -0
- package/dist/discovery/index.d.ts +3 -0
- package/dist/discovery/index.d.ts.map +1 -0
- package/dist/discovery/index.js +1 -0
- package/dist/discovery/testDiscovery.d.ts +11 -0
- package/dist/discovery/testDiscovery.d.ts.map +1 -0
- package/dist/discovery/testDiscovery.js +29 -0
- package/dist/errors/appNotInstalledError.d.ts +7 -0
- package/dist/errors/appNotInstalledError.d.ts.map +1 -0
- package/dist/errors/appNotInstalledError.js +12 -0
- package/dist/errors/bridgeTimeoutError.d.ts +7 -0
- package/dist/errors/bridgeTimeoutError.d.ts.map +1 -0
- package/dist/errors/bridgeTimeoutError.js +12 -0
- package/dist/errors/errorHandler.d.ts +2 -0
- package/dist/errors/errorHandler.d.ts.map +1 -0
- package/dist/errors/errorHandler.js +152 -0
- package/dist/errors/errors.d.ts +45 -0
- package/dist/errors/errors.d.ts.map +1 -0
- package/dist/errors/errors.js +89 -0
- package/dist/index.js +113 -6
- package/dist/jest.d.ts +2 -0
- package/dist/jest.d.ts.map +1 -0
- package/dist/jest.js +7 -0
- package/dist/platform-commands.d.ts +18 -0
- package/dist/platform-commands.d.ts.map +1 -0
- package/dist/platform-commands.js +84 -0
- package/dist/platforms/android/build.d.ts +5 -0
- package/dist/platforms/android/build.d.ts.map +1 -0
- package/dist/platforms/android/build.js +29 -0
- package/dist/platforms/android/device.d.ts +5 -0
- package/dist/platforms/android/device.d.ts.map +1 -0
- package/dist/platforms/android/device.js +36 -0
- package/dist/platforms/android/emulator.d.ts +10 -0
- package/dist/platforms/android/emulator.d.ts.map +1 -0
- package/dist/platforms/android/emulator.js +116 -0
- package/dist/platforms/android/index.d.ts +4 -0
- package/dist/platforms/android/index.d.ts.map +1 -0
- package/dist/platforms/android/index.js +56 -0
- package/dist/platforms/ios/build.d.ts +7 -0
- package/dist/platforms/ios/build.d.ts.map +1 -0
- package/dist/platforms/ios/build.js +48 -0
- package/dist/platforms/ios/device.d.ts +11 -0
- package/dist/platforms/ios/device.d.ts.map +1 -0
- package/dist/platforms/ios/device.js +51 -0
- package/dist/platforms/ios/index.d.ts +4 -0
- package/dist/platforms/ios/index.d.ts.map +1 -0
- package/dist/platforms/ios/index.js +43 -0
- package/dist/platforms/ios/simulator.d.ts +11 -0
- package/dist/platforms/ios/simulator.d.ts.map +1 -0
- package/dist/platforms/ios/simulator.js +129 -0
- package/dist/platforms/platform-adapter.d.ts +10 -0
- package/dist/platforms/platform-adapter.d.ts.map +1 -0
- package/dist/platforms/platform-adapter.js +1 -0
- package/dist/platforms/platform-registry.d.ts +3 -0
- package/dist/platforms/platform-registry.d.ts.map +1 -0
- package/dist/platforms/platform-registry.js +21 -0
- package/dist/platforms/vega/build.d.ts +23 -0
- package/dist/platforms/vega/build.d.ts.map +1 -0
- package/dist/platforms/vega/build.js +55 -0
- package/dist/platforms/vega/device.d.ts +57 -0
- package/dist/platforms/vega/device.d.ts.map +1 -0
- package/dist/platforms/vega/device.js +206 -0
- package/dist/platforms/vega/index.d.ts +4 -0
- package/dist/platforms/vega/index.d.ts.map +1 -0
- package/dist/platforms/vega/index.js +75 -0
- package/dist/platforms/web/index.d.ts +4 -0
- package/dist/platforms/web/index.d.ts.map +1 -0
- package/dist/platforms/web/index.js +9 -0
- package/dist/process.d.ts +3 -0
- package/dist/process.d.ts.map +1 -0
- package/dist/process.js +28 -0
- package/dist/reporters/default-reporter.d.ts +3 -0
- package/dist/reporters/default-reporter.d.ts.map +1 -0
- package/dist/reporters/default-reporter.js +116 -0
- package/dist/reporters/junit-reporter.d.ts +3 -0
- package/dist/reporters/junit-reporter.d.ts.map +1 -0
- package/dist/reporters/junit-reporter.js +119 -0
- package/dist/reporters/live-reporter.d.ts +20 -0
- package/dist/reporters/live-reporter.d.ts.map +1 -0
- package/dist/reporters/live-reporter.js +176 -0
- package/dist/src/reporters/default-reporter.js +135 -0
- package/dist/test-reporter-demo.js +95 -0
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/dist/utils/status-formatter.d.ts +27 -0
- package/dist/utils/status-formatter.d.ts.map +1 -0
- package/dist/utils/status-formatter.js +54 -0
- package/dist/utils.d.ts +6 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +26 -0
- package/dist/wizard/bundleId.js +1 -1
- package/dist/wizard/jestIntegration.d.ts +2 -0
- package/dist/wizard/jestIntegration.d.ts.map +1 -0
- package/dist/wizard/jestIntegration.js +15 -0
- package/dist/wizard/packageManager.d.ts +2 -0
- package/dist/wizard/packageManager.d.ts.map +1 -0
- package/dist/wizard/packageManager.js +10 -0
- package/eslint.config.mjs +1 -1
- package/package.json +8 -8
- package/skills/core.md +92 -0
- package/skills/mocking.md +87 -0
- package/skills/ui.md +59 -0
- package/src/__tests__/platform-commands.test.ts +232 -0
- package/src/index.ts +152 -5
- package/src/platform-commands.ts +148 -0
- package/src/wizard/bundleId.ts +1 -1
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { SuiteResult, LiveReportingEvent } from '@react-native-harness/bridge';
|
|
2
|
+
import { Reporter } from '@react-native-harness/config';
|
|
3
|
+
export declare class LiveReporter {
|
|
4
|
+
private state;
|
|
5
|
+
private progressSpinner;
|
|
6
|
+
constructor();
|
|
7
|
+
start(): void;
|
|
8
|
+
handleLiveEvent(event: LiveReportingEvent): void;
|
|
9
|
+
private getStatusSymbol;
|
|
10
|
+
private updateProgress;
|
|
11
|
+
private formatDuration;
|
|
12
|
+
stop(message: string): void;
|
|
13
|
+
countTests(suite: SuiteResult): number;
|
|
14
|
+
setTotalTests(results: SuiteResult[]): void;
|
|
15
|
+
}
|
|
16
|
+
export declare const createLiveReporter: () => {
|
|
17
|
+
reporter: Reporter;
|
|
18
|
+
liveReporter: LiveReporter;
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=live-reporter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"live-reporter.d.ts","sourceRoot":"","sources":["../../src/reporters/live-reporter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,WAAW,EAEX,kBAAkB,EACnB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAcxD,qBAAa,YAAY;IACvB,OAAO,CAAC,KAAK,CAAoB;IACjC,OAAO,CAAC,eAAe,CAA6B;;IAiBpD,KAAK;IAKL,eAAe,CAAC,KAAK,EAAE,kBAAkB;IA4DzC,OAAO,CAAC,eAAe;IAevB,OAAO,CAAC,cAAc;IA6BtB,OAAO,CAAC,cAAc;IAMtB,IAAI,CAAC,OAAO,EAAE,MAAM;IAKpB,UAAU,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM;IAQtC,aAAa,CAAC,OAAO,EAAE,WAAW,EAAE;CAMrC;AAED,eAAO,MAAM,kBAAkB,QAAO;IACpC,QAAQ,EAAE,QAAQ,CAAC;IACnB,YAAY,EAAE,YAAY,CAAC;CA0C5B,CAAC"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { color, spinner } from '@react-native-harness/tools';
|
|
2
|
+
export class LiveReporter {
|
|
3
|
+
state;
|
|
4
|
+
progressSpinner;
|
|
5
|
+
constructor() {
|
|
6
|
+
this.state = {
|
|
7
|
+
totalTests: 0,
|
|
8
|
+
completedTests: 0,
|
|
9
|
+
passedTests: 0,
|
|
10
|
+
failedTests: 0,
|
|
11
|
+
skippedTests: 0,
|
|
12
|
+
todoTests: 0,
|
|
13
|
+
currentTest: null,
|
|
14
|
+
currentSuite: null,
|
|
15
|
+
startTime: Date.now(),
|
|
16
|
+
};
|
|
17
|
+
this.progressSpinner = spinner();
|
|
18
|
+
}
|
|
19
|
+
start() {
|
|
20
|
+
this.state.startTime = Date.now();
|
|
21
|
+
this.progressSpinner.start('Initializing tests...');
|
|
22
|
+
}
|
|
23
|
+
handleLiveEvent(event) {
|
|
24
|
+
switch (event.type) {
|
|
25
|
+
case 'suite_started':
|
|
26
|
+
this.state.currentSuite = event.suiteHierarchy.join(' > ');
|
|
27
|
+
this.updateProgress(`Starting suite: ${this.state.currentSuite}`);
|
|
28
|
+
break;
|
|
29
|
+
case 'test_started':
|
|
30
|
+
this.state.currentTest = `${event.suiteHierarchy.join(' > ')} > ${event.testName}`;
|
|
31
|
+
this.updateProgress(`Running: ${event.testName}`);
|
|
32
|
+
break;
|
|
33
|
+
case 'test_completed':
|
|
34
|
+
this.state.completedTests++;
|
|
35
|
+
switch (event.result.status) {
|
|
36
|
+
case 'passed':
|
|
37
|
+
this.state.passedTests++;
|
|
38
|
+
break;
|
|
39
|
+
case 'failed':
|
|
40
|
+
this.state.failedTests++;
|
|
41
|
+
break;
|
|
42
|
+
case 'skipped':
|
|
43
|
+
this.state.skippedTests++;
|
|
44
|
+
break;
|
|
45
|
+
case 'todo':
|
|
46
|
+
this.state.todoTests++;
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
const statusSymbol = this.getStatusSymbol(event.result.status);
|
|
50
|
+
const duration = event.result.duration
|
|
51
|
+
? ` (${event.result.duration}ms)`
|
|
52
|
+
: '';
|
|
53
|
+
this.updateProgress(`${statusSymbol} ${event.testName}${duration}`, event.result.status === 'failed'
|
|
54
|
+
? event.result.error?.message
|
|
55
|
+
: undefined);
|
|
56
|
+
break;
|
|
57
|
+
case 'suite_completed':
|
|
58
|
+
const suiteStatusSymbol = this.getStatusSymbol(event.result.status);
|
|
59
|
+
const suiteDuration = event.result.duration
|
|
60
|
+
? ` (${event.result.duration}ms)`
|
|
61
|
+
: '';
|
|
62
|
+
this.updateProgress(`${suiteStatusSymbol} Suite completed: ${event.suiteHierarchy.join(' > ')}${suiteDuration}`);
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
getStatusSymbol(status) {
|
|
67
|
+
switch (status) {
|
|
68
|
+
case 'passed':
|
|
69
|
+
return color.green('✓');
|
|
70
|
+
case 'failed':
|
|
71
|
+
return color.red('✗');
|
|
72
|
+
case 'skipped':
|
|
73
|
+
return color.yellow('-');
|
|
74
|
+
case 'todo':
|
|
75
|
+
return color.blue('○');
|
|
76
|
+
default:
|
|
77
|
+
return '?';
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
updateProgress(message, error) {
|
|
81
|
+
const elapsed = Date.now() - this.state.startTime;
|
|
82
|
+
const elapsedFormatted = this.formatDuration(elapsed);
|
|
83
|
+
const progress = this.state.totalTests > 0
|
|
84
|
+
? ` [${this.state.completedTests}/${this.state.totalTests}]`
|
|
85
|
+
: ` [${this.state.completedTests} completed]`;
|
|
86
|
+
const summary = [
|
|
87
|
+
color.green(`${this.state.passedTests} passed`),
|
|
88
|
+
...(this.state.failedTests > 0
|
|
89
|
+
? [color.red(`${this.state.failedTests} failed`)]
|
|
90
|
+
: []),
|
|
91
|
+
...(this.state.skippedTests > 0
|
|
92
|
+
? [color.yellow(`${this.state.skippedTests} skipped`)]
|
|
93
|
+
: []),
|
|
94
|
+
...(this.state.todoTests > 0
|
|
95
|
+
? [color.blue(`${this.state.todoTests} todo`)]
|
|
96
|
+
: []),
|
|
97
|
+
].join(', ');
|
|
98
|
+
this.progressSpinner.message(`${message}${progress} | ${summary} | ${elapsedFormatted}${error ? `\n ${color.red('Error:')} ${error}` : ''}`);
|
|
99
|
+
}
|
|
100
|
+
formatDuration(ms) {
|
|
101
|
+
if (ms < 1000)
|
|
102
|
+
return `${ms}ms`;
|
|
103
|
+
if (ms < 60000)
|
|
104
|
+
return `${(ms / 1000).toFixed(1)}s`;
|
|
105
|
+
return `${Math.floor(ms / 60000)}m ${Math.floor((ms % 60000) / 1000)}s`;
|
|
106
|
+
}
|
|
107
|
+
stop(message) {
|
|
108
|
+
this.progressSpinner.stop(message);
|
|
109
|
+
}
|
|
110
|
+
// Count total tests in suite hierarchy
|
|
111
|
+
countTests(suite) {
|
|
112
|
+
let count = suite.tests.length;
|
|
113
|
+
for (const childSuite of suite.suites) {
|
|
114
|
+
count += this.countTests(childSuite);
|
|
115
|
+
}
|
|
116
|
+
return count;
|
|
117
|
+
}
|
|
118
|
+
setTotalTests(results) {
|
|
119
|
+
this.state.totalTests = results.reduce((sum, suite) => sum + this.countTests(suite), 0);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
export const createLiveReporter = () => {
|
|
123
|
+
const liveReporter = new LiveReporter();
|
|
124
|
+
const reporter = {
|
|
125
|
+
report: async (results) => {
|
|
126
|
+
// Final summary is handled by the existing default reporter logic
|
|
127
|
+
const totalPassed = results.reduce((sum, suite) => sum + getTestSummary(suite).passed, 0);
|
|
128
|
+
const totalFailed = results.reduce((sum, suite) => sum + getTestSummary(suite).failed, 0);
|
|
129
|
+
const totalSkipped = results.reduce((sum, suite) => sum + getTestSummary(suite).skipped, 0);
|
|
130
|
+
const totalTodo = results.reduce((sum, suite) => sum + getTestSummary(suite).todo, 0);
|
|
131
|
+
const totalDuration = results.reduce((sum, suite) => sum + (suite.duration || 0), 0);
|
|
132
|
+
const summaryText = [
|
|
133
|
+
color.green(`${totalPassed} passed`),
|
|
134
|
+
color.red(`${totalFailed} failed`),
|
|
135
|
+
color.yellow(`${totalSkipped} skipped`),
|
|
136
|
+
color.blue(`${totalTodo} todo`),
|
|
137
|
+
].join(', ');
|
|
138
|
+
liveReporter.stop(`Summary: ${summaryText} | Total time: ${formatDuration(totalDuration)}`);
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
return { reporter, liveReporter };
|
|
142
|
+
};
|
|
143
|
+
const getTestSummary = (suite) => {
|
|
144
|
+
let passed = 0, failed = 0, skipped = 0, todo = 0;
|
|
145
|
+
// Count tests in current suite
|
|
146
|
+
for (const test of suite.tests) {
|
|
147
|
+
switch (test.status) {
|
|
148
|
+
case 'passed':
|
|
149
|
+
passed++;
|
|
150
|
+
break;
|
|
151
|
+
case 'failed':
|
|
152
|
+
failed++;
|
|
153
|
+
break;
|
|
154
|
+
case 'skipped':
|
|
155
|
+
skipped++;
|
|
156
|
+
break;
|
|
157
|
+
case 'todo':
|
|
158
|
+
todo++;
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
// Count tests in nested suites
|
|
163
|
+
for (const childSuite of suite.suites) {
|
|
164
|
+
const childSummary = getTestSummary(childSuite);
|
|
165
|
+
passed += childSummary.passed;
|
|
166
|
+
failed += childSummary.failed;
|
|
167
|
+
skipped += childSummary.skipped;
|
|
168
|
+
todo += childSummary.todo;
|
|
169
|
+
}
|
|
170
|
+
return { passed, failed, skipped, todo };
|
|
171
|
+
};
|
|
172
|
+
const formatDuration = (duration) => duration
|
|
173
|
+
? duration < 1000
|
|
174
|
+
? `${duration}ms`
|
|
175
|
+
: `${(duration / 1000).toFixed(2)}s`
|
|
176
|
+
: '0ms';
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { color, logger } from '@react-native-harness/tools';
|
|
2
|
+
export const defaultReporter = {
|
|
3
|
+
report: async (results) => {
|
|
4
|
+
logger.log('\n📋 Test Results');
|
|
5
|
+
console.log(color.dim('━'.repeat(60)));
|
|
6
|
+
for (const suite of results) {
|
|
7
|
+
console.log(formatSuiteResult(suite));
|
|
8
|
+
}
|
|
9
|
+
console.log(color.dim('━'.repeat(60)));
|
|
10
|
+
// Summary
|
|
11
|
+
let totalPassed = 0, totalFailed = 0, totalSkipped = 0, totalTodo = 0;
|
|
12
|
+
let totalDuration = 0;
|
|
13
|
+
for (const suite of results) {
|
|
14
|
+
const summary = getTestSummary(suite);
|
|
15
|
+
totalPassed += summary.passed;
|
|
16
|
+
totalFailed += summary.failed;
|
|
17
|
+
totalSkipped += summary.skipped;
|
|
18
|
+
totalTodo += summary.todo;
|
|
19
|
+
totalDuration += suite.duration || 0;
|
|
20
|
+
}
|
|
21
|
+
// Create summary with modern styling
|
|
22
|
+
const summaryParts = [];
|
|
23
|
+
if (totalPassed > 0) {
|
|
24
|
+
summaryParts.push(color.green(`${totalPassed} passed`));
|
|
25
|
+
}
|
|
26
|
+
if (totalFailed > 0) {
|
|
27
|
+
summaryParts.push(color.red(`${totalFailed} failed`));
|
|
28
|
+
}
|
|
29
|
+
if (totalSkipped > 0) {
|
|
30
|
+
summaryParts.push(color.yellow(`${totalSkipped} skipped`));
|
|
31
|
+
}
|
|
32
|
+
if (totalTodo > 0) {
|
|
33
|
+
summaryParts.push(color.blue(`${totalTodo} todo`));
|
|
34
|
+
}
|
|
35
|
+
const summaryText = summaryParts.join(color.dim(' • '));
|
|
36
|
+
const durationText = formatDuration(totalDuration);
|
|
37
|
+
logger.info(`📊 Summary: ${summaryText}${durationText}`);
|
|
38
|
+
// Show appropriate final message
|
|
39
|
+
if (totalFailed === 0 && totalPassed > 0) {
|
|
40
|
+
logger.success('All tests passed! 🎉');
|
|
41
|
+
}
|
|
42
|
+
else if (totalFailed > 0) {
|
|
43
|
+
logger.error(`${totalFailed} test${totalFailed === 1 ? '' : 's'} failed`);
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
const formatDuration = (duration) => {
|
|
48
|
+
if (!duration)
|
|
49
|
+
return '';
|
|
50
|
+
return color.dim(` (${duration}ms)`);
|
|
51
|
+
};
|
|
52
|
+
const getStatusIcon = (status) => {
|
|
53
|
+
switch (status) {
|
|
54
|
+
case 'passed':
|
|
55
|
+
return color.green('✓');
|
|
56
|
+
case 'failed':
|
|
57
|
+
return color.red('✗');
|
|
58
|
+
case 'skipped':
|
|
59
|
+
return color.yellow('○');
|
|
60
|
+
case 'todo':
|
|
61
|
+
return color.blue('◐');
|
|
62
|
+
default:
|
|
63
|
+
return '?';
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
const formatTestResult = (test, indent = '') => {
|
|
67
|
+
const icon = getStatusIcon(test.status);
|
|
68
|
+
const name = test.status === 'failed' ? color.red(test.name) : test.name;
|
|
69
|
+
const duration = formatDuration(test.duration);
|
|
70
|
+
let result = `${indent}${icon} ${name}${duration}`;
|
|
71
|
+
if (test.error) {
|
|
72
|
+
const errorLines = test.error.message?.split('\n') || [];
|
|
73
|
+
result +=
|
|
74
|
+
'\n' +
|
|
75
|
+
errorLines
|
|
76
|
+
.map((line) => `${indent} ${color.red(line)}`)
|
|
77
|
+
.join('\n');
|
|
78
|
+
}
|
|
79
|
+
return result;
|
|
80
|
+
};
|
|
81
|
+
const formatSuiteResult = (suite, indent = '') => {
|
|
82
|
+
const icon = getStatusIcon(suite.status);
|
|
83
|
+
const name = suite.status === 'failed'
|
|
84
|
+
? color.red(color.bold(suite.name))
|
|
85
|
+
: color.bold(color.cyan(suite.name));
|
|
86
|
+
const duration = formatDuration(suite.duration);
|
|
87
|
+
let result = `${indent}${icon} ${name}${duration}`;
|
|
88
|
+
if (suite.error) {
|
|
89
|
+
const errorLines = suite.error.message.split('\n');
|
|
90
|
+
result +=
|
|
91
|
+
'\n' +
|
|
92
|
+
errorLines
|
|
93
|
+
.map((line) => `${indent} ${color.red(line)}`)
|
|
94
|
+
.join('\n');
|
|
95
|
+
}
|
|
96
|
+
const childIndent = indent + ' ';
|
|
97
|
+
// Format tests
|
|
98
|
+
for (const test of suite.tests) {
|
|
99
|
+
result += '\n' + formatTestResult(test, childIndent);
|
|
100
|
+
}
|
|
101
|
+
// Format nested suites
|
|
102
|
+
for (const childSuite of suite.suites) {
|
|
103
|
+
result += '\n' + formatSuiteResult(childSuite, childIndent);
|
|
104
|
+
}
|
|
105
|
+
return result;
|
|
106
|
+
};
|
|
107
|
+
const getTestSummary = (suite) => {
|
|
108
|
+
let passed = 0, failed = 0, skipped = 0, todo = 0;
|
|
109
|
+
// Count tests in current suite
|
|
110
|
+
for (const test of suite.tests) {
|
|
111
|
+
switch (test.status) {
|
|
112
|
+
case 'passed':
|
|
113
|
+
passed++;
|
|
114
|
+
break;
|
|
115
|
+
case 'failed':
|
|
116
|
+
failed++;
|
|
117
|
+
break;
|
|
118
|
+
case 'skipped':
|
|
119
|
+
skipped++;
|
|
120
|
+
break;
|
|
121
|
+
case 'todo':
|
|
122
|
+
todo++;
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// Count tests in nested suites
|
|
127
|
+
for (const childSuite of suite.suites) {
|
|
128
|
+
const childSummary = getTestSummary(childSuite);
|
|
129
|
+
passed += childSummary.passed;
|
|
130
|
+
failed += childSummary.failed;
|
|
131
|
+
skipped += childSummary.skipped;
|
|
132
|
+
todo += childSummary.todo;
|
|
133
|
+
}
|
|
134
|
+
return { passed, failed, skipped, todo };
|
|
135
|
+
};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { defaultReporter } from './src/reporters/default-reporter.js';
|
|
2
|
+
// Sample test results to demonstrate the new styling
|
|
3
|
+
const sampleResults = [
|
|
4
|
+
{
|
|
5
|
+
name: 'User Authentication Tests',
|
|
6
|
+
status: 'passed',
|
|
7
|
+
duration: 1250,
|
|
8
|
+
tests: [
|
|
9
|
+
{
|
|
10
|
+
name: 'should login with valid credentials',
|
|
11
|
+
status: 'passed',
|
|
12
|
+
duration: 450,
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
name: 'should show error with invalid credentials',
|
|
16
|
+
status: 'passed',
|
|
17
|
+
duration: 320,
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
name: 'should handle network errors gracefully',
|
|
21
|
+
status: 'failed',
|
|
22
|
+
duration: 180,
|
|
23
|
+
error: {
|
|
24
|
+
name: 'NetworkError',
|
|
25
|
+
message: 'Connection timeout after 30 seconds',
|
|
26
|
+
stack: 'NetworkError: Connection timeout after 30 seconds\n at fetch (native)\n at login (auth.js:15:10)',
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
suites: [],
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: 'Navigation Tests',
|
|
34
|
+
status: 'passed',
|
|
35
|
+
duration: 890,
|
|
36
|
+
tests: [
|
|
37
|
+
{
|
|
38
|
+
name: 'should navigate to home screen',
|
|
39
|
+
status: 'passed',
|
|
40
|
+
duration: 210,
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: 'should navigate to profile screen',
|
|
44
|
+
status: 'skipped',
|
|
45
|
+
duration: 0,
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: 'should handle deep linking',
|
|
49
|
+
status: 'todo',
|
|
50
|
+
duration: 0,
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
suites: [],
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
name: 'Component Tests',
|
|
57
|
+
status: 'failed',
|
|
58
|
+
duration: 650,
|
|
59
|
+
tests: [
|
|
60
|
+
{
|
|
61
|
+
name: 'should render button correctly',
|
|
62
|
+
status: 'passed',
|
|
63
|
+
duration: 120,
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: 'should handle button press',
|
|
67
|
+
status: 'failed',
|
|
68
|
+
duration: 95,
|
|
69
|
+
error: {
|
|
70
|
+
name: 'AssertionError',
|
|
71
|
+
message: 'Expected element to be visible but it was not found',
|
|
72
|
+
stack: 'AssertionError: Expected element to be visible but it was not found\n at expect (test-utils.js:25:10)',
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
suites: [
|
|
77
|
+
{
|
|
78
|
+
name: 'Nested Component Tests',
|
|
79
|
+
status: 'passed',
|
|
80
|
+
duration: 280,
|
|
81
|
+
tests: [
|
|
82
|
+
{
|
|
83
|
+
name: 'should render nested component',
|
|
84
|
+
status: 'passed',
|
|
85
|
+
duration: 150,
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
suites: [],
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
},
|
|
92
|
+
];
|
|
93
|
+
// Run the demo
|
|
94
|
+
console.log('🧪 Testing Updated Default Reporter\n');
|
|
95
|
+
await defaultReporter.report(sampleResults);
|