Skip to content

Commit

Permalink
chrore(ng-schematics): Update ng e2e to custom builder (#9300)
Browse files Browse the repository at this point in the history
**What kind of change does this PR introduce?**

This replaces the default `ng e2e` with our custom builder. In the
feature it seem possible to remove the necessity of the user running the
server separately and run it from the builder - that will improve the
easy of use and CI of this schematic.

**Did you add tests for your changes?**

**If relevant, did you update the documentation?**

Yes - Updated `@puppeteer/ng-schematics` README.md

**Summary**

We want to not see the default `ng e2e` and we want to make it easier
for the user to run commands.
Angular Developer are likely to also use its' CLI.

**Does this PR introduce a breaking change?**

Yes. Users need to delete the default and initialize the schematics
again.

**Other information**
  • Loading branch information
Lightning00Blade committed Nov 22, 2022
1 parent 0107ad8 commit 4613f03
Show file tree
Hide file tree
Showing 14 changed files with 340 additions and 56 deletions.
105 changes: 87 additions & 18 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions packages/ng-schematics/README.md
Expand Up @@ -20,13 +20,14 @@ Currently, this schematic supports the following test frameworks:
- **Mocha** [https://mochajs.org/]
- **Node Test Runner** _(Experimental)_ [https://nodejs.org/api/test.html]

With the schematics installed, you can run E2E tests:
With the schematics installed you can run E2E tests:

```bash
npm run e2e
# or yarn e2e
ng e2e
```

> Note: Server must be running before executing the command.
## Options

When adding schematics to your project you can to provide following options:
Expand Down
4 changes: 3 additions & 1 deletion packages/ng-schematics/package.json
Expand Up @@ -26,6 +26,7 @@
"node": ">=14.1.0"
},
"dependencies": {
"@angular-devkit/architect": "^0.1402.10",
"@angular-devkit/core": "^14.2.6",
"@angular-devkit/schematics": "^14.2.6"
},
Expand All @@ -40,5 +41,6 @@
"ng-add": {
"save": "devDependencies"
},
"schematics": "./lib/schematics/collection.json"
"schematics": "./lib/schematics/collection.json",
"builders": "./lib/builders/builders.json"
}
10 changes: 10 additions & 0 deletions packages/ng-schematics/src/builders/builders.json
@@ -0,0 +1,10 @@
{
"$schema": "../../../../node_modules/@angular-devkit/architect/src/builders-schema.json",
"builders": {
"puppeteer": {
"implementation": "./puppeteer",
"schema": "./puppeteer/schema.json",
"description": "Run e2e test with Puppeteer"
}
}
}
82 changes: 82 additions & 0 deletions packages/ng-schematics/src/builders/puppeteer/index.ts
@@ -0,0 +1,82 @@
import {
createBuilder,
BuilderContext,
BuilderOutput,
} from '@angular-devkit/architect';
import {spawn} from 'child_process';

import {PuppeteerBuilderOptions} from './types.js';

function getError(executable: string, args: string[]) {
return (
`Puppeteer E2E tests failed!` +
'\n' +
`Error running '${executable}' with arguments '${args.join(' ')}'.` +
`\n` +
'Please look at the output above to determine the issue!'
);
}

function getExecutable(command: string[]) {
const executable = command.shift()!;
const error = getError(executable, command);

if (executable === 'node') {
return {
executable: executable,
args: command,
error,
};
}

return {
executable: `./node_modules/.bin/${executable}`,
args: command,
error,
};
}

async function executeCommand(context: BuilderContext, command: string[]) {
await new Promise((resolve, reject) => {
const {executable, args, error} = getExecutable(command);

const child = spawn(executable, args, {
cwd: context.workspaceRoot,
stdio: 'inherit',
});

child.on('error', message => {
console.log(message);
reject(error);
});

child.on('exit', code => {
if (code === 0) {
resolve(true);
} else {
reject(error);
}
});
});
}

async function executeE2ETest(
options: PuppeteerBuilderOptions,
context: BuilderContext
): Promise<BuilderOutput> {
context.logger.debug('Running commands for E2E test.');
try {
for (const command of options.commands) {
await executeCommand(context, command);
}

return {success: true};
} catch (error) {
if (error instanceof Error) {
return {success: false, error: error.message};
}
return {success: false, error: error as any};
}
}

export default createBuilder<PuppeteerBuilderOptions>(executeE2ETest) as any;
18 changes: 18 additions & 0 deletions packages/ng-schematics/src/builders/puppeteer/schema.json
@@ -0,0 +1,18 @@
{
"title": "Puppeteer",
"description": "Options for Puppeteer Angular Schematics",
"type": "object",
"properties": {
"commands": {
"type": "array",
"items": {
"type": "array",
"item": {
"type": "string"
}
},
"description": "Commands to execute in the repo. Commands prefixed with `./node_modules/bin` (Exception: 'node')."
}
},
"additionalProperties": true
}
23 changes: 23 additions & 0 deletions packages/ng-schematics/src/builders/puppeteer/types.ts
@@ -0,0 +1,23 @@
/**
* Copyright 2022 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import {JsonObject} from '@angular-devkit/core';

type Command = [string, ...string[]];

export interface PuppeteerBuilderOptions extends JsonObject {
commands: Command[];
}
Expand Up @@ -7,7 +7,7 @@
<% } %><% if(testingFramework == 'node') { %>
"module": "CommonJS",
"rootDir": "tests/",
"outDir": "out-tsc/",
"outDir": "test/",
<% } %>
"types": ["<%= testingFramework %>"]
},
Expand Down
@@ -1,3 +1,3 @@
# Compiled e2e tests output
# Compiled e2e tests output Node auto resolves files in folders named 'test'

/out-tsc
test/
20 changes: 15 additions & 5 deletions packages/ng-schematics/src/schematics/ng-add/index.ts
Expand Up @@ -31,6 +31,7 @@ import {
getPackageLatestNpmVersion,
DependencyType,
type NodePackage,
updateAngularJsonScripts,
} from '../utils/packages.js';

import {type SchematicsOptions} from '../utils/types.js';
Expand All @@ -45,6 +46,7 @@ export function ngAdd(options: SchematicsOptions): Rule {
addPuppeteerFiles(options),
addOtherFiles(options),
updateScripts(options),
updateAngularConfig(options),
])(tree, context);
};
}
Expand Down Expand Up @@ -73,23 +75,22 @@ function addDependencies(options: SchematicsOptions): Rule {
};
}

function updateScripts(options: SchematicsOptions): Rule {
function updateScripts(_options: SchematicsOptions): Rule {
return (tree: Tree, context: SchematicContext): Tree => {
context.logger.debug('Updating "package.json" scripts');
const script = getScriptFromOptions(options);

return addPackageJsonScripts(tree, [
{
name: 'e2e',
script,
script: 'ng e2e',
},
]);
};
}

function addPuppeteerFiles(options: SchematicsOptions): Rule {
return (tree: Tree, context: SchematicContext) => {
context.logger.debug('Adding Puppeteer base files');
context.logger.debug('Adding Puppeteer base files.');
const {projects} = getAngularConfig(tree);

return addBaseFiles(tree, context, {
Expand All @@ -101,7 +102,7 @@ function addPuppeteerFiles(options: SchematicsOptions): Rule {

function addOtherFiles(options: SchematicsOptions): Rule {
return (tree: Tree, context: SchematicContext) => {
context.logger.debug('Adding Puppeteer additional files');
context.logger.debug('Adding Puppeteer additional files.');
const {projects} = getAngularConfig(tree);

return addFrameworkFiles(tree, context, {
Expand All @@ -110,3 +111,12 @@ function addOtherFiles(options: SchematicsOptions): Rule {
});
};
}

function updateAngularConfig(options: SchematicsOptions): Rule {
return (tree: Tree, context: SchematicContext): Tree => {
context.logger.debug('Updating "angular.json".');
const script = getScriptFromOptions(options);

return updateAngularJsonScripts(tree, script);
};
}

0 comments on commit 4613f03

Please sign in to comment.