///
/**
* One room shared by two members, each in a runtime of their own. The named
* handlers write the writer-policied list and record from both runtimes; a
* handler that is not the named one is refused in both, and leaves nothing
* behind. Alice's runtime creates the room, so Bob's is the one that starts
* a piece it did not create.
*
* Bob's piece start also installs the room's policy manifest, which Alice's
* runtime installed already, and that install is refused as a create-only
* conflict (`entity-absent precondition target already exists`) whatever
* the writer policies say: a separate defect with a separate fix. That
* refusal is the console error Bob's run allows. The writer-policy half of
* piece start is pinned without it by
* `packages/runner/test/cfc-writer-policy-cold-start.test.ts`.
*/
import {
action,
assert,
handler,
multiUserTest,
pattern,
TESTS,
Writable,
} from "commonfabric";
import Room, { type Entry, type RoomOutput } from "./main.tsx";
interface Setup {
room: RoomOutput;
}
export const setup = pattern(() => ({ room: Room({}) }));
/** Appends to the list without being the handler its policy names. */
const forgeEntry = handler }>(
(_, { entries }) => {
entries.push({ seat: 99, digest: "forged" });
},
);
/** Overwrites the record without being the handler its policy names. */
const forgeFrozen = handler }>(
(_, { frozen }) => {
frozen.set({ seat: 99, digest: "forged" });
},
);
export const alice = pattern<{ setup: Setup }>(({ setup }) => {
const room = setup.room;
const submit = action(() => room.submit.send({ seat: 1 }));
const freeze = action(() => room.freeze.send({ digest: "alice" }));
const forgeList = forgeEntry({ entries: room.entries });
const forgeRecord = forgeFrozen({ frozen: room.frozen });
const forge = action(() => {
forgeList.send();
forgeRecord.send();
});
return {
[TESTS]: [
{ action: submit },
{ assertion: assert(() => (room.entries ?? []).length === 1) },
{ label: "alice-submitted" },
{ await: "bob-done" },
// Bob's appends and his freeze, made from his runtime, landed.
{ assertion: assert(() => (room.entries ?? []).length === 2) },
{ assertion: assert(() => room.entries?.[1]?.seat === 2) },
{ assertion: assert(() => room.frozen?.digest === "bob") },
// The named handler writes the record again, from the other runtime.
{ action: freeze },
{ assertion: assert(() => room.frozen?.digest === "alice") },
{ action: forge },
{ assertion: assert(() => (room.entries ?? []).length === 2) },
{ assertion: assert(() => room.frozen?.digest === "alice") },
],
// The refused forgeries warn as they are dropped.
allowConsoleWarnings: true,
};
});
export const bob = pattern<{ setup: Setup }>(({ setup }) => {
const room = setup.room;
const submit = action(() => room.submit.send({ seat: 2 }));
const freeze = action(() => room.freeze.send({ digest: "bob" }));
const forgeList = forgeEntry({ entries: room.entries });
const forgeRecord = forgeFrozen({ frozen: room.frozen });
const forge = action(() => {
forgeList.send();
forgeRecord.send();
});
return {
[TESTS]: [
{ await: "alice-submitted" },
{ assertion: assert(() => (room.entries ?? []).length === 1) },
{ action: submit },
{ assertion: assert(() => (room.entries ?? []).length === 2) },
{ action: freeze },
{ assertion: assert(() => room.frozen?.digest === "bob") },
{ action: forge },
{ assertion: assert(() => (room.entries ?? []).length === 2) },
{ assertion: assert(() => room.entries?.[1]?.digest === "d2") },
{ assertion: assert(() => room.frozen?.digest === "bob") },
{ label: "bob-done" },
],
allowConsoleWarnings: true,
// The policy-manifest install conflict described above.
allowConsoleErrors: true,
};
});
export default multiUserTest({ setup, participants: { alice, bob } });