Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions packages/jest/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@
},
"dependencies": {
"@jest/test-result": "^30.2.0",
"@react-native-harness/bridge": "workspace:*",
"@react-native-harness/cli": "workspace:*",
"@react-native-harness/config": "workspace:*",
"chalk": "^4.1.2",
"jest-message-util": "^30.2.0",
"jest-runner": "^30.2.0",
"p-limit": "^7.1.1",
"tslib": "^2.3.0",
"yargs": "^17.7.2",
"@react-native-harness/cli": "workspace:*",
"@react-native-harness/bridge": "workspace:*",
"@react-native-harness/config": "workspace:*"
"yargs": "^17.7.2"
},
"devDependencies": {
"@types/yargs": "^17.0.32"
Expand Down
5 changes: 5 additions & 0 deletions packages/jest/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
} from '@react-native-harness/config';
import { getAdditionalCliArgs, HarnessCliArgs } from './cli-args.js';
import type { Harness } from '@react-native-harness/cli/external';
import { logTestEnvironmentReady, logTestRunHeader } from './logs.js';

class CancelRun extends Error {
constructor(message?: string) {
Expand Down Expand Up @@ -67,6 +68,8 @@ export default class JestHarness implements CallbackTestRunnerInterface {
const cliArgs = getAdditionalCliArgs();
const selectedRunner = getHarnessRunner(harnessConfig, cliArgs);

logTestRunHeader(selectedRunner);

if (this.#globalConfig.collectCoverage) {
// This is going to be used by @react-native-harness/babel-preset
// to enable instrumentation of test files.
Expand All @@ -75,6 +78,8 @@ export default class JestHarness implements CallbackTestRunnerInterface {

const harness = await getHarness(selectedRunner);

logTestEnvironmentReady(selectedRunner);

try {
return await this._createInBandTestRun(
tests,
Expand Down
21 changes: 21 additions & 0 deletions packages/jest/src/logs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { TestRunnerConfig } from '@react-native-harness/config';
import chalk from 'chalk';

const TAG = chalk.supportsColor
? chalk.reset.inverse.bold.magenta(` HARNESS `)
: 'HARNESS';

// @see https://github.com/jestjs/jest/blob/main/packages/jest-reporters/src/BaseReporter.ts#L25
export const log = (message: string): void => {
process.stderr.write(`${message}\n`);
};

export const logTestRunHeader = (runner: TestRunnerConfig): void => {
log(
`${TAG} Preparing to run tests using ${chalk.bold(runner.name)} runner\n`
);
};

export const logTestEnvironmentReady = (runner: TestRunnerConfig): void => {
log(`${TAG} Runner ${chalk.bold(runner.name)} ready\n`);
};
57 changes: 44 additions & 13 deletions packages/jest/src/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,28 @@ import type {
TestResult as HarnessTestResult,
} from '@react-native-harness/bridge';
import type { Harness } from '@react-native-harness/cli/external';

import { formatResultsErrors } from 'jest-message-util';
import { toTestResult } from './toTestResult.js';

// Helper function to flatten nested test suites into a flat array of tests
// Helper function to flatten nested test suites into a flat array of tests with hierarchy
const flattenTests = (
suiteResult: HarnessTestSuiteResult
): HarnessTestResult[] => {
const tests: HarnessTestResult[] = [...suiteResult.tests];
suiteResult: HarnessTestSuiteResult,
ancestorTitles: string[] = []
): Array<HarnessTestResult & { ancestorTitles: string[] }> => {
const tests: Array<HarnessTestResult & { ancestorTitles: string[] }> = [];

// Add tests from current suite with current hierarchy
for (const test of suiteResult.tests) {
tests.push({
...test,
ancestorTitles: [...ancestorTitles],
});
}

// Process child suites with updated hierarchy
for (const childSuite of suiteResult.suites) {
tests.push(...flattenTests(childSuite));
const newAncestorTitles = [...ancestorTitles, childSuite.name];
tests.push(...flattenTests(childSuite, newAncestorTitles));
}

return tests;
Expand Down Expand Up @@ -85,20 +96,31 @@ export const runHarnessTestFile: RunHarnessTestFile = async ({
const stats = calculateStats(allTests);

// Convert TestResult[] to the format expected by toTestResult
const tests = allTests.map((test) => ({
duration: test.duration,
errorMessage: test.error?.message,
title: test.name,
status: test.status,
}));
const tests = allTests.map((test) => {
const errorMessage = test.error?.message;
const codeFrame = test.error?.codeFrame;

return {
duration: test.duration,
errorMessage: errorMessage
? `${errorMessage}${codeFrame ? `\n\n${codeFrame.content}` : ''}`
: undefined,
title: test.name,
status: test.status,
location: codeFrame?.location
? { column: codeFrame.location.column, line: codeFrame.location.row }
: undefined,
ancestorTitles: test.ancestorTitles,
};
});

// Check if the entire suite was skipped
const skipped = results.status === 'skipped';

// Get error message from suite if it failed
const errorMessage = results.error?.message || null;

return toTestResult({
const totalResults = toTestResult({
stats: {
failures: stats.failures,
pending: stats.pending,
Expand All @@ -113,4 +135,13 @@ export const runHarnessTestFile: RunHarnessTestFile = async ({
jestTestPath: testPath,
coverage: results.coverage as JestTestResult['coverage'],
});

totalResults.failureMessage = formatResultsErrors(
totalResults.testResults,
projectConfig,
globalConfig,
testPath
);

return totalResults;
};
8 changes: 7 additions & 1 deletion packages/jest/src/toTestResult.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ export type Options = {
testPath?: string;
title?: string;
status: Status;
location?: {
column: number;
line: number;
};
ancestorTitles?: string[];
}>;
jestTestPath: string;
coverage?: TestResult['coverage'];
Expand Down Expand Up @@ -63,14 +68,15 @@ const getTestResults = ({
const actualErrorMessage = errorMessage || test.errorMessage;

return {
ancestorTitles: [],
ancestorTitles: test.ancestorTitles || [],
duration: test.duration,
failureDetails: [],
failureMessages: actualErrorMessage ? [actualErrorMessage] : [],
fullName: jestTestPath || test.testPath || '',
numPassingAsserts: test.errorMessage ? 1 : 0,
status: test.status,
title: test.title || '',
location: test.location,
};
});
};
Expand Down
8 changes: 7 additions & 1 deletion pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.