/** * @license * Copyright 2023 Google Inc. * SPDX-License-Identifier: Apache-2.0 */ import { chain, type Rule, type SchematicContext, SchematicsException, type Tree, } from '@angular-devkit/schematics'; import {addCommonFiles} from '../utils/files.js'; import {getApplicationProjects} from '../utils/json.js'; import { TestRunner, type SchematicsSpec, type AngularProject, type PuppeteerSchematicsConfig, } 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 e2e(userArgs: Record): Rule { const options = parseUserTestArgs(userArgs); return (tree: Tree, context: SchematicContext) => { return chain([addE2EFile(options)])(tree, context); }; } function parseUserTestArgs(userArgs: Record): SchematicsSpec { const options: Partial = { ...userArgs, }; if ('p' in userArgs) { options['project'] = userArgs['p']; } if ('n' in userArgs) { options['name'] = userArgs['n']; } if ('r' in userArgs) { options['route'] = userArgs['r']; } if (options['route'] && options['route'].startsWith('/')) { options['route'] = options['route'].substring(1); } return options as SchematicsSpec; } function findTestingOption< Property extends keyof PuppeteerSchematicsConfig['options'], >( [name, project]: [string, AngularProject | undefined], property: Property, ): PuppeteerSchematicsConfig['options'][Property] { if (!project) { throw new Error(`Project "${name}" not found.`); } const e2e = project.architect?.e2e; const puppeteer = project.architect?.puppeteer; const builder = '@puppeteer/ng-schematics:puppeteer'; if (e2e?.builder === builder) { return e2e.options[property]; } else if (puppeteer?.builder === builder) { return puppeteer.options[property]; } throw new Error(`Can't find property "${property}" for project "${name}".`); } function addE2EFile(options: SchematicsSpec): Rule { return async (tree: Tree, context: SchematicContext) => { context.logger.debug('Adding Spec file.'); const projects = getApplicationProjects(tree); const projectNames = Object.keys(projects) as [string, ...string[]]; const foundProject: [string, AngularProject | undefined] | undefined = projectNames.length === 1 ? [projectNames[0], projects[projectNames[0]]] : Object.entries(projects).find(([name, project]) => { return options.project ? options.project === name : project.root === ''; }); if (!foundProject) { throw new SchematicsException( `Project not found! Please run "ng generate @puppeteer/ng-schematics:test "`, ); } const testRunner = findTestingOption(foundProject, 'testRunner'); const port = findTestingOption(foundProject, 'port'); context.logger.debug('Creating Spec file.'); return addCommonFiles( {[foundProject[0]]: foundProject[1]} as Record, { options: { name: options.name, route: options.route, testRunner, // Node test runner does not support glob patterns // It looks for files `*.test.js` ext: testRunner === TestRunner.Node ? 'test' : 'e2e', port, }, }, ); }; }