Skip to content

Commit 03351a3

Browse files
test: assert a loaded workflow survives being saved again
The existing round-trip tests compare a second serialisation to the first. That proves the output is a fixed point; it says nothing about whether the input survived. Nothing currently asserts that opening a workflow and saving it preserves what the user had. Adds that assertion over three fixtures (linked nodes, floating link, complex reroutes — 9 nodes / 6 links / 13 reroutes): every node id, link, reroute id and group survives; the input object is not mutated; and saving twice is stable. Compares entity sets rather than bytes, deliberately. Serialisation normalises by design — the schema version is rewritten and conflicting ids are reassigned — so byte equality would be the wrong property to assert and would fail for reasons that are not defects. 18 tests, all passing on main.
1 parent 28bd73a commit 03351a3

1 file changed

Lines changed: 97 additions & 0 deletions

File tree

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import { describe, expect, test } from 'vitest'
2+
3+
import { LGraph } from '@/lib/litegraph/src/litegraph'
4+
import type { ISerialisedGraph } from '@/lib/litegraph/src/litegraph'
5+
6+
import floatingLink from './__fixtures__/assets/floatingLink.json'
7+
import linkedNodes from './__fixtures__/assets/linkedNodes.json'
8+
import reroutesComplex from './__fixtures__/assets/reroutesComplex.json'
9+
10+
/**
11+
* Loading a workflow and saving it again must not lose entities.
12+
*
13+
* The existing round-trip tests compare a second serialisation to the first,
14+
* which proves the output is a fixed point but says nothing about whether the
15+
* *input* survived. These assert the property users actually depend on: open a
16+
* workflow, save it, and everything you had is still there.
17+
*
18+
* Serialisation deliberately normalises — schema version is rewritten and
19+
* conflicting ids are reassigned — so this compares entity sets and counts
20+
* rather than bytes.
21+
*/
22+
23+
interface RoundTripFixture {
24+
name: string
25+
graph: ISerialisedGraph
26+
}
27+
28+
const fixtures: RoundTripFixture[] = [
29+
{ name: 'linked nodes', graph: linkedNodes as unknown as ISerialisedGraph },
30+
{ name: 'floating link', graph: floatingLink as unknown as ISerialisedGraph },
31+
{
32+
name: 'complex reroutes',
33+
graph: reroutesComplex as unknown as ISerialisedGraph
34+
}
35+
]
36+
37+
function roundTrip(source: ISerialisedGraph) {
38+
const loaded = new LGraph(structuredClone(source))
39+
return loaded.serialize()
40+
}
41+
42+
function ascending(a: number | string, b: number | string) {
43+
return String(a).localeCompare(String(b), undefined, { numeric: true })
44+
}
45+
46+
function rerouteIds(graph: { extra?: { reroutes?: { id: number }[] } }) {
47+
return (graph.extra?.reroutes ?? [])
48+
.map((reroute) => reroute.id)
49+
.sort(ascending)
50+
}
51+
52+
describe('LGraph round trip preserves the input', () => {
53+
for (const { name, graph } of fixtures) {
54+
describe(name, () => {
55+
test('keeps every node, by id', () => {
56+
const before = graph.nodes.map((node) => node.id).sort(ascending)
57+
const after = roundTrip(graph)
58+
.nodes.map((node) => node.id)
59+
.sort(ascending)
60+
61+
expect(after).toEqual(before)
62+
})
63+
64+
test('keeps every link', () => {
65+
const before = graph.links?.length ?? 0
66+
67+
expect(roundTrip(graph).links?.length ?? 0).toBe(before)
68+
})
69+
70+
test('keeps every reroute, by id', () => {
71+
expect(rerouteIds(roundTrip(graph))).toEqual(rerouteIds(graph))
72+
})
73+
74+
test('keeps every group', () => {
75+
const before = graph.groups?.length ?? 0
76+
77+
expect(roundTrip(graph).groups?.length ?? 0).toBe(before)
78+
})
79+
80+
test('does not mutate the workflow it was given', () => {
81+
const untouched = structuredClone(graph)
82+
const subject = structuredClone(graph)
83+
84+
new LGraph(subject).serialize()
85+
86+
expect(subject).toEqual(untouched)
87+
})
88+
89+
test('is stable when saved twice', () => {
90+
const once = roundTrip(graph)
91+
const twice = new LGraph(structuredClone(once)).serialize()
92+
93+
expect(twice).toEqual(once)
94+
})
95+
})
96+
}
97+
})

0 commit comments

Comments
 (0)