Skip to content

[Bug]: --test-list cannot round-trip --list output when test declaration file differs from root loaded file #42298

Description

@michkot

Version

1.62.1

Steps to reproduce

Self-contained minimal reproduction; no external repository is needed.

Run this in an empty directory:

mkdir pw-test-list-mre
cd pw-test-list-mre
mkdir tests

cat > package.json <<'JSON'
{"private":true,"devDependencies":{"@playwright/test":"1.62.1"},"scripts":{"repro":"playwright test --list tests/root-loaded.spec.ts && printf '[chromium] > tests/declared-tests.ts:4:7 > declared in imported file\n' > test-list.txt && playwright test --test-list test-list.txt --list"}}
JSON

cat > playwright.config.ts <<'TS'
import { defineConfig } from '@playwright/test';
export default defineConfig({ projects: [{ name: 'chromium', testDir: './tests' }] });
TS

cat > tests/declared-tests.ts <<'TS'
import { test, expect } from '@playwright/test';

export function defineTests() {
  test('declared in imported file', async () => {
    expect(1).toBe(1);
  });
}
TS

cat > tests/root-loaded.spec.ts <<'TS'
import { defineTests } from './declared-tests';

defineTests();
TS

npm install
npx playwright test --list tests/root-loaded.spec.ts
printf '[chromium] > tests/declared-tests.ts:4:7 > declared in imported file\n' > test-list.txt
npx playwright test --test-list test-list.txt --list

Observed locally on Windows with Playwright 1.62.1:

Listing tests:
  [chromium] > tests\declared-tests.ts:4:7 > declared in imported file
Total: 1 test in 1 file
Listing tests:
Total: 0 tests in 0 files

Expected behavior

A test-list entry derived from --list output should select the same test.

One possible fix is to extend the --list / --test-list text format so one logical test-list entry, on one line, carries both paths when they differ:

  • root loaded file: tests/root-loaded.spec.ts, which Playwright must load to register the test;
  • declaration/location file: tests/declared-tests.ts, which owns the TestCase.location line/column and title identity.

This should not require two test-list lines. --test-list needs the root loaded file for loading/file filtering and the declaration file/title/line for matching the concrete TestCase. When both paths are the same, the format can remain unchanged.

If Playwright intentionally does not support this, the docs should explicitly say that --list output is not always usable as --test-list input when the declaration file differs from the root loaded file.

Actual behavior

No tests are selected. The declaration file alone does not register the test unless it is imported/called by the root loaded file.

This makes --list and --test-list non-round-trippable for this pattern. loadTestList() parses one file field per line and uses it both to filter loaded files and to match test.location.file. Here those are different files: the root loaded file causes registration, while the declaration file is stored in test.location.file and printed by --list.

Playwright already has both paths internally and in the reporter-visible suite model:

  • test.location.file: declaration/location file, used by --list and current --test-list test matching.
  • test._requireFile: internal root loaded file copied from the file suite's suite._requireFile during TestTypeImpl._createTest().
  • Reporter-visible root loaded file: TestCase.titlePath()[2] relative to the root test dir, or the parent file-suite's Suite.location.file in its suite path form.

Our custom reporter therefore computes the root loaded file from TestCase.titlePath()[2] and the declaration file from TestCase.location.file. The incompatibility is that plain --test-list has only one file field but currently needs two meanings.

Additional context

There is also ambiguity if public identity uses only declaration/location file plus title. The same test(...) callback can be registered through multiple root loaded files, producing distinct Playwright tests that look identical unless root loaded file is part of the identity.

We added a defensive guard in our custom test-listing reporter for this case: same declaration file and effective title, different root loaded files. Such tests cannot be selected independently by the current plain --test-list identity.

HTML report data preserves the distinction, but not as one explicit per-test _requireFile field: per-test source location comes from test.location, while grouping testFile.fileName comes from fileSuite.location.file. So serialized/displayed identity should consistently distinguish root loaded file for loading/grouping from declaration/location file for source location.

If Playwright does not want to support this pattern, it may be worth documenting that declaring tests from a file imported by multiple root loaded files is discouraged because it can create ambiguous public identities.

A related change, #39901, intentionally avoids loading files not matching --test-list. That optimization is reasonable, but exposes this incompatibility because --list prints the declaration file, not necessarily the root executable test file that must be loaded.

Environment

System:
    OS: Windows 11 10.0.26200
    CPU: (16) x64 11th Gen Intel(R) Core(TM) i7-11850H @ 2.50GHz
    Memory: 12.65 GB / 63.73 GB
  Binaries:
    Node: 24.11.1 - C:\Program Files\nodejs\node.EXE
    Yarn: 4.12.0 - C:\Program Files\nodejs\yarn.CMD
    npm: 10.9.4 - C:\Program Files\nodejs\npm.CMD
    pnpm: 10.33.2 - C:\Program Files\nodejs\pnpm.CMD
  IDEs:
    VSCode: 1.109.4 - C:\Users\mkotoun\AppData\Local\Programs\Microsoft VS Code\bin\code.CMD
    Claude Code: 2.1.68 - C:\Users\mkotoun\.local\bin\claude.EXE
  Languages:
    Bash: 5.2.37 - C:\msys64\usr\bin\bash.EXE
  npmPackages:
    @playwright/test: 1.62.1 => 1.62.1

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions