Skip to content

Commit

Permalink
chore: tests for multi projects angular (puppeteer#10675)
Browse files Browse the repository at this point in the history
  • Loading branch information
Lightning00Blade authored Aug 3, 2023
1 parent 2f68706 commit 7ecfe15
Show file tree
Hide file tree
Showing 17 changed files with 504 additions and 209 deletions.
6 changes: 6 additions & 0 deletions docs/ng-schematics.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,12 @@ To run the creating of single test schematic:
npm run sandbox:test
```

To create a multi project workspace use the following command

```bash
npm run sandbox -- --init --multi
```

### Unit Testing

The schematics utilize `@angular-devkit/schematics/testing` for verifying correct file creation and `package.json` updates. To execute the test suit:
Expand Down
6 changes: 6 additions & 0 deletions packages/ng-schematics/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,12 @@ To run the creating of single test schematic:
npm run sandbox:test
```

To create a multi project workspace use the following command

```bash
npm run sandbox -- --init --multi
```

### Unit Testing

The schematics utilize `@angular-devkit/schematics/testing` for verifying correct file creation and `package.json` updates. To execute the test suit:
Expand Down
66 changes: 57 additions & 9 deletions packages/ng-schematics/src/schematics/ng-add/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ import {of} from 'rxjs';
import {concatMap, map, scan} from 'rxjs/operators';

import {
addBaseFiles,
addCommonFiles as addCommonFilesHelper,
addFilesSingle,
addFrameworkFiles,
getNgCommandName,
} from '../utils/files.js';
Expand All @@ -34,22 +35,55 @@ import {
type NodePackage,
updateAngularJsonScripts,
} from '../utils/packages.js';
import {TestingFramework, type SchematicsOptions} from '../utils/types.js';
import {
TestingFramework,
type SchematicsOptions,
AngularProject,
} from '../utils/types.js';

// You don't have to export the function as default. You can also have more than one rule
// factory per file.
export function ngAdd(options: SchematicsOptions): Rule {
export function ngAdd(userArgs: Record<string, string>): Rule {
const options = parseUserAddArgs(userArgs);

return (tree: Tree, context: SchematicContext) => {
return chain([
addDependencies(options),
addPuppeteerFiles(options),
addPuppeteerConfig(options),
addCommonFiles(options),
addOtherFiles(options),
updateScripts(options),
updateAngularConfig(options),
])(tree, context);
};
}

function parseUserAddArgs(userArgs: Record<string, string>): SchematicsOptions {
const options: Partial<SchematicsOptions> = {
...userArgs,
};
if ('p' in userArgs) {
options['port'] = Number(userArgs['p']);
}
if ('t' in userArgs) {
options['testingFramework'] = userArgs['t'] as TestingFramework;
}
if ('c' in userArgs) {
options['exportConfig'] =
typeof userArgs['c'] === 'string'
? userArgs['c'] === 'true'
: userArgs['c'];
}
if ('d' in userArgs) {
options['isDefaultTester'] =
typeof userArgs['d'] === 'string'
? userArgs['d'] === 'true'
: userArgs['d'];
}

return options as SchematicsOptions;
}

function addDependencies(options: SchematicsOptions): Rule {
return (tree: Tree, context: SchematicContext) => {
context.logger.debug('Adding dependencies to "package.json"');
Expand Down Expand Up @@ -94,13 +128,28 @@ function updateScripts(options: SchematicsOptions): Rule {
};
}

function addPuppeteerFiles(options: SchematicsOptions): Rule {
function addPuppeteerConfig(options: SchematicsOptions): Rule {
return (tree: Tree, context: SchematicContext) => {
context.logger.debug('Adding Puppeteer config file.');

if (options.exportConfig) {
return addFilesSingle(tree, context, '', {root: ''} as AngularProject, {
options: options,
applyPath: './files/base',
relativeToWorkspacePath: `/`,
});
}

return tree;
};
}

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

return addBaseFiles(tree, context, {
projects,
return addCommonFilesHelper(tree, context, projects, {
options: {
...options,
ext:
Expand All @@ -115,8 +164,7 @@ function addOtherFiles(options: SchematicsOptions): Rule {
context.logger.debug('Adding Puppeteer additional files.');
const {projects} = getAngularConfig(tree);

return addFrameworkFiles(tree, context, {
projects,
return addFrameworkFiles(tree, context, projects, {
options,
});
};
Expand Down
48 changes: 34 additions & 14 deletions packages/ng-schematics/src/schematics/test/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
Tree,
} from '@angular-devkit/schematics';

import {addBaseFiles} from '../utils/files.js';
import {addCommonFiles} from '../utils/files.js';
import {getAngularConfig} from '../utils/json.js';
import {
TestingFramework,
Expand All @@ -33,12 +33,28 @@ import {

// You don't have to export the function as default. You can also have more than one rule
// factory per file.
export function test(options: SchematicsSpec): Rule {
export function test(userArgs: Record<string, string>): Rule {
const options = parseUserTestArgs(userArgs);

return (tree: Tree, context: SchematicContext) => {
return chain([addSpecFile(options)])(tree, context);
};
}

function parseUserTestArgs(userArgs: Record<string, string>): SchematicsSpec {
const options: Partial<SchematicsSpec> = {
...userArgs,
};
if ('p' in userArgs) {
options['project'] = userArgs['p'];
}
if ('n' in userArgs) {
options['name'] = userArgs['n'];
}

return options as SchematicsSpec;
}

function findTestingOption<Property extends keyof SchematicsOptions>(
[name, project]: [string, AngularProject | undefined],
property: Property
Expand Down Expand Up @@ -76,7 +92,7 @@ function addSpecFile(options: SchematicsSpec): Rule {
});
if (!foundProject) {
throw new SchematicsException(
`Project not found! Please use -p to specify in which project to run.`
`Project not found! Please run "ng generate @puppeteer/ng-schematics:test <Test> <Project>"`
);
}

Expand All @@ -88,16 +104,20 @@ function addSpecFile(options: SchematicsSpec): Rule {

context.logger.debug('Creating Spec file.');

return addBaseFiles(tree, context, {
projects: {[foundProject[0]]: foundProject[1]},
options: {
name: options.name,
testingFramework,
// Node test runner does not support glob patterns
// It looks for files `*.test.js`
ext: testingFramework === TestingFramework.Node ? 'test' : 'e2e',
port,
},
});
return addCommonFiles(
tree,
context,
{[foundProject[0]]: foundProject[1]} as Record<string, AngularProject>,
{
options: {
name: options.name,
testingFramework,
// Node test runner does not support glob patterns
// It looks for files `*.test.js`
ext: testingFramework === TestingFramework.Node ? 'test' : 'e2e',
port,
},
}
);
};
}
4 changes: 4 additions & 0 deletions packages/ng-schematics/src/schematics/test/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
},
"project": {
"type": "string",
"$default": {
"$source": "argv",
"index": 1
},
"alias": "p"
}
},
Expand Down
104 changes: 49 additions & 55 deletions packages/ng-schematics/src/schematics/utils/files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import {
apply,
applyTemplates,
chain,
filter,
mergeWith,
move,
url,
Expand All @@ -32,7 +31,6 @@ import {
import {AngularProject, SchematicsOptions, TestingFramework} from './types.js';

export interface FilesOptions {
projects: Record<string, any>;
options: {
testingFramework: TestingFramework;
port: number;
Expand All @@ -43,61 +41,61 @@ export interface FilesOptions {
applyPath: string;
relativeToWorkspacePath: string;
movePath?: string;
filterPredicate?: (path: string) => boolean;
}

const PUPPETEER_CONFIG_TEMPLATE = '.puppeteerrc.cjs.template';

export function addFiles(
export function addFilesToProjects(
tree: Tree,
context: SchematicContext,
{
projects,
options,
applyPath,
movePath,
relativeToWorkspacePath,
filterPredicate,
}: FilesOptions
projects: Record<string, AngularProject>,
options: FilesOptions
): any {
return chain(
Object.keys(projects).map(name => {
const project = projects[name] as AngularProject;
const projectPath = resolve(getSystemPath(normalize(project.root)));
const workspacePath = resolve(getSystemPath(normalize('')));

const relativeToWorkspace = relative(
`${projectPath}${relativeToWorkspacePath}`,
workspacePath
);

const baseUrl = getProjectBaseUrl(project, options.port);
const tsConfigPath = getTsConfigPath(project);

return mergeWith(
apply(url(applyPath), [
filter(
filterPredicate ??
(() => {
return true;
})
),
move(movePath ? `${project.root}${movePath}` : project.root),
applyTemplates({
...options,
...strings,
root: project.root ? `${project.root}/` : project.root,
baseUrl,
tsConfigPath,
project: name,
relativeToWorkspace,
}),
])
return addFilesSingle(
tree,
context,
name,
projects[name] as AngularProject,
options
);
})
)(tree, context);
}

export function addFilesSingle(
_tree: Tree,
_context: SchematicContext,
name: string,
project: AngularProject,
{options, applyPath, movePath, relativeToWorkspacePath}: FilesOptions
): any {
const projectPath = resolve(getSystemPath(normalize(project.root)));
const workspacePath = resolve(getSystemPath(normalize('')));

const relativeToWorkspace = relative(
`${projectPath}${relativeToWorkspacePath}`,
workspacePath
);

const baseUrl = getProjectBaseUrl(project, options.port);
const tsConfigPath = getTsConfigPath(project);

return mergeWith(
apply(url(applyPath), [
move(movePath ? `${project.root}${movePath}` : project.root),
applyTemplates({
...options,
...strings,
root: project.root ? `${project.root}/` : project.root,
baseUrl,
tsConfigPath,
project: name,
relativeToWorkspace,
}),
])
);
}

function getProjectBaseUrl(project: any, port: number): string {
let options = {protocol: 'http', port, host: 'localhost'};

Expand All @@ -118,29 +116,25 @@ function getTsConfigPath(project: AngularProject): string {
return `../tsconfig.app.json`;
}

export function addBaseFiles(
export function addCommonFiles(
tree: Tree,
context: SchematicContext,
projects: Record<string, AngularProject>,
filesOptions: Omit<FilesOptions, 'applyPath' | 'relativeToWorkspacePath'>
): any {
const options: FilesOptions = {
...filesOptions,
applyPath: './files/base',
applyPath: './files/common',
relativeToWorkspacePath: `/`,
filterPredicate: path => {
return path.includes(PUPPETEER_CONFIG_TEMPLATE) &&
!filesOptions.options.exportConfig
? false
: true;
},
};

return addFiles(tree, context, options);
return addFilesToProjects(tree, context, projects, options);
}

export function addFrameworkFiles(
tree: Tree,
context: SchematicContext,
projects: Record<string, AngularProject>,
filesOptions: Omit<FilesOptions, 'applyPath' | 'relativeToWorkspacePath'>
): any {
const testingFramework = filesOptions.options.testingFramework;
Expand All @@ -150,7 +144,7 @@ export function addFrameworkFiles(
relativeToWorkspacePath: `/`,
};

return addFiles(tree, context, options);
return addFilesToProjects(tree, context, projects, options);
}

export function getScriptFromOptions(
Expand Down
Loading

0 comments on commit 7ecfe15

Please sign in to comment.