@pixeyedev/playwright 0.4.3 → 0.4.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/dist/browser.iife.js +4 -4
- package/dist/reporter.d.ts +12 -1
- package/dist/reporter.js +18 -5
- package/package.json +1 -1
package/dist/browser.iife.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
"use strict";var __pixeye=(()=>{var c=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var
|
|
1
|
+
"use strict";var __pixeye=(()=>{var c=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var h=Object.prototype.hasOwnProperty;var g=(e,t)=>{for(var o in t)c(e,o,{get:t[o],enumerable:!0})},b=(e,t,o,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of f(t))!h.call(e,i)&&i!==o&&c(e,i,{get:()=>t[i],enumerable:!(n=p(t,i))||n.enumerable});return e};var S=e=>b(c({},"__esModule",{value:!0}),e);var T={};g(T,{scanRegions:()=>l,stabilize:()=>m,waitForReady:()=>y});var x=[{selector:"[data-pixeye-mask]",type:"mask"},{selector:"[data-pixeye-ignore]",type:"ignore"},{selector:"[data-pixeye-dynamic]",type:"dynamic"},{selector:'[data-visual-test="blackout"]',type:"mask"},{selector:'[data-visual-test="removed"]',type:"ignore"},{selector:'[data-visual-test="transparent"]',type:"mask"},{selector:"[data-percy-ignore]",type:"ignore"},{selector:"[data-percy-mask]",type:"mask"},{selector:'[data-chromatic="ignore"]',type:"ignore"}],l=()=>{let e=[],t=new Set;for(let{selector:o,type:n}of x){let i=document.querySelectorAll(o);for(let a of i){if(t.has(a))continue;t.add(a);let r=a.getBoundingClientRect();r.width===0||r.height===0||e.push({type:n,selector:o,bounds:{x:Math.max(0,Math.round(r.x)),y:Math.max(0,Math.round(r.y)),width:Math.round(r.width),height:Math.round(r.height)}})}}return e};var d="__pixeye_stabilize",s=e=>{let t=document.getElementById(d);t||(t=document.createElement("style"),t.id=d,document.head.appendChild(t)),t.textContent+=e+`
|
|
2
2
|
`},w=()=>{s(`
|
|
3
3
|
* {
|
|
4
4
|
-webkit-font-smoothing: antialiased !important;
|
|
5
5
|
-moz-osx-font-smoothing: grayscale !important;
|
|
6
6
|
}
|
|
7
|
-
`)},E=()=>{s(`
|
|
7
|
+
`)},E=()=>{if(s(`
|
|
8
8
|
*, *::before, *::after {
|
|
9
9
|
animation-duration: 0s !important;
|
|
10
10
|
animation-delay: 0s !important;
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
transition-delay: 0s !important;
|
|
13
13
|
scroll-behavior: auto !important;
|
|
14
14
|
}
|
|
15
|
-
`)},
|
|
15
|
+
`),typeof document.getAnimations=="function")for(let e of document.getAnimations())try{e.finish()}catch{e.cancel()}for(let e of document.querySelectorAll("svg")){let t=e;if(typeof t.pauseAnimations=="function")try{t.pauseAnimations(),t.setCurrentTime(0)}catch{}}},A=()=>{s(`
|
|
16
16
|
* { caret-color: transparent !important; }
|
|
17
17
|
::-webkit-scrollbar { display: none !important; }
|
|
18
18
|
* { scrollbar-width: none !important; }
|
|
19
|
-
`),document.querySelectorAll("[contenteditable], textarea, input").forEach(e=>{e.setAttribute("spellcheck","false")})},v=()=>{document.querySelectorAll("img").forEach(e=>{let t=e.getBoundingClientRect(),o=Math.round(t.width),n=Math.round(t.height);(o!==t.width||n!==t.height)&&(e.style.width=`${o}px`,e.style.height=`${n}px`)})},
|
|
19
|
+
`),document.querySelectorAll("[contenteditable], textarea, input").forEach(e=>{e.setAttribute("spellcheck","false")})},v=()=>{document.querySelectorAll("img").forEach(e=>{let t=e.getBoundingClientRect(),o=Math.round(t.width),n=Math.round(t.height);(o!==t.width||n!==t.height)&&(e.style.width=`${o}px`,e.style.height=`${n}px`)})},R=()=>{document.querySelectorAll("*").forEach(e=>{let t=getComputedStyle(e);(t.position==="sticky"||t.position==="fixed")&&(e.style.position="absolute")})},m=(e={})=>{e.colorScheme&&(document.documentElement.style.colorScheme=e.colorScheme),e.fontAntialiasing!==!1&&w(),e.disableAnimations!==!1&&E(),e.hideNonDeterministic!==!1&&A(),e.roundImageSizes!==!1&&v(),e.stabilizeStickyFixed!==!1&&R(),e.css&&s(e.css)};var u=async(e,t,o)=>{let n=Date.now();for(;!e();){if(Date.now()-n>o)throw new Error(`[pixeye] waitForReady timed out waiting for: ${t}`);await new Promise(i=>setTimeout(i,100))}},y=async(e={})=>{let t=e.timeout??1e4,o=async()=>{await document.fonts.ready;let i=Array.from(document.querySelectorAll("img"));await Promise.all(i.filter(a=>!a.complete).map(a=>new Promise(r=>{a.addEventListener("load",()=>r(),{once:!0}),a.addEventListener("error",()=>r(),{once:!0})}))),await u(()=>!document.querySelector('[aria-busy="true"]'),'aria-busy="true" elements to clear',t),await u(()=>!document.querySelector("[data-pixeye-loading]"),"data-pixeye-loading elements to disappear",t)},n=new Promise((i,a)=>{setTimeout(()=>a(new Error(`[pixeye] waitForReady timed out after ${t}ms`)),t)});await Promise.race([o(),n])};return S(T);})();
|
|
20
20
|
if(typeof window!=="undefined")window.__pixeye=__pixeye;
|
package/dist/reporter.d.ts
CHANGED
|
@@ -3,6 +3,14 @@ interface ReporterOptions {
|
|
|
3
3
|
token?: string;
|
|
4
4
|
server?: string;
|
|
5
5
|
uploadConcurrency?: number;
|
|
6
|
+
/**
|
|
7
|
+
* Fail the test run (non-zero exit) when the upload is rejected for a
|
|
8
|
+
* CUSTOMER misconfiguration (bad token, lapsed plan/quota, permissions) so a
|
|
9
|
+
* run can't pass green with zero screenshots uploaded. Default `true`. Our
|
|
10
|
+
* transient faults (5xx/network) never fail the run regardless. Opt out with
|
|
11
|
+
* `failOnError: false` or `PIXEYE_FAIL_ON_ERROR=false`.
|
|
12
|
+
*/
|
|
13
|
+
failOnError?: boolean;
|
|
6
14
|
}
|
|
7
15
|
declare const detectShard: (config: FullConfig) => {
|
|
8
16
|
index: number;
|
|
@@ -12,10 +20,13 @@ declare class PixeyeReporter implements Reporter {
|
|
|
12
20
|
private options;
|
|
13
21
|
private shard;
|
|
14
22
|
private skipUpload;
|
|
23
|
+
private failOnError;
|
|
15
24
|
constructor(options?: ReporterOptions);
|
|
16
25
|
onBegin(config: FullConfig, _suite: Suite): void;
|
|
17
26
|
onTestEnd(_test: TestCase, _result: TestResult): void;
|
|
18
|
-
onEnd(_result: FullResult): Promise<
|
|
27
|
+
onEnd(_result: FullResult): Promise<{
|
|
28
|
+
status: FullResult['status'];
|
|
29
|
+
} | undefined>;
|
|
19
30
|
}
|
|
20
31
|
export default PixeyeReporter;
|
|
21
32
|
export { detectShard };
|
package/dist/reporter.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
|
-
import { detectCIEnvironment, discoverScreenshots, PixeyeClient,
|
|
3
|
+
import { detectCIEnvironment, discoverScreenshots, isUploadMisconfig, PixeyeClient, renderUploadFailureBanner, resolveFailOnError, runParallel, uploadErrorSummary } from '@pixeyedev/core';
|
|
4
4
|
import { getContext } from './screenshot.js';
|
|
5
5
|
const DEFAULT_UPLOAD_CONCURRENCY = 32;
|
|
6
6
|
const detectShard = (config) => {
|
|
@@ -27,8 +27,10 @@ class PixeyeReporter {
|
|
|
27
27
|
options;
|
|
28
28
|
shard = { index: 0, total: 1 };
|
|
29
29
|
skipUpload = false;
|
|
30
|
+
failOnError;
|
|
30
31
|
constructor(options = {}) {
|
|
31
32
|
this.options = options;
|
|
33
|
+
this.failOnError = resolveFailOnError(options.failOnError, process.env.PIXEYE_FAIL_ON_ERROR);
|
|
32
34
|
}
|
|
33
35
|
onBegin(config, _suite) {
|
|
34
36
|
const token = this.options.token ?? process.env.PIXEYE_TOKEN;
|
|
@@ -150,12 +152,23 @@ class PixeyeReporter {
|
|
|
150
152
|
console.log(`[pixeye] ${files.length} screenshots (${uploaded} new, ${presign.existing.length} cached) — ${server}/builds/${buildId}`);
|
|
151
153
|
}
|
|
152
154
|
catch (err) {
|
|
153
|
-
//
|
|
154
|
-
|
|
155
|
-
|
|
155
|
+
// P0-2: a CUSTOMER misconfiguration (bad token, lapsed plan/quota,
|
|
156
|
+
// permissions) must NOT pass silently — surface a loud banner and fail
|
|
157
|
+
// the run by default so a green CI can't hide zero uploaded screenshots.
|
|
158
|
+
// Our transient faults (5xx/network/R2) only warn — never break their CI.
|
|
159
|
+
if (isUploadMisconfig(err)) {
|
|
160
|
+
console.error(renderUploadFailureBanner(err, { willFail: this.failOnError }));
|
|
161
|
+
if (this.failOnError) {
|
|
162
|
+
// Playwright IGNORES `process.exitCode` — its runner calls
|
|
163
|
+
// `process.exit(status === 'passed' ? 0 : 1)`, overriding it. The ONLY
|
|
164
|
+
// reporter-side lever is returning a status from onEnd, which the
|
|
165
|
+
// multiplexer applies (`result.status = outResult.status`). Return
|
|
166
|
+
// 'failed' so a passing run with a rejected upload still exits non-zero.
|
|
167
|
+
return { status: 'failed' };
|
|
168
|
+
}
|
|
156
169
|
}
|
|
157
170
|
else {
|
|
158
|
-
console.warn(`[pixeye] Upload failed: ${err
|
|
171
|
+
console.warn(`[pixeye] Upload failed (transient — CI not failed): ${uploadErrorSummary(err)}`);
|
|
159
172
|
}
|
|
160
173
|
}
|
|
161
174
|
}
|