From 05ab1cc49102d6f611067a127a1d25abbad23b35 Mon Sep 17 00:00:00 2001 From: AgentEnder Date: Wed, 6 Dec 2023 18:11:26 -0500 Subject: [PATCH] cleanup(testing): clear require cache when loading playwright config --- .../generators/configuration/configuration.ts | 3 +- .../playwright/src/plugins/plugin.spec.ts | 31 +++++++++- packages/playwright/src/plugins/plugin.ts | 58 +++++++------------ .../playwright/src/utils/load-config-file.ts | 12 ++++ 4 files changed, 64 insertions(+), 40 deletions(-) diff --git a/packages/playwright/src/generators/configuration/configuration.ts b/packages/playwright/src/generators/configuration/configuration.ts index 4e0449edd05582..0c27905856fdad 100644 --- a/packages/playwright/src/generators/configuration/configuration.ts +++ b/packages/playwright/src/generators/configuration/configuration.ts @@ -46,10 +46,9 @@ export async function configurationGenerator( if (!hasPlugin) { addE2eTarget(tree, options); + setupE2ETargetDefaults(tree); } - setupE2ETargetDefaults(tree); - tasks.push( await addLinterToPlaywrightProject(tree, { project: options.project, diff --git a/packages/playwright/src/plugins/plugin.spec.ts b/packages/playwright/src/plugins/plugin.spec.ts index 48a1bbedff288f..7353f5f86abe2e 100644 --- a/packages/playwright/src/plugins/plugin.spec.ts +++ b/packages/playwright/src/plugins/plugin.spec.ts @@ -51,7 +51,6 @@ describe('@nx/playwright/plugin', () => { expect(projects).toMatchInlineSnapshot(` { ".": { - "projectType": "library", "root": ".", "targets": { "e2e": { @@ -68,6 +67,18 @@ describe('@nx/playwright/plugin', () => { "{projectRoot}/test-results", ], }, + "e2e-ci": { + "cache": true, + "dependsOn": [], + "executor": "nx:noop", + "inputs": [ + "default", + "^production", + ], + "outputs": [ + "{projectRoot}/test-results", + ], + }, }, }, } @@ -93,7 +104,6 @@ describe('@nx/playwright/plugin', () => { expect(projects).toMatchInlineSnapshot(` { ".": { - "projectType": "library", "root": ".", "targets": { "e2e": { @@ -113,6 +123,21 @@ describe('@nx/playwright/plugin', () => { "{projectRoot}/test-results", ], }, + "e2e-ci": { + "cache": true, + "dependsOn": [], + "executor": "nx:noop", + "inputs": [ + "default", + "^production", + ], + "outputs": [ + "{projectRoot}/playwright-report", + "{projectRoot}/test-results/report.json", + "{projectRoot}/test-results/html", + "{projectRoot}/test-results", + ], + }, }, }, } @@ -132,6 +157,7 @@ describe('@nx/playwright/plugin', () => { 'tests/run-me-2.spec.ts': '', 'tests/skip-me.spec.ts': '', 'tests/ignored/run-me.spec.ts': '', + 'not-tests/run-me.spec.ts': '', }); const { projects } = await createNodesFunction( @@ -202,6 +228,7 @@ describe('@nx/playwright/plugin', () => { `); expect(targets['e2e-ci--tests/skip-me.spec.ts']).not.toBeDefined(); expect(targets['e2e-ci--tests/ignored/run-me.spec.ts']).not.toBeDefined(); + expect(targets['e2e-ci--not-tests/run-me.spec.ts']).not.toBeDefined(); }); }); diff --git a/packages/playwright/src/plugins/plugin.ts b/packages/playwright/src/plugins/plugin.ts index 58ff3882011a60..d886dad83e9335 100644 --- a/packages/playwright/src/plugins/plugin.ts +++ b/packages/playwright/src/plugins/plugin.ts @@ -1,5 +1,4 @@ import { readdirSync } from 'fs'; -import { readTargetDefaultsForTarget } from 'nx/src/project-graph/utils/project-configuration-utils'; import { basename, dirname, join, relative } from 'path'; import { @@ -40,13 +39,11 @@ export const createNodes: CreateNodes = [ } const normalizedOptions = normalizeOptions(options); - const projectName = basename(projectRoot); return { projects: { - [projectName]: { + [projectRoot]: { root: projectRoot, - projectType: 'library', targets: await buildPlaywrightTargets( configFilePath, projectRoot, @@ -69,12 +66,6 @@ async function buildPlaywrightTargets( join(context.workspaceRoot, configFilePath) ); - const targetDefaults = readTargetDefaultsForTarget( - options.targetName, - context.nxJsonConfiguration.targetDefaults, - 'nx:run-commands' - ); - const namedInputs = getNamedInputs(projectRoot, context); const targets: Record> = {}; @@ -88,43 +79,29 @@ async function buildPlaywrightTargets( targets[options.targetName] = { ...baseTargetConfig, - cache: targetDefaults?.cache ?? true, + cache: true, inputs: - targetDefaults?.inputs ?? 'production' in namedInputs + 'production' in namedInputs ? ['default', '^production'] : ['default', '^default'], - outputs: - targetDefaults?.outputs ?? getOutputs(projectRoot, playwrightConfig), - options: { - ...baseTargetConfig.options, - ...targetDefaults?.options, - }, + outputs: getOutputs(projectRoot, playwrightConfig), }; if (options.ciTargetName) { - const ciTargetDefaults = readTargetDefaultsForTarget( - options.ciTargetName, - context.nxJsonConfiguration.targetDefaults, - 'nx:run-commands' - ); - const ciBaseTargetConfig: TargetConfiguration = { ...baseTargetConfig, - cache: ciTargetDefaults?.cache ?? true, + cache: true, inputs: - ciTargetDefaults?.inputs ?? 'production' in namedInputs + 'production' in namedInputs ? ['default', '^production'] : ['default', '^default'], - outputs: - ciTargetDefaults?.outputs ?? getOutputs(projectRoot, playwrightConfig), - options: { - ...baseTargetConfig.options, - ...ciTargetDefaults?.options, - }, + outputs: getOutputs(projectRoot, playwrightConfig), }; - const testDir = - joinPathFragments(projectRoot, playwrightConfig.testDir) ?? projectRoot; + const testDir = playwrightConfig.testDir + ? joinPathFragments(projectRoot, playwrightConfig.testDir) + : projectRoot; + // Playwright defaults to the following pattern. playwrightConfig.testMatch ??= '**/*.@(spec|test).?(c|m)[jt]s?(x)'; @@ -177,7 +154,9 @@ async function forEachTestFile( opts.path ); const matcher = createMatcher(opts.config.testMatch); - const ignoredMatcher = createMatcher(opts.config.testIgnore); + const ignoredMatcher = opts.config.testIgnore + ? createMatcher(opts.config.testIgnore) + : () => false; for (const file of files) { if (matcher(file) && !ignoredMatcher(file)) { cb(file); @@ -192,7 +171,13 @@ function createMatcher(pattern: string | RegExp | Array) { } else if (pattern instanceof RegExp) { return (path: string) => pattern.test(path); } else { - return (path: string) => minimatch(path, pattern); + return (path: string) => { + try { + return minimatch(path, pattern); + } catch (e) { + throw new Error(`Error matching ${path} with ${pattern}: ${e.message}`); + } + }; } } @@ -250,5 +235,6 @@ function normalizeOptions(options: PlaywrightPluginOptions): NormalizedOptions { return { ...options, targetName: options.targetName ?? 'e2e', + ciTargetName: options.ciTargetName ?? 'e2e-ci', }; } diff --git a/packages/playwright/src/utils/load-config-file.ts b/packages/playwright/src/utils/load-config-file.ts index 9f4303eeba14fb..1ab3e9d80dd0ac 100644 --- a/packages/playwright/src/utils/load-config-file.ts +++ b/packages/playwright/src/utils/load-config-file.ts @@ -20,6 +20,12 @@ export async function loadPlaywrightConfig( if (tsConfigPath) { const unregisterTsProject = registerTsProject(tsConfigPath); try { + // Require's cache doesn't notice when the file is updated, and + // this function is ran during daemon operation. If the config file + // is updated, we need to read its new contents, so we need to clear the cache. + // We can't just delete the cache entry for the config file, because + // it might have imports that need to be updated as well. + clearRequireCache(); // ts-node doesn't support dynamic import, so we need to use require module = require(configFilePath); } finally { @@ -34,3 +40,9 @@ export async function loadPlaywrightConfig( return module.default ?? module; } } + +function clearRequireCache() { + Object.keys(require.cache).forEach((key) => { + delete require.cache[key]; + }); +}