Files
klz-cables.com/.pnpm-store/v10/files/37/ba56afe06b0aab110255c8b110dd6e1b97c2768920666cce6193cd1a0c5b166d9b3a2aa8be6daf8c92dc356110a020bcf9ddd13c1de3995c009a95db5a2a21
Marc Mintel 5397309103
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 20s
Build & Deploy / 🧪 QA (push) Failing after 34s
Build & Deploy / 🏗️ Build (push) Has started running
Build & Deploy / 🚀 Deploy (push) Has been cancelled
Build & Deploy / 🧪 Smoke Test (push) Has been cancelled
Build & Deploy / ⚡ Lighthouse (push) Has been cancelled
Build & Deploy / 🔔 Notify (push) Has been cancelled
fix(products): fix breadcrumbs and product filtering (backport from main)
2026-02-24 16:04:21 +01:00

145 lines
4.5 KiB
Plaintext

/**
*
* audit/utils
*
*/
export * from '../utils.mjs';
/**
* Wrap and prepare an audit for testing.
*
* @private
*/
export function audit(id, name, fn) {
return {
id,
name,
fn: async () => {
try {
await fn();
return {
id,
name,
status: 'ok',
};
}
catch (err) {
if (!(err instanceof AuditError)) {
// anything thrown that is not an assertion error is considered fatal
throw err;
}
return {
id,
name,
status: name.startsWith('MUST')
? // failing MUSTs are considered errors
'error'
: name.startsWith('SHOULD')
? // recommendations are warnings
'warn'
: // everything else is truly optional
'notice',
reason: err.reason,
response: err.response,
};
}
},
};
}
/**
* Error thrown when an assertion test fails.
*
* @private
*/
export class AuditError {
constructor(response, reason) {
this.response = response;
this.reason = reason;
}
}
/**
* Will throw an AuditError if the assertion on Response fails.
*
* All fatal problems will throw an instance of an Error.
*
* The name "ressert" is a wordplay combining "response" and "assert".
*
* @private
*/
export function ressert(res) {
return {
status: {
toBe(code) {
if (res.status !== code) {
throw new AuditError(res, `Response status code is not ${code}`);
}
},
toBeBetween: (min, max) => {
if (!(min <= res.status && res.status <= max)) {
throw new AuditError(res, `Response status is not between ${min} and ${max}`);
}
},
},
header(key) {
return {
toContain(part) {
var _a;
if (!((_a = res.headers.get(key)) === null || _a === void 0 ? void 0 : _a.includes(part))) {
throw new AuditError(res, `Response header ${key} does not contain ${part}`);
}
},
notToContain(part) {
var _a;
if ((_a = res.headers.get(key)) === null || _a === void 0 ? void 0 : _a.includes(part)) {
throw new AuditError(res, `Response header ${key} contains ${part}`);
}
},
};
},
bodyAsExecutionResult: {
data: {
async toBe(val) {
const clonedRes = res.clone(); // allow the body to be re-read
const body = await assertBodyAsExecutionResult(res);
if (body.data !== val) {
throw new AuditError(clonedRes, `Response body execution result data is not "${val}"`);
}
},
},
async toHaveProperty(key) {
const clonedRes = res.clone(); // allow the body to be re-read
const body = await assertBodyAsExecutionResult(res);
if (!(key in body)) {
throw new AuditError(clonedRes, `Response body execution result does not have a property "${key}"`);
}
},
async notToHaveProperty(key) {
const clonedRes = res.clone(); // allow the body to be re-read
const body = await assertBodyAsExecutionResult(res);
if (key in body) {
throw new AuditError(clonedRes, `Response body execution result has a property "${key}"`);
}
},
},
};
}
/** @private */
async function assertBodyAsExecutionResult(res) {
let decoded;
try {
const decoder = new TextDecoder('utf-8');
const buff = await res.arrayBuffer();
decoded = decoder.decode(buff);
}
catch (err) {
throw new AuditError(res, 'Response body is not UTF-8 encoded');
}
let body;
try {
body = JSON.parse(decoded);
}
catch (err) {
throw new AuditError(res, 'Response body is not valid JSON');
}
return body;
}