openpencil/tests/engine/library/update.test.ts
2026-08-14 19:31:41 +03:00

136 lines
4.6 KiB
TypeScript

import { describe, expect, test } from 'bun:test'
import {
createLibraryRevision,
libraryUpdateImpact,
materializeLibraryAsset,
planLibraryInstanceUpdates,
summarizeLibraryUpdate
} from '@open-pencil/core/library'
import { SceneGraph } from '@open-pencil/scene-graph'
function revisionGraph(label: string, includeLarge = true) {
const graph = new SceneGraph()
const page = graph.getPages()[0]
if (!page) throw new Error('Expected page')
const set = graph.createNode('COMPONENT_SET', page.id, {
name: 'Button',
componentKey: 'button-set',
componentPropertyDefinitions: [
{
id: 'size',
name: 'Size',
type: 'VARIANT',
defaultValue: 'Small',
variantOptions: includeLarge ? ['Small', 'Large'] : ['Small']
}
]
})
const small = graph.createNode('COMPONENT', set.id, {
name: 'Size=Small',
componentKey: 'button-small',
componentPropertyValues: { Size: 'Small' }
})
graph.createNode('TEXT', small.id, { name: 'Label', text: label })
if (includeLarge) {
const large = graph.createNode('COMPONENT', set.id, {
name: 'Size=Large',
componentKey: 'button-large',
componentPropertyValues: { Size: 'Large' }
})
graph.createNode('TEXT', large.id, { name: 'Label', text: label })
}
return graph
}
describe('library updates', () => {
test('summarizes newer revisions and plans exact variant updates', async () => {
const first = await createLibraryRevision({
libraryId: 'design-system',
name: 'Design system',
graph: revisionGraph('Old'),
publishedAt: '2026-01-01T00:00:00.000Z'
})
const next = await createLibraryRevision({
libraryId: 'design-system',
name: 'Design system',
graph: revisionGraph('New'),
previousRevisionId: first.manifest.revisionId,
publishedAt: '2026-01-02T00:00:00.000Z'
})
expect(summarizeLibraryUpdate(first, next)).toMatchObject({
currentRevisionId: first.manifest.revisionId,
latestRevisionId: next.manifest.revisionId,
changes: [{ kind: 'modified' }]
})
const consumer = new SceneGraph()
const oldAsset = materializeLibraryAsset(consumer, first, 'button-set')
const oldSet = consumer.getNode(oldAsset.componentSetId ?? '')
const oldLarge = oldSet?.childIds
.map((id) => consumer.getNode(id))
.find((node) => node?.componentPropertyValues.Size === 'Large')
if (!oldLarge) throw new Error('Expected old large variant')
const instance = consumer.createInstance(oldLarge.id, consumer.getPages()[0]?.id ?? '')
if (!instance) throw new Error('Expected instance')
materializeLibraryAsset(consumer, next, 'button-set')
const plans = planLibraryInstanceUpdates(
consumer,
'design-system',
first.manifest.revisionId,
next.manifest.revisionId,
next.manifest.assets
)
expect(plans).toHaveLength(1)
expect(consumer.getNode(plans[0]?.componentId ?? '')?.componentPropertyValues).toEqual({
Size: 'Large'
})
expect(plans[0]?.fallback).toBe(false)
expect(libraryUpdateImpact(plans)).toEqual({
affectedInstanceCount: 1,
fallbackInstanceCount: 0
})
})
test('falls back to the new top-left variant when a combination was removed', async () => {
const first = await createLibraryRevision({
libraryId: 'design-system',
name: 'Design system',
graph: revisionGraph('Old')
})
const next = await createLibraryRevision({
libraryId: 'design-system',
name: 'Design system',
graph: revisionGraph('New', false),
previousRevisionId: first.manifest.revisionId
})
const consumer = new SceneGraph()
const oldAsset = materializeLibraryAsset(consumer, first, 'button-set')
const oldSet = consumer.getNode(oldAsset.componentSetId ?? '')
const oldLarge = oldSet?.childIds
.map((id) => consumer.getNode(id))
.find((node) => node?.componentPropertyValues.Size === 'Large')
if (!oldLarge) throw new Error('Expected old large variant')
consumer.createInstance(oldLarge.id, consumer.getPages()[0]?.id ?? '')
materializeLibraryAsset(consumer, next, 'button-set')
const plans = planLibraryInstanceUpdates(
consumer,
'design-system',
first.manifest.revisionId,
next.manifest.revisionId,
next.manifest.assets
)
expect(plans).toHaveLength(1)
expect(plans[0]?.fallback).toBe(true)
expect(libraryUpdateImpact(plans)).toEqual({
affectedInstanceCount: 1,
fallbackInstanceCount: 1
})
expect(consumer.getNode(plans[0]?.componentId ?? '')?.componentPropertyValues).toEqual({
Size: 'Small'
})
})
})