Skip to content

Commit cae7174

Browse files
authored
feat: add support for setup files in jest (#6)
This pull request adds support for Jest’s setupFiles and setupFilesAfterEnv features. Both are executed before the test files - with setupFiles running first, followed by setupFilesAfterEnv. These files are bundled by Metro, just like the test files, so you can freely use TypeScript and import modules.
1 parent 0aad766 commit cae7174

8 files changed

Lines changed: 134 additions & 1 deletion

File tree

apps/playground/jest.config.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ module.exports = {
55
testMatch: [
66
'<rootDir>/src/__tests__/**/*.(test|spec|harness).(js|jsx|ts|tsx)',
77
],
8+
setupFiles: ['./src/setupFile.ts'],
9+
setupFilesAfterEnv: ['./src/setupFileAfterEnv.ts'],
810
},
911
],
1012
};
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { describe, test, expect } from 'react-native-harness';
2+
3+
describe('Setup files', () => {
4+
test('should execute setup file', () => {
5+
expect(global.SETUP_FILE_EXECUTED).toBe(true);
6+
});
7+
8+
test('should execute setup file after env', () => {
9+
expect(global.SETUP_FILE_EXECUTED_AFTER_ENV).toBe(true);
10+
});
11+
});

apps/playground/src/setupFile.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
declare global {
2+
var SETUP_FILE_EXECUTED: boolean;
3+
}
4+
5+
global.SETUP_FILE_EXECUTED = true;
6+
export {};
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
declare global {
2+
var SETUP_FILE_EXECUTED_AFTER_ENV: boolean;
3+
}
4+
5+
global.SETUP_FILE_EXECUTED_AFTER_ENV = true;
6+
export {};

packages/bridge/src/shared.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ export type {
3131
ModuleBundlingStartedEvent,
3232
ModuleBundlingFinishedEvent,
3333
ModuleBundlingFailedEvent,
34+
SetupFileBundlingStartedEvent,
35+
SetupFileBundlingFinishedEvent,
36+
SetupFileBundlingFailedEvent,
3437
BundlerEvents,
3538
} from './shared/bundler.js';
3639

@@ -54,6 +57,8 @@ export type BridgeEventsMap = {
5457

5558
export type TestExecutionOptions = {
5659
testNamePattern?: string;
60+
setupFiles?: string[];
61+
setupFilesAfterEnv?: string[];
5762
};
5863

5964
export type BridgeClientFunctions = {

packages/bridge/src/shared/bundler.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,31 @@ export type ModuleBundlingFailedEvent = {
1616
error: string;
1717
};
1818

19+
export type SetupFileBundlingStartedEvent = {
20+
type: 'setup-file-bundling-started';
21+
file: string;
22+
setupType: 'setupFiles' | 'setupFilesAfterEnv';
23+
};
24+
25+
export type SetupFileBundlingFinishedEvent = {
26+
type: 'setup-file-bundling-finished';
27+
file: string;
28+
setupType: 'setupFiles' | 'setupFilesAfterEnv';
29+
duration: number;
30+
};
31+
32+
export type SetupFileBundlingFailedEvent = {
33+
type: 'setup-file-bundling-failed';
34+
file: string;
35+
setupType: 'setupFiles' | 'setupFilesAfterEnv';
36+
duration: number;
37+
error: string;
38+
};
39+
1940
export type BundlerEvents =
2041
| ModuleBundlingStartedEvent
2142
| ModuleBundlingFinishedEvent
22-
| ModuleBundlingFailedEvent;
43+
| ModuleBundlingFailedEvent
44+
| SetupFileBundlingStartedEvent
45+
| SetupFileBundlingFinishedEvent
46+
| SetupFileBundlingFailedEvent;

packages/jest/src/run.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,25 @@ export type RunHarnessTestFile = (options: {
5959
export const runHarnessTestFile: RunHarnessTestFile = async ({
6060
testPath,
6161
globalConfig,
62+
projectConfig,
6263
harness,
6364
}) => {
6465
const start = Date.now();
6566
const relativeTestPath = path.relative(globalConfig.rootDir, testPath);
67+
68+
// Extract setup files from Jest config and convert to relative paths
69+
const setupFiles = projectConfig.setupFiles?.map((setupFile) =>
70+
path.relative(globalConfig.rootDir, setupFile)
71+
);
72+
const setupFilesAfterEnv = projectConfig.setupFilesAfterEnv?.map(
73+
(setupFile) => path.relative(globalConfig.rootDir, setupFile)
74+
);
75+
6676
const client = harness.bridge.rpc.clients.at(-1)!;
6777
const results = await client.runTests(relativeTestPath, {
6878
testNamePattern: globalConfig.testNamePattern,
79+
setupFiles,
80+
setupFilesAfterEnv,
6981
});
7082
const end = Date.now();
7183

packages/runtime/src/client/factory.ts

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,73 @@ export const getClient = async () => {
5151
client.rpc.emitEvent(event.type, event);
5252
});
5353

54+
// Execute setup files before test collection
55+
if (options.setupFiles) {
56+
for (const setupFile of options.setupFiles) {
57+
const startTime = Date.now();
58+
events.emit({
59+
type: 'setup-file-bundling-started',
60+
file: setupFile,
61+
setupType: 'setupFiles',
62+
});
63+
64+
try {
65+
const setupModuleJs = await bundler.getModule(setupFile);
66+
events.emit({
67+
type: 'setup-file-bundling-finished',
68+
file: setupFile,
69+
setupType: 'setupFiles',
70+
duration: Date.now() - startTime,
71+
});
72+
evaluateModule(setupModuleJs, setupFile);
73+
} catch (error) {
74+
const errorMessage =
75+
error instanceof Error ? error.message : 'Unknown error';
76+
events.emit({
77+
type: 'setup-file-bundling-failed',
78+
file: setupFile,
79+
setupType: 'setupFiles',
80+
duration: Date.now() - startTime,
81+
error: errorMessage,
82+
});
83+
throw error;
84+
}
85+
}
86+
}
87+
88+
if (options.setupFilesAfterEnv) {
89+
for (const setupFile of options.setupFilesAfterEnv) {
90+
const startTime = Date.now();
91+
events.emit({
92+
type: 'setup-file-bundling-started',
93+
file: setupFile,
94+
setupType: 'setupFilesAfterEnv',
95+
});
96+
97+
try {
98+
const setupModuleJs = await bundler.getModule(setupFile);
99+
events.emit({
100+
type: 'setup-file-bundling-finished',
101+
file: setupFile,
102+
setupType: 'setupFilesAfterEnv',
103+
duration: Date.now() - startTime,
104+
});
105+
evaluateModule(setupModuleJs, setupFile);
106+
} catch (error) {
107+
const errorMessage =
108+
error instanceof Error ? error.message : 'Unknown error';
109+
events.emit({
110+
type: 'setup-file-bundling-failed',
111+
file: setupFile,
112+
setupType: 'setupFilesAfterEnv',
113+
duration: Date.now() - startTime,
114+
error: errorMessage,
115+
});
116+
throw error;
117+
}
118+
}
119+
}
120+
54121
const moduleJs = await bundler.getModule(path);
55122
const collectionResult = await collector.collect(
56123
() => evaluateModule(moduleJs, path),

0 commit comments

Comments
 (0)