Skip to content

feat: implement unit testing with bundle #4437

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Mar 19, 2019
4 changes: 4 additions & 0 deletions config/test-dependencies.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
{
"name": "karma-nativescript-launcher"
},
{
"name": "karma-webpack",
"excludedPeerDependencies": ["webpack"]
},
{
"name": "mocha",
"framework": "mocha"
Expand Down
16 changes: 6 additions & 10 deletions lib/commands/test-init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,7 @@ class TestInitCommand implements ICommand {

let modulesToInstall: IDependencyInformation[] = [];
try {
const dependencies = this.$testInitializationService.getDependencies(frameworkToInstall);
const dependenciesVersions = this.$testInitializationService.getDependenciesVersions();
modulesToInstall = dependencies.map(dependency => {
const dependencyVersion = dependenciesVersions[dependency];
if (!dependencyVersion) {
this.$errors.failWithoutHelp(`'${dependency}' is not a registered dependency.`);
}

return { name: dependency, version: dependencyVersion };
});
modulesToInstall = this.$testInitializationService.getDependencies(frameworkToInstall);
} catch (err) {
this.$errors.failWithoutHelp(`Unable to install the unit testing dependencies. Error: '${err.message}'`);
}
Expand All @@ -66,6 +57,11 @@ class TestInitCommand implements ICommand {
const modulePeerDependencies = modulePackageJsonContent.peerDependencies || {};

for (const peerDependency in modulePeerDependencies) {
const isPeerDependencyExcluded = _.includes(mod.excludedPeerDependencies, peerDependency);
if (isPeerDependencyExcluded) {
continue;
}

const dependencyVersion = modulePeerDependencies[peerDependency] || "*";

// catch errors when a peerDependency is already installed
Expand Down
1 change: 1 addition & 0 deletions lib/common/declarations.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1466,6 +1466,7 @@ interface IProcessService {
interface IDependencyInformation {
name: string;
version?: string;
excludedPeerDependencies?: string[];
}

/**
Expand Down
3 changes: 1 addition & 2 deletions lib/definitions/project.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -482,8 +482,7 @@ interface ITestExecutionService {
}

interface ITestInitializationService {
getDependencies(framework: string): string[];
getDependenciesVersions(): IDictionary<string>;
getDependencies(framework: string): IDependencyInformation[];
}

/**
Expand Down
33 changes: 13 additions & 20 deletions lib/services/test-execution-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ export class TestExecutionService implements ITestExecutionService {
private $fs: IFileSystem,
private $options: IOptions,
private $pluginsService: IPluginsService,
private $errors: IErrors,
private $devicesService: Mobile.IDevicesService,
private $childProcess: IChildProcess) {
}
Expand Down Expand Up @@ -59,25 +58,8 @@ export class TestExecutionService implements ITestExecutionService {
this.$fs.writeFile(path.join(projectDir, TestExecutionService.CONFIG_FILE_NAME), configJs);
}

const appFilesUpdaterOptions: IAppFilesUpdaterOptions = {
bundle: !!this.$options.bundle,
release: this.$options.release,
useHotModuleReload: this.$options.hmr
};
const preparePlatformInfo: IPreparePlatformInfo = {
platform,
appFilesUpdaterOptions,
platformTemplate: this.$options.platformTemplate,
projectData,
config: this.$options,
env: this.$options.env
};

// Prepare the project AFTER the TestExecutionService.CONFIG_FILE_NAME file is created in node_modules
// so it will be sent to device.
if (!await this.$platformService.preparePlatform(preparePlatformInfo)) {
this.$errors.failWithoutHelp("Verify that listed files are well-formed and try again the operation.");
}

let devices = [];
if (this.$options.debugBrk) {
Expand Down Expand Up @@ -125,21 +107,29 @@ export class TestExecutionService implements ITestExecutionService {
return info;
});

const env = this.$options.env || {};
env.unitTesting = !!this.$options.bundle;

const liveSyncInfo: ILiveSyncInfo = {
projectDir: projectData.projectDir,
skipWatcher: !this.$options.watch || this.$options.justlaunch,
watchAllFiles: this.$options.syncAllFiles,
bundle: !!this.$options.bundle,
release: this.$options.release,
env: this.$options.env,
env,
timeout: this.$options.timeout,
useHotModuleReload: this.$options.hmr
};

await this.$liveSyncService.liveSync(deviceDescriptors, liveSyncInfo);
};

karmaRunner.on("message", (karmaData: any) => {
karmaRunner.on("message", (karmaData: any) => {
this.$logger.trace(`The received message from karma is: `, karmaData);
if (!karmaData.launcherConfig && !karmaData.url) {
return;
}

launchKarmaTests(karmaData)
.catch((result) => {
this.$logger.error(result);
Expand Down Expand Up @@ -207,6 +197,7 @@ export class TestExecutionService implements ITestExecutionService {
debugTransport: this.$options.debugTransport,
debugBrk: this.$options.debugBrk,
watch: !!this.$options.watch,
bundle: !!this.$options.bundle,
appDirectoryRelativePath: projectData.getAppDirectoryRelativePath()
}
},
Expand All @@ -226,6 +217,8 @@ export class TestExecutionService implements ITestExecutionService {
}

karmaConfig.projectDir = projectData.projectDir;
karmaConfig.bundle = this.$options.bundle;
karmaConfig.platform = platform.toLowerCase();
this.$logger.debug(JSON.stringify(karmaConfig, null, 4));

return karmaConfig;
Expand Down
27 changes: 15 additions & 12 deletions lib/services/test-initialization-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,28 @@ import { cache } from "../common/decorators";
export class TestInitializationService implements ITestInitializationService {
private configsPath = path.join(__dirname, "..", "..", "config");

constructor(private $fs: IFileSystem) { }
constructor(private $errors: IErrors,
private $fs: IFileSystem) { }

@cache()
public getDependencies(selectedFramework: string): string[] {
public getDependencies(selectedFramework: string): IDependencyInformation[] {
const dependenciesPath = path.join(this.configsPath, "test-dependencies.json");
const allDependencies: { name: string, framework: string }[] = this.$fs.readJson(dependenciesPath);
const targetFrameworkDependencies: string[] = allDependencies
.filter(dependency => !dependency.framework || dependency.framework === selectedFramework)
.map(dependency => dependency.name);

return targetFrameworkDependencies;
}
const allDependencies: { name: string, framework?: string, excludedPeerDependencies?: string[] }[] = this.$fs.readJson(dependenciesPath);

@cache()
public getDependenciesVersions(): IDictionary<string> {
const dependenciesVersionsPath = path.join(this.configsPath, "test-deps-versions-generated.json");
const dependenciesVersions = this.$fs.readJson(dependenciesVersionsPath);

return dependenciesVersions;
const targetFrameworkDependencies: IDependencyInformation[] = allDependencies
.filter(dependency => !dependency.framework || dependency.framework === selectedFramework)
.map(dependency => {
const dependencyVersion = dependenciesVersions[dependency.name];
if (!dependencyVersion) {
this.$errors.failWithoutHelp(`'${dependency}' is not a registered dependency.`);
}
return { ...dependency, version: dependencyVersion };
});

return targetFrameworkDependencies;
}
}

Expand Down
34 changes: 32 additions & 2 deletions resources/test/karma.conf.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module.exports = function(config) {
config.set({
const options = {

// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: '',
Expand Down Expand Up @@ -73,5 +73,35 @@ module.exports = function(config) {
// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
singleRun: false
})
};

setWebpackPreprocessor(config, options);
setWebpack(config, options);

config.set(options);
}

function setWebpackPreprocessor(config, options) {
if (config && config.bundle) {
if (!options.preprocessors) {
options.preprocessors = {};
}

options.files.forEach(file => {
if (!options.preprocessors[file]) {
options.preprocessors[file] = [];
}
options.preprocessors[file].push('webpack');
});
}
}

function setWebpack(config, options) {
if (config && config.bundle) {
const env = {};
env[config.platform] = true;
options.webpack = require('./webpack.config')(env);
delete options.webpack.entry;
delete options.webpack.output.libraryTarget;
}
}