Skip to content

Commit 35446fc

Browse files
Merge pull request #1207 from NativeScript/vladimirov/fix-unit-test-runner
Fix unit test runner on Windows
2 parents dccee5e + 6925a14 commit 35446fc

File tree

4 files changed

+160
-76
lines changed

4 files changed

+160
-76
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
test android
2+
==========
3+
4+
Usage | Synopsis
5+
------|-------
6+
Run tests on all connected devices | `$ tns test android [--watch] [--debug-brk]`
7+
Run tests on a selected device | `$ tns test android --device <Device ID> [--watch] [--debug-brk]`
8+
9+
Runs the tests in your project on connected Android devices and running native emulators.<% if(isConsole) { %> Your project must already be configured for unit testing by running `$ tns test init`.<% } %>
10+
11+
### Options
12+
* `--watch` - If set, when you save changes to the project, changes are automatically synchronized to the connected device and tests are re-run.
13+
* `--device` - Specifies the serial number or the index of the connected device on which to run the tests. To list all connected devices, grouped by platform, run `$ tns device`
14+
* `--debug-brk` - Runs the tests under the debugger. The debugger will break just before your tests are executed, so you have a chance to place breakpoints.
15+
16+
### Attributes
17+
* `<Device ID>` is the device index or identifier as listed by `$ tns device`
18+
19+
<% if(isHtml) { %>
20+
### Prerequisites
21+
22+
* Verify that [you have configured your project for unit testing](test-init.html).
23+
* Verify that [you have stored your unit tests in `app` &#8594; `tests`](http://docs.nativescript.org/testing).
24+
* Verify that [you have configured your system and devices properly](http://docs.nativescript.org/testing).
25+
26+
### Related Commands
27+
Command | Description
28+
--------|------------
29+
[test init](test-init.html) | Configures your project for unit testing with a selected framework.
30+
[test ios](test-ios.html) | Runs the tests in your project on iOS devices or the iOS Simulator.
31+
<% } %>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
test ios
2+
==========
3+
4+
Usage | Synopsis
5+
------|-------
6+
Run tests on all connected devices | `$ tns test ios [--watch] [--debug-brk]`
7+
Run tests on a selected device | `$ tns test ios --device <Device ID> [--watch] [--debug-brk]`
8+
Run tests in the iOS Simulator | `$ tns test ios --emulator [--watch] [--debug-brk]`
9+
10+
Runs the tests in your project on connected iOS devices or the iOS Simulator.<% if(isConsole && isMacOS) { %> Your project must already be configured for unit testing by running `$ tns test init`.<% } %>
11+
12+
<% if(isConsole && (isLinux || isWindows)) { %>WARNING: You can run this command only on OS X systems. To view the complete help for this command, run `$ tns help test ios`<% } %>
13+
14+
<% if((isConsole && isMacOS) || isHtml) { %>
15+
### Options
16+
* `--watch` - If set, when you save changes to the project, changes are automatically synchronized to the connected device and tests are re-ran.
17+
* `--device` - Specifies the serial number or the index of the connected device on which you want to run tests. To list all connected devices, grouped by platform, run `$ tns device`. You cannot set `--device` and `--emulator` simultaneously.
18+
* `--emulator` - Runs tests on the iOS Simulator. You cannot set `--device` and `--emulator` simultaneously.
19+
* `--debug-brk` - Runs the tests under the debugger. The debugger will break just before your tests are executed, so you have a chance to place breakpoints.
20+
21+
### Attributes
22+
* `<Device ID>` is the device index or identifier as listed by `$ tns device`<% } %>
23+
24+
<% if(isHtml) { %>
25+
### Prerequisites
26+
27+
* Verify that [you have configured your project for unit testing](test-init.html).
28+
* Verify that [you have stored your unit tests in `app` &#8594; `tests`](http://docs.nativescript.org/testing).
29+
* Verify that [you have configured your system and devices properly](http://docs.nativescript.org/testing).
30+
31+
### Related Commands
32+
Command | Description
33+
--------|------------
34+
[test init](test-init.html) | Configures your project for unit testing with a selected framework.
35+
[test android](test-android.html) | Runs the tests in your project on Android devices or native emulators.
36+
<% } %>

lib/common

lib/services/test-execution-service.ts

+92-75
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import * as constants from "../constants";
66
import * as path from 'path';
77
import Future = require('fibers/future');
88
import * as os from 'os';
9+
import * as fiberBootstrap from "../common/fiber-bootstrap";
910

1011
interface IKarmaConfigOptions {
1112
debugBrk: boolean;
@@ -31,93 +32,109 @@ class TestExecutionService implements ITestExecutionService {
3132
private $config: IConfiguration,
3233
private $logger: ILogger,
3334
private $fs: IFileSystem,
34-
private $options: IOptions) {
35+
private $options: IOptions,
36+
private $pluginsService: IPluginsService) {
3537
}
3638

3739
public startTestRunner(platform: string) : IFuture<void> {
3840
return (() => {
3941
this.$options.justlaunch = true;
42+
let blockingOperationFuture = new Future<void>();
43+
process.on('message', (launcherConfig: any) => {
44+
fiberBootstrap.run(() => {
45+
try {
46+
let platformData = this.$platformsData.getPlatformData(platform.toLowerCase());
47+
let projectDir = this.$projectData.projectDir;
48+
49+
let projectFilesPath = path.join(platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME);
50+
51+
let configOptions: IKarmaConfigOptions = JSON.parse(launcherConfig);
52+
this.$options.debugBrk = configOptions.debugBrk;
53+
this.$options.debugTransport = configOptions.debugTransport;
54+
let configJs = this.generateConfig(configOptions);
55+
this.$fs.writeFile(path.join(projectDir, TestExecutionService.CONFIG_FILE_NAME), configJs).wait();
56+
57+
let socketIoJsUrl = `http://localhost:${this.$options.port}/socket.io/socket.io.js`;
58+
let socketIoJs = this.$httpClient.httpRequest(socketIoJsUrl).wait().body;
59+
this.$fs.writeFile(path.join(projectDir, TestExecutionService.SOCKETIO_JS_FILE_NAME), socketIoJs).wait();
60+
61+
this.$platformService.preparePlatform(platform).wait();
62+
this.detourEntryPoint(projectFilesPath).wait();
63+
64+
let watchGlob = path.join(projectDir, constants.APP_FOLDER_NAME);
65+
66+
let platformSpecificLiveSyncServices: IDictionary<any> = {
67+
android: (_device: Mobile.IDevice, $injector: IInjector): IPlatformSpecificLiveSyncService => {
68+
return $injector.resolve(this.$androidUsbLiveSyncServiceLocator.factory, {_device: _device});
69+
},
70+
ios: (_device: Mobile.IDevice, $injector: IInjector) => {
71+
return $injector.resolve(this.$iosUsbLiveSyncServiceLocator.factory, {_device: _device});
72+
}
73+
};
74+
75+
let notInstalledAppOnDeviceAction = (device: Mobile.IDevice): IFuture<void> => {
76+
return (() => {
77+
this.$platformService.installOnDevice(platform).wait();
78+
this.detourEntryPoint(projectFilesPath).wait();
79+
}).future<void>()();
80+
};
81+
82+
let notRunningiOSSimulatorAction = (): IFuture<void> => {
83+
return (() => {
84+
this.$platformService.deployOnEmulator(this.$devicePlatformsConstants.iOS.toLowerCase()).wait();
85+
this.detourEntryPoint(projectFilesPath).wait();
86+
}).future<void>()();
87+
};
88+
89+
let beforeBatchLiveSyncAction = (filePath: string): IFuture<string> => {
90+
return (() => {
91+
this.$platformService.preparePlatform(platform).wait();
92+
return path.join(projectFilesPath, path.relative(path.join(this.$projectData.projectDir, constants.APP_FOLDER_NAME), filePath));
93+
}).future<string>()();
94+
};
95+
96+
let localProjectRootPath = platform.toLowerCase() === "ios" ? platformData.appDestinationDirectoryPath : null;
97+
98+
let liveSyncData = {
99+
platform: platform,
100+
appIdentifier: this.$projectData.projectId,
101+
projectFilesPath: projectFilesPath,
102+
excludedProjectDirsAndFiles: constants.LIVESYNC_EXCLUDED_DIRECTORIES,
103+
watchGlob: watchGlob,
104+
platformSpecificLiveSyncServices: platformSpecificLiveSyncServices,
105+
notInstalledAppOnDeviceAction: notInstalledAppOnDeviceAction,
106+
notRunningiOSSimulatorAction: notRunningiOSSimulatorAction,
107+
localProjectRootPath: localProjectRootPath,
108+
beforeBatchLiveSyncAction: beforeBatchLiveSyncAction,
109+
shouldRestartApplication: (localToDevicePaths: Mobile.ILocalToDevicePathData[]) => Future.fromResult(!this.$options.debugBrk),
110+
canExecuteFastLiveSync: (filePath: string) => false,
111+
};
112+
113+
this.$usbLiveSyncServiceBase.sync(liveSyncData).wait();
114+
115+
if (this.$options.debugBrk) {
116+
this.$logger.info('Starting debugger...');
117+
let debugService: IDebugService = this.$injector.resolve(`${platform}DebugService`);
118+
debugService.debugStart().wait();
119+
}
120+
blockingOperationFuture.return();
121+
} catch(err) {
122+
// send the error to the real future
123+
blockingOperationFuture.throw(err);
124+
}
125+
});
126+
});
40127

41-
let platformData = this.$platformsData.getPlatformData(platform.toLowerCase());
42-
let projectDir = this.$projectData.projectDir;
43-
44-
let projectFilesPath = path.join(platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME);
45-
46-
let configOptions: IKarmaConfigOptions = JSON.parse(this.$fs.readStdin().wait());
47-
this.$options.debugBrk = configOptions.debugBrk;
48-
this.$options.debugTransport = configOptions.debugTransport;
49-
let configJs = this.generateConfig(configOptions);
50-
this.$fs.writeFile(path.join(projectDir, TestExecutionService.CONFIG_FILE_NAME), configJs).wait();
51-
52-
let socketIoJsUrl = `http://localhost:${this.$options.port}/socket.io/socket.io.js`;
53-
let socketIoJs = this.$httpClient.httpRequest(socketIoJsUrl).wait().body;
54-
this.$fs.writeFile(path.join(projectDir, TestExecutionService.SOCKETIO_JS_FILE_NAME), socketIoJs).wait();
55-
56-
this.$platformService.preparePlatform(platform).wait();
57-
this.detourEntryPoint(projectFilesPath).wait();
58-
59-
let watchGlob = path.join(projectDir, constants.APP_FOLDER_NAME);
60-
61-
let platformSpecificLiveSyncServices: IDictionary<any> = {
62-
android: (_device: Mobile.IDevice, $injector: IInjector): IPlatformSpecificLiveSyncService => {
63-
return $injector.resolve(this.$androidUsbLiveSyncServiceLocator.factory, {_device: _device});
64-
},
65-
ios: (_device: Mobile.IDevice, $injector: IInjector) => {
66-
return $injector.resolve(this.$iosUsbLiveSyncServiceLocator.factory, {_device: _device});
67-
}
68-
};
69-
70-
let notInstalledAppOnDeviceAction = (device: Mobile.IDevice): IFuture<void> => {
71-
return (() => {
72-
this.$platformService.installOnDevice(platform).wait();
73-
this.detourEntryPoint(projectFilesPath).wait();
74-
}).future<void>()();
75-
};
76-
77-
let notRunningiOSSimulatorAction = (): IFuture<void> => {
78-
return (() => {
79-
this.$platformService.deployOnEmulator(this.$devicePlatformsConstants.iOS.toLowerCase()).wait();
80-
this.detourEntryPoint(projectFilesPath).wait();
81-
}).future<void>()();
82-
};
83-
84-
let beforeBatchLiveSyncAction = (filePath: string): IFuture<string> => {
85-
return (() => {
86-
this.$platformService.preparePlatform(platform).wait();
87-
return path.join(projectFilesPath, path.relative(path.join(this.$projectData.projectDir, constants.APP_FOLDER_NAME), filePath));
88-
}).future<string>()();
89-
};
90-
91-
let localProjectRootPath = platform.toLowerCase() === "ios" ? platformData.appDestinationDirectoryPath : null;
92-
93-
let liveSyncData = {
94-
platform: platform,
95-
appIdentifier: this.$projectData.projectId,
96-
projectFilesPath: projectFilesPath,
97-
excludedProjectDirsAndFiles: constants.LIVESYNC_EXCLUDED_DIRECTORIES,
98-
watchGlob: watchGlob,
99-
platformSpecificLiveSyncServices: platformSpecificLiveSyncServices,
100-
notInstalledAppOnDeviceAction: notInstalledAppOnDeviceAction,
101-
notRunningiOSSimulatorAction: notRunningiOSSimulatorAction,
102-
localProjectRootPath: localProjectRootPath,
103-
beforeBatchLiveSyncAction: beforeBatchLiveSyncAction,
104-
shouldRestartApplication: (localToDevicePaths: Mobile.ILocalToDevicePathData[]) => Future.fromResult(!this.$options.debugBrk),
105-
canExecuteFastLiveSync: (filePath: string) => false,
106-
};
107-
108-
this.$usbLiveSyncServiceBase.sync(liveSyncData).wait();
109-
110-
if (this.$options.debugBrk) {
111-
this.$logger.info('Starting debugger...');
112-
let debugService: IDebugService = this.$injector.resolve(`${platform}DebugService`);
113-
debugService.debugStart().wait();
114-
}
128+
// Tell the parent that we are ready to receive the data.
129+
process.send("ready");
130+
blockingOperationFuture.wait();
115131
}).future<void>()();
116132
}
117133

118134
public startKarmaServer(platform: string): IFuture<void> {
119135
return (() => {
120136
platform = platform.toLowerCase();
137+
this.$pluginsService.ensureAllDependenciesAreInstalled().wait();
121138
let pathToKarma = path.join(this.$projectData.projectDir, 'node_modules/karma');
122139
let KarmaServer = require(path.join(pathToKarma, 'lib/server'));
123140
if (platform === 'ios' && this.$options.emulator) {

0 commit comments

Comments
 (0)