Some checks failed
Deploy analytics worker / Deploy analytics worker to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
i18n upload strings / Upload latest strings (push) Failing after 1s
Deploy bemo / Deploy bemo to ${{ (github.ref == 'refs/heads/bemo-production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
Deploy grafana resources / ${{ github.event_name == 'push' && 'Deploy grafana resources' || 'Validate grafana resources (dry run)' }} (push) Failing after 0s
End to end tests (dotcom) / Check for relevant changes (push) Failing after 0s
End to end tests (examples) / Check for relevant changes (push) Failing after 0s
End to end tests (mermaid readability) / Check for relevant changes (push) Failing after 1s
End to end tests (perf) / Check for relevant changes (push) Failing after 0s
Publish editor extensions / Publish editor extensions (push) Failing after 1s
Publish SDK packages / Remove the publish-packages label (push) Has been skipped
Checks / Tests & checks (push) Has been cancelled
Checks / Build all projects (push) Has been cancelled
Deploy templates / Deploy templates (push) Has been cancelled
End to end tests (dotcom) / End to end tests (dotcom) (push) Has been cancelled
End to end tests (mermaid readability) / End to end tests (mermaid readability) (push) Has been cancelled
End to end tests (perf) / End to end tests (perf) (push) Has been cancelled
Deploy .com / Deploy dotcom to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Has been cancelled
End to end tests (examples) / End to end tests (examples) (push) Has been cancelled
Publish SDK packages / Publish SDK packages (push) Has been cancelled
Publish SDK packages / Tell user released version (push) Has been cancelled
Publish SDK packages / Publishes code templates to separate repositories (push) Has been cancelled
Publish SDK packages / Deploys the template demos with the new SDK version (push) Has been cancelled
245 lines
6.2 KiB
TypeScript
245 lines
6.2 KiB
TypeScript
import { PageRecordType, TLStore, createShapeId } from '@tldraw/tlschema'
|
|
import { IndexKey } from '@tldraw/utils'
|
|
import { Editor } from '../editor/Editor'
|
|
import { Box } from '../primitives/Box'
|
|
import { createTLStore } from './createTLStore'
|
|
import { TLEditorSnapshot, getSnapshot, loadSnapshot } from './TLEditorSnapshot'
|
|
|
|
const createEditor = (store: TLStore) => {
|
|
return new Editor({
|
|
store,
|
|
bindingUtils: [],
|
|
shapeUtils: [],
|
|
getContainer: () => document.createElement('div'),
|
|
tools: [],
|
|
})
|
|
}
|
|
|
|
describe('getSnapshot', () => {
|
|
it('should return a TLEditorSnapshot', () => {
|
|
const store = createTLStore({})
|
|
store.ensureStoreIsUsable()
|
|
const snapshot = getSnapshot(store)
|
|
expect(snapshot).toMatchObject({
|
|
document: {
|
|
schema: {},
|
|
store: {
|
|
'document:document': {},
|
|
'page:page': {},
|
|
},
|
|
},
|
|
session: {
|
|
currentPageId: 'page:page',
|
|
exportBackground: true,
|
|
isDebugMode: false,
|
|
isFocusMode: false,
|
|
isGridMode: false,
|
|
isToolLocked: false,
|
|
pageStates: [
|
|
{
|
|
camera: { x: 0, y: 0, z: 1 },
|
|
focusedGroupId: null,
|
|
pageId: 'page:page',
|
|
selectedShapeIds: [],
|
|
},
|
|
],
|
|
version: 0,
|
|
},
|
|
})
|
|
|
|
const editor = createEditor(store)
|
|
|
|
editor.updateInstanceState({ isDebugMode: true })
|
|
editor.createPage({ id: PageRecordType.createId('page2') })
|
|
editor.setCurrentPage(PageRecordType.createId('page2'))
|
|
|
|
const snapshot2 = getSnapshot(store)
|
|
expect(snapshot2).toMatchObject({
|
|
document: {
|
|
schema: {},
|
|
store: {
|
|
'document:document': {},
|
|
'page:page': {},
|
|
'page:page2': {},
|
|
},
|
|
},
|
|
session: {
|
|
currentPageId: 'page:page2',
|
|
isDebugMode: true,
|
|
pageStates: [{}, {}],
|
|
version: 0,
|
|
},
|
|
})
|
|
})
|
|
})
|
|
|
|
const page2Id = PageRecordType.createId('page2')
|
|
function addPage2(snapshot: TLEditorSnapshot) {
|
|
// sneakily add a page
|
|
snapshot = structuredClone(snapshot)
|
|
snapshot.document.store[page2Id] = PageRecordType.create({
|
|
id: page2Id,
|
|
name: 'my lovely page',
|
|
index: 'a4' as IndexKey,
|
|
})
|
|
|
|
// and set the current page id
|
|
snapshot.session.currentPageId = page2Id
|
|
return snapshot
|
|
}
|
|
|
|
describe('loadSnapshot', () => {
|
|
it('loads a snapshot into the store', () => {
|
|
const store = createTLStore({})
|
|
const editor = createEditor(store)
|
|
|
|
const snapshot = addPage2(getSnapshot(store))
|
|
|
|
loadSnapshot(store, snapshot)
|
|
|
|
expect(
|
|
editor
|
|
.getPages()
|
|
.map((p) => p.id)
|
|
.sort()
|
|
).toEqual(['page:page', 'page:page2'])
|
|
expect(editor.getCurrentPageId()).toBe(page2Id)
|
|
})
|
|
|
|
it('does not overwrite changes to the viewport page bounds', () => {
|
|
const store = createTLStore({})
|
|
const editor = createEditor(store)
|
|
|
|
const snapshot = addPage2(getSnapshot(store))
|
|
|
|
expect(editor.getViewportScreenBounds()).not.toEqual(new Box(0, 0, 100, 100))
|
|
editor.updateViewportScreenBounds(new Box(0, 0, 100, 100))
|
|
expect(editor.getViewportScreenBounds()).toEqual(new Box(0, 0, 100, 100))
|
|
|
|
loadSnapshot(store, snapshot)
|
|
|
|
expect(editor.getViewportScreenBounds()).toEqual(new Box(0, 0, 100, 100))
|
|
})
|
|
|
|
it('works with just the document bits (1)', () => {
|
|
const store = createTLStore({})
|
|
const editor = createEditor(store)
|
|
|
|
const snapshot = addPage2(getSnapshot(store))
|
|
|
|
loadSnapshot(store, snapshot.document)
|
|
|
|
expect(
|
|
editor
|
|
.getPages()
|
|
.map((p) => p.id)
|
|
.sort()
|
|
).toEqual(['page:page', 'page:page2'])
|
|
expect(editor.getCurrentPageId()).toBe('page:page')
|
|
})
|
|
|
|
it('works with just the document bits (2)', () => {
|
|
const store = createTLStore({})
|
|
const editor = createEditor(store)
|
|
|
|
const snapshot = addPage2(getSnapshot(store))
|
|
|
|
loadSnapshot(store, { document: snapshot.document })
|
|
|
|
expect(
|
|
editor
|
|
.getPages()
|
|
.map((p) => p.id)
|
|
.sort()
|
|
).toEqual(['page:page', 'page:page2'])
|
|
expect(editor.getCurrentPageId()).toBe('page:page')
|
|
})
|
|
|
|
it('allows loading the session bits later', () => {
|
|
const store = createTLStore({})
|
|
const editor = createEditor(store)
|
|
|
|
const snapshot = addPage2(getSnapshot(store))
|
|
|
|
loadSnapshot(store, snapshot.document)
|
|
|
|
expect(
|
|
editor
|
|
.getPages()
|
|
.map((p) => p.id)
|
|
.sort()
|
|
).toEqual(['page:page', 'page:page2'])
|
|
expect(editor.getCurrentPageId()).toBe('page:page')
|
|
|
|
loadSnapshot(store, { session: snapshot.session })
|
|
expect(editor.getCurrentPageId()).toBe('page:page2')
|
|
})
|
|
|
|
it('preserves session stuff if no session snapshot is provided', () => {
|
|
const store = createTLStore({})
|
|
const editor = createEditor(store)
|
|
|
|
const snapshot = getSnapshot(store)
|
|
|
|
expect(editor.getCamera()).toMatchObject({ x: 0, y: 0, z: 1 })
|
|
|
|
editor.setCamera({ x: 1, y: 2, z: 3 })
|
|
|
|
loadSnapshot(store, snapshot.document)
|
|
|
|
expect(editor.getCamera()).toMatchObject({ x: 1, y: 2, z: 3 })
|
|
|
|
loadSnapshot(store, { document: snapshot.document })
|
|
|
|
expect(editor.getCamera()).toMatchObject({ x: 1, y: 2, z: 3 })
|
|
|
|
loadSnapshot(store, snapshot)
|
|
|
|
expect(editor.getCamera()).toMatchObject({ x: 0, y: 0, z: 1 })
|
|
})
|
|
|
|
it('preserves session stuff if only a partial session snapshot is provided', () => {
|
|
const store = createTLStore({})
|
|
const editor = createEditor(store)
|
|
const page1Id = editor.getCurrentPageId()
|
|
|
|
const page2Id = PageRecordType.createId('page2')
|
|
editor.createPage({ id: page2Id })
|
|
editor.setCurrentPage(PageRecordType.createId('page2'))
|
|
|
|
const snapshot = getSnapshot(store)
|
|
|
|
delete snapshot.session.pageStates
|
|
|
|
editor.setCurrentPage(page1Id)
|
|
editor.setCamera({ x: 1, y: 2, z: 3 })
|
|
|
|
loadSnapshot(store, snapshot)
|
|
|
|
// the page should have switched back to page2 with the default camera
|
|
expect(editor.getCurrentPageId()).toBe(page2Id)
|
|
expect(editor.getCamera()).toMatchObject({ x: 0, y: 0, z: 1 })
|
|
|
|
// and because we updated the page1 camera after the snapshot was taken, it should still be the same
|
|
editor.setCurrentPage(page1Id)
|
|
expect(editor.getCamera()).toMatchObject({ x: 1, y: 2, z: 3 })
|
|
})
|
|
|
|
it('cleans up references to missing shapes from page state', () => {
|
|
const store = createTLStore({})
|
|
const editor = createEditor(store)
|
|
|
|
const shapeA = createShapeId('a')
|
|
editor.createShape({ type: 'group', id: shapeA })
|
|
|
|
const snapshot = getSnapshot(store)
|
|
|
|
const shapeB = createShapeId('b')
|
|
editor.createShape({ type: 'group', id: shapeB }).select(shapeB, shapeA)
|
|
|
|
loadSnapshot(store, snapshot.document)
|
|
|
|
expect(editor.getCurrentPageState().selectedShapeIds).toEqual([shapeA])
|
|
})
|
|
})
|