136 lines
4.6 KiB
TypeScript
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'
|
|
})
|
|
})
|
|
})
|