Skip to content

Commit 3424477

Browse files
Merge pull request #1222 from NativeScript/vladimirov/merge-rel-master-pre-150-3
Merge release in master pre 1.5.0 (third time)
2 parents 691c9f9 + bb4b54e commit 3424477

11 files changed

+205
-92
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/commands/livesync.ts

-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ export class LivesyncCommand implements ICommand {
99
private $errors: IErrors) { }
1010

1111
public execute(args: string[]): IFuture<void> {
12-
this.$options.justlaunch = true;
1312
return this.$usbLiveSyncService.liveSync(args[0]);
1413
}
1514

lib/nativescript-cli.ts

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ require("./common/verify-node-version").verifyNodeVersion(require("../package.js
77
require("./bootstrap");
88
import * as fiber from "fibers";
99
import Future = require("fibers/future");
10+
import * as shelljs from "shelljs";
11+
shelljs.config.silent = true;
1012
import {installUncaughtExceptionListener} from "./common/errors";
1113
installUncaughtExceptionListener(process.exit);
1214

lib/providers/device-log-provider.ts

+31-3
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,38 @@
22
"use strict";
33

44
export class DeviceLogProvider implements Mobile.IDeviceLogProvider {
5-
constructor(private $logger: ILogger) { }
5+
//sample line is "I/Web Console( 4438): Received Event: deviceready at file:///storage/emulated/0/Icenium/com.telerik.TestApp/js/index.js:48"
6+
private static LINE_REGEX = /.\/(.+?)\s*\(\s*(\d+?)\): (.*)/;
67

7-
public logData(line: string, platform: string, deviceIdentifier: string): void {
8-
this.$logger.out(line);
8+
constructor(private $devicePlatformsConstants: Mobile.IDevicePlatformsConstants,
9+
private $logger: ILogger) { }
10+
11+
public logData(lineText: string, platform: string, deviceIdentifier: string): void {
12+
if (!platform || platform.toLowerCase() === this.$devicePlatformsConstants.iOS.toLowerCase()) {
13+
this.$logger.out(lineText);
14+
} else if (platform === this.$devicePlatformsConstants.Android) {
15+
let log = this.getConsoleLogFromLine(lineText);
16+
if (log) {
17+
if (log.tag) {
18+
this.$logger.out(`${log.tag}: ${log.message}`);
19+
} else {
20+
this.$logger.out(log.message);
21+
}
22+
}
23+
}
24+
}
25+
26+
private getConsoleLogFromLine(lineText: String): any {
27+
let acceptedTags = ["chromium", "Web Console", "JS"];
28+
let match = lineText.match(DeviceLogProvider.LINE_REGEX);
29+
if (match) {
30+
if(acceptedTags.indexOf(match[1]) !== -1) {
31+
return {tag: match[1], message: match[3]};
32+
}
33+
} else if (_.any(acceptedTags, (tag: string) => { return lineText.indexOf(tag) !== -1; })) {
34+
return {message: match[3]};
35+
}
36+
return null;
937
}
1038
}
1139
$injector.register("deviceLogProvider", DeviceLogProvider);

lib/services/android-project-service.ts

+8-6
Original file line numberDiff line numberDiff line change
@@ -296,18 +296,20 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject
296296
this.$fs.ensureDirectoryExists(configurationsDirectoryPath).wait();
297297

298298
let pluginConfigurationDirectoryPath = path.join(configurationsDirectoryPath, pluginName);
299-
this.$fs.ensureDirectoryExists(pluginConfigurationDirectoryPath).wait();
299+
if (this.$fs.exists(pluginPlatformsFolderPath).wait()) {
300+
this.$fs.ensureDirectoryExists(pluginConfigurationDirectoryPath).wait();
301+
302+
// Copy all resources from plugin
303+
let resourcesDestinationDirectoryPath = path.join(this.platformData.projectRoot, "src", pluginName);
304+
this.$fs.ensureDirectoryExists(resourcesDestinationDirectoryPath).wait();
305+
shell.cp("-Rf", path.join(pluginPlatformsFolderPath, "*"), resourcesDestinationDirectoryPath);
306+
}
300307

301308
// Copy include.gradle file
302309
let includeGradleFilePath = path.join(pluginPlatformsFolderPath, "include.gradle");
303310
if(this.$fs.exists(includeGradleFilePath).wait()) {
304311
shell.cp("-f", includeGradleFilePath, pluginConfigurationDirectoryPath);
305312
}
306-
307-
// Copy all resources from plugin
308-
let resourcesDestinationDirectoryPath = path.join(this.platformData.projectRoot, "src", pluginName);
309-
this.$fs.ensureDirectoryExists(resourcesDestinationDirectoryPath).wait();
310-
shell.cp("-Rf", path.join(pluginPlatformsFolderPath, "*"), resourcesDestinationDirectoryPath);
311313
}).future<void>()();
312314
}
313315

lib/services/platform-service.ts

-4
Original file line numberDiff line numberDiff line change
@@ -353,10 +353,6 @@ export class PlatformService implements IPlatformService {
353353
return (() => {
354354
platformData.platformProjectService.deploy(device.deviceInfo.identifier).wait();
355355
device.deploy(packageFile, this.$projectData.projectId).wait();
356-
357-
if (!this.$options.justlaunch) {
358-
device.openDeviceLogStream();
359-
}
360356
}).future<void>()();
361357
};
362358
this.$devicesService.execute(action).wait();

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) {

lib/services/usb-livesync-service.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,9 @@ export class UsbLiveSyncService extends usbLivesyncServiceBaseLib.UsbLiveSyncSer
135135

136136
let devices = this.$devicesService.getDeviceInstances();
137137
_.each(devices, (device: Mobile.IDevice) => {
138-
this.transferFiles(device, deviceAppData, localToDevicePaths, projectFilesPath, true).wait();
138+
if (this.$fs.exists(filePath).wait()) {
139+
this.transferFiles(device, deviceAppData, localToDevicePaths, projectFilesPath, true).wait();
140+
}
139141
let platformSpecificUsbLiveSyncService = this.resolvePlatformSpecificLiveSyncService(platform || this.$devicesService.platform, device, platformSpecificLiveSyncServices);
140142
return platformSpecificUsbLiveSyncService.sendPageReloadMessageToDevice(deviceAppData).wait();
141143
});

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
"gulp": "3.9.0",
4343
"iconv-lite": "0.4.11",
4444
"inquirer": "0.9.0",
45-
"ios-sim-portable": "1.0.13-delta",
45+
"ios-sim-portable": "1.0.13-epsilon",
4646
"lockfile": "1.0.1",
4747
"lodash": "3.10.0",
4848
"log4js": "0.6.26",

0 commit comments

Comments
 (0)