From 8f9eadedcf390a6f94b96c20d4e922c21260ca51 Mon Sep 17 00:00:00 2001 From: Martin Hochel Date: Thu, 1 Jun 2023 15:34:35 +0200 Subject: [PATCH 1/5] fix(tools): remove backtick from just-config template that was causing parsing errors --- .../migrate-converged-pkg/files/just-config.ts__tmpl__ | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/generators/migrate-converged-pkg/files/just-config.ts__tmpl__ b/tools/generators/migrate-converged-pkg/files/just-config.ts__tmpl__ index 4e711a1d5dea35..b7b2c9a33bf435 100644 --- a/tools/generators/migrate-converged-pkg/files/just-config.ts__tmpl__ +++ b/tools/generators/migrate-converged-pkg/files/just-config.ts__tmpl__ @@ -2,4 +2,4 @@ import { preset, task } from '@fluentui/scripts-tasks'; preset(); -task('build', 'build:react-components').cached?.();` +task('build', 'build:react-components').cached?.(); From 0c7003ea3a790982318881d3af5ca43b85f01c15 Mon Sep 17 00:00:00 2001 From: Martin Hochel Date: Thu, 1 Jun 2023 17:29:06 +0200 Subject: [PATCH 2/5] feat(tools): add e2e-setup generation to migrate-converged-pkg --- .../generators/migrate-converged-pkg/index.ts | 45 +------ .../lib/cypress-component-setup.spec.ts | 126 ++++++++++++++++++ .../lib/cypress-component-setup.ts | 62 +++++++++ .../migrate-converged-pkg/lib/utils.ts | 4 + tools/utils.ts | 1 + 5 files changed, 198 insertions(+), 40 deletions(-) create mode 100644 tools/generators/migrate-converged-pkg/lib/cypress-component-setup.spec.ts create mode 100644 tools/generators/migrate-converged-pkg/lib/cypress-component-setup.ts diff --git a/tools/generators/migrate-converged-pkg/index.ts b/tools/generators/migrate-converged-pkg/index.ts index 5086e159c02442..430309ecd7d81c 100644 --- a/tools/generators/migrate-converged-pkg/index.ts +++ b/tools/generators/migrate-converged-pkg/index.ts @@ -20,7 +20,8 @@ import * as path from 'path'; import * as os from 'os'; import * as ts from 'typescript'; -import { getTemplate } from './lib/utils'; +import { getTemplate, uniqueArray } from './lib/utils'; +import { setupCypressComponentTesting } from './lib/cypress-component-setup'; import { PackageJson, TsConfig } from '../../types'; import { arePromptsEnabled, @@ -576,10 +577,6 @@ function hasConformanceSetup(tree: Tree, options: NormalizedSchema) { return tree.exists(options.paths.conformanceSetup); } -function uniqueArray(value: T[]) { - return Array.from(new Set(value)); -} - function updateNxWorkspace(tree: Tree, options: NormalizedSchema) { const packageType = getPackageType(tree, options); const tags = { @@ -922,48 +919,16 @@ function shouldSetupStorybook(tree: Tree, options: NormalizedSchema) { } function setupCypress(tree: Tree, options: NormalizedSchema) { - const template = { - exclude: ['**/*.cy.ts', '**/*.cy.tsx'], - }; + const shouldSetupCypress = tree.exists(options.paths.tsconfig.cypress); - if (!shouldSetupCypress(tree, options)) { + if (!shouldSetupCypress) { return tree; } - writeJson(tree, options.paths.tsconfig.cypress, templates.cypress.tsconfig); - - updateJson(tree, options.paths.tsconfig.main, (json: TsConfig) => { - json.references?.push({ - path: `./${path.basename(options.paths.tsconfig.cypress)}`, - }); - - return json; - }); - - // update lib ts with new exclude globs - updateJson(tree, options.paths.tsconfig.lib, (json: TsConfig) => { - json.exclude = json.exclude || []; - json.exclude.push(...template.exclude); - json.exclude = uniqueArray(json.exclude); - - return json; - }); - - updateJson(tree, options.paths.packageJson, (json: PackageJson) => { - json.scripts = json.scripts ?? {}; - json.scripts.e2e = 'cypress run --component'; - json.scripts['e2e:local'] = 'cypress open --component'; - - return json; - }); - + tree = setupCypressComponentTesting(tree, options); return tree; } -function shouldSetupCypress(tree: Tree, options: NormalizedSchema) { - return tree.exists(options.paths.tsconfig.cypress); -} - function updateLocalJestConfig(tree: Tree, options: NormalizedSchema) { const jestSetupFilePath = options.paths.jestSetupFile; const packageType = getPackageType(tree, options); diff --git a/tools/generators/migrate-converged-pkg/lib/cypress-component-setup.spec.ts b/tools/generators/migrate-converged-pkg/lib/cypress-component-setup.spec.ts new file mode 100644 index 00000000000000..165f5930bc0fbd --- /dev/null +++ b/tools/generators/migrate-converged-pkg/lib/cypress-component-setup.spec.ts @@ -0,0 +1,126 @@ +import { + addProjectConfiguration, + joinPathFragments, + NxJsonConfiguration, + readJson, + readNxJson, + serializeJson, + Tree, +} from '@nrwl/devkit'; +import { createTreeWithEmptyV1Workspace } from '@nrwl/devkit/testing'; +import { getProjectConfig } from '../../../utils'; + +import { setupCypressComponentTesting } from './cypress-component-setup'; + +describe(`cypress-component-setup`, () => { + let tree: Tree; + beforeEach(() => { + tree = createTreeWithEmptyV1Workspace(); + }); + + it(`should setup cypress for project`, () => { + tree = setupDummyPackage(tree, { name: '@proj/one' }); + const options = { ...getProjectConfig(tree, { packageName: '@proj/one' }) }; + + setupCypressComponentTesting(tree, options); + + expect(tree.read('packages/one/cypress.config.ts', 'utf-8')).toMatchInlineSnapshot(` + "import { baseConfig } from '@fluentui/scripts-cypress'; + + export default baseConfig;" + `); + expect(readJson(tree, 'packages/one/tsconfig.json').references).toEqual( + expect.arrayContaining([ + { + path: './tsconfig.cy.json', + }, + ]), + ); + expect(readJson(tree, 'packages/one/tsconfig.lib.json').exclude).toEqual( + expect.arrayContaining(['**/*.cy.ts', '**/*.cy.tsx']), + ); + expect(readJson(tree, 'packages/one/tsconfig.cy.json')).toMatchInlineSnapshot(` + Object { + "compilerOptions": Object { + "isolatedModules": false, + "lib": Array [ + "ES2019", + "dom", + ], + "types": Array [ + "node", + "cypress", + "cypress-storybook/cypress", + "cypress-real-events", + ], + }, + "extends": "./tsconfig.json", + "include": Array [ + "**/*.cy.ts", + "**/*.cy.tsx", + ], + } + `); + + expect(readJson(tree, 'packages/one/package.json').scripts).toEqual( + expect.objectContaining({ + e2e: 'cypress run --component', + 'e2e:local': 'cypress open --component', + }), + ); + }); +}); + +function setupDummyPackage(tree: Tree, options: { name: string }) { + const pkgName = options.name; + + const workspaceConfig = readNxJson(tree) ?? {}; + const normalizedPkgName = getNormalizedPkgName({ pkgName, workspaceConfig }); + const paths = { + root: `packages/${normalizedPkgName}`, + }; + + const templates = { + packageJson: { + name: pkgName, + version: '0.0.1', + typings: 'lib/index.d.ts', + main: 'lib-commonjs/index.js', + scripts: {}, + dependencies: {}, + devDependencies: {}, + }, + tsconfigs: { + root: { + references: [ + { + path: './tsconfig.lib.json', + }, + ], + }, + lib: { + extends: './tsconfig.json', + compilerOptions: {}, + exclude: ['./src/testing/**', '**/*.spec.ts', '**/*.spec.tsx', '**/*.test.ts', '**/*.test.tsx'], + }, + }, + }; + + tree.write(`${paths.root}/package.json`, serializeJson(templates.packageJson)); + tree.write(`${paths.root}/tsconfig.json`, serializeJson(templates.tsconfigs.root)); + tree.write(`${paths.root}/tsconfig.lib.json`, serializeJson(templates.tsconfigs.lib)); + tree.write(`${paths.root}/src/index.ts`, `export const greet = 'hello' `); + + addProjectConfiguration(tree, pkgName, { + root: paths.root, + sourceRoot: joinPathFragments(paths.root, 'src'), + projectType: 'library', + targets: {}, + }); + + return tree; +} + +function getNormalizedPkgName(options: { pkgName: string; workspaceConfig: NxJsonConfiguration }) { + return options.pkgName.replace(`@${options.workspaceConfig.npmScope}/`, ''); +} diff --git a/tools/generators/migrate-converged-pkg/lib/cypress-component-setup.ts b/tools/generators/migrate-converged-pkg/lib/cypress-component-setup.ts new file mode 100644 index 00000000000000..208a27a239d1ec --- /dev/null +++ b/tools/generators/migrate-converged-pkg/lib/cypress-component-setup.ts @@ -0,0 +1,62 @@ +import { stripIndents, Tree, updateJson, writeJson } from '@nrwl/devkit'; +import * as path from 'path'; + +import { PackageJson, TsConfig } from '../../../types'; +import { getProjectConfig } from '../../../utils'; +import { uniqueArray } from './utils'; + +const template = { + exclude: ['**/*.cy.ts', '**/*.cy.tsx'], +}; + +const templates = { + config: stripIndents` + import { baseConfig } from '@fluentui/scripts-cypress'; + + export default baseConfig; + `, + tsconfig: { + extends: './tsconfig.json', + compilerOptions: { + isolatedModules: false, + types: ['node', 'cypress', 'cypress-storybook/cypress', 'cypress-real-events'], + lib: ['ES2019', 'dom'], + }, + include: ['**/*.cy.ts', '**/*.cy.tsx'], + }, +}; + +type Options = ReturnType; + +export function setupCypressComponentTesting(tree: Tree, options: Options) { + tree.write(options.paths.cypressConfig, templates.config); + + writeJson(tree, options.paths.tsconfig.cypress, templates.tsconfig); + + updateJson(tree, options.paths.tsconfig.main, (json: TsConfig) => { + json.references?.push({ + path: `./${path.basename(options.paths.tsconfig.cypress)}`, + }); + + return json; + }); + + // update lib ts with new exclude globs + updateJson(tree, options.paths.tsconfig.lib, (json: TsConfig) => { + json.exclude = json.exclude || []; + json.exclude.push(...['**/*.cy.ts', '**/*.cy.tsx']); + json.exclude = uniqueArray(json.exclude); + + return json; + }); + + updateJson(tree, options.paths.packageJson, (json: PackageJson) => { + json.scripts = json.scripts ?? {}; + json.scripts.e2e = 'cypress run --component'; + json.scripts['e2e:local'] = 'cypress open --component'; + + return json; + }); + + return tree; +} diff --git a/tools/generators/migrate-converged-pkg/lib/utils.ts b/tools/generators/migrate-converged-pkg/lib/utils.ts index f4c4b8039de8d8..d3d6bb27d68101 100644 --- a/tools/generators/migrate-converged-pkg/lib/utils.ts +++ b/tools/generators/migrate-converged-pkg/lib/utils.ts @@ -28,3 +28,7 @@ export function getTemplate(src: string, substitutions: Record) throw err; } } + +export function uniqueArray(value: T[]) { + return Array.from(new Set(value)); +} diff --git a/tools/utils.ts b/tools/utils.ts index 6007a8fba3d222..74be1bb389054d 100644 --- a/tools/utils.ts +++ b/tools/utils.ts @@ -100,6 +100,7 @@ export function getProjectConfig(tree: Tree, options: { packageName: string }) { rootPackageJson: joinPathFragments(projectConfig.root, 'src', 'unstable', 'package.json__tmpl__'), }, conformanceSetup: joinPathFragments(projectConfig.root, 'src', 'testing', 'isConformant.ts'), + cypressConfig: joinPathFragments(projectConfig.root, 'cypress.config.ts'), babelConfig: joinPathFragments(projectConfig.root, '.babelrc.json'), jestConfig: joinPathFragments(projectConfig.root, 'jest.config.js'), jestSetupFile: joinPathFragments(projectConfig.root, 'config', 'tests.js'), From fca721a1cb5fb1214eb0f52285b20942a1170841 Mon Sep 17 00:00:00 2001 From: Martin Hochel Date: Fri, 2 Jun 2023 12:55:37 +0200 Subject: [PATCH 3/5] feat(tools): bootstrap cypress-component-configuration generator --- .../cypress-component-configuration/README.md | 38 ++++++++++++++ .../files/constants.ts__tmpl__ | 1 + .../index.spec.ts | 20 ++++++++ .../cypress-component-configuration/index.ts | 50 +++++++++++++++++++ .../lib/utils.spec.ts | 7 +++ .../lib/utils.ts | 5 ++ .../schema.json | 17 +++++++ .../cypress-component-configuration/schema.ts | 6 +++ 8 files changed, 144 insertions(+) create mode 100644 tools/generators/cypress-component-configuration/README.md create mode 100644 tools/generators/cypress-component-configuration/files/constants.ts__tmpl__ create mode 100644 tools/generators/cypress-component-configuration/index.spec.ts create mode 100644 tools/generators/cypress-component-configuration/index.ts create mode 100644 tools/generators/cypress-component-configuration/lib/utils.spec.ts create mode 100644 tools/generators/cypress-component-configuration/lib/utils.ts create mode 100644 tools/generators/cypress-component-configuration/schema.json create mode 100644 tools/generators/cypress-component-configuration/schema.ts diff --git a/tools/generators/cypress-component-configuration/README.md b/tools/generators/cypress-component-configuration/README.md new file mode 100644 index 00000000000000..4dbc9c0edb6174 --- /dev/null +++ b/tools/generators/cypress-component-configuration/README.md @@ -0,0 +1,38 @@ +# cypress-component-configuration + +Workspace Generator ...TODO... + + + +- [Usage](#usage) + - [Examples](#examples) +- [Options](#options) + - [`name`](#name) + + + +## Usage + +```sh +yarn nx workspace-generator cypress-component-configuration ... +``` + +Show what will be generated without writing to disk: + +```sh +yarn nx workspace-generator cypress-component-configuration --dry-run +``` + +### Examples + +```sh +yarn nx workspace-generator cypress-component-configuration +``` + +## Options + +#### `name` + +Type: `string` + +TODO... diff --git a/tools/generators/cypress-component-configuration/files/constants.ts__tmpl__ b/tools/generators/cypress-component-configuration/files/constants.ts__tmpl__ new file mode 100644 index 00000000000000..d9913111a9dc76 --- /dev/null +++ b/tools/generators/cypress-component-configuration/files/constants.ts__tmpl__ @@ -0,0 +1 @@ +export const variable = "<%= name %>"; \ No newline at end of file diff --git a/tools/generators/cypress-component-configuration/index.spec.ts b/tools/generators/cypress-component-configuration/index.spec.ts new file mode 100644 index 00000000000000..9598d4eb1b9b05 --- /dev/null +++ b/tools/generators/cypress-component-configuration/index.spec.ts @@ -0,0 +1,20 @@ +import { createTreeWithEmptyV1Workspace } from '@nrwl/devkit/testing'; +import { Tree, readProjectConfiguration } from '@nrwl/devkit'; + +import generator from './index'; +import { CypressComponentConfigurationGeneratorSchema } from './schema'; + +describe('cypress-component-configuration generator', () => { + let appTree: Tree; + const options: CypressComponentConfigurationGeneratorSchema = { name: 'test' }; + + beforeEach(() => { + appTree = createTreeWithEmptyV1Workspace(); + }); + + it('should run successfully', async () => { + await generator(appTree, options); + const config = readProjectConfiguration(appTree, 'test'); + expect(config).toBeDefined(); + }); +}); diff --git a/tools/generators/cypress-component-configuration/index.ts b/tools/generators/cypress-component-configuration/index.ts new file mode 100644 index 00000000000000..0dbd1a5163ad01 --- /dev/null +++ b/tools/generators/cypress-component-configuration/index.ts @@ -0,0 +1,50 @@ +import * as path from 'path'; +import { Tree, formatFiles, installPackagesTask, names, generateFiles } from '@nrwl/devkit'; +import { libraryGenerator } from '@nrwl/workspace/generators'; + +import { getProjectConfig } from '../../utils'; + +import { CypressComponentConfigurationGeneratorSchema } from './schema'; + +interface NormalizedSchema extends ReturnType {} + +export default async function (tree: Tree, schema: CypressComponentConfigurationGeneratorSchema) { + await libraryGenerator(tree, { name: schema.name }); + + const normalizedOptions = normalizeOptions(tree, schema); + + addFiles(tree, normalizedOptions); + + await formatFiles(tree); + + return () => { + installPackagesTask(tree); + }; +} + +function normalizeOptions(tree: Tree, options: CypressComponentConfigurationGeneratorSchema) { + const project = getProjectConfig(tree, { packageName: options.name }); + + return { + ...options, + ...project, + ...names(options.name), + }; +} + +/** + * NOTE: remove this if your generator doesn't process any static/dynamic templates + */ +function addFiles(tree: Tree, options: NormalizedSchema) { + const templateOptions = { + ...options, + tmpl: '', + }; + + generateFiles( + tree, + path.join(__dirname, 'files'), + path.join(options.projectConfig.root, options.name), + templateOptions, + ); +} diff --git a/tools/generators/cypress-component-configuration/lib/utils.spec.ts b/tools/generators/cypress-component-configuration/lib/utils.spec.ts new file mode 100644 index 00000000000000..91e05a54a86f53 --- /dev/null +++ b/tools/generators/cypress-component-configuration/lib/utils.spec.ts @@ -0,0 +1,7 @@ +import { dummyHelper } from './utils'; + +describe(`utils`, () => { + it(`should behave...`, () => { + expect(dummyHelper()).toBe(undefined); + }); +}); diff --git a/tools/generators/cypress-component-configuration/lib/utils.ts b/tools/generators/cypress-component-configuration/lib/utils.ts new file mode 100644 index 00000000000000..c340a27c29c8b0 --- /dev/null +++ b/tools/generators/cypress-component-configuration/lib/utils.ts @@ -0,0 +1,5 @@ +// use this module to define any kind of generic utilities that are used in more than 1 place within the generator implementation + +export function dummyHelper() { + return; +} diff --git a/tools/generators/cypress-component-configuration/schema.json b/tools/generators/cypress-component-configuration/schema.json new file mode 100644 index 00000000000000..d18b530d238b1a --- /dev/null +++ b/tools/generators/cypress-component-configuration/schema.json @@ -0,0 +1,17 @@ +{ + "$schema": "http://json-schema.org/schema", + "cli": "nx", + "id": "cypress-component-configuration", + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Library name", + "$default": { + "$source": "argv", + "index": 0 + } + } + }, + "required": ["name"] +} diff --git a/tools/generators/cypress-component-configuration/schema.ts b/tools/generators/cypress-component-configuration/schema.ts new file mode 100644 index 00000000000000..496f977853dbe0 --- /dev/null +++ b/tools/generators/cypress-component-configuration/schema.ts @@ -0,0 +1,6 @@ +export interface CypressComponentConfigurationGeneratorSchema { + /** + * Library name + */ + name: string; +} From d2fa83001b4b67184b3cdc9000c6dd003cd1aecb Mon Sep 17 00:00:00 2001 From: Martin Hochel Date: Fri, 2 Jun 2023 13:10:51 +0200 Subject: [PATCH 4/5] feat(tools): implement cypress-component-configuration generator and use it within migrate-converged-pkg --- .../cypress-component-configuration/README.md | 8 +- .../files/.gitkeep | 0 .../files/constants.ts__tmpl__ | 1 - .../index.spec.ts | 141 ++++++++++++++++-- .../cypress-component-configuration/index.ts | 47 ++---- .../lib/add-files.ts} | 6 +- .../lib/utils.spec.ts | 6 +- .../lib/utils.ts | 6 +- .../schema.json | 11 +- .../cypress-component-configuration/schema.ts | 4 +- .../generators/migrate-converged-pkg/index.ts | 7 +- .../lib/cypress-component-setup.spec.ts | 126 ---------------- 12 files changed, 170 insertions(+), 193 deletions(-) create mode 100644 tools/generators/cypress-component-configuration/files/.gitkeep delete mode 100644 tools/generators/cypress-component-configuration/files/constants.ts__tmpl__ rename tools/generators/{migrate-converged-pkg/lib/cypress-component-setup.ts => cypress-component-configuration/lib/add-files.ts} (91%) delete mode 100644 tools/generators/migrate-converged-pkg/lib/cypress-component-setup.spec.ts diff --git a/tools/generators/cypress-component-configuration/README.md b/tools/generators/cypress-component-configuration/README.md index 4dbc9c0edb6174..ebcbdfdbc4b6eb 100644 --- a/tools/generators/cypress-component-configuration/README.md +++ b/tools/generators/cypress-component-configuration/README.md @@ -1,13 +1,13 @@ # cypress-component-configuration -Workspace Generator ...TODO... +Workspace Generator for setting up Cypress component testing for a project - [Usage](#usage) - [Examples](#examples) - [Options](#options) - - [`name`](#name) + - [`project`](#project) @@ -31,8 +31,8 @@ yarn nx workspace-generator cypress-component-configuration ## Options -#### `name` +#### `project` Type: `string` -TODO... +The name of the project to add cypress component testing to diff --git a/tools/generators/cypress-component-configuration/files/.gitkeep b/tools/generators/cypress-component-configuration/files/.gitkeep new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/tools/generators/cypress-component-configuration/files/constants.ts__tmpl__ b/tools/generators/cypress-component-configuration/files/constants.ts__tmpl__ deleted file mode 100644 index d9913111a9dc76..00000000000000 --- a/tools/generators/cypress-component-configuration/files/constants.ts__tmpl__ +++ /dev/null @@ -1 +0,0 @@ -export const variable = "<%= name %>"; \ No newline at end of file diff --git a/tools/generators/cypress-component-configuration/index.spec.ts b/tools/generators/cypress-component-configuration/index.spec.ts index 9598d4eb1b9b05..e6d8b4e9aa94ec 100644 --- a/tools/generators/cypress-component-configuration/index.spec.ts +++ b/tools/generators/cypress-component-configuration/index.spec.ts @@ -1,20 +1,141 @@ +import { + addProjectConfiguration, + joinPathFragments, + NxJsonConfiguration, + readJson, + readNxJson, + serializeJson, + Tree, +} from '@nrwl/devkit'; import { createTreeWithEmptyV1Workspace } from '@nrwl/devkit/testing'; -import { Tree, readProjectConfiguration } from '@nrwl/devkit'; import generator from './index'; -import { CypressComponentConfigurationGeneratorSchema } from './schema'; -describe('cypress-component-configuration generator', () => { - let appTree: Tree; - const options: CypressComponentConfigurationGeneratorSchema = { name: 'test' }; +describe(`cypress-component-configuration`, () => { + // eslint-disable-next-line @typescript-eslint/no-empty-function + const noop = () => {}; + let tree: Tree; beforeEach(() => { - appTree = createTreeWithEmptyV1Workspace(); + jest.spyOn(console, 'log').mockImplementation(noop); + jest.spyOn(console, 'info').mockImplementation(noop); + jest.spyOn(console, 'warn').mockImplementation(noop); + + tree = createTreeWithEmptyV1Workspace(); + }); + + it(`should not create component testing for application`, async () => { + const project = '@proj/app-one'; + tree = setupDummyPackage(tree, { name: project, projectType: 'application' }); + + await generator(tree, { project }); + + expect(tree.exists('apps/app-one/cypress.config.ts')).toBe(false); }); - it('should run successfully', async () => { - await generator(appTree, options); - const config = readProjectConfiguration(appTree, 'test'); - expect(config).toBeDefined(); + it(`should setup cypress component testing for existing project`, async () => { + const project = '@proj/one'; + tree = setupDummyPackage(tree, { name: project }); + + await generator(tree, { project }); + + expect(tree.read('packages/one/cypress.config.ts', 'utf-8')).toMatchInlineSnapshot(` + "import { baseConfig } from '@fluentui/scripts-cypress'; + + export default baseConfig;" + `); + expect(readJson(tree, 'packages/one/tsconfig.json').references).toEqual( + expect.arrayContaining([ + { + path: './tsconfig.cy.json', + }, + ]), + ); + expect(readJson(tree, 'packages/one/tsconfig.lib.json').exclude).toEqual( + expect.arrayContaining(['**/*.cy.ts', '**/*.cy.tsx']), + ); + expect(readJson(tree, 'packages/one/tsconfig.cy.json')).toMatchInlineSnapshot(` + Object { + "compilerOptions": Object { + "isolatedModules": false, + "lib": Array [ + "ES2019", + "dom", + ], + "types": Array [ + "node", + "cypress", + "cypress-storybook/cypress", + "cypress-real-events", + ], + }, + "extends": "./tsconfig.json", + "include": Array [ + "**/*.cy.ts", + "**/*.cy.tsx", + ], + } + `); + + expect(readJson(tree, 'packages/one/package.json').scripts).toEqual( + expect.objectContaining({ + e2e: 'cypress run --component', + 'e2e:local': 'cypress open --component', + }), + ); }); }); + +function setupDummyPackage(tree: Tree, options: { name: string; projectType?: 'application' | 'library' }) { + const { name: pkgName, projectType = 'library' } = options; + + const workspaceConfig = readNxJson(tree) ?? {}; + const normalizedPkgName = getNormalizedPkgName({ pkgName, workspaceConfig }); + const paths = { + root: `${projectType === 'application' ? 'apps' : 'packages'}/${normalizedPkgName}`, + }; + + const templates = { + packageJson: { + name: pkgName, + version: '0.0.1', + typings: 'lib/index.d.ts', + main: 'lib-commonjs/index.js', + scripts: {}, + dependencies: {}, + devDependencies: {}, + }, + tsconfigs: { + root: { + references: [ + { + path: './tsconfig.lib.json', + }, + ], + }, + lib: { + extends: './tsconfig.json', + compilerOptions: {}, + exclude: ['./src/testing/**', '**/*.spec.ts', '**/*.spec.tsx', '**/*.test.ts', '**/*.test.tsx'], + }, + }, + }; + + tree.write(`${paths.root}/package.json`, serializeJson(templates.packageJson)); + tree.write(`${paths.root}/tsconfig.json`, serializeJson(templates.tsconfigs.root)); + tree.write(`${paths.root}/tsconfig.lib.json`, serializeJson(templates.tsconfigs.lib)); + tree.write(`${paths.root}/src/index.ts`, `export const greet = 'hello' `); + + addProjectConfiguration(tree, pkgName, { + root: paths.root, + sourceRoot: joinPathFragments(paths.root, 'src'), + projectType, + targets: {}, + }); + + return tree; +} + +function getNormalizedPkgName(options: { pkgName: string; workspaceConfig: NxJsonConfiguration }) { + return options.pkgName.replace(`@${options.workspaceConfig.npmScope}/`, ''); +} diff --git a/tools/generators/cypress-component-configuration/index.ts b/tools/generators/cypress-component-configuration/index.ts index 0dbd1a5163ad01..a417f05307c1b0 100644 --- a/tools/generators/cypress-component-configuration/index.ts +++ b/tools/generators/cypress-component-configuration/index.ts @@ -1,50 +1,35 @@ -import * as path from 'path'; -import { Tree, formatFiles, installPackagesTask, names, generateFiles } from '@nrwl/devkit'; -import { libraryGenerator } from '@nrwl/workspace/generators'; +import { Tree, formatFiles, names } from '@nrwl/devkit'; -import { getProjectConfig } from '../../utils'; +import { getProjectConfig, printUserLogs, UserLog } from '../../utils'; -import { CypressComponentConfigurationGeneratorSchema } from './schema'; +import type { CypressComponentConfigurationGeneratorSchema } from './schema'; -interface NormalizedSchema extends ReturnType {} +import { addFiles } from './lib/add-files'; -export default async function (tree: Tree, schema: CypressComponentConfigurationGeneratorSchema) { - await libraryGenerator(tree, { name: schema.name }); +// eslint-disable-next-line @typescript-eslint/naming-convention +interface _NormalizedSchema extends ReturnType {} +export default async function (tree: Tree, schema: CypressComponentConfigurationGeneratorSchema) { + const userLog: UserLog = []; const normalizedOptions = normalizeOptions(tree, schema); + if (normalizedOptions.projectConfig.projectType === 'application') { + userLog.push({ type: 'warn', message: 'we dont support cypress component tests for applications' }); + printUserLogs(userLog); + return; + } + addFiles(tree, normalizedOptions); await formatFiles(tree); - - return () => { - installPackagesTask(tree); - }; } function normalizeOptions(tree: Tree, options: CypressComponentConfigurationGeneratorSchema) { - const project = getProjectConfig(tree, { packageName: options.name }); + const project = getProjectConfig(tree, { packageName: options.project }); return { ...options, ...project, - ...names(options.name), + ...names(options.project), }; } - -/** - * NOTE: remove this if your generator doesn't process any static/dynamic templates - */ -function addFiles(tree: Tree, options: NormalizedSchema) { - const templateOptions = { - ...options, - tmpl: '', - }; - - generateFiles( - tree, - path.join(__dirname, 'files'), - path.join(options.projectConfig.root, options.name), - templateOptions, - ); -} diff --git a/tools/generators/migrate-converged-pkg/lib/cypress-component-setup.ts b/tools/generators/cypress-component-configuration/lib/add-files.ts similarity index 91% rename from tools/generators/migrate-converged-pkg/lib/cypress-component-setup.ts rename to tools/generators/cypress-component-configuration/lib/add-files.ts index 208a27a239d1ec..0ace2ae8ea0735 100644 --- a/tools/generators/migrate-converged-pkg/lib/cypress-component-setup.ts +++ b/tools/generators/cypress-component-configuration/lib/add-files.ts @@ -5,10 +5,6 @@ import { PackageJson, TsConfig } from '../../../types'; import { getProjectConfig } from '../../../utils'; import { uniqueArray } from './utils'; -const template = { - exclude: ['**/*.cy.ts', '**/*.cy.tsx'], -}; - const templates = { config: stripIndents` import { baseConfig } from '@fluentui/scripts-cypress'; @@ -28,7 +24,7 @@ const templates = { type Options = ReturnType; -export function setupCypressComponentTesting(tree: Tree, options: Options) { +export function addFiles(tree: Tree, options: Options) { tree.write(options.paths.cypressConfig, templates.config); writeJson(tree, options.paths.tsconfig.cypress, templates.tsconfig); diff --git a/tools/generators/cypress-component-configuration/lib/utils.spec.ts b/tools/generators/cypress-component-configuration/lib/utils.spec.ts index 91e05a54a86f53..62640aacb1ace7 100644 --- a/tools/generators/cypress-component-configuration/lib/utils.spec.ts +++ b/tools/generators/cypress-component-configuration/lib/utils.spec.ts @@ -1,7 +1,7 @@ -import { dummyHelper } from './utils'; +import { uniqueArray } from './utils'; describe(`utils`, () => { - it(`should behave...`, () => { - expect(dummyHelper()).toBe(undefined); + it(`should create uniquie array`, () => { + expect(uniqueArray(['a', 'b', 'a', 'c', 'd', 'b'])).toEqual(['a', 'b', 'c', 'd']); }); }); diff --git a/tools/generators/cypress-component-configuration/lib/utils.ts b/tools/generators/cypress-component-configuration/lib/utils.ts index c340a27c29c8b0..773199330b2dbf 100644 --- a/tools/generators/cypress-component-configuration/lib/utils.ts +++ b/tools/generators/cypress-component-configuration/lib/utils.ts @@ -1,5 +1,3 @@ -// use this module to define any kind of generic utilities that are used in more than 1 place within the generator implementation - -export function dummyHelper() { - return; +export function uniqueArray(value: T[]) { + return Array.from(new Set(value)); } diff --git a/tools/generators/cypress-component-configuration/schema.json b/tools/generators/cypress-component-configuration/schema.json index d18b530d238b1a..67c30c616a5377 100644 --- a/tools/generators/cypress-component-configuration/schema.json +++ b/tools/generators/cypress-component-configuration/schema.json @@ -3,15 +3,18 @@ "cli": "nx", "id": "cypress-component-configuration", "type": "object", + "title": "Set up Cypress component testing for a project", + "description": "Set up Cypress component test for a project.", "properties": { - "name": { + "project": { "type": "string", - "description": "Library name", + "description": "The name of the project to add cypress component testing to", "$default": { "$source": "argv", "index": 0 - } + }, + "x-prompt": "What project should we add Cypress component testing to?" } }, - "required": ["name"] + "required": ["project"] } diff --git a/tools/generators/cypress-component-configuration/schema.ts b/tools/generators/cypress-component-configuration/schema.ts index 496f977853dbe0..42f6fffc6cc2c8 100644 --- a/tools/generators/cypress-component-configuration/schema.ts +++ b/tools/generators/cypress-component-configuration/schema.ts @@ -1,6 +1,6 @@ export interface CypressComponentConfigurationGeneratorSchema { /** - * Library name + * The name of the project to add cypress component testing to */ - name: string; + project: string; } diff --git a/tools/generators/migrate-converged-pkg/index.ts b/tools/generators/migrate-converged-pkg/index.ts index 430309ecd7d81c..4b158af035e783 100644 --- a/tools/generators/migrate-converged-pkg/index.ts +++ b/tools/generators/migrate-converged-pkg/index.ts @@ -21,7 +21,7 @@ import * as os from 'os'; import * as ts from 'typescript'; import { getTemplate, uniqueArray } from './lib/utils'; -import { setupCypressComponentTesting } from './lib/cypress-component-setup'; +import setupCypressComponentTesting from '../cypress-component-configuration'; import { PackageJson, TsConfig } from '../../types'; import { arePromptsEnabled, @@ -918,14 +918,15 @@ function shouldSetupStorybook(tree: Tree, options: NormalizedSchema) { } } -function setupCypress(tree: Tree, options: NormalizedSchema) { +async function setupCypress(tree: Tree, options: NormalizedSchema) { const shouldSetupCypress = tree.exists(options.paths.tsconfig.cypress); if (!shouldSetupCypress) { return tree; } - tree = setupCypressComponentTesting(tree, options); + await setupCypressComponentTesting(tree, { project: options.name }); + return tree; } diff --git a/tools/generators/migrate-converged-pkg/lib/cypress-component-setup.spec.ts b/tools/generators/migrate-converged-pkg/lib/cypress-component-setup.spec.ts deleted file mode 100644 index 165f5930bc0fbd..00000000000000 --- a/tools/generators/migrate-converged-pkg/lib/cypress-component-setup.spec.ts +++ /dev/null @@ -1,126 +0,0 @@ -import { - addProjectConfiguration, - joinPathFragments, - NxJsonConfiguration, - readJson, - readNxJson, - serializeJson, - Tree, -} from '@nrwl/devkit'; -import { createTreeWithEmptyV1Workspace } from '@nrwl/devkit/testing'; -import { getProjectConfig } from '../../../utils'; - -import { setupCypressComponentTesting } from './cypress-component-setup'; - -describe(`cypress-component-setup`, () => { - let tree: Tree; - beforeEach(() => { - tree = createTreeWithEmptyV1Workspace(); - }); - - it(`should setup cypress for project`, () => { - tree = setupDummyPackage(tree, { name: '@proj/one' }); - const options = { ...getProjectConfig(tree, { packageName: '@proj/one' }) }; - - setupCypressComponentTesting(tree, options); - - expect(tree.read('packages/one/cypress.config.ts', 'utf-8')).toMatchInlineSnapshot(` - "import { baseConfig } from '@fluentui/scripts-cypress'; - - export default baseConfig;" - `); - expect(readJson(tree, 'packages/one/tsconfig.json').references).toEqual( - expect.arrayContaining([ - { - path: './tsconfig.cy.json', - }, - ]), - ); - expect(readJson(tree, 'packages/one/tsconfig.lib.json').exclude).toEqual( - expect.arrayContaining(['**/*.cy.ts', '**/*.cy.tsx']), - ); - expect(readJson(tree, 'packages/one/tsconfig.cy.json')).toMatchInlineSnapshot(` - Object { - "compilerOptions": Object { - "isolatedModules": false, - "lib": Array [ - "ES2019", - "dom", - ], - "types": Array [ - "node", - "cypress", - "cypress-storybook/cypress", - "cypress-real-events", - ], - }, - "extends": "./tsconfig.json", - "include": Array [ - "**/*.cy.ts", - "**/*.cy.tsx", - ], - } - `); - - expect(readJson(tree, 'packages/one/package.json').scripts).toEqual( - expect.objectContaining({ - e2e: 'cypress run --component', - 'e2e:local': 'cypress open --component', - }), - ); - }); -}); - -function setupDummyPackage(tree: Tree, options: { name: string }) { - const pkgName = options.name; - - const workspaceConfig = readNxJson(tree) ?? {}; - const normalizedPkgName = getNormalizedPkgName({ pkgName, workspaceConfig }); - const paths = { - root: `packages/${normalizedPkgName}`, - }; - - const templates = { - packageJson: { - name: pkgName, - version: '0.0.1', - typings: 'lib/index.d.ts', - main: 'lib-commonjs/index.js', - scripts: {}, - dependencies: {}, - devDependencies: {}, - }, - tsconfigs: { - root: { - references: [ - { - path: './tsconfig.lib.json', - }, - ], - }, - lib: { - extends: './tsconfig.json', - compilerOptions: {}, - exclude: ['./src/testing/**', '**/*.spec.ts', '**/*.spec.tsx', '**/*.test.ts', '**/*.test.tsx'], - }, - }, - }; - - tree.write(`${paths.root}/package.json`, serializeJson(templates.packageJson)); - tree.write(`${paths.root}/tsconfig.json`, serializeJson(templates.tsconfigs.root)); - tree.write(`${paths.root}/tsconfig.lib.json`, serializeJson(templates.tsconfigs.lib)); - tree.write(`${paths.root}/src/index.ts`, `export const greet = 'hello' `); - - addProjectConfiguration(tree, pkgName, { - root: paths.root, - sourceRoot: joinPathFragments(paths.root, 'src'), - projectType: 'library', - targets: {}, - }); - - return tree; -} - -function getNormalizedPkgName(options: { pkgName: string; workspaceConfig: NxJsonConfiguration }) { - return options.pkgName.replace(`@${options.workspaceConfig.npmScope}/`, ''); -} From 0515f7c5f63884b205b35dde184f41eb3025e7dd Mon Sep 17 00:00:00 2001 From: Martin Hochel Date: Fri, 16 Jun 2023 14:41:57 +0200 Subject: [PATCH 5/5] refactor(tools): use static templates to generate cypress config files --- .../cypress-component-configuration/files/.gitkeep | 0 .../files/cypress.config.ts__tmpl__ | 3 +++ .../files/tsconfig.cy.json__tmpl__ | 9 +++++++++ .../cypress-component-configuration/index.spec.ts | 3 ++- .../cypress-component-configuration/lib/add-files.ts | 6 ++---- 5 files changed, 16 insertions(+), 5 deletions(-) delete mode 100644 tools/generators/cypress-component-configuration/files/.gitkeep create mode 100644 tools/generators/cypress-component-configuration/files/cypress.config.ts__tmpl__ create mode 100644 tools/generators/cypress-component-configuration/files/tsconfig.cy.json__tmpl__ diff --git a/tools/generators/cypress-component-configuration/files/.gitkeep b/tools/generators/cypress-component-configuration/files/.gitkeep deleted file mode 100644 index e69de29bb2d1d6..00000000000000 diff --git a/tools/generators/cypress-component-configuration/files/cypress.config.ts__tmpl__ b/tools/generators/cypress-component-configuration/files/cypress.config.ts__tmpl__ new file mode 100644 index 00000000000000..ca52cf041bbf2c --- /dev/null +++ b/tools/generators/cypress-component-configuration/files/cypress.config.ts__tmpl__ @@ -0,0 +1,3 @@ +import { baseConfig } from '@fluentui/scripts-cypress'; + +export default baseConfig; diff --git a/tools/generators/cypress-component-configuration/files/tsconfig.cy.json__tmpl__ b/tools/generators/cypress-component-configuration/files/tsconfig.cy.json__tmpl__ new file mode 100644 index 00000000000000..5db18f12b7ef23 --- /dev/null +++ b/tools/generators/cypress-component-configuration/files/tsconfig.cy.json__tmpl__ @@ -0,0 +1,9 @@ +{ + "extends":"./tsconfig.json", + "compilerOptions":{ + "isolatedModules":false, + "types":["node", "cypress", "cypress-storybook/cypress", "cypress-real-events"], + "lib":["ES2019", "dom"] + }, + "include":["**/*.cy.ts", "**/*.cy.tsx"] +} diff --git a/tools/generators/cypress-component-configuration/index.spec.ts b/tools/generators/cypress-component-configuration/index.spec.ts index e6d8b4e9aa94ec..ce7411397e2a9a 100644 --- a/tools/generators/cypress-component-configuration/index.spec.ts +++ b/tools/generators/cypress-component-configuration/index.spec.ts @@ -42,7 +42,8 @@ describe(`cypress-component-configuration`, () => { expect(tree.read('packages/one/cypress.config.ts', 'utf-8')).toMatchInlineSnapshot(` "import { baseConfig } from '@fluentui/scripts-cypress'; - export default baseConfig;" + export default baseConfig; + " `); expect(readJson(tree, 'packages/one/tsconfig.json').references).toEqual( expect.arrayContaining([ diff --git a/tools/generators/cypress-component-configuration/lib/add-files.ts b/tools/generators/cypress-component-configuration/lib/add-files.ts index 0ace2ae8ea0735..8eca64ec75745f 100644 --- a/tools/generators/cypress-component-configuration/lib/add-files.ts +++ b/tools/generators/cypress-component-configuration/lib/add-files.ts @@ -1,4 +1,4 @@ -import { stripIndents, Tree, updateJson, writeJson } from '@nrwl/devkit'; +import { stripIndents, Tree, updateJson, generateFiles, joinPathFragments } from '@nrwl/devkit'; import * as path from 'path'; import { PackageJson, TsConfig } from '../../../types'; @@ -25,9 +25,7 @@ const templates = { type Options = ReturnType; export function addFiles(tree: Tree, options: Options) { - tree.write(options.paths.cypressConfig, templates.config); - - writeJson(tree, options.paths.tsconfig.cypress, templates.tsconfig); + generateFiles(tree, joinPathFragments(__dirname, '../files'), options.projectConfig.root, { tmpl: '' }); updateJson(tree, options.paths.tsconfig.main, (json: TsConfig) => { json.references?.push({