From aa52ab1b5011958180552bc6ecd336937cc206bc Mon Sep 17 00:00:00 2001 From: Ferran Diaz Date: Mon, 10 Nov 2025 10:31:25 +0100 Subject: [PATCH 1/5] fix: ingoreDirectoriesMatch correctly populated --- packages/cli/src/constructs/project.ts | 1 + packages/cli/src/services/project-parser.ts | 1 + packages/cli/src/services/util.ts | 7 +++++-- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/constructs/project.ts b/packages/cli/src/constructs/project.ts index 6fd5f56a..d8d796cf 100644 --- a/packages/cli/src/constructs/project.ts +++ b/packages/cli/src/constructs/project.ts @@ -243,6 +243,7 @@ export class Session { static privateLocations: PrivateLocationApi[] static parsers = new Map() static constructExports: ConstructExport[] = [] + static ignoreDirectoriesMatch: string[] = [] static async loadFile (filePath: string): Promise { const loader = this.loader diff --git a/packages/cli/src/services/project-parser.ts b/packages/cli/src/services/project-parser.ts index 7971419d..2d2eec07 100644 --- a/packages/cli/src/services/project-parser.ts +++ b/packages/cli/src/services/project-parser.ts @@ -81,6 +81,7 @@ export async function parseProject (opts: ProjectParseOpts): Promise { Session.availableRuntimes = availableRuntimes Session.defaultRuntimeId = defaultRuntimeId Session.verifyRuntimeDependencies = verifyRuntimeDependencies ?? true + Session.ignoreDirectoriesMatch = ignoreDirectoriesMatch // TODO: Do we really need all of the ** globs, or could we just put node_modules? const ignoreDirectories = ['**/node_modules/**', '**/.git/**', ...ignoreDirectoriesMatch] diff --git a/packages/cli/src/services/util.ts b/packages/cli/src/services/util.ts index 52a4a40d..54e0be31 100644 --- a/packages/cli/src/services/util.ts +++ b/packages/cli/src/services/util.ts @@ -284,7 +284,7 @@ export async function loadPlaywrightProjectFiles ( dir: string, pwConfigParsed: PlaywrightConfig, include: string[], archive: Archiver, lockFile: string, ) { - const ignoredFiles = ['**/node_modules/**', '.git/**'] + const ignoredFiles = ['**/node_modules/**', '.git/**', ...Session.ignoreDirectoriesMatch] const parser = new Parser({}) const { files, errors } = await parser.getFilesAndDependencies(pwConfigParsed) if (errors.length) { @@ -320,7 +320,10 @@ export async function loadPlaywrightProjectFiles ( prefix, }) for (const includePattern of include) { - archive.glob(includePattern, { cwd: dir }, { + archive.glob(includePattern, { + cwd: dir, + ignore: ignoredFiles, + }, { ...entryDefaults, prefix, }) From 756493225728b11aa4ff83829bf42784c73d5300 Mon Sep 17 00:00:00 2001 From: Ferran Diaz Date: Mon, 10 Nov 2025 11:26:41 +0100 Subject: [PATCH 2/5] fix: add tests --- .../fixtures/mock-data.json | 6 ++ .../playwright-bundle-test/package-lock.json | 20 +++++ .../playwright-bundle-test/package.json | 7 ++ .../playwright.config.ts | 6 ++ .../tests/example.spec.ts | 6 ++ .../cli/src/services/__tests__/util.spec.ts | 89 ++++++++++++++++++- 6 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 packages/cli/src/services/__tests__/fixtures/playwright-bundle-test/fixtures/mock-data.json create mode 100644 packages/cli/src/services/__tests__/fixtures/playwright-bundle-test/package-lock.json create mode 100644 packages/cli/src/services/__tests__/fixtures/playwright-bundle-test/package.json create mode 100644 packages/cli/src/services/__tests__/fixtures/playwright-bundle-test/playwright.config.ts create mode 100644 packages/cli/src/services/__tests__/fixtures/playwright-bundle-test/tests/example.spec.ts diff --git a/packages/cli/src/services/__tests__/fixtures/playwright-bundle-test/fixtures/mock-data.json b/packages/cli/src/services/__tests__/fixtures/playwright-bundle-test/fixtures/mock-data.json new file mode 100644 index 00000000..0b2a9ac0 --- /dev/null +++ b/packages/cli/src/services/__tests__/fixtures/playwright-bundle-test/fixtures/mock-data.json @@ -0,0 +1,6 @@ +{ + "mockUser": { + "id": 1, + "name": "Test User" + } +} diff --git a/packages/cli/src/services/__tests__/fixtures/playwright-bundle-test/package-lock.json b/packages/cli/src/services/__tests__/fixtures/playwright-bundle-test/package-lock.json new file mode 100644 index 00000000..2942f5b2 --- /dev/null +++ b/packages/cli/src/services/__tests__/fixtures/playwright-bundle-test/package-lock.json @@ -0,0 +1,20 @@ +{ + "name": "playwright-bundle-test", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "playwright-bundle-test", + "version": "1.0.0", + "dependencies": { + "@playwright/test": "^1.40.0" + } + }, + "node_modules/@playwright/test": { + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.40.0.tgz", + "integrity": "sha512-example" + } + } +} diff --git a/packages/cli/src/services/__tests__/fixtures/playwright-bundle-test/package.json b/packages/cli/src/services/__tests__/fixtures/playwright-bundle-test/package.json new file mode 100644 index 00000000..f48b5133 --- /dev/null +++ b/packages/cli/src/services/__tests__/fixtures/playwright-bundle-test/package.json @@ -0,0 +1,7 @@ +{ + "name": "playwright-bundle-test", + "version": "1.0.0", + "dependencies": { + "@playwright/test": "^1.40.0" + } +} diff --git a/packages/cli/src/services/__tests__/fixtures/playwright-bundle-test/playwright.config.ts b/packages/cli/src/services/__tests__/fixtures/playwright-bundle-test/playwright.config.ts new file mode 100644 index 00000000..eed093e2 --- /dev/null +++ b/packages/cli/src/services/__tests__/fixtures/playwright-bundle-test/playwright.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from '@playwright/test' + +export default defineConfig({ + testDir: './tests', + timeout: 30000, +}) diff --git a/packages/cli/src/services/__tests__/fixtures/playwright-bundle-test/tests/example.spec.ts b/packages/cli/src/services/__tests__/fixtures/playwright-bundle-test/tests/example.spec.ts new file mode 100644 index 00000000..4cbbbc71 --- /dev/null +++ b/packages/cli/src/services/__tests__/fixtures/playwright-bundle-test/tests/example.spec.ts @@ -0,0 +1,6 @@ +import { test, expect } from '@playwright/test' + +test('basic test', async ({ page }) => { + await page.goto('https://playwright.dev/') + expect(await page.title()).toContain('Playwright') +}) diff --git a/packages/cli/src/services/__tests__/util.spec.ts b/packages/cli/src/services/__tests__/util.spec.ts index b39cecb8..1cc38b53 100644 --- a/packages/cli/src/services/__tests__/util.spec.ts +++ b/packages/cli/src/services/__tests__/util.spec.ts @@ -1,11 +1,15 @@ import path from 'node:path' -import { describe, it, expect } from 'vitest' +import fs from 'node:fs/promises' +import { describe, it, expect, beforeEach, afterEach } from 'vitest' +import { extract } from 'tar' import { pathToPosix, isFileSync, getPlaywrightVersionFromPackage, + bundlePlayWrightProject, } from '../util' +import { Session } from '../../constructs/project' describe('util', () => { describe('pathToPosix()', () => { @@ -46,4 +50,87 @@ describe('util', () => { expect(version).toMatch(/^\d+\.\d+\.\d+/) }) }) + + describe('bundlePlayWrightProject()', () => { + let originalBasePath: string | undefined + let extractDir: string + + beforeEach(async () => { + // Save original Session state + originalBasePath = Session.basePath + + // Set up Session for bundling + const fixtureDir = path.join(__dirname, 'fixtures', 'playwright-bundle-test') + Session.basePath = fixtureDir + + // Create temp directory for extraction + extractDir = await fs.mkdtemp(path.join(__dirname, 'temp-extract-')) + }) + + afterEach(async () => { + // Restore Session state + Session.basePath = originalBasePath + Session.ignoreDirectoriesMatch = [] + + // Clean up extraction directory + try { + await fs.rm(extractDir, { recursive: true, force: true }) + } catch (error) { + // Ignore cleanup errors + } + }) + + it('should exclude directories matching ignoreDirectoriesMatch pattern', async () => { + const fixtureDir = path.join(__dirname, 'fixtures', 'playwright-bundle-test') + const playwrightConfigPath = path.join(fixtureDir, 'playwright.config.ts') + + // Set ignoreDirectoriesMatch to exclude fixtures directory + Session.ignoreDirectoriesMatch = ['**/fixtures/**'] + + // Bundle the project + const result = await bundlePlayWrightProject(playwrightConfigPath, []) + + // Extract the bundle + await extract({ + file: result.outputFile, + cwd: extractDir, + }) + + // Check that test files are included + const testsDir = path.join(extractDir, 'tests') + const testFiles = await fs.readdir(testsDir) + expect(testFiles).toContain('example.spec.ts') + + // Check that fixtures directory is NOT included + const fixturesPath = path.join(extractDir, 'fixtures') + await expect(fs.access(fixturesPath)).rejects.toThrow() + }, 30000) + + it('should include all directories when ignoreDirectoriesMatch is empty', async () => { + const fixtureDir = path.join(__dirname, 'fixtures', 'playwright-bundle-test') + const playwrightConfigPath = path.join(fixtureDir, 'playwright.config.ts') + + // Set empty ignoreDirectoriesMatch + Session.ignoreDirectoriesMatch = [] + + // Bundle the project with include pattern that matches fixtures + const result = await bundlePlayWrightProject(playwrightConfigPath, ['fixtures/**/*']) + + // Extract the bundle + await extract({ + file: result.outputFile, + cwd: extractDir, + }) + + // Check that fixtures directory IS included when explicitly in include + const fixturesPath = path.join(extractDir, 'fixtures') + const fixturesExists = await fs.access(fixturesPath).then(() => true).catch(() => false) + expect(fixturesExists).toBe(true) + + if (fixturesExists) { + const fixtureFiles = await fs.readdir(fixturesPath) + expect(fixtureFiles).toContain('mock-data.json') + } + }, 30000) + }) }) From 55fdda6e852ae78250873d06ec74914a902972fc Mon Sep 17 00:00:00 2001 From: Ferran Diaz Date: Tue, 11 Nov 2025 11:16:28 +0100 Subject: [PATCH 3/5] fix: skip ignore if explicitly included --- .../cli/src/services/__tests__/util.spec.ts | 98 ++++++++++++++++++- packages/cli/src/services/util.ts | 7 +- 2 files changed, 103 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/services/__tests__/util.spec.ts b/packages/cli/src/services/__tests__/util.spec.ts index 1cc38b53..9707495d 100644 --- a/packages/cli/src/services/__tests__/util.spec.ts +++ b/packages/cli/src/services/__tests__/util.spec.ts @@ -75,7 +75,7 @@ describe('util', () => { // Clean up extraction directory try { await fs.rm(extractDir, { recursive: true, force: true }) - } catch (error) { + } catch { // Ignore cleanup errors } }) @@ -132,5 +132,101 @@ describe('util', () => { expect(fixtureFiles).toContain('mock-data.json') } }, 30000) + + it('should include explicit node_modules patterns bypassing default ignores', async () => { + const fixtureDir = path.join(__dirname, 'fixtures', 'playwright-bundle-test') + const playwrightConfigPath = path.join(fixtureDir, 'playwright.config.ts') + + // Set empty ignoreDirectoriesMatch + Session.ignoreDirectoriesMatch = [] + + // Bundle the project with explicit node_modules pattern + const result = await bundlePlayWrightProject(playwrightConfigPath, ['node_modules/@internal/test-helpers/**']) + + // Extract the bundle + await extract({ + file: result.outputFile, + cwd: extractDir, + }) + + // Check that node_modules directory IS included when explicitly specified + const nodeModulesPath = path.join(extractDir, 'node_modules', '@internal', 'test-helpers') + const nodeModulesExists = await fs.access(nodeModulesPath).then(() => true).catch(() => false) + expect(nodeModulesExists).toBe(true) + + if (nodeModulesExists) { + const helperFiles = await fs.readdir(nodeModulesPath) + expect(helperFiles).toContain('helper.js') + } + }, 30000) + + it('should include explicit .git patterns bypassing default ignores', async () => { + const fixtureDir = path.join(__dirname, 'fixtures', 'playwright-bundle-test') + const playwrightConfigPath = path.join(fixtureDir, 'playwright.config.ts') + + // Set empty ignoreDirectoriesMatch + Session.ignoreDirectoriesMatch = [] + + // Bundle the project with explicit .git pattern + const result = await bundlePlayWrightProject(playwrightConfigPath, ['.git/**']) + + // Extract the bundle + await extract({ + file: result.outputFile, + cwd: extractDir, + }) + + // Check that .git directory IS included when explicitly specified + const gitPath = path.join(extractDir, '.git') + const gitExists = await fs.access(gitPath).then(() => true).catch(() => false) + expect(gitExists).toBe(true) + + if (gitExists) { + const gitFiles = await fs.readdir(gitPath) + expect(gitFiles).toContain('config') + } + }, 30000) + + it('should still respect custom ignoreDirectoriesMatch for explicit patterns', async () => { + const fixtureDir = path.join(__dirname, 'fixtures', 'playwright-bundle-test') + const playwrightConfigPath = path.join(fixtureDir, 'playwright.config.ts') + + // Set custom ignoreDirectoriesMatch to exclude @internal + Session.ignoreDirectoriesMatch = ['**/@internal/**'] + + // Bundle the project with explicit node_modules pattern + const result = await bundlePlayWrightProject(playwrightConfigPath, ['node_modules/@internal/test-helpers/**']) + + // Extract the bundle + await extract({ + file: result.outputFile, + cwd: extractDir, + }) + + // Check that @internal is NOT included (custom ignore still applies) + const nodeModulesPath = path.join(extractDir, 'node_modules', '@internal') + await expect(fs.access(nodeModulesPath)).rejects.toThrow() + }, 30000) + + it('should exclude node_modules with broad patterns despite include', async () => { + const fixtureDir = path.join(__dirname, 'fixtures', 'playwright-bundle-test') + const playwrightConfigPath = path.join(fixtureDir, 'playwright.config.ts') + + // Set empty ignoreDirectoriesMatch + Session.ignoreDirectoriesMatch = [] + + // Bundle with a broad pattern that would match node_modules but doesn't explicitly target it + const result = await bundlePlayWrightProject(playwrightConfigPath, ['**/*.js']) + + // Extract the bundle + await extract({ + file: result.outputFile, + cwd: extractDir, + }) + + // Check that node_modules is NOT included (default ignore still applies for broad patterns) + const nodeModulesPath = path.join(extractDir, 'node_modules') + await expect(fs.access(nodeModulesPath)).rejects.toThrow() + }, 30000) }) }) diff --git a/packages/cli/src/services/util.ts b/packages/cli/src/services/util.ts index 54e0be31..67a6bb8d 100644 --- a/packages/cli/src/services/util.ts +++ b/packages/cli/src/services/util.ts @@ -320,9 +320,14 @@ export async function loadPlaywrightProjectFiles ( prefix, }) for (const includePattern of include) { + // If pattern explicitly targets an ignored directory, only apply custom ignores + const explicitlyTargetsIgnored = + includePattern.startsWith('node_modules/') + || includePattern.startsWith('.git/') + archive.glob(includePattern, { cwd: dir, - ignore: ignoredFiles, + ignore: explicitlyTargetsIgnored ? Session.ignoreDirectoriesMatch : ignoredFiles, }, { ...entryDefaults, prefix, From 5706f89442ec45f7a8e43ddbdf2c5ced28c868dc Mon Sep 17 00:00:00 2001 From: Ferran Diaz Date: Tue, 11 Nov 2025 11:43:12 +0100 Subject: [PATCH 4/5] fix: add files for testing --- .../__tests__/fixtures/playwright-bundle-test/.gitignore | 3 +++ .../node_modules/@internal/test-helpers/helper.js | 4 ++++ 2 files changed, 7 insertions(+) create mode 100644 packages/cli/src/services/__tests__/fixtures/playwright-bundle-test/.gitignore create mode 100644 packages/cli/src/services/__tests__/fixtures/playwright-bundle-test/node_modules/@internal/test-helpers/helper.js diff --git a/packages/cli/src/services/__tests__/fixtures/playwright-bundle-test/.gitignore b/packages/cli/src/services/__tests__/fixtures/playwright-bundle-test/.gitignore new file mode 100644 index 00000000..44f688ba --- /dev/null +++ b/packages/cli/src/services/__tests__/fixtures/playwright-bundle-test/.gitignore @@ -0,0 +1,3 @@ +# Allow node_modules and .git in test fixtures +!node_modules +!.git diff --git a/packages/cli/src/services/__tests__/fixtures/playwright-bundle-test/node_modules/@internal/test-helpers/helper.js b/packages/cli/src/services/__tests__/fixtures/playwright-bundle-test/node_modules/@internal/test-helpers/helper.js new file mode 100644 index 00000000..7fce0164 --- /dev/null +++ b/packages/cli/src/services/__tests__/fixtures/playwright-bundle-test/node_modules/@internal/test-helpers/helper.js @@ -0,0 +1,4 @@ +// Internal test helper +module.exports = { + helperFunction: () => 'helper' +} From 6ce43da59f6bf0f467099797bc0add85adb0eea9 Mon Sep 17 00:00:00 2001 From: Ferran Diaz Date: Tue, 11 Nov 2025 12:00:32 +0100 Subject: [PATCH 5/5] fix: ignoring .git for testing --- .../playwright-bundle-test/.gitignore | 3 +-- .../cli/src/services/__tests__/util.spec.ts | 27 ------------------- 2 files changed, 1 insertion(+), 29 deletions(-) diff --git a/packages/cli/src/services/__tests__/fixtures/playwright-bundle-test/.gitignore b/packages/cli/src/services/__tests__/fixtures/playwright-bundle-test/.gitignore index 44f688ba..79631759 100644 --- a/packages/cli/src/services/__tests__/fixtures/playwright-bundle-test/.gitignore +++ b/packages/cli/src/services/__tests__/fixtures/playwright-bundle-test/.gitignore @@ -1,3 +1,2 @@ -# Allow node_modules and .git in test fixtures +# Allow node_modules in test fixtures !node_modules -!.git diff --git a/packages/cli/src/services/__tests__/util.spec.ts b/packages/cli/src/services/__tests__/util.spec.ts index 9707495d..53daa566 100644 --- a/packages/cli/src/services/__tests__/util.spec.ts +++ b/packages/cli/src/services/__tests__/util.spec.ts @@ -160,33 +160,6 @@ describe('util', () => { } }, 30000) - it('should include explicit .git patterns bypassing default ignores', async () => { - const fixtureDir = path.join(__dirname, 'fixtures', 'playwright-bundle-test') - const playwrightConfigPath = path.join(fixtureDir, 'playwright.config.ts') - - // Set empty ignoreDirectoriesMatch - Session.ignoreDirectoriesMatch = [] - - // Bundle the project with explicit .git pattern - const result = await bundlePlayWrightProject(playwrightConfigPath, ['.git/**']) - - // Extract the bundle - await extract({ - file: result.outputFile, - cwd: extractDir, - }) - - // Check that .git directory IS included when explicitly specified - const gitPath = path.join(extractDir, '.git') - const gitExists = await fs.access(gitPath).then(() => true).catch(() => false) - expect(gitExists).toBe(true) - - if (gitExists) { - const gitFiles = await fs.readdir(gitPath) - expect(gitFiles).toContain('config') - } - }, 30000) - it('should still respect custom ignoreDirectoriesMatch for explicit patterns', async () => { const fixtureDir = path.join(__dirname, 'fixtures', 'playwright-bundle-test') const playwrightConfigPath = path.join(fixtureDir, 'playwright.config.ts')