@react-native-harness/jest 1.0.0-alpha.17
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 +40 -0
- package/dist/cli-args.d.ts +5 -0
- package/dist/cli-args.d.ts.map +1 -0
- package/dist/cli-args.js +17 -0
- package/dist/cli-args.test.d.ts +2 -0
- package/dist/cli-args.test.d.ts.map +1 -0
- package/dist/cli-args.test.js +1 -0
- package/dist/event-mapper.d.ts +16 -0
- package/dist/event-mapper.d.ts.map +1 -0
- package/dist/event-mapper.js +120 -0
- package/dist/global-setup.d.ts +3 -0
- package/dist/global-setup.d.ts.map +1 -0
- package/dist/global-setup.js +60 -0
- package/dist/global-teardown.d.ts +3 -0
- package/dist/global-teardown.d.ts.map +1 -0
- package/dist/global-teardown.js +11 -0
- package/dist/harness-reporter.d.ts +8 -0
- package/dist/harness-reporter.d.ts.map +1 -0
- package/dist/harness-reporter.js +12 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +64 -0
- package/dist/jest-options.d.ts +2 -0
- package/dist/jest-options.d.ts.map +1 -0
- package/dist/jest-options.js +1 -0
- package/dist/jest-preset.d.ts +5 -0
- package/dist/jest-preset.d.ts.map +1 -0
- package/dist/jest-preset.js +3 -0
- package/dist/logs.d.ts +5 -0
- package/dist/logs.d.ts.map +1 -0
- package/dist/logs.js +14 -0
- package/dist/run.d.ts +11 -0
- package/dist/run.d.ts.map +1 -0
- package/dist/run.js +98 -0
- package/dist/setup.d.ts +3 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +60 -0
- package/dist/teardown.d.ts +3 -0
- package/dist/teardown.d.ts.map +1 -0
- package/dist/teardown.js +11 -0
- package/dist/toTestResult.d.ts +29 -0
- package/dist/toTestResult.d.ts.map +1 -0
- package/dist/toTestResult.js +64 -0
- package/dist/tsconfig.lib.tsbuildinfo +1 -0
- package/dist/types.d.ts +17 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/eslint.config.mjs +20 -0
- package/package.json +52 -0
- package/src/cli-args.ts +23 -0
- package/src/env.d.ts +9 -0
- package/src/index.ts +118 -0
- package/src/jest-preset.ts +3 -0
- package/src/logs.ts +21 -0
- package/src/run.ts +147 -0
- package/src/setup.ts +95 -0
- package/src/teardown.ts +15 -0
- package/src/toTestResult.ts +101 -0
- package/tsconfig.json +19 -0
- package/tsconfig.lib.json +25 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
CallbackTestRunnerInterface,
|
|
3
|
+
Config,
|
|
4
|
+
OnTestFailure,
|
|
5
|
+
OnTestStart,
|
|
6
|
+
OnTestSuccess,
|
|
7
|
+
Test,
|
|
8
|
+
TestRunnerOptions,
|
|
9
|
+
TestWatcher,
|
|
10
|
+
} from 'jest-runner';
|
|
11
|
+
import pLimit from 'p-limit';
|
|
12
|
+
import { runHarnessTestFile } from './run.js';
|
|
13
|
+
import { Config as HarnessConfig } from '@react-native-harness/config';
|
|
14
|
+
import { formatError, type Harness } from '@react-native-harness/cli/external';
|
|
15
|
+
import { setup } from './setup.js';
|
|
16
|
+
import { teardown } from './teardown.js';
|
|
17
|
+
|
|
18
|
+
class CancelRun extends Error {
|
|
19
|
+
constructor(message?: string) {
|
|
20
|
+
super(message);
|
|
21
|
+
this.name = 'CancelRun';
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export default class JestHarness implements CallbackTestRunnerInterface {
|
|
26
|
+
readonly isSerial = true;
|
|
27
|
+
|
|
28
|
+
#globalConfig: Config.GlobalConfig;
|
|
29
|
+
|
|
30
|
+
constructor(globalConfig: Config.GlobalConfig) {
|
|
31
|
+
this.#globalConfig = globalConfig;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async runTests(
|
|
35
|
+
tests: Array<Test>,
|
|
36
|
+
watcher: TestWatcher,
|
|
37
|
+
onStart: OnTestStart,
|
|
38
|
+
onResult: OnTestSuccess,
|
|
39
|
+
onFailure: OnTestFailure,
|
|
40
|
+
options: TestRunnerOptions
|
|
41
|
+
): Promise<void> {
|
|
42
|
+
if (!options.serial) {
|
|
43
|
+
throw new Error('Parallel test running is not supported');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
// This is necessary as Harness may throw and we want to catch it and display a helpful error message.
|
|
48
|
+
await setup(this.#globalConfig);
|
|
49
|
+
|
|
50
|
+
const harness = global.HARNESS;
|
|
51
|
+
const harnessConfig = global.HARNESS_CONFIG;
|
|
52
|
+
|
|
53
|
+
return await this._createInBandTestRun(
|
|
54
|
+
tests,
|
|
55
|
+
watcher,
|
|
56
|
+
harness,
|
|
57
|
+
harnessConfig,
|
|
58
|
+
onStart,
|
|
59
|
+
onResult,
|
|
60
|
+
onFailure
|
|
61
|
+
);
|
|
62
|
+
} catch (error) {
|
|
63
|
+
// Jest will print strings as they are, without processing them further.
|
|
64
|
+
throw formatError(error);
|
|
65
|
+
} finally {
|
|
66
|
+
// This is necessary as Harness may throw and we want to catch it and display a helpful error message.
|
|
67
|
+
await teardown(this.#globalConfig);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async _createInBandTestRun(
|
|
72
|
+
tests: Array<Test>,
|
|
73
|
+
watcher: TestWatcher,
|
|
74
|
+
harness: Harness,
|
|
75
|
+
harnessConfig: HarnessConfig,
|
|
76
|
+
onStart: OnTestStart,
|
|
77
|
+
onResult: OnTestSuccess,
|
|
78
|
+
onFailure: OnTestFailure
|
|
79
|
+
): Promise<void> {
|
|
80
|
+
const mutex = pLimit(1);
|
|
81
|
+
let isFirstTest = true;
|
|
82
|
+
|
|
83
|
+
return tests.reduce(
|
|
84
|
+
(promise, test) =>
|
|
85
|
+
mutex(() =>
|
|
86
|
+
promise
|
|
87
|
+
.then(async () => {
|
|
88
|
+
if (watcher.isInterrupted()) {
|
|
89
|
+
throw new CancelRun();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (
|
|
93
|
+
harnessConfig.resetEnvironmentBetweenTestFiles &&
|
|
94
|
+
!isFirstTest
|
|
95
|
+
) {
|
|
96
|
+
await new Promise((resolve) => {
|
|
97
|
+
harness.bridge.once('ready', resolve);
|
|
98
|
+
harness.environment.restart();
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
isFirstTest = false;
|
|
102
|
+
|
|
103
|
+
return onStart(test).then(() =>
|
|
104
|
+
runHarnessTestFile({
|
|
105
|
+
testPath: test.path,
|
|
106
|
+
harness,
|
|
107
|
+
globalConfig: this.#globalConfig,
|
|
108
|
+
projectConfig: test.context.config,
|
|
109
|
+
})
|
|
110
|
+
);
|
|
111
|
+
})
|
|
112
|
+
.then((result) => onResult(test, result))
|
|
113
|
+
.catch((err) => onFailure(test, err))
|
|
114
|
+
),
|
|
115
|
+
Promise.resolve()
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
}
|
package/src/logs.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { TestRunnerConfig } from '@react-native-harness/config';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
|
|
4
|
+
const TAG = chalk.supportsColor
|
|
5
|
+
? chalk.reset.inverse.bold.magenta(` HARNESS `)
|
|
6
|
+
: 'HARNESS';
|
|
7
|
+
|
|
8
|
+
// @see https://github.com/jestjs/jest/blob/main/packages/jest-reporters/src/BaseReporter.ts#L25
|
|
9
|
+
export const log = (message: string): void => {
|
|
10
|
+
process.stderr.write(`${message}\n`);
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const logTestRunHeader = (runner: TestRunnerConfig): void => {
|
|
14
|
+
log(
|
|
15
|
+
`${TAG} Preparing to run tests using ${chalk.bold(runner.name)} runner\n`
|
|
16
|
+
);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const logTestEnvironmentReady = (runner: TestRunnerConfig): void => {
|
|
20
|
+
log(`${TAG} Runner ${chalk.bold(runner.name)} ready\n`);
|
|
21
|
+
};
|
package/src/run.ts
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import type { Config as JestConfig } from 'jest-runner';
|
|
3
|
+
import { TestResult as JestTestResult } from '@jest/test-result';
|
|
4
|
+
import type {
|
|
5
|
+
TestSuiteResult as HarnessTestSuiteResult,
|
|
6
|
+
TestResult as HarnessTestResult,
|
|
7
|
+
} from '@react-native-harness/bridge';
|
|
8
|
+
import type { Harness } from '@react-native-harness/cli/external';
|
|
9
|
+
import { formatResultsErrors } from 'jest-message-util';
|
|
10
|
+
import { toTestResult } from './toTestResult.js';
|
|
11
|
+
|
|
12
|
+
// Helper function to flatten nested test suites into a flat array of tests with hierarchy
|
|
13
|
+
const flattenTests = (
|
|
14
|
+
suiteResult: HarnessTestSuiteResult,
|
|
15
|
+
ancestorTitles: string[] = []
|
|
16
|
+
): Array<HarnessTestResult & { ancestorTitles: string[] }> => {
|
|
17
|
+
const tests: Array<HarnessTestResult & { ancestorTitles: string[] }> = [];
|
|
18
|
+
|
|
19
|
+
// Add tests from current suite with current hierarchy
|
|
20
|
+
for (const test of suiteResult.tests) {
|
|
21
|
+
tests.push({
|
|
22
|
+
...test,
|
|
23
|
+
ancestorTitles: [...ancestorTitles],
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Process child suites with updated hierarchy
|
|
28
|
+
for (const childSuite of suiteResult.suites) {
|
|
29
|
+
const newAncestorTitles = [...ancestorTitles, childSuite.name];
|
|
30
|
+
tests.push(...flattenTests(childSuite, newAncestorTitles));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return tests;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
// Helper function to calculate test statistics
|
|
37
|
+
const calculateStats = (tests: HarnessTestResult[]) => {
|
|
38
|
+
let passes = 0;
|
|
39
|
+
let failures = 0;
|
|
40
|
+
let pending = 0;
|
|
41
|
+
let todo = 0;
|
|
42
|
+
|
|
43
|
+
for (const test of tests) {
|
|
44
|
+
switch (test.status) {
|
|
45
|
+
case 'passed':
|
|
46
|
+
passes++;
|
|
47
|
+
break;
|
|
48
|
+
case 'failed':
|
|
49
|
+
failures++;
|
|
50
|
+
break;
|
|
51
|
+
case 'skipped':
|
|
52
|
+
pending++;
|
|
53
|
+
break;
|
|
54
|
+
case 'todo':
|
|
55
|
+
todo++;
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return { passes, failures, pending, todo };
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export type RunHarnessTestFile = (options: {
|
|
64
|
+
testPath: string;
|
|
65
|
+
harness: Harness;
|
|
66
|
+
projectConfig: JestConfig.ProjectConfig;
|
|
67
|
+
globalConfig: JestConfig.GlobalConfig;
|
|
68
|
+
}) => Promise<JestTestResult>;
|
|
69
|
+
|
|
70
|
+
export const runHarnessTestFile: RunHarnessTestFile = async ({
|
|
71
|
+
testPath,
|
|
72
|
+
globalConfig,
|
|
73
|
+
projectConfig,
|
|
74
|
+
harness,
|
|
75
|
+
}) => {
|
|
76
|
+
const start = Date.now();
|
|
77
|
+
const relativeTestPath = path.relative(globalConfig.rootDir, testPath);
|
|
78
|
+
|
|
79
|
+
// Extract setup files from Jest config and convert to relative paths
|
|
80
|
+
const setupFiles = projectConfig.setupFiles?.map((setupFile) =>
|
|
81
|
+
path.relative(globalConfig.rootDir, setupFile)
|
|
82
|
+
);
|
|
83
|
+
const setupFilesAfterEnv = projectConfig.setupFilesAfterEnv?.map(
|
|
84
|
+
(setupFile) => path.relative(globalConfig.rootDir, setupFile)
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
const client = harness.bridge.rpc.clients.at(-1)!;
|
|
88
|
+
const results = await client.runTests(relativeTestPath, {
|
|
89
|
+
testNamePattern: globalConfig.testNamePattern,
|
|
90
|
+
setupFiles,
|
|
91
|
+
setupFilesAfterEnv,
|
|
92
|
+
});
|
|
93
|
+
const end = Date.now();
|
|
94
|
+
|
|
95
|
+
const allTests = flattenTests(results);
|
|
96
|
+
const stats = calculateStats(allTests);
|
|
97
|
+
|
|
98
|
+
// Convert TestResult[] to the format expected by toTestResult
|
|
99
|
+
const tests = allTests.map((test) => {
|
|
100
|
+
const errorMessage = test.error?.message;
|
|
101
|
+
const codeFrame = test.error?.codeFrame;
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
duration: test.duration,
|
|
105
|
+
errorMessage: errorMessage
|
|
106
|
+
? `${errorMessage}${codeFrame ? `\n\n${codeFrame.content}` : ''}`
|
|
107
|
+
: undefined,
|
|
108
|
+
title: test.name,
|
|
109
|
+
status: test.status,
|
|
110
|
+
location: codeFrame?.location
|
|
111
|
+
? { column: codeFrame.location.column, line: codeFrame.location.row }
|
|
112
|
+
: undefined,
|
|
113
|
+
ancestorTitles: test.ancestorTitles,
|
|
114
|
+
};
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// Check if the entire suite was skipped
|
|
118
|
+
const skipped = results.status === 'skipped';
|
|
119
|
+
|
|
120
|
+
// Get error message from suite if it failed
|
|
121
|
+
const errorMessage = results.error?.message || null;
|
|
122
|
+
|
|
123
|
+
const totalResults = toTestResult({
|
|
124
|
+
stats: {
|
|
125
|
+
failures: stats.failures,
|
|
126
|
+
pending: stats.pending,
|
|
127
|
+
passes: stats.passes,
|
|
128
|
+
todo: stats.todo,
|
|
129
|
+
start,
|
|
130
|
+
end,
|
|
131
|
+
},
|
|
132
|
+
skipped,
|
|
133
|
+
errorMessage,
|
|
134
|
+
tests,
|
|
135
|
+
jestTestPath: testPath,
|
|
136
|
+
coverage: results.coverage as JestTestResult['coverage'],
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
totalResults.failureMessage = formatResultsErrors(
|
|
140
|
+
totalResults.testResults,
|
|
141
|
+
projectConfig,
|
|
142
|
+
globalConfig,
|
|
143
|
+
testPath
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
return totalResults;
|
|
147
|
+
};
|
package/src/setup.ts
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getConfig,
|
|
3
|
+
TestRunnerConfig,
|
|
4
|
+
type Config as HarnessConfig,
|
|
5
|
+
type TestRunnerConfig as HarnessTestRunnerConfig,
|
|
6
|
+
} from '@react-native-harness/config';
|
|
7
|
+
import type { Config as JestConfig } from 'jest-runner';
|
|
8
|
+
import {
|
|
9
|
+
getHarness as getHarnessExternal,
|
|
10
|
+
NoRunnerSpecifiedError,
|
|
11
|
+
RunnerNotFoundError,
|
|
12
|
+
type Harness,
|
|
13
|
+
} from '@react-native-harness/cli/external';
|
|
14
|
+
import { preRunMessage } from 'jest-util';
|
|
15
|
+
import { getAdditionalCliArgs, HarnessCliArgs } from './cli-args.js';
|
|
16
|
+
import { logTestEnvironmentReady, logTestRunHeader } from './logs.js';
|
|
17
|
+
|
|
18
|
+
const getHarnessConfig = async (
|
|
19
|
+
globalConfig: JestConfig.GlobalConfig
|
|
20
|
+
): Promise<HarnessConfig> => {
|
|
21
|
+
const projectRoot = globalConfig.rootDir;
|
|
22
|
+
const { config: harnessConfig } = await getConfig(projectRoot);
|
|
23
|
+
return harnessConfig;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const getHarnessRunner = (
|
|
27
|
+
config: HarnessConfig,
|
|
28
|
+
cliArgs: HarnessCliArgs
|
|
29
|
+
): HarnessTestRunnerConfig => {
|
|
30
|
+
const selectedRunnerName = cliArgs.harnessRunner ?? config.defaultRunner;
|
|
31
|
+
|
|
32
|
+
if (!selectedRunnerName) {
|
|
33
|
+
throw new NoRunnerSpecifiedError(config.runners);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const runner = config.runners.find(
|
|
37
|
+
(runner) => runner.name === selectedRunnerName
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
if (!runner) {
|
|
41
|
+
throw new RunnerNotFoundError(selectedRunnerName, config.runners);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return runner;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const getHarness = async (runner: TestRunnerConfig): Promise<Harness> => {
|
|
48
|
+
return await getHarnessExternal(runner);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export const setup = async (globalConfig: JestConfig.GlobalConfig) => {
|
|
52
|
+
preRunMessage.remove(process.stderr);
|
|
53
|
+
const harnessConfig =
|
|
54
|
+
global.HARNESS_CONFIG ?? (await getHarnessConfig(globalConfig));
|
|
55
|
+
const isWatchMode = globalConfig.watch || globalConfig.watchAll;
|
|
56
|
+
|
|
57
|
+
if (global.HARNESS) {
|
|
58
|
+
// Do not setup again if HARNESS is already initialized
|
|
59
|
+
// This is useful when running tests in watch mode
|
|
60
|
+
|
|
61
|
+
if (harnessConfig.resetEnvironmentBetweenTestFiles) {
|
|
62
|
+
// In watch mode, we want to restart the environment before each test run
|
|
63
|
+
await new Promise((resolve) => {
|
|
64
|
+
global.HARNESS.bridge.once('ready', resolve);
|
|
65
|
+
global.HARNESS.environment.restart();
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (isWatchMode) {
|
|
73
|
+
// In watch mode, we want to dispose the Harness when the process exits.
|
|
74
|
+
process.on('exit', async () => {
|
|
75
|
+
await global.HARNESS.bridge.dispose();
|
|
76
|
+
await global.HARNESS.environment.dispose();
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const cliArgs = getAdditionalCliArgs();
|
|
81
|
+
const selectedRunner = getHarnessRunner(harnessConfig, cliArgs);
|
|
82
|
+
|
|
83
|
+
if (globalConfig.collectCoverage) {
|
|
84
|
+
// This is going to be used by @react-native-harness/babel-preset
|
|
85
|
+
// to enable instrumentation of test files.
|
|
86
|
+
process.env.RN_HARNESS_COLLECT_COVERAGE = 'true';
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
logTestRunHeader(selectedRunner);
|
|
90
|
+
const harness = await getHarness(selectedRunner);
|
|
91
|
+
logTestEnvironmentReady(selectedRunner);
|
|
92
|
+
|
|
93
|
+
global.HARNESS_CONFIG = harnessConfig;
|
|
94
|
+
global.HARNESS = harness;
|
|
95
|
+
};
|
package/src/teardown.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Config as JestConfig } from 'jest-runner';
|
|
2
|
+
|
|
3
|
+
export const teardown = async (globalConfig: JestConfig.GlobalConfig) => {
|
|
4
|
+
const isWatchMode = globalConfig.watch || globalConfig.watchAll;
|
|
5
|
+
|
|
6
|
+
if (isWatchMode) {
|
|
7
|
+
// In watch mode, we don't want to dispose the Harness.
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
if (global.HARNESS) {
|
|
12
|
+
await global.HARNESS.bridge.dispose();
|
|
13
|
+
await global.HARNESS.environment.dispose();
|
|
14
|
+
}
|
|
15
|
+
};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import type { Status, TestResult } from '@jest/test-result';
|
|
2
|
+
|
|
3
|
+
export type Options = {
|
|
4
|
+
stats: {
|
|
5
|
+
failures: number;
|
|
6
|
+
passes: number;
|
|
7
|
+
pending: number;
|
|
8
|
+
todo: number;
|
|
9
|
+
start: number;
|
|
10
|
+
end: number;
|
|
11
|
+
};
|
|
12
|
+
skipped: boolean;
|
|
13
|
+
errorMessage?: string | null;
|
|
14
|
+
tests: Array<{
|
|
15
|
+
duration?: number | null;
|
|
16
|
+
errorMessage?: string;
|
|
17
|
+
testPath?: string;
|
|
18
|
+
title?: string;
|
|
19
|
+
status: Status;
|
|
20
|
+
location?: {
|
|
21
|
+
column: number;
|
|
22
|
+
line: number;
|
|
23
|
+
};
|
|
24
|
+
ancestorTitles?: string[];
|
|
25
|
+
}>;
|
|
26
|
+
jestTestPath: string;
|
|
27
|
+
coverage?: TestResult['coverage'];
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const getPerfStats = ({ stats }: Options): TestResult['perfStats'] => {
|
|
31
|
+
const start = new Date(stats.start).getTime();
|
|
32
|
+
const end = new Date(stats.end).getTime();
|
|
33
|
+
const runtime = end - start;
|
|
34
|
+
// Note: this flag is set in 'lib/createJestRunner.ts'
|
|
35
|
+
const slow = false;
|
|
36
|
+
return {
|
|
37
|
+
start,
|
|
38
|
+
end,
|
|
39
|
+
runtime,
|
|
40
|
+
slow,
|
|
41
|
+
loadTestEnvironmentStart: 0,
|
|
42
|
+
loadTestEnvironmentEnd: 0,
|
|
43
|
+
setupAfterEnvStart: 0,
|
|
44
|
+
setupAfterEnvEnd: 0,
|
|
45
|
+
setupFilesStart: 0,
|
|
46
|
+
setupFilesEnd: 0,
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const getSnapshot = (): TestResult['snapshot'] => {
|
|
51
|
+
return {
|
|
52
|
+
added: 0,
|
|
53
|
+
fileDeleted: false,
|
|
54
|
+
matched: 0,
|
|
55
|
+
unchecked: 0,
|
|
56
|
+
uncheckedKeys: [],
|
|
57
|
+
unmatched: 0,
|
|
58
|
+
updated: 0,
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const getTestResults = ({
|
|
63
|
+
errorMessage,
|
|
64
|
+
tests,
|
|
65
|
+
jestTestPath,
|
|
66
|
+
}: Options): TestResult['testResults'] => {
|
|
67
|
+
return tests.map((test) => {
|
|
68
|
+
const actualErrorMessage = errorMessage || test.errorMessage;
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
ancestorTitles: test.ancestorTitles || [],
|
|
72
|
+
duration: test.duration,
|
|
73
|
+
failureDetails: [],
|
|
74
|
+
failureMessages: actualErrorMessage ? [actualErrorMessage] : [],
|
|
75
|
+
fullName: jestTestPath || test.testPath || '',
|
|
76
|
+
numPassingAsserts: test.errorMessage ? 1 : 0,
|
|
77
|
+
status: test.status,
|
|
78
|
+
title: test.title || '',
|
|
79
|
+
location: test.location,
|
|
80
|
+
};
|
|
81
|
+
});
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export const toTestResult = (options: Options): TestResult => {
|
|
85
|
+
const { stats, skipped, errorMessage, jestTestPath, coverage } = options;
|
|
86
|
+
return {
|
|
87
|
+
failureMessage: errorMessage,
|
|
88
|
+
leaks: false,
|
|
89
|
+
numFailingTests: stats.failures,
|
|
90
|
+
numPassingTests: stats.passes,
|
|
91
|
+
numPendingTests: stats.pending,
|
|
92
|
+
numTodoTests: stats.todo,
|
|
93
|
+
openHandles: [],
|
|
94
|
+
perfStats: getPerfStats(options),
|
|
95
|
+
skipped,
|
|
96
|
+
snapshot: getSnapshot(),
|
|
97
|
+
testFilePath: jestTestPath,
|
|
98
|
+
testResults: getTestResults(options),
|
|
99
|
+
coverage,
|
|
100
|
+
};
|
|
101
|
+
};
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
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": ["src/**/*.ts"],
|
|
14
|
+
"references": [
|
|
15
|
+
{
|
|
16
|
+
"path": "../cli/tsconfig.lib.json"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"path": "../config/tsconfig.lib.json"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"path": "../bridge/tsconfig.lib.json"
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}
|