Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
## [2.0.8](https://github.com/NativeScript/nx/compare/2.0.7...2.0.8) (2021-12-18)


### Features

* unit testing executor and configuration ([98f0216](https://github.com/NativeScript/nx/commit/98f02167df538d9a1828a88f7116ef534238ebb1))



## [2.0.7](https://github.com/NativeScript/nx/compare/2.0.6...2.0.7) (2021-11-20)


Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "nativescript-nx-plugins",
"version": "2.0.7",
"version": "2.0.8",
"license": "MIT",
"scripts": {
"nx": "nx",
Expand Down
54 changes: 53 additions & 1 deletion packages/nx/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
- [Develop on simulators and devices](#develop-on-simulators-and-devices)
- [Configuration options](#configuration-options)
- [Run with a specific configuration](#run-with-a-specific-configuration)
- [Run tests](#run-tests)
- [Create a build](#create-a-build)
- [Clean](#clean)
- [Create NativeScript library](#create-nativescript-library)
Expand Down Expand Up @@ -192,7 +193,7 @@ The options follow the [NativeScript command line option flags](https://docs.nat

Here's an example app config:

```
```json
"nativescript-mobile": {
"projectType": "application",
"root": "apps/nativescript-mobile/",
Expand Down Expand Up @@ -253,6 +254,17 @@ Here's an example app config:
}
}
},
"test": {
"executor": "@nativescript/nx:test",
"outputs": ["coverage/apps/nativescript-mobile"],
"options": {
"coverage": false
},
"configurations": {
"android": {},
"ios": {}
}
},
"clean": {
"builder": "@nativescript/nx:build",
"options": {
Expand All @@ -277,6 +289,46 @@ npx nx run <app-name>:android:prod
npx nx run <app-name>:ios:prod
```

#### Run tests

**Android:**

```sh
npx nx run <app-name>:test:android
```

**iOS:** (Mac only)

```sh
npx nx run <app-name>:test:ios
```

You can generate coverage reports by using the flag with iOS or Android, for example:

```sh
npx nx run <app-name>:test:ios --coverage
```

You can also set this option in the config, for example:

```json
"test": {
"executor": "@nativescript/nx:test",
"outputs": ["coverage/apps/nativescript-mobile"],
"options": {
"coverage": true // can set to always be on for both platforms
},
"configurations": {
"android": {
"coverage": false // or can override per platform if needed
},
"ios": {
"coverage": true
}
}
}
```

#### Create a build

Instead of running the app on a simulator or device you can create a build for the purposes of distribution/release. Various release settings will be needed for iOS and Android which can be passed as additional command line arguments. [See more in the NativeScript docs here](https://docs.nativescript.org/releasing.html#overview). Any additional cli flags as stated in the docs can be passed on the end of the `nx build` command that follows.
Expand Down
5 changes: 5 additions & 0 deletions packages/nx/builders.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
"implementation": "./src/builders/build/builder",
"schema": "./src/builders/build/schema.json",
"description": "NativeScript builder"
},
"test": {
"implementation": "./src/builders/test/builder",
"schema": "./src/builders/test/schema.json",
"description": "Start the NativeScript unit test runner"
}
}
}
2 changes: 1 addition & 1 deletion packages/nx/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@nativescript/nx",
"version": "2.0.7",
"version": "2.0.8",
"description": "NativeScript Plugin for Nx",
"repository": {
"type": "git",
Expand Down
35 changes: 35 additions & 0 deletions packages/nx/src/builders/test/builder.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Architect } from '@angular-devkit/architect';
import { TestingArchitectHost } from '@angular-devkit/architect/testing';
import { schema } from '@angular-devkit/core';
import { join } from 'path';
import { TestBuilderSchema } from './schema';
import runBuilder from './builder';

const options: TestBuilderSchema = {
codeCoverage: false,
platform: 'ios',
};

xdescribe('NativeScript Test Builder', () => {
const context = {
logger: {
info: (args) => {
console.log(args);
},
},
} as any;
let architect: Architect;
let architectHost: TestingArchitectHost;

beforeEach(async () => {
const registry = new schema.CoreSchemaRegistry();
registry.addPostTransform(schema.transforms.addUndefinedDefaults);

architectHost = new TestingArchitectHost('/root', '/root');
architect = new Architect(architectHost, registry);

// This will either take a Node package name, or a path to the directory
// for the package.json file.
await architectHost.addBuilderFromPackage(join(__dirname, '../../..'));
});
});
110 changes: 110 additions & 0 deletions packages/nx/src/builders/test/builder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import { ExecutorContext, convertNxExecutor } from '@nrwl/devkit';
import * as childProcess from 'child_process';
import { TestBuilderSchema } from './schema';

export function runBuilder(options: TestBuilderSchema, context: ExecutorContext): Promise<{ success: boolean }> {
return new Promise((resolve, reject) => {
const projectConfig = context.workspace.projects[context.projectName];
// console.log('context.projectName:', context.projectName);
const projectCwd = projectConfig.root;
// console.log('projectCwd:', projectCwd);
// console.log('context.targetName:', context.targetName);
// console.log('context.configurationName:', context.configurationName);
// console.log('context.target.options:', context.target.options);

let targetConfigName = '';
if (context.configurationName && context.configurationName !== 'build') {
targetConfigName = context.configurationName;
}

// determine if any trailing args that need to be added to run/build command
const configTarget = targetConfigName ? `:${targetConfigName}` : '';
const projectTargetCmd = `${context.projectName}:${context.targetName}${configTarget}`;
const projectTargetCmdIndex = process.argv.findIndex((c) => c === projectTargetCmd);
// const additionalCliFlagArgs = [];
// if (process.argv.length > projectTargetCmdIndex+1) {
// additionalCliFlagArgs.push(...process.argv.slice(projectTargetCmdIndex+1, process.argv.length));
// // console.log('additionalCliFlagArgs:', additionalCliFlagArgs);
// }

const throwPlatformError = () => {
throw new Error(`Configuration must exist for 'ios' or 'android' or options.platform should be set for this target.`);
}

const nsOptions = ['test'];

const fileReplacements: Array<string> = [];
let configOptions;
if (context.target.configurations) {
configOptions = context.target.configurations[targetConfigName];
// console.log('configOptions:', configOptions)

if (configOptions) {
if (['ios', 'android'].includes(targetConfigName)) {
nsOptions.push(targetConfigName);
} else if (options.platform) {
nsOptions.push(options.platform);
} else {
throwPlatformError();
}
if (configOptions.coverage) {
nsOptions.push('--env.codeCoverage');
}
if (configOptions.fileReplacements) {
for (const r of configOptions.fileReplacements) {
fileReplacements.push(`${r.replace.replace(projectCwd, './')}:${r.with.replace(projectCwd, './')}`);
}
}
}
}

const hasPlatform = nsOptions.filter(o => ['ios', 'android'].includes(o)).length > 0;
if (!hasPlatform) {
throwPlatformError();
}

if (options.coverage && !nsOptions.includes('--env.codeCoverage')) {
// allow target override for all configurations
nsOptions.push('--env.codeCoverage');
}

if (options.device) {
nsOptions.push('--device');
nsOptions.push(options.device);
}

if (fileReplacements.length) {
// console.log('fileReplacements:', fileReplacements);
nsOptions.push('--env.replace');
nsOptions.push(fileReplacements.join(','));
}
// always add --force (unless explicity set to false) for now since within Nx we use @nativescript/webpack at root only and the {N} cli shows a blocking error if not within the app
if (options?.force !== false) {
nsOptions.push('--force');
}

// additional args after -- should be passed through
const argSeparator = process.argv.findIndex((arg) => arg === '--');
let additionalArgs = [];
if (argSeparator >= 0) {
additionalArgs = process.argv.slice(argSeparator + 1);
}

console.log('---');
console.log(`Running NativeScript unit tests within ${projectCwd}`);
console.log(' ');
console.log([`ns`, ...nsOptions, ...additionalArgs].join(' '));
console.log('---');
// console.log('command:', [`ns`, ...nsOptions].join(' '));
const child = childProcess.spawn(/^win/.test(process.platform) ? 'ns.cmd' : 'ns', [...nsOptions, ...additionalArgs], {
cwd: projectCwd,
stdio: 'inherit',
});
child.on('close', (code) => {
console.log(`Done.`);
resolve({ success: code === 0 });
});
});
}

export default convertNxExecutor(runBuilder);
8 changes: 8 additions & 0 deletions packages/nx/src/builders/test/schema.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { JsonObject } from '@angular-devkit/core';

export interface TestBuilderSchema extends JsonObject {
platform?: 'ios' | 'android';
coverage?: boolean;
device?: string;
force?: boolean;
}
28 changes: 28 additions & 0 deletions packages/nx/src/builders/test/schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"$schema": "http://json-schema.org/schema",
"title": "Start the NativeScript unit test runner",
"description": "",
"type": "object",
"properties": {
"platform": {
"type": "string",
"description": "Platform to test."
},
"coverage": {
"type": "boolean",
"default": false,
"description": "Enable code coverage reports."
},
"device": {
"type": "string",
"description": "Device identifier to run tests on.",
"alias": "d"
},
"force": {
"type": "boolean",
"default": true,
"description": "If true, skips the application compatibility checks and forces npm i to ensure all dependencies are installed. Otherwise, the command will check the application compatibility with the current CLI version and could fail requiring ns migrate."
}
},
"required": []
}