@sentinelqa/playwright 0.1.1 → 0.1.5

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.
package/README.md CHANGED
@@ -16,6 +16,12 @@ import { withSentinel } from "@sentinelqa/playwright";
16
16
 
17
17
  export default withSentinel(
18
18
  defineConfig({
19
+ reporter: [
20
+ ["line"],
21
+ ["json", { outputFile: "test-results/report.json" }],
22
+ ["html", { outputFolder: "playwright-report", open: "never" }]
23
+ ],
24
+ outputDir: "test-results",
19
25
  use: {
20
26
  trace: "retain-on-failure",
21
27
  screenshot: "only-on-failure",
@@ -48,9 +54,10 @@ npx playwright test
48
54
 
49
55
  ## What it does
50
56
 
51
- - Ensures a Playwright JSON report is written
52
- - Ensures the Playwright HTML report is written
53
- - Uploads `playwright-report/` and `test-results/` to Sentinel after the run
57
+ - Preserves existing Playwright JSON and HTML report paths if you already configured them
58
+ - Injects JSON and HTML reporters only when they are missing
59
+ - Uses your configured `outputDir` for test results when present
60
+ - Uploads the detected report and test result paths to Sentinel after the run
54
61
  - Preserves the same Sentinel link output as the uploader CLI
55
62
 
56
63
  ## Notes
package/dist/env.d.ts ADDED
@@ -0,0 +1 @@
1
+ export declare const loadSentinelEnv: () => void;
package/dist/env.js ADDED
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.loadSentinelEnv = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const parseLine = (line) => {
10
+ const trimmed = line.trim();
11
+ if (!trimmed || trimmed.startsWith("#"))
12
+ return null;
13
+ const eqIndex = trimmed.indexOf("=");
14
+ if (eqIndex === -1)
15
+ return null;
16
+ const key = trimmed.slice(0, eqIndex).trim();
17
+ if (!key)
18
+ return null;
19
+ let value = trimmed.slice(eqIndex + 1).trim();
20
+ if ((value.startsWith('"') && value.endsWith('"')) ||
21
+ (value.startsWith("'") && value.endsWith("'"))) {
22
+ value = value.slice(1, -1);
23
+ }
24
+ return { key, value };
25
+ };
26
+ const loadSentinelEnv = () => {
27
+ const candidates = [".env", ".env.local"];
28
+ for (const candidate of candidates) {
29
+ const fullPath = path_1.default.resolve(process.cwd(), candidate);
30
+ if (!fs_1.default.existsSync(fullPath))
31
+ continue;
32
+ if (!fs_1.default.statSync(fullPath).isFile())
33
+ continue;
34
+ const raw = fs_1.default.readFileSync(fullPath, "utf8");
35
+ for (const line of raw.split(/\r?\n/)) {
36
+ const parsed = parseLine(line);
37
+ if (!parsed)
38
+ continue;
39
+ if (typeof process.env[parsed.key] === "undefined") {
40
+ process.env[parsed.key] = parsed.value;
41
+ }
42
+ }
43
+ }
44
+ };
45
+ exports.loadSentinelEnv = loadSentinelEnv;
package/dist/index.d.ts CHANGED
@@ -10,12 +10,20 @@ type PlaywrightConfig = {
10
10
  use?: PlaywrightUseOptions;
11
11
  [key: string]: unknown;
12
12
  };
13
+ export type SentinelResolvedPaths = {
14
+ playwrightJsonPath: string;
15
+ playwrightReportDir: string;
16
+ testResultsDir: string;
17
+ artifactDirs: string[];
18
+ };
13
19
  export type SentinelPlaywrightOptions = {
14
20
  project?: string;
15
21
  playwrightJsonPath?: string;
16
22
  playwrightReportDir?: string;
17
23
  testResultsDir?: string;
18
24
  artifactDirs?: string[];
25
+ verbose?: boolean;
19
26
  };
20
27
  export declare function withSentinel(config: PlaywrightConfig, options?: SentinelPlaywrightOptions): PlaywrightConfig;
28
+ export declare function resolveSentinelPaths(config: PlaywrightConfig, options?: SentinelPlaywrightOptions): SentinelResolvedPaths;
21
29
  export {};
package/dist/index.js CHANGED
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.withSentinel = withSentinel;
7
+ exports.resolveSentinelPaths = resolveSentinelPaths;
7
8
  const path_1 = __importDefault(require("path"));
8
9
  const DEFAULT_REPORT_DIR = "playwright-report";
9
10
  const DEFAULT_TEST_RESULTS_DIR = "test-results";
@@ -33,6 +34,14 @@ const normalizeReporter = (reporter) => {
33
34
  const getReporterName = (entry) => {
34
35
  return Array.isArray(entry) ? entry[0] : entry;
35
36
  };
37
+ const getReporterOptions = (entry) => {
38
+ if (!entry || !Array.isArray(entry))
39
+ return {};
40
+ return entry[1] || {};
41
+ };
42
+ const normalizePath = (value) => {
43
+ return value.replace(/\\/g, "/");
44
+ };
36
45
  const setReporterOptions = (reporters, name, options) => {
37
46
  const index = reporters.findIndex((entry) => getReporterName(entry) === name);
38
47
  if (index === -1) {
@@ -56,11 +65,24 @@ function withSentinel(config, options = {}) {
56
65
  video: config.use?.video || "retain-on-failure"
57
66
  }
58
67
  };
68
+ const reporters = normalizeReporter(config.reporter);
69
+ const existingJsonReporter = reporters.find((entry) => getReporterName(entry) === "json");
70
+ const existingHtmlReporter = reporters.find((entry) => getReporterName(entry) === "html");
71
+ const existingJsonOutputFile = getReporterOptions(existingJsonReporter).outputFile;
72
+ const existingHtmlOutputFolder = getReporterOptions(existingHtmlReporter).outputFolder;
59
73
  const testResultsDir = options.testResultsDir || config.outputDir || DEFAULT_TEST_RESULTS_DIR;
60
- const playwrightReportDir = options.playwrightReportDir || DEFAULT_REPORT_DIR;
61
- const playwrightJsonPath = options.playwrightJsonPath || path_1.default.join(playwrightReportDir, "report.json");
74
+ const playwrightReportDir = options.playwrightReportDir ||
75
+ (typeof existingHtmlOutputFolder === "string"
76
+ ? existingHtmlOutputFolder
77
+ : DEFAULT_REPORT_DIR);
78
+ const playwrightJsonPath = options.playwrightJsonPath ||
79
+ (typeof existingJsonOutputFile === "string"
80
+ ? existingJsonOutputFile
81
+ : path_1.default.join(playwrightReportDir, "report.json"));
82
+ const artifactDirs = Array.from(new Set((options.artifactDirs || [])
83
+ .filter(Boolean)
84
+ .map((entry) => normalizePath(entry))));
62
85
  nextConfig.outputDir = testResultsDir;
63
- const reporters = normalizeReporter(config.reporter);
64
86
  setReporterOptions(reporters, "json", { outputFile: playwrightJsonPath });
65
87
  setReporterOptions(reporters, "html", {
66
88
  outputFolder: playwrightReportDir,
@@ -72,7 +94,8 @@ function withSentinel(config, options = {}) {
72
94
  playwrightJsonPath,
73
95
  playwrightReportDir,
74
96
  testResultsDir,
75
- artifactDirs: options.artifactDirs || []
97
+ artifactDirs,
98
+ verbose: options.verbose ?? true
76
99
  };
77
100
  const sentinelIndex = reporters.findIndex((entry) => getReporterName(entry) === sentinelReporterPath);
78
101
  if (sentinelIndex !== -1) {
@@ -82,3 +105,28 @@ function withSentinel(config, options = {}) {
82
105
  nextConfig.reporter = reporters;
83
106
  return nextConfig;
84
107
  }
108
+ function resolveSentinelPaths(config, options = {}) {
109
+ const reporters = normalizeReporter(config.reporter);
110
+ const existingJsonReporter = reporters.find((entry) => getReporterName(entry) === "json");
111
+ const existingHtmlReporter = reporters.find((entry) => getReporterName(entry) === "html");
112
+ const existingJsonOutputFile = getReporterOptions(existingJsonReporter).outputFile;
113
+ const existingHtmlOutputFolder = getReporterOptions(existingHtmlReporter).outputFolder;
114
+ const testResultsDir = options.testResultsDir || config.outputDir || DEFAULT_TEST_RESULTS_DIR;
115
+ const playwrightReportDir = options.playwrightReportDir ||
116
+ (typeof existingHtmlOutputFolder === "string"
117
+ ? existingHtmlOutputFolder
118
+ : DEFAULT_REPORT_DIR);
119
+ const playwrightJsonPath = options.playwrightJsonPath ||
120
+ (typeof existingJsonOutputFile === "string"
121
+ ? existingJsonOutputFile
122
+ : path_1.default.join(playwrightReportDir, "report.json"));
123
+ const artifactDirs = Array.from(new Set((options.artifactDirs || [])
124
+ .filter(Boolean)
125
+ .map((entry) => normalizePath(entry))));
126
+ return {
127
+ playwrightJsonPath: normalizePath(playwrightJsonPath),
128
+ playwrightReportDir: normalizePath(playwrightReportDir),
129
+ testResultsDir: normalizePath(testResultsDir),
130
+ artifactDirs
131
+ };
132
+ }
@@ -4,6 +4,7 @@ type ReporterOptions = {
4
4
  playwrightReportDir: string;
5
5
  testResultsDir: string;
6
6
  artifactDirs?: string[];
7
+ verbose?: boolean;
7
8
  };
8
9
  declare class SentinelReporter {
9
10
  private failedCount;
package/dist/reporter.js CHANGED
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  const node_1 = require("@sentinelqa/uploader/node");
3
+ const env_1 = require("./env");
3
4
  const pluralize = (count, singular, plural) => {
4
5
  return count === 1 ? singular : plural;
5
6
  };
@@ -7,6 +8,7 @@ class SentinelReporter {
7
8
  constructor(options) {
8
9
  this.failedCount = 0;
9
10
  this.totalCount = 0;
11
+ (0, env_1.loadSentinelEnv)();
10
12
  this.options = options;
11
13
  }
12
14
  onBegin(config, suite) {
@@ -14,6 +16,16 @@ class SentinelReporter {
14
16
  if (config?.projects?.length && !this.options.project) {
15
17
  this.options.project = config.projects[0]?.name || null;
16
18
  }
19
+ if (this.options.verbose !== false) {
20
+ console.log("Sentinel detected Playwright artifact paths:");
21
+ console.log(`- JSON report: ${this.options.playwrightJsonPath}`);
22
+ console.log(`- HTML report: ${this.options.playwrightReportDir}`);
23
+ console.log(`- Test results: ${this.options.testResultsDir}`);
24
+ for (const dir of this.options.artifactDirs || []) {
25
+ console.log(`- Extra artifacts: ${dir}`);
26
+ }
27
+ console.log("");
28
+ }
17
29
  }
18
30
  onTestEnd(_test, result) {
19
31
  if (!result)
@@ -26,6 +38,8 @@ class SentinelReporter {
26
38
  console.log("Playwright run finished");
27
39
  console.log(`${this.failedCount} ${pluralize(this.failedCount, "test", "tests")} failed`);
28
40
  if (!process.env.SENTINEL_TOKEN) {
41
+ console.log("");
42
+ console.log("Sentinel upload disabled. Set SENTINEL_TOKEN to enable uploads.");
29
43
  return;
30
44
  }
31
45
  const hasCiEnv = (0, node_1.hasSupportedCiEnv)(process.env);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentinelqa/playwright",
3
- "version": "0.1.1",
3
+ "version": "0.1.5",
4
4
  "private": false,
5
5
  "description": "Playwright config wrapper and reporter for SentinelQA",
6
6
  "license": "MIT",