happo 6.0.4 → 6.0.6
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/cli/{cancelJob-GCTVJGYB.js → cancelJob-NIUI7GBR.js} +4 -3
- package/dist/cli/{cancelJob-GCTVJGYB.js.map → cancelJob-NIUI7GBR.js.map} +1 -1
- package/dist/cli/{chunk-TPF2272Y.js → chunk-6SJAK2WZ.js} +2 -2
- package/dist/cli/chunk-BLNR2H52.js +51 -0
- package/dist/cli/chunk-BLNR2H52.js.map +7 -0
- package/dist/cli/{chunk-DYCU4INF.js → chunk-FCZLLRXU.js} +8 -8
- package/dist/cli/chunk-FCZLLRXU.js.map +7 -0
- package/dist/cli/{chunk-TCHC2O3E.js → chunk-NNZOCTDI.js} +3 -48
- package/dist/cli/chunk-NNZOCTDI.js.map +7 -0
- package/dist/cli/createAsyncComparison-DTUUZUEX.js +10 -0
- package/dist/cli/{createAsyncReport-ZIO2Q6SS.js → createAsyncReport-7QIIMSNX.js} +4 -3
- package/dist/cli/{createAsyncReport-ZIO2Q6SS.js.map → createAsyncReport-7QIIMSNX.js.map} +1 -1
- package/dist/cli/main.d.ts +2 -0
- package/dist/cli/main.d.ts.map +1 -0
- package/dist/cli/{index.js → main.js} +29 -24
- package/dist/cli/main.js.map +7 -0
- package/dist/cli/package-BYHQMCNB.js +7 -0
- package/dist/cli/{prepareSnapRequests-NPYZG2AI.js → prepareSnapRequests-T6RBWTYD.js} +4 -3
- package/dist/cli/{prepareSnapRequests-NPYZG2AI.js.map → prepareSnapRequests-T6RBWTYD.js.map} +1 -1
- package/dist/cli/{startJob-T3PWEYOP.js → startJob-74BLUAGF.js} +4 -3
- package/dist/cli/{startJob-T3PWEYOP.js.map → startJob-74BLUAGF.js.map} +1 -1
- package/dist/cli/{wrapper-WKKUKM7T.js → wrapper-IM3TNBSL.js} +5 -4
- package/dist/cli/{wrapper-WKKUKM7T.js.map → wrapper-IM3TNBSL.js.map} +1 -1
- package/dist/config/loadConfig.d.ts.map +1 -1
- package/dist/cypress/task.js +126 -120
- package/dist/cypress/task.js.map +3 -3
- package/dist/playwright/index.js +126 -120
- package/dist/playwright/index.js.map +3 -3
- package/package.json +7 -7
- package/dist/cli/chunk-DYCU4INF.js.map +0 -7
- package/dist/cli/chunk-TCHC2O3E.js.map +0 -7
- package/dist/cli/createAsyncComparison-5X5OBHF2.js +0 -9
- package/dist/cli/index.js.map +0 -7
- package/dist/cli/package-CB7WD7JO.js +0 -7
- /package/dist/cli/{chunk-TPF2272Y.js.map → chunk-6SJAK2WZ.js.map} +0 -0
- /package/dist/cli/{createAsyncComparison-5X5OBHF2.js.map → createAsyncComparison-DTUUZUEX.js.map} +0 -0
- /package/dist/cli/{package-CB7WD7JO.js.map → package-BYHQMCNB.js.map} +0 -0
package/dist/playwright/index.js
CHANGED
|
@@ -10,119 +10,6 @@ import limitConcur from "limit-concur";
|
|
|
10
10
|
// src/config/loadConfig.ts
|
|
11
11
|
import fs from "node:fs";
|
|
12
12
|
import { any as findAny } from "empathic/find";
|
|
13
|
-
var CONFIG_FILENAMES = [
|
|
14
|
-
"happo.config.js",
|
|
15
|
-
"happo.config.mjs",
|
|
16
|
-
"happo.config.cjs",
|
|
17
|
-
"happo.config.ts",
|
|
18
|
-
"happo.config.mts",
|
|
19
|
-
"happo.config.cts"
|
|
20
|
-
];
|
|
21
|
-
var DEFAULT_ENDPOINT = "https://happo.io";
|
|
22
|
-
function findConfigFile() {
|
|
23
|
-
if (process.env.HAPPO_CONFIG_FILE) {
|
|
24
|
-
return process.env.HAPPO_CONFIG_FILE;
|
|
25
|
-
}
|
|
26
|
-
const configFilePath = findAny(CONFIG_FILENAMES, { cwd: process.cwd() });
|
|
27
|
-
if (!configFilePath) {
|
|
28
|
-
throw new Error(
|
|
29
|
-
"Happo config file could not be found. Please create a config file in the root of your project."
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
return configFilePath;
|
|
33
|
-
}
|
|
34
|
-
function assertIsPullRequestTokenResponse(response) {
|
|
35
|
-
if (typeof response !== "object" || response === null || !("secret" in response)) {
|
|
36
|
-
throw new TypeError("Unexpected pull request token response");
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
async function getPullRequestSecret(endpoint, prUrl) {
|
|
40
|
-
const res = await fetch(`${endpoint}/api/pull-request-token`, {
|
|
41
|
-
method: "POST",
|
|
42
|
-
headers: { "Content-Type": "application/json" },
|
|
43
|
-
body: JSON.stringify({ prUrl })
|
|
44
|
-
});
|
|
45
|
-
if (!res || !res.ok) {
|
|
46
|
-
throw new Error(
|
|
47
|
-
`Failed to get pull request secret: ${res.status} - ${await res.text()}`
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
const json = await res.json();
|
|
51
|
-
assertIsPullRequestTokenResponse(json);
|
|
52
|
-
return json.secret;
|
|
53
|
-
}
|
|
54
|
-
async function loadConfigFile(configFilePath, environment, logger = console) {
|
|
55
|
-
try {
|
|
56
|
-
const stats = await fs.promises.stat(configFilePath);
|
|
57
|
-
if (!stats.isFile()) {
|
|
58
|
-
throw new Error(`Happo config file path is not a file: ${configFilePath}`);
|
|
59
|
-
}
|
|
60
|
-
} catch (error) {
|
|
61
|
-
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
62
|
-
throw new Error(`Happo config file could not be found: ${configFilePath}`);
|
|
63
|
-
}
|
|
64
|
-
throw error;
|
|
65
|
-
}
|
|
66
|
-
const config = (await import(configFilePath)).default;
|
|
67
|
-
if (!config.apiKey && process.env.HAPPO_API_KEY) {
|
|
68
|
-
config.apiKey = process.env.HAPPO_API_KEY;
|
|
69
|
-
}
|
|
70
|
-
if (!config.apiSecret && process.env.HAPPO_API_SECRET) {
|
|
71
|
-
config.apiSecret = process.env.HAPPO_API_SECRET;
|
|
72
|
-
}
|
|
73
|
-
if (!config.apiKey || !config.apiSecret) {
|
|
74
|
-
const missing = [
|
|
75
|
-
config.apiKey ? null : "apiKey",
|
|
76
|
-
config.apiSecret ? null : "apiSecret"
|
|
77
|
-
].filter(Boolean).map((key) => `\`${key}\``).join(" and ");
|
|
78
|
-
if (!environment?.link) {
|
|
79
|
-
throw new Error(
|
|
80
|
-
`Missing ${missing} in your Happo config. Reference yours at https://happo.io/settings`
|
|
81
|
-
);
|
|
82
|
-
}
|
|
83
|
-
try {
|
|
84
|
-
logger.log(
|
|
85
|
-
`Missing ${missing} in Happo config. Falling back to pull-request authentication.`
|
|
86
|
-
);
|
|
87
|
-
config.apiKey = environment.link;
|
|
88
|
-
config.apiSecret = await getPullRequestSecret(
|
|
89
|
-
config.endpoint || DEFAULT_ENDPOINT,
|
|
90
|
-
environment.link
|
|
91
|
-
);
|
|
92
|
-
} catch (e) {
|
|
93
|
-
throw new Error("Failed to obtain temporary pull-request token", { cause: e });
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
if (!config.targets) {
|
|
97
|
-
config.targets = {
|
|
98
|
-
chrome: {
|
|
99
|
-
type: "chrome",
|
|
100
|
-
viewport: "1024x768"
|
|
101
|
-
}
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
if (!config.integration) {
|
|
105
|
-
config.integration = {
|
|
106
|
-
type: "storybook"
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
const allTargets = Object.values(config.targets);
|
|
110
|
-
for (const target of allTargets) {
|
|
111
|
-
target.viewport = target.viewport || "1024x768";
|
|
112
|
-
target.freezeAnimations = target.freezeAnimations || "last-frame";
|
|
113
|
-
target.prefersReducedMotion = target.prefersReducedMotion ?? true;
|
|
114
|
-
}
|
|
115
|
-
const configWithDefaults = {
|
|
116
|
-
endpoint: DEFAULT_ENDPOINT,
|
|
117
|
-
githubApiUrl: "https://api.github.com",
|
|
118
|
-
targets: allTargets,
|
|
119
|
-
...config
|
|
120
|
-
};
|
|
121
|
-
return configWithDefaults;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// src/network/makeHappoAPIRequest.ts
|
|
125
|
-
import { SignJWT } from "jose";
|
|
126
13
|
|
|
127
14
|
// src/network/fetchWithRetry.ts
|
|
128
15
|
import asyncRetry from "async-retry";
|
|
@@ -130,7 +17,7 @@ import asyncRetry from "async-retry";
|
|
|
130
17
|
// package.json
|
|
131
18
|
var package_default = {
|
|
132
19
|
name: "happo",
|
|
133
|
-
version: "6.0.
|
|
20
|
+
version: "6.0.6",
|
|
134
21
|
description: "Catch unexpected visual and accessibility changes and UI bugs",
|
|
135
22
|
license: "MIT",
|
|
136
23
|
repository: {
|
|
@@ -140,7 +27,7 @@ var package_default = {
|
|
|
140
27
|
bugs: "https://github.com/happo/happo/issues",
|
|
141
28
|
homepage: "https://happo.io",
|
|
142
29
|
bin: {
|
|
143
|
-
happo: "dist/cli/
|
|
30
|
+
happo: "dist/cli/main.js"
|
|
144
31
|
},
|
|
145
32
|
type: "module",
|
|
146
33
|
main: "./dist/config/index.js",
|
|
@@ -198,12 +85,12 @@ var package_default = {
|
|
|
198
85
|
prepublishOnly: "pnpm clean && pnpm build",
|
|
199
86
|
"storybook:dev": "storybook dev --config-dir src/storybook/__tests__/storybook-app -p ${PORT:-6007}",
|
|
200
87
|
test: "node --env-file-if-exists=.env.local ./scripts/test.ts",
|
|
201
|
-
"test:custom": "pnpm build:dist && pnpm build:custom && node --env-file-if-exists=.env.local dist/cli/
|
|
202
|
-
"test:cypress": "pnpm build:dist && node --env-file-if-exists=.env.local dist/cli/
|
|
88
|
+
"test:custom": "pnpm build:dist && pnpm build:custom && node --env-file-if-exists=.env.local dist/cli/main.js -c ./happoconfigs/happo.custom.config.ts",
|
|
89
|
+
"test:cypress": "pnpm build:dist && node --env-file-if-exists=.env.local dist/cli/main.js -c ./happoconfigs/happo.cypress.config.ts e2e -- cypress run -C src/cypress/__cypress__/cypress.config.ts",
|
|
203
90
|
"test:cypress:open": "cypress open -C src/cypress/__cypress__/cypress.config.ts",
|
|
204
|
-
"test:playwright": "pnpm build:dist && node --env-file-if-exists=.env.local dist/cli/
|
|
205
|
-
"test:storybook": "pnpm build:dist && node --env-file-if-exists=.env.local dist/cli/
|
|
206
|
-
"test:pages": "pnpm build:dist && node --env-file-if-exists=.env.local dist/cli/
|
|
91
|
+
"test:playwright": "pnpm build:dist && node --env-file-if-exists=.env.local dist/cli/main.js -c ./happoconfigs/happo.playwright.config.ts e2e -- playwright test",
|
|
92
|
+
"test:storybook": "pnpm build:dist && node --env-file-if-exists=.env.local dist/cli/main.js -c ./happoconfigs/happo.storybook.config.ts",
|
|
93
|
+
"test:pages": "pnpm build:dist && node --env-file-if-exists=.env.local dist/cli/main.js -c ./happoconfigs/happo.pages.config.ts",
|
|
207
94
|
tsc: "tsc --build tsconfig.json"
|
|
208
95
|
},
|
|
209
96
|
browserslist: {
|
|
@@ -397,7 +284,126 @@ async function fetchWithRetry(url, {
|
|
|
397
284
|
);
|
|
398
285
|
}
|
|
399
286
|
|
|
287
|
+
// src/config/loadConfig.ts
|
|
288
|
+
var CONFIG_FILENAMES = [
|
|
289
|
+
"happo.config.js",
|
|
290
|
+
"happo.config.mjs",
|
|
291
|
+
"happo.config.cjs",
|
|
292
|
+
"happo.config.ts",
|
|
293
|
+
"happo.config.mts",
|
|
294
|
+
"happo.config.cts"
|
|
295
|
+
];
|
|
296
|
+
var DEFAULT_ENDPOINT = "https://happo.io";
|
|
297
|
+
function findConfigFile() {
|
|
298
|
+
if (process.env.HAPPO_CONFIG_FILE) {
|
|
299
|
+
return process.env.HAPPO_CONFIG_FILE;
|
|
300
|
+
}
|
|
301
|
+
const configFilePath = findAny(CONFIG_FILENAMES, { cwd: process.cwd() });
|
|
302
|
+
if (!configFilePath) {
|
|
303
|
+
throw new Error(
|
|
304
|
+
"Happo config file could not be found. Please create a config file in the root of your project."
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
return configFilePath;
|
|
308
|
+
}
|
|
309
|
+
function assertIsPullRequestTokenResponse(response) {
|
|
310
|
+
if (typeof response !== "object" || response === null || !("secret" in response)) {
|
|
311
|
+
throw new TypeError("Unexpected pull request token response");
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
async function getPullRequestSecret(endpoint, prUrl, logger) {
|
|
315
|
+
const url = new URL("/api/pull-request-token", endpoint);
|
|
316
|
+
const res = await fetchWithRetry(
|
|
317
|
+
url,
|
|
318
|
+
{
|
|
319
|
+
method: "POST",
|
|
320
|
+
body: { prUrl },
|
|
321
|
+
retryCount: 3
|
|
322
|
+
},
|
|
323
|
+
logger
|
|
324
|
+
);
|
|
325
|
+
if (!res || !res.ok) {
|
|
326
|
+
throw new Error(
|
|
327
|
+
`Failed to get pull request secret: ${res.status} - ${await res.text()}`
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
const json = await res.json();
|
|
331
|
+
assertIsPullRequestTokenResponse(json);
|
|
332
|
+
return json.secret;
|
|
333
|
+
}
|
|
334
|
+
async function loadConfigFile(configFilePath, environment, logger = console) {
|
|
335
|
+
try {
|
|
336
|
+
const stats = await fs.promises.stat(configFilePath);
|
|
337
|
+
if (!stats.isFile()) {
|
|
338
|
+
throw new Error(`Happo config file path is not a file: ${configFilePath}`);
|
|
339
|
+
}
|
|
340
|
+
} catch (error) {
|
|
341
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
342
|
+
throw new Error(`Happo config file could not be found: ${configFilePath}`);
|
|
343
|
+
}
|
|
344
|
+
throw error;
|
|
345
|
+
}
|
|
346
|
+
const config = (await import(configFilePath)).default;
|
|
347
|
+
if (!config.apiKey && process.env.HAPPO_API_KEY) {
|
|
348
|
+
config.apiKey = process.env.HAPPO_API_KEY;
|
|
349
|
+
}
|
|
350
|
+
if (!config.apiSecret && process.env.HAPPO_API_SECRET) {
|
|
351
|
+
config.apiSecret = process.env.HAPPO_API_SECRET;
|
|
352
|
+
}
|
|
353
|
+
if (!config.apiKey || !config.apiSecret) {
|
|
354
|
+
const missing = [
|
|
355
|
+
config.apiKey ? null : "apiKey",
|
|
356
|
+
config.apiSecret ? null : "apiSecret"
|
|
357
|
+
].filter(Boolean).map((key) => `\`${key}\``).join(" and ");
|
|
358
|
+
if (!environment?.link) {
|
|
359
|
+
throw new Error(
|
|
360
|
+
`Missing ${missing} in your Happo config. Reference yours at https://happo.io/settings`
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
try {
|
|
364
|
+
logger.log(
|
|
365
|
+
`Missing ${missing} in Happo config. Falling back to pull-request authentication.`
|
|
366
|
+
);
|
|
367
|
+
config.apiKey = environment.link;
|
|
368
|
+
config.apiSecret = await getPullRequestSecret(
|
|
369
|
+
config.endpoint || DEFAULT_ENDPOINT,
|
|
370
|
+
environment.link,
|
|
371
|
+
logger
|
|
372
|
+
);
|
|
373
|
+
} catch (e) {
|
|
374
|
+
throw new Error("Failed to obtain temporary pull-request token", { cause: e });
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
if (!config.targets) {
|
|
378
|
+
config.targets = {
|
|
379
|
+
chrome: {
|
|
380
|
+
type: "chrome",
|
|
381
|
+
viewport: "1024x768"
|
|
382
|
+
}
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
if (!config.integration) {
|
|
386
|
+
config.integration = {
|
|
387
|
+
type: "storybook"
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
const allTargets = Object.values(config.targets);
|
|
391
|
+
for (const target of allTargets) {
|
|
392
|
+
target.viewport = target.viewport || "1024x768";
|
|
393
|
+
target.freezeAnimations = target.freezeAnimations || "last-frame";
|
|
394
|
+
target.prefersReducedMotion = target.prefersReducedMotion ?? true;
|
|
395
|
+
}
|
|
396
|
+
const configWithDefaults = {
|
|
397
|
+
endpoint: DEFAULT_ENDPOINT,
|
|
398
|
+
githubApiUrl: "https://api.github.com",
|
|
399
|
+
targets: allTargets,
|
|
400
|
+
...config
|
|
401
|
+
};
|
|
402
|
+
return configWithDefaults;
|
|
403
|
+
}
|
|
404
|
+
|
|
400
405
|
// src/network/makeHappoAPIRequest.ts
|
|
406
|
+
import { SignJWT } from "jose";
|
|
401
407
|
async function signRequest(apiKey, apiSecret) {
|
|
402
408
|
const encodedSecret = new TextEncoder().encode(apiSecret);
|
|
403
409
|
return await new SignJWT({ key: apiKey }).setProtectedHeader({ alg: "HS256", kid: apiKey }).sign(encodedSecret);
|