diff --git a/lib/services/karma-execution.ts b/lib/services/karma-execution.ts new file mode 100644 index 0000000000..23ba20f8d1 --- /dev/null +++ b/lib/services/karma-execution.ts @@ -0,0 +1,15 @@ +/// + +"use strict"; + +import * as path from "path"; + +process.on("message", (data: any) => { + if(data.karmaConfig) { + let pathToKarma = path.join(data.karmaConfig.projectDir, 'node_modules/karma'), + KarmaServer = require(path.join(pathToKarma, 'lib/server')), + karma = new KarmaServer(data.karmaConfig); + + karma.start(); + } +}); diff --git a/lib/services/test-execution-service.ts b/lib/services/test-execution-service.ts index 254d6f5eb5..666f0c96fc 100644 --- a/lib/services/test-execution-service.ts +++ b/lib/services/test-execution-service.ts @@ -32,11 +32,16 @@ class TestExecutionService implements ITestExecutionService { private $options: IOptions, private $pluginsService: IPluginsService, private $errors: IErrors, + private $androidDebugService:IDebugService, + private $iOSDebugService: IDebugService, private $devicesService: Mobile.IDevicesService) { } + public platform: string; + public startTestRunner(platform: string) : IFuture { return (() => { + this.platform = platform; this.$options.justlaunch = true; let blockingOperationFuture = new Future(); process.on('message', (launcherConfig: any) => { @@ -50,7 +55,7 @@ class TestExecutionService implements ITestExecutionService { let configOptions: IKarmaConfigOptions = JSON.parse(launcherConfig); this.$options.debugBrk = configOptions.debugBrk; this.$options.debugTransport = configOptions.debugTransport; - let configJs = this.generateConfig(configOptions); + let configJs = this.generateConfig(this.$options.port.toString(), configOptions); this.$fs.writeFile(path.join(projectDir, TestExecutionService.CONFIG_FILE_NAME), configJs).wait(); let socketIoJsUrl = `http://localhost:${this.$options.port}/socket.io/socket.io.js`; @@ -93,12 +98,30 @@ class TestExecutionService implements ITestExecutionService { public startKarmaServer(platform: string): IFuture { return (() => { platform = platform.toLowerCase(); - this.$pluginsService.ensureAllDependenciesAreInstalled().wait(); - let pathToKarma = path.join(this.$projectData.projectDir, 'node_modules/karma'); - let KarmaServer = require(path.join(pathToKarma, 'lib/server')); - if (platform === 'ios' && this.$options.emulator) { - platform = 'ios_simulator'; + this.platform = platform; + + if(this.$options.debugBrk && this.$options.watch) { + this.$errors.failWithoutHelp("You cannot use --watch and --debug-brk simultaneously. Remove one of the flags and try again."); + } + + if (!this.$platformService.preparePlatform(platform).wait()) { + this.$errors.failWithoutHelp("Verify that listed files are well-formed and try again the operation."); } + + let platformData = this.$platformsData.getPlatformData(platform.toLowerCase()); + let projectDir = this.$projectData.projectDir; + this.$devicesService.initialize({ platform: platform, deviceId: this.$options.device }).wait(); + let projectFilesPath = path.join(platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME); + + let liveSyncData: ILiveSyncData = { + platform: platform, + appIdentifier: this.$projectData.projectId, + projectFilesPath: projectFilesPath, + syncWorkingDirectory: path.join(projectDir, constants.APP_FOLDER_NAME), + canExecuteFastSync: false, // Always restart the application when change is detected, so tests will be rerun. + excludedProjectDirsAndFiles: ["**/*.js.map", "**/*.ts"] + }; + let karmaConfig: any = { browsers: [platform], configFile: path.join(this.$projectData.projectDir, 'karma.conf.js'), @@ -122,8 +145,36 @@ class TestExecutionService implements ITestExecutionService { if (this.$options.debugBrk) { karmaConfig.browserNoActivityTimeout = 1000000000; } + + karmaConfig.projectDir = this.$projectData.projectDir; this.$logger.debug(JSON.stringify(karmaConfig, null, 4)); - new KarmaServer(karmaConfig).start(); + + let karmaRunner = require("child_process").fork(path.join(__dirname, "karma-execution.js")); + karmaRunner.send({karmaConfig: karmaConfig}); + karmaRunner.on("message", (karmaData: any) => { + fiberBootstrap.run(() => { + this.$logger.trace("## Unit-testing: Parent process received message", karmaData); + let port: string; + if(karmaData.url) { + port = karmaData.url.port; + let socketIoJsUrl = `http://localhost:${port}/socket.io/socket.io.js`; + let socketIoJs = this.$httpClient.httpRequest(socketIoJsUrl).wait().body; + this.$fs.writeFile(path.join(projectDir, TestExecutionService.SOCKETIO_JS_FILE_NAME), socketIoJs).wait(); + } + + if(karmaData.launcherConfig) { + let configOptions: IKarmaConfigOptions = JSON.parse(karmaData.launcherConfig); + let configJs = this.generateConfig(port, configOptions); + this.$fs.writeFile(path.join(projectDir, TestExecutionService.CONFIG_FILE_NAME), configJs).wait(); + } + + if(this.$options.debugBrk) { + this.getDebugService(platform).debug().wait(); + } else { + this.$liveSyncServiceBase.sync(liveSyncData).wait(); + } + }); + }); }).future()(); } @@ -138,8 +189,7 @@ class TestExecutionService implements ITestExecutionService { }).future()(); } - private generateConfig(options: any): string { - let port = this.$options.port; + private generateConfig(port: string, options: any): string { let nics = os.networkInterfaces(); let ips = Object.keys(nics) .map(nicName => nics[nicName].filter((binding: any) => binding.family === 'IPv4' && !binding.internal)[0]) @@ -154,5 +204,16 @@ class TestExecutionService implements ITestExecutionService { return 'module.exports = ' + JSON.stringify(config); } + + private getDebugService(platform: string): IDebugService { + let lowerCasedPlatform = platform.toLowerCase(); + if(platform.toLowerCase() === this.$devicePlatformsConstants.iOS.toLowerCase()) { + return this.$iOSDebugService; + } else if(lowerCasedPlatform === this.$devicePlatformsConstants.Android.toLowerCase()) { + return this.$androidDebugService; + } + + throw new Error(`Invalid platform ${platform}. Valid platforms are ${this.$devicePlatformsConstants.iOS} and ${this.$devicePlatformsConstants.Android}`); + } } $injector.register('testExecutionService', TestExecutionService);