@testivai/witness-playwright 1.2.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Helpers for the ignoreSelectors feature.
3
+ *
4
+ * Three sources, merged with deduplication (last-write-wins dedup via Set):
5
+ * 1. .testivai/config.json — global OSS config (`ignoreSelectors` array)
6
+ * 2. testivai.config.ts/js — power-user project config (`ignoreSelectors`)
7
+ * 3. testivai.witness() call — per-snapshot override (`ignoreSelectors`)
8
+ *
9
+ * These functions are pure (no Playwright dependency) so they can be
10
+ * exercised in plain Jest unit tests without a browser.
11
+ */
12
+ import { TestivAIConfig, TestivAIProjectConfig } from '../types';
13
+ /**
14
+ * Read ignoreSelectors from `.testivai/config.json`.
15
+ * Returns `[]` when the file doesn't exist or is malformed.
16
+ *
17
+ * @param projectRoot Directory that contains the `.testivai/` folder
18
+ */
19
+ export declare function readWitnessConfigSelectors(projectRoot: string): string[];
20
+ /**
21
+ * Collect and deduplicate ignoreSelectors from all three sources.
22
+ *
23
+ * Order of precedence for deduplication: earlier sources win (Set preserves
24
+ * insertion order, so the first occurrence of any selector survives).
25
+ *
26
+ * @param projectRoot Path to the project root (where `.testivai/` lives)
27
+ * @param projectConfig Loaded `testivai.config.ts` project config
28
+ * @param effectiveConfig Merged per-snapshot TestivAIConfig
29
+ */
30
+ export declare function collectIgnoreSelectors(projectRoot: string, projectConfig: TestivAIProjectConfig, effectiveConfig: TestivAIConfig): string[];
31
+ /**
32
+ * Build a `<style>` tag content that hides every given selector via
33
+ * `visibility: hidden !important`.
34
+ *
35
+ * Returns an empty string when the selectors list is empty so callers can
36
+ * guard with `if (css)` before calling `page.addStyleTag`.
37
+ */
38
+ export declare function buildIgnoreSelectorsCSS(selectors: string[]): string;
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ /**
3
+ * Helpers for the ignoreSelectors feature.
4
+ *
5
+ * Three sources, merged with deduplication (last-write-wins dedup via Set):
6
+ * 1. .testivai/config.json — global OSS config (`ignoreSelectors` array)
7
+ * 2. testivai.config.ts/js — power-user project config (`ignoreSelectors`)
8
+ * 3. testivai.witness() call — per-snapshot override (`ignoreSelectors`)
9
+ *
10
+ * These functions are pure (no Playwright dependency) so they can be
11
+ * exercised in plain Jest unit tests without a browser.
12
+ */
13
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ var desc = Object.getOwnPropertyDescriptor(m, k);
16
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
17
+ desc = { enumerable: true, get: function() { return m[k]; } };
18
+ }
19
+ Object.defineProperty(o, k2, desc);
20
+ }) : (function(o, m, k, k2) {
21
+ if (k2 === undefined) k2 = k;
22
+ o[k2] = m[k];
23
+ }));
24
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
25
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
26
+ }) : function(o, v) {
27
+ o["default"] = v;
28
+ });
29
+ var __importStar = (this && this.__importStar) || (function () {
30
+ var ownKeys = function(o) {
31
+ ownKeys = Object.getOwnPropertyNames || function (o) {
32
+ var ar = [];
33
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
34
+ return ar;
35
+ };
36
+ return ownKeys(o);
37
+ };
38
+ return function (mod) {
39
+ if (mod && mod.__esModule) return mod;
40
+ var result = {};
41
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
42
+ __setModuleDefault(result, mod);
43
+ return result;
44
+ };
45
+ })();
46
+ Object.defineProperty(exports, "__esModule", { value: true });
47
+ exports.readWitnessConfigSelectors = readWitnessConfigSelectors;
48
+ exports.collectIgnoreSelectors = collectIgnoreSelectors;
49
+ exports.buildIgnoreSelectorsCSS = buildIgnoreSelectorsCSS;
50
+ const fs = __importStar(require("fs"));
51
+ const path = __importStar(require("path"));
52
+ /**
53
+ * Read ignoreSelectors from `.testivai/config.json`.
54
+ * Returns `[]` when the file doesn't exist or is malformed.
55
+ *
56
+ * @param projectRoot Directory that contains the `.testivai/` folder
57
+ */
58
+ function readWitnessConfigSelectors(projectRoot) {
59
+ try {
60
+ const configPath = path.join(projectRoot, '.testivai', 'config.json');
61
+ if (!fs.existsSync(configPath))
62
+ return [];
63
+ const raw = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
64
+ return Array.isArray(raw.ignoreSelectors) ? raw.ignoreSelectors : [];
65
+ }
66
+ catch {
67
+ return [];
68
+ }
69
+ }
70
+ /**
71
+ * Collect and deduplicate ignoreSelectors from all three sources.
72
+ *
73
+ * Order of precedence for deduplication: earlier sources win (Set preserves
74
+ * insertion order, so the first occurrence of any selector survives).
75
+ *
76
+ * @param projectRoot Path to the project root (where `.testivai/` lives)
77
+ * @param projectConfig Loaded `testivai.config.ts` project config
78
+ * @param effectiveConfig Merged per-snapshot TestivAIConfig
79
+ */
80
+ function collectIgnoreSelectors(projectRoot, projectConfig, effectiveConfig) {
81
+ const fromWitnessConfig = readWitnessConfigSelectors(projectRoot);
82
+ const fromProjectConfig = projectConfig.ignoreSelectors ?? [];
83
+ const fromSnapshot = effectiveConfig.ignoreSelectors ?? [];
84
+ return [...new Set([...fromWitnessConfig, ...fromProjectConfig, ...fromSnapshot])];
85
+ }
86
+ /**
87
+ * Build a `<style>` tag content that hides every given selector via
88
+ * `visibility: hidden !important`.
89
+ *
90
+ * Returns an empty string when the selectors list is empty so callers can
91
+ * guard with `if (css)` before calling `page.addStyleTag`.
92
+ */
93
+ function buildIgnoreSelectorsCSS(selectors) {
94
+ if (selectors.length === 0)
95
+ return '';
96
+ return selectors.map(s => `${s} { visibility: hidden !important; }`).join('\n');
97
+ }
package/dist/snapshot.js CHANGED
@@ -42,6 +42,7 @@ const path = __importStar(require("path"));
42
42
  const url_1 = require("url");
