react-native-harness 0.0.0 → 1.0.0-alpha.1
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/LICENSE +20 -0
- package/README.md +7 -0
- package/bin.js +3 -0
- package/dist/bundlers/metro.d.ts +5 -0
- package/dist/bundlers/metro.d.ts.map +1 -0
- package/dist/bundlers/metro.js +52 -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 +2 -0
- package/dist/commands/test.d.ts.map +1 -0
- package/dist/commands/test.js +111 -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 +138 -0
- package/dist/errors/errors.d.ts +41 -0
- package/dist/errors/errors.d.ts.map +1 -0
- package/dist/errors/errors.js +83 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -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 +11 -0
- package/dist/platforms/android/emulator.d.ts.map +1 -0
- package/dist/platforms/android/emulator.js +110 -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 +51 -0
- package/dist/platforms/ios/device.d.ts +7 -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 +38 -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 +133 -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 +19 -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 +73 -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 -0
- package/dist/utils.d.ts +5 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +11 -0
- package/eslint.config.mjs +19 -0
- package/package.json +16 -8
- package/src/bundlers/metro.ts +79 -0
- package/src/commands/test.ts +189 -0
- package/src/errors/errorHandler.ts +184 -0
- package/src/errors/errors.ts +109 -0
- package/src/index.ts +52 -0
- package/src/platforms/android/build.ts +48 -0
- package/src/platforms/android/device.ts +48 -0
- package/src/platforms/android/emulator.ts +139 -0
- package/src/platforms/android/index.ts +87 -0
- package/src/platforms/ios/build.ts +76 -0
- package/src/platforms/ios/device.ts +76 -0
- package/src/platforms/ios/index.ts +55 -0
- package/src/platforms/ios/simulator.ts +177 -0
- package/src/platforms/platform-adapter.ts +11 -0
- package/src/platforms/platform-registry.ts +24 -0
- package/src/platforms/web/index.ts +95 -0
- package/src/process.ts +33 -0
- package/src/reporters/default-reporter.ts +149 -0
- package/src/reporters/junit-reporter.ts +179 -0
- package/src/utils.ts +12 -0
- package/tsconfig.json +16 -0
- package/tsconfig.lib.json +33 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { Reporter } from '@react-native-harness/config';
|
|
2
|
+
import type { TestSuiteResult, TestResult } from '@react-native-harness/bridge';
|
|
3
|
+
import { writeFileSync } from 'fs';
|
|
4
|
+
import { join } from 'path';
|
|
5
|
+
|
|
6
|
+
export const junitReporter: Reporter = {
|
|
7
|
+
report: async (results) => {
|
|
8
|
+
const xml = generateJUnitXML(results);
|
|
9
|
+
|
|
10
|
+
// Write to junit.xml file
|
|
11
|
+
const outputPath = join(process.cwd(), 'junit.xml');
|
|
12
|
+
writeFileSync(outputPath, xml, 'utf8');
|
|
13
|
+
|
|
14
|
+
console.log(`📄 JUnit report written to: ${outputPath}`);
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const generateJUnitXML = (results: TestSuiteResult[]): string => {
|
|
19
|
+
const { totalTests, totalFailures, totalSkipped, totalTime } =
|
|
20
|
+
calculateTotals(results);
|
|
21
|
+
|
|
22
|
+
let xml = '<?xml version="1.0" encoding="UTF-8"?>\n';
|
|
23
|
+
xml += `<testsuites tests="${totalTests}" failures="${totalFailures}" skipped="${totalSkipped}" time="${
|
|
24
|
+
totalTime / 1000
|
|
25
|
+
}">\n`;
|
|
26
|
+
|
|
27
|
+
for (const suite of results) {
|
|
28
|
+
xml += generateTestSuiteXML(suite, ' ');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
xml += '</testsuites>\n';
|
|
32
|
+
|
|
33
|
+
return xml;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const generateTestSuiteXML = (
|
|
37
|
+
suite: TestSuiteResult,
|
|
38
|
+
indent: string
|
|
39
|
+
): string => {
|
|
40
|
+
const { tests, failures, skipped, time } = getSuiteStats(suite);
|
|
41
|
+
|
|
42
|
+
let xml = `${indent}<testsuite name="${escapeXML(
|
|
43
|
+
suite.name
|
|
44
|
+
)}" tests="${tests}" failures="${failures}" skipped="${skipped}" time="${
|
|
45
|
+
time / 1000
|
|
46
|
+
}"`;
|
|
47
|
+
|
|
48
|
+
if (suite.error) {
|
|
49
|
+
xml += ` errors="1"`;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
xml += '>\n';
|
|
53
|
+
|
|
54
|
+
// Add suite-level error if present
|
|
55
|
+
if (suite.error) {
|
|
56
|
+
xml += `${indent} <error message="${escapeXML(
|
|
57
|
+
suite.error.message || 'Suite failed'
|
|
58
|
+
)}"`;
|
|
59
|
+
if (suite.error.name) {
|
|
60
|
+
xml += ` type="${escapeXML(suite.error.name)}"`;
|
|
61
|
+
}
|
|
62
|
+
xml += '>';
|
|
63
|
+
if (suite.error.stack) {
|
|
64
|
+
xml += escapeXML(suite.error.stack);
|
|
65
|
+
}
|
|
66
|
+
xml += '</error>\n';
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Add individual test cases
|
|
70
|
+
for (const test of suite.tests) {
|
|
71
|
+
xml += generateTestCaseXML(test, indent + ' ');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Add nested suites
|
|
75
|
+
for (const nestedSuite of suite.suites) {
|
|
76
|
+
xml += generateTestSuiteXML(nestedSuite, indent + ' ');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
xml += `${indent}</testsuite>\n`;
|
|
80
|
+
|
|
81
|
+
return xml;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const generateTestCaseXML = (test: TestResult, indent: string): string => {
|
|
85
|
+
const time = (test.duration || 0) / 1000;
|
|
86
|
+
let xml = `${indent}<testcase name="${escapeXML(test.name)}" time="${time}"`;
|
|
87
|
+
|
|
88
|
+
if (test.status === 'passed') {
|
|
89
|
+
xml += '/>\n';
|
|
90
|
+
} else {
|
|
91
|
+
xml += '>\n';
|
|
92
|
+
|
|
93
|
+
switch (test.status) {
|
|
94
|
+
case 'failed':
|
|
95
|
+
xml += `${indent} <failure message="${escapeXML(
|
|
96
|
+
test.error?.message || 'Test failed'
|
|
97
|
+
)}"`;
|
|
98
|
+
if (test.error?.name) {
|
|
99
|
+
xml += ` type="${escapeXML(test.error.name)}"`;
|
|
100
|
+
}
|
|
101
|
+
xml += '>';
|
|
102
|
+
if (test.error?.stack) {
|
|
103
|
+
xml += escapeXML(test.error.stack);
|
|
104
|
+
}
|
|
105
|
+
xml += '</failure>\n';
|
|
106
|
+
break;
|
|
107
|
+
case 'skipped':
|
|
108
|
+
xml += `${indent} <skipped/>\n`;
|
|
109
|
+
break;
|
|
110
|
+
case 'todo':
|
|
111
|
+
xml += `${indent} <skipped message="TODO: Test not implemented"/>\n`;
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
xml += `${indent}</testcase>\n`;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return xml;
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const calculateTotals = (
|
|
122
|
+
results: TestSuiteResult[]
|
|
123
|
+
): {
|
|
124
|
+
totalTests: number;
|
|
125
|
+
totalFailures: number;
|
|
126
|
+
totalSkipped: number;
|
|
127
|
+
totalTime: number;
|
|
128
|
+
} => {
|
|
129
|
+
let totalTests = 0;
|
|
130
|
+
let totalFailures = 0;
|
|
131
|
+
let totalSkipped = 0;
|
|
132
|
+
let totalTime = 0;
|
|
133
|
+
|
|
134
|
+
for (const suite of results) {
|
|
135
|
+
const stats = getSuiteStats(suite);
|
|
136
|
+
totalTests += stats.tests;
|
|
137
|
+
totalFailures += stats.failures;
|
|
138
|
+
totalSkipped += stats.skipped;
|
|
139
|
+
totalTime += stats.time;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return { totalTests, totalFailures, totalSkipped, totalTime };
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
const getSuiteStats = (
|
|
146
|
+
suite: TestSuiteResult
|
|
147
|
+
): {
|
|
148
|
+
tests: number;
|
|
149
|
+
failures: number;
|
|
150
|
+
skipped: number;
|
|
151
|
+
time: number;
|
|
152
|
+
} => {
|
|
153
|
+
let tests = suite.tests.length;
|
|
154
|
+
let failures = suite.tests.filter((t) => t.status === 'failed').length;
|
|
155
|
+
let skipped = suite.tests.filter(
|
|
156
|
+
(t) => t.status === 'skipped' || t.status === 'todo'
|
|
157
|
+
).length;
|
|
158
|
+
let time = suite.duration || 0;
|
|
159
|
+
|
|
160
|
+
// Add stats from nested suites
|
|
161
|
+
for (const nestedSuite of suite.suites) {
|
|
162
|
+
const nestedStats = getSuiteStats(nestedSuite);
|
|
163
|
+
tests += nestedStats.tests;
|
|
164
|
+
failures += nestedStats.failures;
|
|
165
|
+
skipped += nestedStats.skipped;
|
|
166
|
+
time += nestedStats.time;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return { tests, failures, skipped, time };
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
const escapeXML = (str: string): string => {
|
|
173
|
+
return str
|
|
174
|
+
.replace(/&/g, '&')
|
|
175
|
+
.replace(/</g, '<')
|
|
176
|
+
.replace(/>/g, '>')
|
|
177
|
+
.replace(/"/g, '"')
|
|
178
|
+
.replace(/'/g, ''');
|
|
179
|
+
};
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export function assert(condition: boolean, message: string): asserts condition {
|
|
2
|
+
if (!condition) {
|
|
3
|
+
throw new AssertionError(message);
|
|
4
|
+
}
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export class AssertionError extends Error {
|
|
8
|
+
constructor(message: string) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = 'AssertionError';
|
|
11
|
+
}
|
|
12
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../tsconfig.base.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"baseUrl": ".",
|
|
5
|
+
"rootDir": "src",
|
|
6
|
+
"outDir": "dist",
|
|
7
|
+
"tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo",
|
|
8
|
+
"emitDeclarationOnly": false,
|
|
9
|
+
"forceConsistentCasingInFileNames": true,
|
|
10
|
+
"types": ["node"],
|
|
11
|
+
"lib": ["DOM"]
|
|
12
|
+
},
|
|
13
|
+
"include": [
|
|
14
|
+
"src/**/*.ts",
|
|
15
|
+
"../tools/src/abort.ts",
|
|
16
|
+
"../tools/src/color.ts",
|
|
17
|
+
"../tools/src/isInteractive.ts",
|
|
18
|
+
"../tools/src/logger.ts",
|
|
19
|
+
"../tools/src/prompts.ts",
|
|
20
|
+
"../tools/src/spawn.ts"
|
|
21
|
+
],
|
|
22
|
+
"references": [
|
|
23
|
+
{
|
|
24
|
+
"path": "../tools/tsconfig.lib.json"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"path": "../config/tsconfig.lib.json"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"path": "../bridge/tsconfig.lib.json"
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"fileNames":[],"fileInfos":[],"root":[],"options":{"composite":true,"declarationMap":true,"emitDeclarationOnly":true,"importHelpers":true,"module":199,"noEmitOnError":true,"noFallthroughCasesInSwitch":true,"noImplicitOverride":true,"noImplicitReturns":true,"noUnusedLocals":true,"skipLibCheck":true,"strict":true,"target":9},"version":"5.8.3"}
|