docs: document topology graph v0.2 contract
This commit is contained in:
@@ -10,6 +10,7 @@ import { shortHash } from "../src/hash.js";
|
||||
const fixturePath = path.resolve("tests/fixtures/context-risk.html");
|
||||
const fixtureFileUrl = pathToFileURL(fixturePath).href;
|
||||
const examplePath = path.resolve("examples/simple.html");
|
||||
const snapshotDiffEffectTypes = ["actionableInventory", "dom", "url", "visibleText"];
|
||||
|
||||
async function withTempOutput<T>(name: string, callback: (out: string) => Promise<T>): Promise<T> {
|
||||
const dir = await mkdtemp(path.join(tmpdir(), "action-topology-engine-test-"));
|
||||
@@ -238,6 +239,72 @@ test("explore records edge effects and opened-by state relationships", async ()
|
||||
assert.equal(openSettingsEdge.effects.some((effect) => effect.description === "Actionable inventory changed after action" && effect.type === "dom"), false);
|
||||
});
|
||||
|
||||
test("explore artifact preserves referential integrity and snapshot-diff effect records", async () => {
|
||||
const graph = await withTempOutput("explore-integrity", (out) => exploreUrl({ url: fixturePath, maxActions: 12, out }));
|
||||
const stateIds = new Set(graph.states.map((state) => state.stateId));
|
||||
const elementIds = new Set(graph.elements.map((element) => element.elementId));
|
||||
const edgeIds = new Set(graph.edges.map((edge) => edge.edgeId));
|
||||
const locatorIds = new Set<string>();
|
||||
const skippedActionIds = new Set(graph.skippedActions.map((skip) => skip.skippedActionId));
|
||||
const failedObservationIds = new Set(graph.failedObservations.map((failure) => failure.failedObservationId));
|
||||
const elementById = new Map(graph.elements.map((element) => [element.elementId, element]));
|
||||
const observedEffectTypes = new Set<string>();
|
||||
|
||||
assert.equal(stateIds.size, graph.states.length);
|
||||
assert.equal(elementIds.size, graph.elements.length);
|
||||
assert.equal(edgeIds.size, graph.edges.length);
|
||||
assert.equal(skippedActionIds.size, graph.skippedActions.length);
|
||||
assert.equal(failedObservationIds.size, graph.failedObservations.length);
|
||||
|
||||
for (const element of graph.elements) {
|
||||
assert.equal(stateIds.has(element.stateId), true);
|
||||
for (const locator of element.locators) {
|
||||
assert.equal(locator.elementId, element.elementId);
|
||||
assert.equal(locatorIds.has(locator.locatorId), false);
|
||||
locatorIds.add(locator.locatorId);
|
||||
}
|
||||
}
|
||||
|
||||
for (const edge of graph.edges) {
|
||||
const targetElement = elementById.get(edge.elementId);
|
||||
assert.equal(stateIds.has(edge.fromStateId), true);
|
||||
if (edge.toStateId !== null) assert.equal(stateIds.has(edge.toStateId), true);
|
||||
assert.ok(targetElement);
|
||||
assert.equal(targetElement.stateId, edge.fromStateId);
|
||||
for (const effect of edge.effects) {
|
||||
assert.equal(snapshotDiffEffectTypes.includes(effect.type), true);
|
||||
assert.equal(typeof effect.before, "string");
|
||||
assert.equal(typeof effect.after, "string");
|
||||
observedEffectTypes.add(effect.type);
|
||||
}
|
||||
}
|
||||
|
||||
assert.deepEqual([...observedEffectTypes].sort(), snapshotDiffEffectTypes);
|
||||
|
||||
for (const state of graph.states) {
|
||||
if (state.openedByEdgeId === null) continue;
|
||||
const openingEdge = graph.edges.find((edge) => edge.edgeId === state.openedByEdgeId);
|
||||
assert.ok(openingEdge);
|
||||
assert.equal(edgeIds.has(state.openedByEdgeId), true);
|
||||
assert.equal(openingEdge.toStateId, state.stateId);
|
||||
}
|
||||
|
||||
for (const skip of graph.skippedActions) {
|
||||
const element = graph.elements.find((item) => item.elementId === skip.elementId);
|
||||
assert.equal(stateIds.has(skip.stateId), true);
|
||||
assert.ok(element);
|
||||
assert.equal(skip.stateId, element.stateId);
|
||||
}
|
||||
|
||||
for (const failure of graph.failedObservations) {
|
||||
assert.equal(stateIds.has(failure.stateId), true);
|
||||
if (failure.elementId === null) continue;
|
||||
const element = graph.elements.find((item) => item.elementId === failure.elementId);
|
||||
assert.ok(element);
|
||||
assert.equal(failure.stateId, element.stateId);
|
||||
}
|
||||
});
|
||||
|
||||
test("explore replays each v0.2.1 edge from the entry state", async () => {
|
||||
const graph = await withTempOutput("explore-entry-replay", (out) => exploreUrl({ url: fixturePath, maxActions: 8, out }));
|
||||
const entryState = graph.states[0];
|
||||
|
||||
Reference in New Issue
Block a user