Skip to content

[Feature]: snapshotPathTemplate as optional function #33098

Open
@ShaMan123

Description

@ShaMan123

🚀 Feature Request

I wish to support the following feature in config:

snapshotPathTemplate?: string | ((testInfo: TestInfo) => string)

OR

snapshotPathResolver?: (filename: string, testInfo: TestInfo) => string

snapshotPathResolver should be invoked with the parsed snapshot path (=filename) for further handling, returning the final path to be used.

Currently I am patching playwright to support this.
As you can see it is a very simple change.

diff --git a/node_modules/playwright/.DS_Store b/node_modules/playwright/.DS_Store
new file mode 100644
index 0000000..5008ddf
Binary files /dev/null and b/node_modules/playwright/.DS_Store differ
diff --git a/node_modules/playwright/lib/common/config.js b/node_modules/playwright/lib/common/config.js
index 4b21d26..690c308 100644
--- a/node_modules/playwright/lib/common/config.js
+++ b/node_modules/playwright/lib/common/config.js
@@ -158,6 +158,7 @@ class FullProjectInternal {
     const testDir = takeFirst(pathResolve(configDir, projectConfig.testDir), pathResolve(configDir, config.testDir), fullConfig.configDir);
     const defaultSnapshotPathTemplate = '{snapshotDir}/{testFileDir}/{testFileName}-snapshots/{arg}{-projectName}{-snapshotSuffix}{ext}';
     this.snapshotPathTemplate = takeFirst(projectConfig.snapshotPathTemplate, config.snapshotPathTemplate, defaultSnapshotPathTemplate);
+    this.snapshotPathResolver = takeFirst(projectConfig.snapshotPathResolver, config.snapshotPathResolver, p => p);
     this.project = {
       grep: takeFirst(projectConfig.grep, config.grep, defaultGrep),
       grepInvert: takeFirst(projectConfig.grepInvert, config.grepInvert, null),
diff --git a/node_modules/playwright/lib/worker/testInfo.js b/node_modules/playwright/lib/worker/testInfo.js
index 5ed9668..61bce7f 100644
--- a/node_modules/playwright/lib/worker/testInfo.js
+++ b/node_modules/playwright/lib/worker/testInfo.js
@@ -386,7 +386,8 @@ class TestInfoImpl {
     const parsedRelativeTestFilePath = _path.default.parse(relativeTestFilePath);
     const projectNamePathSegment = (0, _utils.sanitizeForFilePath)(this.project.name);
     const snapshotPath = (this._projectInternal.snapshotPathTemplate || '').replace(/\{(.)?testDir\}/g, '$1' + this.project.testDir).replace(/\{(.)?snapshotDir\}/g, '$1' + this.project.snapshotDir).replace(/\{(.)?snapshotSuffix\}/g, this.snapshotSuffix ? '$1' + this.snapshotSuffix : '').replace(/\{(.)?testFileDir\}/g, '$1' + parsedRelativeTestFilePath.dir).replace(/\{(.)?platform\}/g, '$1' + process.platform).replace(/\{(.)?projectName\}/g, projectNamePathSegment ? '$1' + projectNamePathSegment : '').replace(/\{(.)?testName\}/g, '$1' + this._fsSanitizedTestName()).replace(/\{(.)?testFileName\}/g, '$1' + parsedRelativeTestFilePath.base).replace(/\{(.)?testFilePath\}/g, '$1' + relativeTestFilePath).replace(/\{(.)?arg\}/g, '$1' + _path.default.join(parsedSubPath.dir, parsedSubPath.name)).replace(/\{(.)?ext\}/g, parsedSubPath.ext ? '$1' + parsedSubPath.ext : '');
-    return _path.default.normalize(_path.default.resolve(this._configInternal.configDir, snapshotPath));
+    const resolvedSnapshotPath = this._projectInternal.snapshotPathResolver ? this._projectInternal.snapshotPathResolver(snapshotPath, this) : snapshotPath;
+    return _path.default.normalize(_path.default.resolve(this._configInternal.configDir, resolvedSnapshotPath));
   }
   skip(...args) {
     this._modifier('skip', args);

Example

It should be used for fine grained runtime control over the snapshot path.

  snapshotPathResolver: (file: string, testInfo: TestInfo) => {
    if (CI) {
      return file;
    }

    const { name, ext, dir } = path.parse(file);
    const resolved = path.join(dir, `${name}.${process.platform}${ext}`);
    if (existsSync(path.resolve(resolved))) {
      console.warn(`Using local snapshot ${resolved}`);
      return resolved;
    }
    return file;
  }

Motivation

In a project I work on some snapshots fail on CI (a very little number) due to OS diffs and we do not want to handle 2 sets of snapshot for dev and for CI so I would like to snapshot locally against a different snapshot

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions