A common, sweet, crunchy fruit, usually green or yellow in color.
A fairly common, sweet, usually green fruit, usually softer than Apples.
A long, curved, yellow fruit, with a fairly gentle flavor.
`}
css={`
#self {
background-color: lightcoral;
}
#self custom-element {
background-color: plum;
}
#self .selected {
font-size: 20px;
}
`}
/>
),
},
Embeds: {
Video: ,
Image: ,
Background: (
),
},
},
Arrows: {
'': {
Arrow1: (
),
Arrow2: (
),
Arrow3: (
),
Arrow4: (
),
Arrow5: (
),
},
},
Regressions: {
'#5020': {
'scaled text within a frame': (
),
},
'#6391': {
'Circles at 45deg from each other': (
<>
>
),
},
},
'Weird elbow arrows': {
'Small segments, contained': {
A: (
<>
>
),
B: (
<>
>
),
'Exact match': (
<>
>
),
C: (
<>
>
),
D: (
<>
>
),
},
'Draw shapes': {
'Hey, near': (
<>
{heyDrawShape}
>
),
'Hey, far': (
<>
{heyDrawShape}
>
),
'Hey, within': (
<>
{heyDrawShape}
>
),
'Convex, far': (
<>
{convexDrawShape}
>
),
'Convex, edge': (
<>
{convexDrawShape}
>
),
},
'Self-bound': {
'Draw shape,\nsame-edge': (
<>
{convexDrawShape}
>
),
'Box,\nsame edge': (
<>
>
),
'Triangle,\nopposites': (
<>
>
),
Outside: (
<>
>
),
},
'Regressions 1': {
'ENG-3332 ✅': (
<>
>
),
'ENG-3333 🚫': (
<>
>
),
'ENG-3335 🚫': (
<>
>
),
'ENG-3336 ✅': (
// this one isn't actually an elbow arrow issue but was introduced by elbow arrows
// work so is still included here.
<>
>
),
'ENG-3342 ✅': (
<>
>
),
},
'Regressions 2': {
'ENG-3366 ✅': (
<>
>
),
'ENG-3371 ✅': (
<>
>
),
'ENG-3375 ✅': (
<>
{heyDrawShape}
>
),
},
},
}
interface SnapshotWithoutJsx {
[row: string]: {
[testCase: string]: { shapes: TLShapePartial[]; assets: TLAsset[]; bindings: TLBindingCreate[] }
}
}
test.describe('Export snapshots', () => {
const snapshotsToTest = Object.entries(snapshots)
test.beforeEach(async ({ page, context, api }) => {
const url = page.url()
if (!url.includes('end-to-end')) {
await setup({ page, context } as any)
} else {
await hardResetEditor(page)
}
// These snapshots lay shapes out by their measured bounds, and text is measured from
// the loaded font - so load the fonts before anything is measured. Otherwise a shape
// can be measured with fallback-font metrics, which shifts the layout and the export's
// size and makes the screenshot diff flaky.
await api.preloadFonts()
})
for (const [name, snapshotWithJsx] of snapshotsToTest) {
for (const colorScheme of ['light', 'dark'] as const) {
test(`${name} (${colorScheme})`, async ({ page, api }) => {
nextNanoId = 0
const snapshot: SnapshotWithoutJsx = mapObjectMapValues(snapshotWithJsx, (i, row) =>
mapObjectMapValues(row, (j, testCase) => {
const { shapes, assets, bindings } = shapesFromJsx(testCase, `${i}-${j}`)
return { shapes, assets, bindings }
})
)
await page.evaluate(
({
colorScheme,
name,
snapshot,
}: {
colorScheme: 'light' | 'dark'
name: string
snapshot: SnapshotWithoutJsx
}) => {
editor.user.updateUserPreferences({ colorScheme })
editor
.updateInstanceState({ exportBackground: true })
.selectAll()
.deleteShapes(editor.getSelectedShapeIds())
const titleId = tldrawApi.createShapeId()
editor.createShape({
id: titleId,
type: 'text',
x: 0,
y: 0,
props: { richText: tldrawApi.toRichText(name), font: 'mono', size: 'xl' },
})
let y = editor.getShapePageBounds(titleId)!.maxY + 30
for (const [rowName, testCases] of Object.entries(snapshot)) {
const rowTitleId = tldrawApi.createShapeId()
editor.createShape({
id: rowTitleId,
type: 'text',
x: 0,
y,
props: { richText: tldrawApi.toRichText(rowName), font: 'mono', size: 'm' },
})
y = editor.getShapePageBounds(rowTitleId)!.maxY + 20
let x = 0
let bottom = y
for (const [testCaseName, { shapes, assets, bindings }] of Object.entries(
testCases
)) {
const testCaseTitleId = tldrawApi.createShapeId()
editor.createShape({
id: testCaseTitleId,
type: 'text',
x,
y,
props: {
richText: tldrawApi.toRichText(testCaseName),
font: 'mono',
size: 's',
},
})
const testCastTitleBounds = editor.getShapePageBounds(testCaseTitleId)!
editor.createAssets(assets)
editor.createShapes(shapes)
editor.createBindings(bindings)
const topLevelShapeIds = shapes
.filter((shape) => !shape.parentId)
.map((shape) => shape.id)
editor.setSelectedShapes(topLevelShapeIds)
let bounds = editor.getSelectionPageBounds()!
editor.nudgeShapes(topLevelShapeIds, {
x: x - bounds.minX,
y: testCastTitleBounds.maxY + 25 - bounds.minY,
})
bounds = editor.getSelectionPageBounds()!
x = Math.max(testCastTitleBounds.maxX, bounds.maxX) + 60
bottom = Math.max(bottom, bounds.maxY)
}
y = bottom + 40
}
tldrawApi.markAllArrowBindings()
editor.selectAll()
},
{ colorScheme, name, snapshot } as any
)
await snapshotTest(page, api)
})
}
}
async function snapshotTest(page: Page, api: ApiFixture) {
const downloadAndSnapshot = page.waitForEvent('download').then(async (download) => {
const path = (await download.path()) as string
assert(path)
await rename(path, path + '.svg')
await writeFile(
path + '.html',
`
`,
'utf-8'
)
await page.goto(`file://${path}.html`)
const clip = await page.$eval('img', (img) => img.getBoundingClientRect())
await expect(page).toHaveScreenshot({
omitBackground: true,
clip,
fullPage: true,
})
})
await api.exportAsSvg()
await downloadAndSnapshot
}
})