Skip to content

Commit ea53638

Browse files
Merge pull request #1553 from NativeScript/vladimirov/merge-rel-master
Merge release in master
2 parents 3e3aa3d + 9481127 commit ea53638

10 files changed

+233
-50
lines changed

lib/constants.ts

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export let DEFAULT_APP_IDENTIFIER_PREFIX = "org.nativescript";
1414
export var LIVESYNC_EXCLUDED_DIRECTORIES = ["app_resources"];
1515
export var TESTING_FRAMEWORKS = ['jasmine', 'mocha', 'qunit'];
1616
export let TEST_RUNNER_NAME = "nativescript-unit-test-runner";
17+
export let LIVESYNC_EXCLUDED_FILE_PATTERNS = ["**/*.js.map", "**/*.ts"];
1718

1819
export class ReleaseType {
1920
static MAJOR = "major";

lib/declarations.ts

-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@ interface IOptions extends ICommonOptions {
6565
frameworkVersion: string;
6666
copyFrom: string;
6767
linkTo: string;
68-
release: boolean;
6968
emulator: boolean;
7069
symlink: boolean;
7170
forDevice: boolean;

lib/options.ts

-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ export class Options extends commonOptionsLibPath.OptionsBase {
1818
frameworkVersion: { type: OptionType.String },
1919
copyFrom: { type: OptionType.String },
2020
linkTo: { type: OptionType.String },
21-
release: { type: OptionType.Boolean },
2221
symlink: { type: OptionType.Boolean },
2322
forDevice: { type: OptionType.Boolean },
2423
client: { type: OptionType.Boolean, default: true},

lib/providers/project-files-provider.ts

+13-6
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,33 @@
44
import minimatch = require("minimatch");
55
import * as constants from "../constants";
66
import * as path from "path";
7+
import { ProjectFilesProviderBase } from "../common/services/project-files-provider-base";
78

8-
export class ProjectFilesProvider implements IProjectFilesProvider {
9+
export class ProjectFilesProvider extends ProjectFilesProviderBase {
910
constructor(private $platformsData: IPlatformsData,
10-
private $projectData: IProjectData) { }
11+
private $projectData: IProjectData,
12+
$mobileHelper: Mobile.IMobileHelper,
13+
$options:IOptions) {
14+
super($mobileHelper, $options);
15+
}
1116

1217
private static INTERNAL_NONPROJECT_FILES = [ "**/*.ts" ];
1318

1419
public mapFilePath(filePath: string, platform: string): string {
1520
let platformData = this.$platformsData.getPlatformData(platform.toLowerCase());
1621
let projectFilesPath = path.join(platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME);
17-
let mappedFilePath = path.join(projectFilesPath, path.relative(path.join(this.$projectData.projectDir, constants.APP_FOLDER_NAME), filePath));
22+
let parsedFilePath = this.getPreparedFilePath(filePath);
23+
let mappedFilePath = path.join(projectFilesPath, path.relative(path.join(this.$projectData.projectDir, constants.APP_FOLDER_NAME), parsedFilePath));
1824

1925
let appResourcesDirectoryPath = path.join(constants.APP_FOLDER_NAME, constants.APP_RESOURCES_FOLDER_NAME);
2026
let platformSpecificAppResourcesDirectoryPath = path.join(appResourcesDirectoryPath, platformData.normalizedPlatformName);
21-
if (filePath.indexOf(appResourcesDirectoryPath) > -1 && filePath.indexOf(platformSpecificAppResourcesDirectoryPath) === -1) {
27+
if (parsedFilePath.indexOf(appResourcesDirectoryPath) > -1 && parsedFilePath.indexOf(platformSpecificAppResourcesDirectoryPath) === -1) {
2228
return null;
2329
}
24-
if (filePath.indexOf(platformSpecificAppResourcesDirectoryPath) > -1) {
30+
31+
if (parsedFilePath.indexOf(platformSpecificAppResourcesDirectoryPath) > -1) {
2532
let appResourcesRelativePath = path.relative(path.join(this.$projectData.projectDir, constants.APP_FOLDER_NAME, constants.APP_RESOURCES_FOLDER_NAME,
26-
platformData.normalizedPlatformName), filePath);
33+
platformData.normalizedPlatformName), parsedFilePath);
2734
mappedFilePath = path.join(platformData.platformProjectService.getAppResourcesDestinationDirectoryPath().wait(), appResourcesRelativePath);
2835
}
2936

lib/services/karma-execution.ts

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
///<reference path="../.d.ts"/>
2+
3+
"use strict";
4+
5+
import * as path from "path";
6+
7+
process.on("message", (data: any) => {
8+
if(data.karmaConfig) {
9+
let pathToKarma = path.join(data.karmaConfig.projectDir, 'node_modules/karma'),
10+
KarmaServer = require(path.join(pathToKarma, 'lib/server')),
11+
karma = new KarmaServer(data.karmaConfig);
12+
13+
karma.start();
14+
}
15+
});

lib/services/livesync/livesync-service.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ class LiveSyncService implements ILiveSyncService {
5858
appIdentifier: this.$projectData.projectId,
5959
projectFilesPath: path.join(platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME),
6060
syncWorkingDirectory: path.join(this.$projectData.projectDir, constants.APP_FOLDER_NAME),
61-
excludedProjectDirsAndFiles: ["**/*.js.map", "**/*.ts"]
61+
excludedProjectDirsAndFiles: constants.LIVESYNC_EXCLUDED_FILE_PATTERNS
6262
};
6363
this.$liveSyncServiceBase.sync(liveSyncData).wait();
6464
}).future<void>()();

lib/services/platform-service.ts

+2-7
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,6 @@ import Future = require("fibers/future");
1111
let clui = require("clui");
1212

1313
export class PlatformService implements IPlatformService {
14-
private static TNS_MODULES_FOLDER_NAME = "tns_modules";
15-
private static EXCLUDE_FILES_PATTERN = [
16-
"**/*.js.map",
17-
"**/*.ts"
18-
];
1914

2015
constructor(private $devicesService: Mobile.IDevicesService,
2116
private $errors: IErrors,
@@ -226,7 +221,7 @@ export class PlatformService implements IPlatformService {
226221
this.$xmlValidator.validateXmlFiles(sourceFiles).wait();
227222

228223
// Remove .ts and .js.map files
229-
PlatformService.EXCLUDE_FILES_PATTERN.forEach(pattern => sourceFiles = sourceFiles.filter(file => !minimatch(file, pattern, {nocase: true})));
224+
constants.LIVESYNC_EXCLUDED_FILE_PATTERNS.forEach(pattern => sourceFiles = sourceFiles.filter(file => !minimatch(file, pattern, {nocase: true})));
230225
let copyFileFutures = sourceFiles.map(source => {
231226
let destinationPath = path.join(appDestinationDirectoryPath, path.relative(appSourceDirectoryPath, source));
232227
if (this.$fs.getFsStats(source).wait().isDirectory()) {
@@ -250,7 +245,7 @@ export class PlatformService implements IPlatformService {
250245
// Process node_modules folder
251246
let appDir = path.join(platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME);
252247
try {
253-
let tnsModulesDestinationPath = path.join(appDir, PlatformService.TNS_MODULES_FOLDER_NAME);
248+
let tnsModulesDestinationPath = path.join(appDir, constants.TNS_MODULES_FOLDER_NAME);
254249
this.$broccoliBuilder.prepareNodeModules(tnsModulesDestinationPath, platform, lastModifiedTime).wait();
255250
} catch(error) {
256251
this.$logger.debug(error);

lib/services/test-execution-service.ts

+108-33
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,17 @@ class TestExecutionService implements ITestExecutionService {
3232
private $options: IOptions,
3333
private $pluginsService: IPluginsService,
3434
private $errors: IErrors,
35-
private $devicesService: Mobile.IDevicesService) {
35+
private $androidDebugService:IDebugService,
36+
private $iOSDebugService: IDebugService,
37+
private $devicesService: Mobile.IDevicesService,
38+
private $childProcess: IChildProcess) {
3639
}
3740

41+
public platform: string;
42+
3843
public startTestRunner(platform: string) : IFuture<void> {
3944
return (() => {
45+
this.platform = platform;
4046
this.$options.justlaunch = true;
4147
let blockingOperationFuture = new Future<void>();
4248
process.on('message', (launcherConfig: any) => {
@@ -50,7 +56,7 @@ class TestExecutionService implements ITestExecutionService {
5056
let configOptions: IKarmaConfigOptions = JSON.parse(launcherConfig);
5157
this.$options.debugBrk = configOptions.debugBrk;
5258
this.$options.debugTransport = configOptions.debugTransport;
53-
let configJs = this.generateConfig(configOptions);
59+
let configJs = this.generateConfig(this.$options.port.toString(), configOptions);
5460
this.$fs.writeFile(path.join(projectDir, TestExecutionService.CONFIG_FILE_NAME), configJs).wait();
5561

5662
let socketIoJsUrl = `http://localhost:${this.$options.port}/socket.io/socket.io.js`;
@@ -93,37 +99,47 @@ class TestExecutionService implements ITestExecutionService {
9399
public startKarmaServer(platform: string): IFuture<void> {
94100
return (() => {
95101
platform = platform.toLowerCase();
96-
this.$pluginsService.ensureAllDependenciesAreInstalled().wait();
97-
let pathToKarma = path.join(this.$projectData.projectDir, 'node_modules/karma');
98-
let KarmaServer = require(path.join(pathToKarma, 'lib/server'));
99-
if (platform === 'ios' && this.$options.emulator) {
100-
platform = 'ios_simulator';
101-
}
102-
let karmaConfig: any = {
103-
browsers: [platform],
104-
configFile: path.join(this.$projectData.projectDir, 'karma.conf.js'),
105-
_NS: {
106-
log: this.$logger.getLevel(),
107-
path: this.$options.path,
108-
tns: process.argv[1],
109-
node: process.execPath,
110-
options: {
111-
debugTransport: this.$options.debugTransport,
112-
debugBrk: this.$options.debugBrk,
113-
}
114-
},
115-
};
116-
if (this.$config.DEBUG || this.$logger.getLevel() === 'TRACE') {
117-
karmaConfig.logLevel = 'DEBUG';
118-
}
119-
if (!this.$options.watch) {
120-
karmaConfig.singleRun = true;
102+
this.platform = platform;
103+
104+
if(this.$options.debugBrk && this.$options.watch) {
105+
this.$errors.failWithoutHelp("You cannot use --watch and --debug-brk simultaneously. Remove one of the flags and try again.");
121106
}
122-
if (this.$options.debugBrk) {
123-
karmaConfig.browserNoActivityTimeout = 1000000000;
107+
108+
if (!this.$platformService.preparePlatform(platform).wait()) {
109+
this.$errors.failWithoutHelp("Verify that listed files are well-formed and try again the operation.");
124110
}
125-
this.$logger.debug(JSON.stringify(karmaConfig, null, 4));
126-
new KarmaServer(karmaConfig).start();
111+
112+
let projectDir = this.$projectData.projectDir;
113+
this.$devicesService.initialize({ platform: platform, deviceId: this.$options.device }).wait();
114+
115+
let karmaConfig = this.getKarmaConfiguration(platform),
116+
karmaRunner = this.$childProcess.fork(path.join(__dirname, "karma-execution.js"));
117+
118+
karmaRunner.send({karmaConfig: karmaConfig});
119+
karmaRunner.on("message", (karmaData: any) => {
120+
fiberBootstrap.run(() => {
121+
this.$logger.trace("## Unit-testing: Parent process received message", karmaData);
122+
let port: string;
123+
if(karmaData.url) {
124+
port = karmaData.url.port;
125+
let socketIoJsUrl = `http://${karmaData.url.host}/socket.io/socket.io.js`;
126+
let socketIoJs = this.$httpClient.httpRequest(socketIoJsUrl).wait().body;
127+
this.$fs.writeFile(path.join(projectDir, TestExecutionService.SOCKETIO_JS_FILE_NAME), socketIoJs).wait();
128+
}
129+
130+
if(karmaData.launcherConfig) {
131+
let configOptions: IKarmaConfigOptions = JSON.parse(karmaData.launcherConfig);
132+
let configJs = this.generateConfig(port, configOptions);
133+
this.$fs.writeFile(path.join(projectDir, TestExecutionService.CONFIG_FILE_NAME), configJs).wait();
134+
}
135+
136+
if(this.$options.debugBrk) {
137+
this.getDebugService(platform).debug().wait();
138+
} else {
139+
this.liveSyncProject(platform).wait();
140+
}
141+
});
142+
});
127143
}).future<void>()();
128144
}
129145

@@ -138,8 +154,7 @@ class TestExecutionService implements ITestExecutionService {
138154
}).future<void>()();
139155
}
140156

141-
private generateConfig(options: any): string {
142-
let port = this.$options.port;
157+
private generateConfig(port: string, options: any): string {
143158
let nics = os.networkInterfaces();
144159
let ips = Object.keys(nics)
145160
.map(nicName => nics[nicName].filter((binding: any) => binding.family === 'IPv4' && !binding.internal)[0])
@@ -154,5 +169,65 @@ class TestExecutionService implements ITestExecutionService {
154169

155170
return 'module.exports = ' + JSON.stringify(config);
156171
}
172+
173+
private getDebugService(platform: string): IDebugService {
174+
let lowerCasedPlatform = platform.toLowerCase();
175+
if(lowerCasedPlatform === this.$devicePlatformsConstants.iOS.toLowerCase()) {
176+
return this.$iOSDebugService;
177+
} else if(lowerCasedPlatform === this.$devicePlatformsConstants.Android.toLowerCase()) {
178+
return this.$androidDebugService;
179+
}
180+
181+
throw new Error(`Invalid platform ${platform}. Valid platforms are ${this.$devicePlatformsConstants.iOS} and ${this.$devicePlatformsConstants.Android}`);
182+
}
183+
184+
private getKarmaConfiguration(platform: string): any {
185+
let karmaConfig: any = {
186+
browsers: [platform],
187+
configFile: path.join(this.$projectData.projectDir, 'karma.conf.js'),
188+
_NS: {
189+
log: this.$logger.getLevel(),
190+
path: this.$options.path,
191+
tns: process.argv[1],
192+
node: process.execPath,
193+
options: {
194+
debugTransport: this.$options.debugTransport,
195+
debugBrk: this.$options.debugBrk,
196+
}
197+
},
198+
};
199+
if (this.$config.DEBUG || this.$logger.getLevel() === 'TRACE') {
200+
karmaConfig.logLevel = 'DEBUG';
201+
}
202+
if (!this.$options.watch) {
203+
karmaConfig.singleRun = true;
204+
}
205+
if (this.$options.debugBrk) {
206+
karmaConfig.browserNoActivityTimeout = 1000000000;
207+
}
208+
209+
karmaConfig.projectDir = this.$projectData.projectDir;
210+
this.$logger.debug(JSON.stringify(karmaConfig, null, 4));
211+
212+
return karmaConfig;
213+
}
214+
215+
private liveSyncProject(platform: string): IFuture<void> {
216+
return (() => {
217+
let platformData = this.$platformsData.getPlatformData(platform.toLowerCase()),
218+
projectFilesPath = path.join(platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME);
219+
220+
let liveSyncData: ILiveSyncData = {
221+
platform: platform,
222+
appIdentifier: this.$projectData.projectId,
223+
projectFilesPath: projectFilesPath,
224+
syncWorkingDirectory: path.join(this.$projectData.projectDir, constants.APP_FOLDER_NAME),
225+
canExecuteFastSync: false, // Always restart the application when change is detected, so tests will be rerun.
226+
excludedProjectDirsAndFiles: constants.LIVESYNC_EXCLUDED_FILE_PATTERNS
227+
};
228+
229+
this.$liveSyncServiceBase.sync(liveSyncData).wait();
230+
}).future<void>()();
231+
}
157232
}
158233
$injector.register('testExecutionService', TestExecutionService);

test/project-files-provider.ts

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/// <reference path=".d.ts" />
2+
"use strict";
3+
4+
import { Yok } from "../lib/common/yok";
5+
import { ProjectFilesProvider } from "../lib/providers/project-files-provider";
6+
import { assert } from "chai";
7+
import * as path from "path";
8+
import Future = require("fibers/future");
9+
10+
let projectDir = "projectDir",
11+
appDestinationDirectoryPath = "appDestinationDirectoryPath",
12+
appResourcesDestinationDirectoryPath = "appResourcesDestinationDirectoryPath",
13+
appSourceDir = path.join(projectDir, "app");
14+
15+
function createTestInjector(): IInjector {
16+
let testInjector = new Yok();
17+
testInjector.register("mobileHelper", {
18+
platformNames: ["Android", "iOS"]
19+
});
20+
21+
testInjector.register("platformsData", {
22+
getPlatformData: (platform: string) => {
23+
return {
24+
appDestinationDirectoryPath: appDestinationDirectoryPath,
25+
normalizedPlatformName: platform.toLowerCase(),
26+
platformProjectService: {
27+
getAppResourcesDestinationDirectoryPath: () => Future.fromResult(appResourcesDestinationDirectoryPath)
28+
}
29+
};
30+
},
31+
});
32+
33+
testInjector.register("projectData", {
34+
projectDir: projectDir
35+
});
36+
37+
testInjector.register("options", { release: false });
38+
39+
return testInjector;
40+
}
41+
42+
describe("project-files-provider", () => {
43+
let testInjector: IInjector,
44+
projectFilesProvider: IProjectFilesProvider;
45+
46+
beforeEach(() => {
47+
testInjector = createTestInjector();
48+
projectFilesProvider = testInjector.resolve(ProjectFilesProvider);
49+
});
50+
51+
describe("isFileExcluded", () => {
52+
it("returns true for .ts files", () => {
53+
assert.isTrue(projectFilesProvider.isFileExcluded("test.ts"));
54+
});
55+
56+
it("returns false for .js files", () => {
57+
assert.isFalse(projectFilesProvider.isFileExcluded("test.js"));
58+
});
59+
});
60+
61+
describe("mapFilePath", () => {
62+
it("returns file path from prepared project when path from app dir is passed", () => {
63+
let mappedFilePath = projectFilesProvider.mapFilePath(path.join(appSourceDir, "test.js"), "android");
64+
assert.deepEqual(mappedFilePath, path.join(appDestinationDirectoryPath, "app", "test.js"));
65+
});
66+
67+
it("returns file path from prepared project when path from app/App_Resources/platform dir is passed", () => {
68+
let mappedFilePath = projectFilesProvider.mapFilePath(path.join(appSourceDir, "App_Resources", "android", "test.js"), "android");
69+
assert.deepEqual(mappedFilePath, path.join(appResourcesDestinationDirectoryPath, "test.js"));
70+
});
71+
72+
it("returns null when path from app/App_Resources/android dir is passed and iOS platform is specified", () => {
73+
let mappedFilePath = projectFilesProvider.mapFilePath(path.join(appSourceDir, "App_Resources", "android", "test.js"), "iOS");
74+
assert.deepEqual(mappedFilePath, null);
75+
});
76+
77+
it("returns null when path from app/App_Resources/ dir (not platform specific) is passed", () => {
78+
let mappedFilePath = projectFilesProvider.mapFilePath(path.join(appSourceDir, "App_Resources", "test.js"), "android");
79+
assert.deepEqual(mappedFilePath, null);
80+
});
81+
82+
it("returns file path from prepared project when path from app dir is passed and it contains platform in its name", () => {
83+
let mappedFilePath = projectFilesProvider.mapFilePath(path.join(appSourceDir, "test.android.js"), "android");
84+
assert.deepEqual(mappedFilePath, path.join(appDestinationDirectoryPath, "app", "test.js"));
85+
});
86+
87+
it("returns file path from prepared project when path from app dir is passed and it contains configuration in its name", () => {
88+
let mappedFilePath = projectFilesProvider.mapFilePath(path.join(appSourceDir, "test.debug.js"), "android");
89+
assert.deepEqual(mappedFilePath, path.join(appDestinationDirectoryPath, "app", "test.js"));
90+
});
91+
});
92+
});

0 commit comments

Comments
 (0)