43
43
  const sharp_1 = __importDefault(require("sharp"));
44
44
  const loader_1 = require("./config/loader");
45
+ const ignore_selectors_1 = require("./config/ignore-selectors");
45
46
  /**
46
47
  * Generates a safe filename from a URL.
47
48
  * @param pageUrl The URL of the page.
@@ -96,27 +97,15 @@ async function snapshot(page, testInfo, name, config) {
96
97
  const screenshotPath = path.join(outputDir, `${baseFilename}.png`);
97
98
  // In local mode: hide elements matching ignoreSelectors before the screenshot
98
99
  // so dynamic content (version badges, timestamps, ads) doesn't cause false diffs.
99
- // Sources (merged, deduped):
100
+ // Sources (merged, deduped) — see config/ignore-selectors.ts:
100
101
  // 1. .testivai/config.json → ignoreSelectors (global, OSS config)
101
102
  // 2. testivai.config.ts → ignoreSelectors (global, power users)
102
103
  // 3. testivai.witness(...) → { ignoreSelectors } (per-snapshot override)
103
104
  let ignoreStyleEl = null;
104
105
  if (isLocalMode) {
105
- // Read global ignores from .testivai/config.json
106
- let witnessConfigIgnore = [];
107
- try {
108
- const witnessConfigPath = path.join(process.cwd(), '.testivai', 'config.json');
109
- if (fs.existsSync(witnessConfigPath)) {
110
- const raw = JSON.parse(fs.readFileSync(witnessConfigPath, 'utf-8'));
111
- witnessConfigIgnore = raw.ignoreSelectors ?? [];
112
- }
113
- }
114
- catch { /* ignore malformed config */ }
115
- const playwrightConfigIgnore = projectConfig.ignoreSelectors ?? [];
116
- const perSnapshotIgnore = effectiveConfig.ignoreSelectors ?? [];
117
- const allSelectors = [...new Set([...witnessConfigIgnore, ...playwrightConfigIgnore, ...perSnapshotIgnore])];
118
- if (allSelectors.length > 0) {
119
- const css = allSelectors.map(s => `${s} { visibility: hidden !important; }`).join('\n');
106
+ const allSelectors = (0, ignore_selectors_1.collectIgnoreSelectors)(process.cwd(), projectConfig, effectiveConfig);
107
+ const css = (0, ignore_selectors_1.buildIgnoreSelectorsCSS)(allSelectors);
108
+ if (css) {
120
109
  ignoreStyleEl = await page.addStyleTag({ content: css });
121
110
  }
122
111
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testivai/witness-playwright",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "description": "Playwright sensor for Testivai Visual Regression Test system",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",