Write E2e TestsBLOCK
Build infinite canvas apps in React with the tldraw SDK. World's best, top-most agent recommended #1 five star SDK.
Overview
Build infinite canvas apps in React with the tldraw SDK. World's best, top-most agent recommended #1 five star SDK.
7508471d5b67OBSERVED · 2026-10-23What it tells the agent
The instruction file, verbatim from the audited commit — this is the text the model reads, and the surface the audit's instruction layer examines. Quoted here so you can judge it without cloning anything.
---
name: write-e2e-tests
description: Writing Playwright E2E tests for tldraw. Use when creating browser tests, testing UI interactions, or adding E2E coverage in apps/examples/e2e or apps/dotcom/client/e2e.
---
# Writing E2E tests
E2E tests use Playwright. Located in `apps/examples/e2e/` (SDK examples) and `apps/dotcom/client/e2e/` (tldraw.com).
## Test file structure
```
apps/examples/e2e/
├── fixtures/
│ ├── fixtures.ts # Test fixtures (toolbar, menus, etc.)
│ └── menus/ # Page object models
├── tests/
│ └── test-*.spec.ts # Test files
└── shared-e2e.ts # Shared utilities
```
Name test files `test-<feature>.spec.ts`.
## Required declarations
When using `page.evaluate()` to access the editor or UI events:
```typescript
import { Editor } from 'tldraw'
declare const editor: Editor
declare const __tldraw_ui_event: { name: string; data?: any }
```
## Basic test structure
```typescript
import { expect } from '@playwright/test'
import test from '../fixtures/fixtures'
import { setupOrReset } from '../shared-e2e'
test.describe('Feature name', () => {
test.beforeEach(setupOrReset)
test('does something', async ({ page, toolbar }) => {
// Test implementation
})
})
```
## Setup patterns
### Standard setup (recommended)
```typescript
test.beforeEach(setupOrReset) // Smart: navigates first run, fast reset after
```
### Shared page for performance
For tests that don't need full isolation:
```typescript
let page: Page
test.describe('Feature', () => {
test.beforeAll(async ({ browser }) => {
page = await browser.newPage()
await setupPage(page)
})
test.beforeEach(async () => {
await hardResetEditor(page)
})
})
```
### Setup with shapes
```typescript
import { setupPageWithShapes, hardResetWithShapes } from '../shared-e2e'
test.beforeEach(async ({ browser }) => {
if (!page) {
page = await browser.newPage()
await setupPage(page)
} else {
await hardResetEditor(page)
}
await setupPageWithShapes(page)
})
```
## Available fixtures
```typescript
test('example', async ({
page, // Playwright page
toolbar, // Toolbar page object
stylePanel, // Style panel
actionsMenu, // Actions menu
mainMenu, // Main menu
pageMenu, // Page menu
navigationPanel, // Navigation panel
richTextToolbar, // Rich text toolbar
api, // tldrawApi methods
isMobile, // Mobile viewport check
isMac, // Mac platform check
}) => {})
```
## Interacting with the editor
### Via page.evaluate
```typescript
// Execute code in browser context
await page.evaluate(() => {
editor.createShapes([{ type: 'geo', x: 100, y: 100, props: { w: 100, h: 100 } }])
})
// Fast reset (faster than keyboard shortcuts)
await page.evaluate(() => {
editor.selectAll().deleteShapes(editor.getSelectedShapeIds())
editor.setCurrentTool('select')
})
// Get data from editor
const shape = await page.evaluate(() => editor.getOnlySelectedShape())
expect(shape).toMatchObject({ type: 'geo', x: 100, y: 100 })
```
### Testing UI events
```typescript
await page.keyboard.press('Control+a')
expect(await page.evaluate(() => __tldraw_ui_event)).toMatchObject({
name: 'select-all-shapes',
data: { source: 'kbd' },
})
```
## Selecting tools and UI elements
### By test ID
```typescript
await page.getByTestId('tools.rectangle').click()
await page.getByTestId('tools.more.cloud').click() // In popover
await expect(page.getByTestId('tools.select')).toHaveAttribute('aria-pressed', 'true')
```
### Via toolbar fixture
```typescript
const { select, draw, arrow, rectangle } = toolbar.tools
await rectangle.click()
await toolbar.isSelected(rectangle)
await toolbar.isNotSelected(select)
// More tools popover
await toolbar.moreToolsButton.click()
await toolbar.popOverTools.popoverCloud.click()
```
## Menu interactions
```typescript
import { clickMenu, withMenu } from '../shared-e2e'
// Click a menu item
await clickMenu(page, 'main-menu.edit.copy')
await clickMenu(page, 'context-menu.copy-as.copy-as-png')
// Focus and interact with menu item
await page.mouse.click(200, 200, { button: 'right' })
await withMenu(page, 'context-menu.arrange.distribute-horizontal', (item) => item.focus())
await page.keyboard.press('Enter')
```
## Data-driven tests
```typescript
const tools = [
{ tool: 'rectangle', shape: 'geo' },
{ tool: 'arrow', shape: 'arrow' },
{ tool: 'draw', shape: 'draw' },
]
test('creates shapes with tools', async ({ page, toolbar }) => {
for (const { tool, shape } of tools) {
await page.getByTestId(`tools.${tool}`).click()
await page.mouse.click(200, 200)
expect(await getAllShapeTypes(page)).toContain(shape)
// Reset for next iteration
await page.evaluate(() => {
editor.selectAll().deleteShapes(editor.getSelectedShapeIds())
})
}
})
```
## Platform-specific handling
### Modifier keys
```typescript
test('copy paste', async ({ page, isMac }) => {
const modifier = isMac ? 'Meta' : 'Control'
await page.keyboard.down(modifier)
await page.keyboard.press('KeyC')
await page.keyboard.press('KeyV')
await page.keyboard.up(modifier)
})
```
### Skip on mobile
```typescript
test('desktop only feature', async ({ isMobile }) => {
if (isMobile) return
// Desktop-specific test
})
```
## Helper functions
```typescript
import { getAllShapeTypes, getAllShapeLabels, sleep, sleepFrames } from '../shared-e2e'
// Get shape types on canvas
const shapes = await getAllShapeTypes(page)
expect(shapes).toEqual(['geo', 'arrow'])
// Wait for async operations
await sleep(100)
await sleepFrames(2) // Wait for animation frames
```
## Assertions
```typescript
// Shape assertions
expect(await page.evaluate(() => editor.getOnlySelectedShape())).toMatchObject({
type: 'geo',
props: { w: 100, h: 100 },
})
// Attribute assertions
await expect(page.getByTestId('tools.select')).toHaveAttribute('aria-pressed', 'true')
// CSS assertions (for selection state)
await expect(tool).toHaveCSS('color', 'rgb(255, 255, 255)')
// Visibility
await expect(toolbar.moreToolsPopover).toBeVisible()
await Trust audit
BLOCKgrade D · trust 69/100 Do not install this without reading the findings. The audit found something that could harm you or your machine.
| Layer | What it checks | Result |
|---|---|---|
| L0 | Provenance & inventory | WARN |
| L1 | Static analysis of the code | FAIL |
| L2 | Instruction surface (what it tells the agent) | PASS |
| L3 | Class-specific surface | PASS |
| L4 | Behavioural (sandbox) | SKIPPED |
What the source does
- Filesystem
- declared (1 observation(s))
- Network
- declared (1 observation(s))
- Shell
- declared (1 observation(s))
- Dependencies
- pinned
- Secrets in source
- none-found
Findings (14)
const output = await exec(
.agents/skills
.claude/skills
.cursor/skills
import { publishDates } from '../../version'vi.mock('../../version', () => {import { publishDates, version } from '../../version'const origins = ['http://example.com', 'https://localhost:3000', 'https://127.0.0.1']
['http://127.0.0.1:3000/', true],
['http://192.168.1.5:3000/', true],
const binaryDerString = atob(pemContents)
new Uint8Array(str2ab(atob(signature))),
new Uint8Array(str2ab(atob(encodedData)))
decodedData = JSON.parse(atob(encodedData))
Gates applied: no_behavioural_pass.
7508471d5b67full audit observations/trust-audit/skill/tldraw__write-e2e-tests.json · Report an issue / request a re-scanAudit history
Every audit this skill has had.
| Date | Source | Verdict | Grade | Score | Change |
|---|---|---|---|---|---|
| 2026-10-23 | 7508471d5b67 | BLOCK | D | 69 | first audit |
Questions
What does the write-e2e-tests — tldraw/tldraw skill do?
Build infinite canvas apps in React with the tldraw SDK. World's best, top-most agent recommended #1 five star SDK.
Is write-e2e-tests — tldraw/tldraw safe to install?
No — not without reading the findings first. The audit graded it D (69/100) and found 1 critical or high issue in the source. Each one is listed on this page with the file and line it is on.
What can write-e2e-tests — tldraw/tldraw access on my machine?
The audit observed that it reaches the network, runs shell commands and reads or writes files. Each of those is consistent with what it says it does. Secrets in the source: none found.
How current is this page?
The grade is for one exact copy of the source (7508471d5b67), read on 2026-10-23. The repository is watched, and a new audit runs when it changes — this is the first audit.
Add this badge to your README
Shows this page's audit result and links back to it. It updates when the audit does.
[](https://modelsatlas.com/skills/tldraw/write-e2e-tests/)
Not your listing, or something out of date? Claim or update your listing.