Skip to content

Commit 2647b68

Browse files
Kureevrotemmiz
authored andcommitted
Basic support for Jest runner (wix#335)
Add basic Jest runner support in Detox core and detox-cli
1 parent 983abe8 commit 2647b68

File tree

6 files changed

+112
-62
lines changed

6 files changed

+112
-62
lines changed

detox/local-cli/detox-test.js

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const program = require('commander');
44
const path = require('path');
55
const cp = require('child_process');
66
program
7-
.option('-r, --runner [runner]', 'Test runner (currently supports mocha)', 'mocha')
7+
.option('-r, --runner [runner]', 'Test runner (currently supports mocha)')
88
.option('-o, --runner-config [config]', 'Test runner config file', 'mocha.opts')
99
.option('-l, --loglevel [value]', 'info, debug, verbose, silly, wss')
1010
.option('-c, --configuration [device configuration]', 'Select a device configuration from your defined configurations,'
@@ -21,26 +21,54 @@ program
2121
const config = require(path.join(process.cwd(), 'package.json')).detox;
2222
const testFolder = config.specs || 'e2e';
2323

24-
const loglevel = program.loglevel ? `--loglevel ${program.loglevel}` : '';
25-
const configuration = program.configuration ? `--configuration ${program.configuration}` : '';
26-
const cleanup = program.cleanup ? `--cleanup` : '';
27-
const reuse = program.reuse ? `--reuse` : '';
28-
const artifactsLocation = program.artifactsLocation ? `--artifacts-location ${program.artifactsLocation}` : '';
24+
let runner = config.runner || 'mocha';
25+
26+
if (program.runner) {
27+
runner = program.runner;
28+
}
29+
30+
function runMocha() {
31+
const loglevel = program.loglevel ? `--loglevel ${program.loglevel}` : '';
32+
const configuration = program.configuration ? `--configuration ${program.configuration}` : '';
33+
const cleanup = program.cleanup ? `--cleanup` : '';
34+
const reuse = program.reuse ? `--reuse` : '';
35+
const artifactsLocation = program.artifactsLocation ? `--artifacts-location ${program.artifactsLocation}` : '';
36+
37+
const debugSynchronization = program.debugSynchronization ? `--debug-synchronization ${program.debugSynchronization}` : '';
38+
const command = `node_modules/.bin/mocha ${testFolder} --opts ${testFolder}/${program.runnerConfig} ${configuration} ${loglevel} ${cleanup} ${reuse} ${debugSynchronization} ${artifactsLocation}`;
39+
40+
console.log(command);
41+
cp.execSync(command, {stdio: 'inherit'});
42+
}
43+
44+
function runJest() {
45+
const command = `node_modules/.bin/jest ${testFolder} --runInBand`;
46+
console.log(command);
47+
cp.execSync(command, {
48+
stdio: 'inherit',
49+
env: {
50+
...process.env,
51+
configuration: program.configuration,
52+
loglevel: program.loglevel,
53+
cleanup: program.cleanup,
54+
reuse: program.reuse,
55+
debugSynchronization: program.debugSynchronization,
56+
artifactsLocation: program.artifactsLocation
57+
}
58+
});
59+
}
2960

3061
if (typeof program.debugSynchronization === "boolean") {
3162
program.debugSynchronization = 3000;
3263
}
33-
let debugSynchronization = program.debugSynchronization ? `--debug-synchronization ${program.debugSynchronization}` : '';
34-
3564

36-
let command;
37-
switch (program.runner) {
65+
switch (runner) {
3866
case 'mocha':
39-
command = `node_modules/.bin/${program.runner} ${testFolder} --opts ${testFolder}/${program.runnerConfig} ${configuration} ${loglevel} ${cleanup} ${reuse} ${debugSynchronization} ${artifactsLocation}`;
67+
runMocha();
68+
break;
69+
case 'jest':
70+
runJest();
4071
break;
4172
default:
42-
throw new Error(`${program.runner} is not supported in detox cli tools. You can still run your tests with the runner's own cli tool`);
73+
throw new Error(`${runner} is not supported in detox cli tools. You can still run your tests with the runner's own cli tool`);
4374
}
44-
45-
console.log(command);
46-
cp.execSync(command, {stdio: 'inherit'});

detox/src/Detox.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ const DEVICE_CLASSES = {
2222
};
2323

2424
class Detox {
25-
2625
constructor(userConfig) {
2726
if (!userConfig) {
2827
throw new Error(`No configuration was passed to detox, make sure you pass a config when calling 'detox.init(config)'`);
@@ -33,10 +32,10 @@ class Detox {
3332
this.device = null;
3433
this._currentTestNumber = 0;
3534
const artifactsLocation = argparse.getArgValue('artifacts-location');
36-
if(artifactsLocation !== undefined) {
35+
if (artifactsLocation !== undefined) {
3736
try {
3837
this._artifactsPathsProvider = new ArtifactsPathsProvider(artifactsLocation);
39-
} catch(ex) {
38+
} catch (ex) {
4039
log.warn(ex);
4140
}
4241
}
@@ -130,7 +129,7 @@ class Detox {
130129
}
131130

132131
if (!deviceConfig) {
133-
throw new Error(`Cannot determine which configuration to use. use --configuration to choose one of the following:
132+
throw new Error(`Cannot determine which configuration to use. use --configuration to choose one of the following:
134133
${Object.keys(configurations)}`);
135134
}
136135

detox/src/Detox.test.js

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,16 @@ describe('Detox', () => {
44
let fs;
55
let Detox;
66
let detox;
7-
let minimist;
8-
let clientMockData = {lastConstructorArguments: null};
9-
let deviceMockData = {lastConstructorArguments: null};
7+
const clientMockData = {lastConstructorArguments: null};
8+
const deviceMockData = {lastConstructorArguments: null};
109

1110
beforeEach(async () => {
1211
function setCustomMock(modulePath, dataObject) {
1312
const JestMock = jest.genMockFromModule(modulePath);
1413
class FinalMock extends JestMock {
15-
constructor() {
16-
super(...arguments);
17-
dataObject.lastConstructorArguments = arguments;
14+
constructor(...rest) {
15+
super(rest);
16+
dataObject.lastConstructorArguments = rest;
1817
}
1918
}
2019
jest.setMock(modulePath, FinalMock);
@@ -23,12 +22,12 @@ describe('Detox', () => {
2322
jest.mock('npmlog');
2423
jest.mock('fs');
2524
fs = require('fs');
26-
jest.mock('minimist');
27-
minimist = require('minimist');
2825
jest.mock('./ios/expect');
2926
setCustomMock('./client/Client', clientMockData);
3027
setCustomMock('./devices/Device', deviceMockData);
3128

29+
process.env = {};
30+
3231
jest.mock('./devices/IosDriver');
3332
jest.mock('./devices/SimulatorDriver');
3433
jest.mock('./devices/Device');
@@ -66,7 +65,7 @@ describe('Detox', () => {
6665
});
6766

6867
it(`Passing --cleanup should shutdown the currently running device`, async () => {
69-
mockCommandLineArgs({cleanup: true});
68+
process.env.cleanup = true;
7069
Detox = require('./Detox');
7170

7271
detox = new Detox(schemes.validOneDeviceNoSession);
@@ -99,7 +98,7 @@ describe('Detox', () => {
9998
});
10099

101100
it(`Two valid devices, detox should init with the device passed in '--configuration' cli option`, async () => {
102-
mockCommandLineArgs({configuration: 'ios.sim.debug'});
101+
process.env.configuration = 'ios.sim.debug';
103102
Detox = require('./Detox');
104103

105104
detox = new Detox(schemes.validTwoDevicesNoSession);
@@ -108,7 +107,7 @@ describe('Detox', () => {
108107
});
109108

110109
it(`Two valid devices, detox should throw if device passed in '--configuration' cli option doesn't exist`, async () => {
111-
mockCommandLineArgs({configuration: 'nonexistent'});
110+
process.env.configuration = 'nonexistent';
112111
Detox = require('./Detox');
113112

114113
detox = new Detox(schemes.validTwoDevicesNoSession);
@@ -121,7 +120,7 @@ describe('Detox', () => {
121120
});
122121

123122
it(`Two valid devices, detox should throw if device passed in '--configuration' cli option doesn't exist`, async () => {
124-
mockCommandLineArgs({configuration: 'nonexistent'});
123+
process.env.configuration = 'nonexistent';
125124
Detox = require('./Detox');
126125

127126
detox = new Detox(schemes.validTwoDevicesNoSession);
@@ -165,22 +164,22 @@ describe('Detox', () => {
165164
});
166165

167166
it(`Detox should use session defined per configuration - none`, async () => {
168-
mockCommandLineArgs({configuration: 'ios.sim.none'});
167+
process.env.configuration = 'ios.sim.none';
169168
Detox = require('./Detox');
170169
detox = new Detox(schemes.sessionPerConfiguration);
171170
await detox.init();
172171

173-
let expectedSession = schemes.sessionPerConfiguration.configurations['ios.sim.none'].session;
172+
const expectedSession = schemes.sessionPerConfiguration.configurations['ios.sim.none'].session;
174173
expect(clientMockData.lastConstructorArguments[0]).toBe(expectedSession);
175174
});
176175

177176
it(`Detox should use session defined per configuration - release`, async () => {
178-
mockCommandLineArgs({configuration: 'ios.sim.release'});
177+
process.env.configuration = 'ios.sim.release';
179178
Detox = require('./Detox');
180179
detox = new Detox(schemes.sessionPerConfiguration);
181180
await detox.init();
182181

183-
let expectedSession = schemes.sessionPerConfiguration.configurations['ios.sim.release'].session;
182+
const expectedSession = schemes.sessionPerConfiguration.configurations['ios.sim.release'].session;
184183
expect(clientMockData.lastConstructorArguments[0]).toBe(expectedSession);
185184
});
186185

@@ -189,12 +188,12 @@ describe('Detox', () => {
189188
detox = new Detox(schemes.sessionInCommonAndInConfiguration);
190189
await detox.init();
191190

192-
let expectedSession = schemes.sessionInCommonAndInConfiguration.configurations['ios.sim.none'].session;
191+
const expectedSession = schemes.sessionInCommonAndInConfiguration.configurations['ios.sim.none'].session;
193192
expect(clientMockData.lastConstructorArguments[0]).toBe(expectedSession);
194193
});
195194

196195
it(`beforeEach() - should set device artifacts destination`, async () => {
197-
mockCommandLineArgs({'artifacts-location': '/tmp'});
196+
process.env.artifactsLocation = '/tmp';
198197
Detox = require('./Detox');
199198
detox = new Detox(schemes.validOneDeviceAndSession);
200199
await detox.init();
@@ -211,7 +210,7 @@ describe('Detox', () => {
211210
});
212211

213212
it(`afterEach() - should call device.finalizeArtifacts`, async () => {
214-
mockCommandLineArgs({'artifacts-location': '/tmp'});
213+
process.env.artifactsLocation = '/tmp';
215214
Detox = require('./Detox');
216215
detox = new Detox(schemes.validOneDeviceAndSession);
217216
await detox.init();
@@ -228,13 +227,11 @@ describe('Detox', () => {
228227
});
229228

230229
it(`the constructor should catch exception from ArtifactsPathsProvider`, async () => {
231-
mockCommandLineArgs({'artifacts-location': '/tmp'});
232-
fs.mkdirSync = jest.fn(() => {throw 'Could not create artifacts root dir'});
230+
process.env.artifactsLocation = '/tmp';
231+
fs.mkdirSync = jest.fn(() => {
232+
throw Error('Could not create artifacts root dir');
233+
});
233234
Detox = require('./Detox');
234235
detox = new Detox(schemes.validOneDeviceAndSession);
235236
});
236-
237-
function mockCommandLineArgs(args) {
238-
minimist.mockReturnValue(args);
239-
}
240237
});

detox/src/utils/argparse.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
11
const argv = require('minimist')(process.argv.slice(2));
22

33
function getArgValue(key) {
4-
const value = argv ? argv[key] : undefined;
4+
let value;
5+
6+
if (argv && argv[key]) {
7+
value = argv[key];
8+
} else {
9+
const camelCasedKey = key.replace(/(\-\w)/g, (m) => m[1].toUpperCase());
10+
value = process.env[camelCasedKey];
11+
}
12+
513
return value;
614
}
715

detox/src/utils/argparse.test.js

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,39 @@
1-
const _ = require('lodash');
1+
jest.unmock('process');
22

33
describe('argparse', () => {
4-
let argparse;
4+
describe('using env variables', () => {
5+
let argparse;
56

6-
beforeEach(() => {
7-
jest.mock('minimist');
8-
const minimist = require('minimist');
9-
minimist.mockReturnValue({test: 'a value'});
10-
argparse = require('./argparse');
11-
});
7+
beforeEach(() => {
8+
process.env.fooBar = 'a value';
9+
argparse = require('./argparse');
10+
});
11+
12+
it(`nonexistent key should return undefined result`, () => {
13+
expect(argparse.getArgValue('blah')).not.toBeDefined();
14+
});
1215

13-
it(`nonexistent key should return undefined result`, () => {
14-
expect(argparse.getArgValue('blah')).not.toBeDefined();
16+
it(`existing key should return a result`, () => {
17+
expect(argparse.getArgValue('foo-bar')).toBe('a value');
18+
});
1519
});
1620

17-
it(`existing key should return a result`, () => {
18-
expect(argparse.getArgValue('test')).toBe('a value');
21+
describe('using arguments', () => {
22+
let argparse;
23+
24+
beforeEach(() => {
25+
jest.mock('minimist');
26+
const minimist = require('minimist');
27+
minimist.mockReturnValue({'kebab-case-key': 'a value'});
28+
argparse = require('./argparse');
29+
});
30+
31+
it(`nonexistent key should return undefined result`, () => {
32+
expect(argparse.getArgValue('blah')).not.toBeDefined();
33+
});
34+
35+
it(`existing key should return a result`, () => {
36+
expect(argparse.getArgValue('kebab-case-key')).toBe('a value');
37+
});
1938
});
2039
});

docs/Guide.Jest.md

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,9 @@ npm install --save-dev jest
1616

1717
You should remove `e2e/mocha.opts`, you no longer need it.
1818

19-
### 3. Write a detox setup file
19+
### 3. Replace generated detox setup file (e2e/init.js)
2020

2121
```js
22-
// ./jest/setup/e2e.js
2322
const detox = require('detox');
2423
const config = require('../package.json').detox;
2524

@@ -44,15 +43,15 @@ beforeEach(async () => {
4443
Add this part to your `package.json`:
4544
```json
4645
"jest": {
47-
"setupTestFrameworkScriptFile": "<rootDir>/jest/setup.js"
46+
"setupTestFrameworkScriptFile": "./e2e/init.js"
4847
},
4948
"scripts": {
50-
"test:e2e": "jest __e2e__ --setupTestFrameworkScriptFile=./jest/setup/e2e-tests.js --runInBand",
49+
"test:e2e": "detox test",
5150
"test:e2e:build": "detox build"
5251
}
5352
```
5453

55-
We need the `--runInBand` as detox doesn't support parallelism yet.
54+
In the `detox` part of your `package.json`, add `"runner": "jest"` to tell detox that you want to use jest runner instead of mocha.
5655

5756
### Writing Tests
5857

0 commit comments

Comments
 (0)