fix: synchronize mounted component props
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/test",
|
||||
"version": "0.8.11",
|
||||
"version": "0.8.12",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -205,3 +205,9 @@ export type {
|
||||
} from "./advanced.ts";
|
||||
export { withDatabaseRollback, createFactory, captureBrowserArtifacts } from "./platform.ts";
|
||||
export type { TransactionalDatabase, BrowserArtifactPage } from "./platform.ts";
|
||||
export { detectMutations } from "./mutation.ts";
|
||||
export type {
|
||||
MutationCase,
|
||||
MutationReport,
|
||||
DetectMutationsOptions,
|
||||
} from "./mutation.ts";
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
export interface MutationCase<T> {
|
||||
name: string;
|
||||
value: T;
|
||||
}
|
||||
|
||||
export interface MutationReport<O> {
|
||||
baseline: O;
|
||||
killed: string[];
|
||||
survived: string[];
|
||||
}
|
||||
|
||||
export interface DetectMutationsOptions<T, O> {
|
||||
baseline: T;
|
||||
mutations: Array<MutationCase<T>>;
|
||||
exercise(value: T): O | Promise<O>;
|
||||
equivalent?(left: O, right: O): boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the same behavioural probe against a baseline and explicit mutations.
|
||||
* A mutation survives when the observable result is unchanged. The helper
|
||||
* throws with every survivor by default, making it suitable for an ordinary
|
||||
* Bun test and CI without a second runner or source-rewriting process.
|
||||
*/
|
||||
export async function detectMutations<T, O>(
|
||||
options: DetectMutationsOptions<T, O>,
|
||||
): Promise<MutationReport<O>> {
|
||||
if (!options.mutations.length) {
|
||||
throw new Error("WRN-MUTATION-EMPTY: declare at least one meaningful mutation");
|
||||
}
|
||||
const equivalent = options.equivalent ?? ((left, right) => Object.is(left, right));
|
||||
const baseline = await options.exercise(options.baseline);
|
||||
const killed: string[] = [];
|
||||
const survived: string[] = [];
|
||||
for (const mutation of options.mutations) {
|
||||
if (!mutation.name.trim()) throw new Error("WRN-MUTATION-NAME: every mutation needs a name");
|
||||
let same = false;
|
||||
try {
|
||||
same = equivalent(baseline, await options.exercise(mutation.value));
|
||||
} catch {
|
||||
// A behavioural failure is a killed mutation.
|
||||
}
|
||||
(same ? survived : killed).push(mutation.name);
|
||||
}
|
||||
if (survived.length) {
|
||||
throw Object.assign(
|
||||
new Error(`WRN-MUTATION-SURVIVED: ${survived.join(", ")}`),
|
||||
{ report: { baseline, killed, survived } },
|
||||
);
|
||||
}
|
||||
return { baseline, killed, survived };
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { expect, test } from "bun:test";
|
||||
import { detectMutations } from "../src/mutation.ts";
|
||||
|
||||
test("detectMutations reports mutations whose behaviour changes", async () => {
|
||||
const report = await detectMutations({
|
||||
baseline: (amount: number) => amount,
|
||||
mutations: [
|
||||
{ name: "invert sign", value: (amount: number) => -amount },
|
||||
{ name: "drop amount", value: () => 0 },
|
||||
],
|
||||
exercise: (adjust) => adjust(7),
|
||||
});
|
||||
expect(report.killed).toEqual(["invert sign", "drop amount"]);
|
||||
expect(report.survived).toEqual([]);
|
||||
});
|
||||
|
||||
test("detectMutations fails with the names of surviving mutations", async () => {
|
||||
await expect(
|
||||
detectMutations({
|
||||
baseline: (amount: number) => amount,
|
||||
mutations: [{ name: "wrong implementation", value: (amount: number) => amount }],
|
||||
exercise: (adjust) => adjust(7),
|
||||
}),
|
||||
).rejects.toThrow(/WRN-MUTATION-SURVIVED: wrong implementation/);
|
||||
});
|
||||
|
||||
test("detectMutations accepts structured observations through an equivalence function", async () => {
|
||||
const report = await detectMutations({
|
||||
baseline: { status: 200 },
|
||||
mutations: [{ name: "deny request", value: { status: 403 } }],
|
||||
exercise: async (response) => ({ ...response, volatile: crypto.randomUUID() }),
|
||||
equivalent: (left, right) => left.status === right.status,
|
||||
});
|
||||
expect(report.killed).toEqual(["deny request"]);
|
||||
});
|
||||
Reference in New Issue
Block a user