chore: migrate tests from tests-ui/ to colocate with source files (#7811)

## Summary

Migrates all unit tests from `tests-ui/` to colocate with their source
files in `src/`, improving discoverability and maintainability.

## Changes

- **What**: Relocated all unit tests to be adjacent to the code they
test, following the `<source>.test.ts` naming convention
- **Config**: Updated `vitest.config.ts` to remove `tests-ui` include
pattern and `@tests-ui` alias
- **Docs**: Moved testing documentation to `docs/testing/` with updated
paths and patterns

## Review Focus

- Migration patterns documented in
`temp/plans/migrate-tests-ui-to-src.md`
- Tests use `@/` path aliases instead of relative imports
- Shared fixtures placed in `__fixtures__/` directories

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7811-chore-migrate-tests-from-tests-ui-to-colocate-with-source-files-2da6d73d36508147a4cce85365dee614)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: GitHub Action <action@github.com>
This commit is contained in:
Alexander Brown
2026-01-05 16:32:24 -08:00
committed by GitHub
parent 832588c7a9
commit 10feb1fd5b
272 changed files with 483 additions and 1239 deletions

View File

@@ -0,0 +1,225 @@
import { describe, expect, it } from 'vitest'
import { LGraph, LGraphNode, LiteGraph } from '@/lib/litegraph/src/litegraph'
import { test } from './__fixtures__/testExtensions'
function swapNodes(nodes: LGraphNode[]) {
const firstNode = nodes[0]
const lastNode = nodes[nodes.length - 1]
nodes[0] = lastNode
nodes[nodes.length - 1] = firstNode
return nodes
}
function createGraph(...nodes: LGraphNode[]) {
const graph = new LGraph()
nodes.forEach((node) => graph.add(node))
return graph
}
class DummyNode extends LGraphNode {
constructor() {
super('dummy')
}
}
describe('LGraph', () => {
it('should serialize deterministic node order', async () => {
LiteGraph.registerNodeType('dummy', DummyNode)
const node1 = new DummyNode()
const node2 = new DummyNode()
const graph = createGraph(node1, node2)
const result1 = graph.serialize({ sortNodes: true })
expect(result1.nodes).not.toHaveLength(0)
graph._nodes = swapNodes(graph.nodes)
const result2 = graph.serialize({ sortNodes: true })
expect(result1).toEqual(result2)
})
test('can be instantiated', ({ expect }) => {
// @ts-expect-error Intentional - extra holds any / all consumer data that should be serialised
const graph = new LGraph({ extra: 'TestGraph' })
expect(graph).toBeInstanceOf(LGraph)
expect(graph.extra).toBe('TestGraph')
expect(graph.extra).toBe('TestGraph')
})
test('is exactly the same type', async ({ expect }) => {
const directImport = await import('@/lib/litegraph/src/LGraph')
const entryPointImport = await import('@/lib/litegraph/src/litegraph')
expect(LiteGraph.LGraph).toBe(directImport.LGraph)
expect(LiteGraph.LGraph).toBe(entryPointImport.LGraph)
})
test('populates optional values', ({ expect, minimalSerialisableGraph }) => {
const dGraph = new LGraph(minimalSerialisableGraph)
expect(dGraph.links).toBeInstanceOf(Map)
expect(dGraph.nodes).toBeInstanceOf(Array)
expect(dGraph.groups).toBeInstanceOf(Array)
})
test('supports schema v0.4 graphs', ({ expect, oldSchemaGraph }) => {
const fromOldSchema = new LGraph(oldSchemaGraph)
expect(fromOldSchema).toMatchSnapshot('oldSchemaGraph')
})
})
describe('Floating Links / Reroutes', () => {
test('Floating reroute should be removed when node and link are removed', ({
expect,
floatingLinkGraph
}) => {
const graph = new LGraph(floatingLinkGraph)
expect(graph.nodes.length).toBe(1)
graph.remove(graph.nodes[0])
expect(graph.nodes.length).toBe(0)
expect(graph.links.size).toBe(0)
expect(graph.floatingLinks.size).toBe(0)
expect(graph.reroutes.size).toBe(0)
})
test('Can add reroute to existing link', ({ expect, linkedNodesGraph }) => {
const graph = new LGraph(linkedNodesGraph)
expect(graph.nodes.length).toBe(2)
expect(graph.links.size).toBe(1)
expect(graph.reroutes.size).toBe(0)
graph.createReroute([0, 0], graph.links.values().next().value!)
expect(graph.links.size).toBe(1)
expect(graph.reroutes.size).toBe(1)
})
test('Create floating reroute when one side of node is removed', ({
expect,
linkedNodesGraph
}) => {
const graph = new LGraph(linkedNodesGraph)
graph.createReroute([0, 0], graph.links.values().next().value!)
graph.remove(graph.nodes[0])
expect(graph.links.size).toBe(0)
expect(graph.floatingLinks.size).toBe(1)
expect(graph.reroutes.size).toBe(1)
expect(graph.reroutes.values().next().value!.floating).not.toBeUndefined()
})
test('Create floating reroute when one side of link is removed', ({
expect,
linkedNodesGraph
}) => {
const graph = new LGraph(linkedNodesGraph)
graph.createReroute([0, 0], graph.links.values().next().value!)
graph.nodes[0].disconnectOutput(0)
expect(graph.links.size).toBe(0)
expect(graph.floatingLinks.size).toBe(1)
expect(graph.reroutes.size).toBe(1)
expect(graph.reroutes.values().next().value!.floating).not.toBeUndefined()
})
test('Reroutes and branches should be retained when the input node is removed', ({
expect,
floatingBranchGraph: graph
}) => {
expect(graph.nodes.length).toBe(3)
graph.remove(graph.nodes[2])
expect(graph.nodes.length).toBe(2)
expect(graph.links.size).toBe(1)
expect(graph.floatingLinks.size).toBe(1)
expect(graph.reroutes.size).toBe(4)
graph.remove(graph.nodes[1])
expect(graph.nodes.length).toBe(1)
expect(graph.links.size).toBe(0)
expect(graph.floatingLinks.size).toBe(2)
expect(graph.reroutes.size).toBe(4)
})
test('Floating reroutes should be removed when neither input nor output is connected', ({
expect,
floatingBranchGraph: graph
}) => {
// Remove output node
graph.remove(graph.nodes[0])
expect(graph.nodes.length).toBe(2)
expect(graph.links.size).toBe(0)
expect(graph.floatingLinks.size).toBe(2)
// The original floating reroute should be removed
expect(graph.reroutes.size).toBe(3)
graph.remove(graph.nodes[0])
expect(graph.nodes.length).toBe(1)
expect(graph.links.size).toBe(0)
expect(graph.floatingLinks.size).toBe(1)
expect(graph.reroutes.size).toBe(3)
graph.remove(graph.nodes[0])
expect(graph.nodes.length).toBe(0)
expect(graph.links.size).toBe(0)
expect(graph.floatingLinks.size).toBe(0)
expect(graph.reroutes.size).toBe(0)
})
})
describe('Graph Clearing and Callbacks', () => {
test('clear() calls both node.onRemoved() and graph.onNodeRemoved()', ({
expect
}) => {
const graph = new LGraph()
// Create test nodes with onRemoved callbacks
const node1 = new LGraphNode('TestNode1')
const node2 = new LGraphNode('TestNode2')
// Add nodes to graph
graph.add(node1)
graph.add(node2)
// Track callback invocations
const nodeRemovedCallbacks = new Set<string>()
const graphRemovedCallbacks = new Set<string>()
// Set up node.onRemoved() callbacks
node1.onRemoved = () => {
nodeRemovedCallbacks.add(String(node1.id))
}
node2.onRemoved = () => {
nodeRemovedCallbacks.add(String(node2.id))
}
// Set up graph.onNodeRemoved() callback
graph.onNodeRemoved = (node) => {
graphRemovedCallbacks.add(String(node.id))
}
// Verify nodes are in graph before clearing
expect(graph.nodes.length).toBe(2)
// Clear the graph
graph.clear()
// Verify both types of callbacks were called
expect(nodeRemovedCallbacks).toContain(String(node1.id))
expect(nodeRemovedCallbacks).toContain(String(node2.id))
expect(graphRemovedCallbacks).toContain(String(node1.id))
expect(graphRemovedCallbacks).toContain(String(node2.id))
// Verify nodes were actually removed
expect(graph.nodes.length).toBe(0)
})
})
describe('Legacy LGraph Compatibility Layer', () => {
test('can be extended via prototype', ({ expect, minimalGraph }) => {
// @ts-expect-error Should always be an error.
LGraph.prototype.newMethod = function () {
return 'New method added via prototype'
}
// @ts-expect-error Should always be an error.
expect(minimalGraph.newMethod()).toBe('New method added via prototype')
})
test('is correctly assigned to LiteGraph', ({ expect }) => {
expect(LiteGraph.LGraph).toBe(LGraph)
})
})