Adds react tests, build tsconfigs

This commit is contained in:
Steve Ruiz 2021-08-14 16:46:21 +01:00
parent af159655e3
commit b8f410b752
82 changed files with 588 additions and 165 deletions

View file

@ -28,18 +28,20 @@
"@babel/plugin-syntax-import-meta": "^7.10.4",
"@babel/preset-react": "^7.14.5",
"@babel/preset-typescript": "^7.15.0",
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^12.0.0",
"@types/jest": "^26.0.24",
"@types/node": "^15.0.1",
"@types/react-dom": "^17.0.9",
"@types/react": "^17.0.16",
"@types/react-dom": "^17.0.9",
"@typescript-eslint/eslint-plugin": "^4.19.0",
"@typescript-eslint/parser": "^4.19.0",
"babel-jest": "^27.0.6",
"esbuild": "^0.11.11",
"jest": "^27.0.6",
"lerna": "^3.15.0",
"react-dom": "^17.0.2",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"ts-jest": "^27.0.4",
"tslib": "^2.3.0",
"typescript": "^4.3.5"
@ -53,6 +55,9 @@
},
"jest": {
"preset": "ts-jest",
"setupFilesAfterEnv": [
"<rootDir>/setupTests.ts"
],
"transform": {
"^.+\\.(tsx|jsx|ts|js)?$": "ts-jest"
},
@ -84,7 +89,8 @@
"testEnvironment": "jsdom",
"modulePathIgnorePatterns": [
"<rootDir>/packages/core/build/",
"<rootDir>/packages/tldraw/build/"
"<rootDir>/packages/tldraw/build/",
"<rootDir>/packages/tldraw/test-utils/"
],
"moduleNameMapper": {
"@tldraw/core": "<rootDir>/packages/core/src",

View file

@ -15,7 +15,7 @@
"types": "./dist/types/index.d.ts",
"scripts": {
"start": "node scripts/dev & tsc --watch --incremental --emitDeclarationOnly --declarationMap --outDir dist/types",
"build": "yarn clean && node scripts/build && tsc --emitDeclarationOnly --outDir dist/types",
"build": "yarn clean && node scripts/build && tsc --project tsconfig.build.json --emitDeclarationOnly --outDir dist/types",
"lint": "eslint src/ --ext .ts,.tsx",
"clean": "rm -rf dist",
"ts-node": "ts-node",
@ -49,4 +49,4 @@
"react-use-gesture": "^9.1.3"
},
"gitHead": "a7dac0f83ad998e205c2aab58182cb4ba4e099a6"
}
}

View file

@ -15,7 +15,7 @@ async function main() {
target: 'es6',
jsxFactory: 'React.createElement',
jsxFragment: 'React.Fragment',
tsconfig: './tsconfig.json',
tsconfig: './tsconfig.build.json',
external: ['react', 'react-dom'],
})

View file

@ -0,0 +1,11 @@
import * as React from 'react'
import { renderWithSvg } from '+test-utils'
import { Binding } from './binding'
jest.spyOn(console, 'error').mockImplementation(() => void null)
describe('binding', () => {
test('mounts component', () => {
renderWithSvg(<Binding point={[0, 0]} type={'anchor'} />)
})
})

View file

@ -1,3 +1,4 @@
import * as React from 'react'
import type { TLBinding } from '+types'
interface BindingProps {

View file

@ -0,0 +1,16 @@
import * as React from 'react'
import { renderWithSvg } from '+test-utils'
import { Bounds } from './bounds'
describe('bounds', () => {
test('mounts component', () => {
renderWithSvg(
<Bounds
zoom={1}
bounds={{ minX: 0, minY: 0, maxX: 100, maxY: 100, width: 100, height: 100 }}
rotation={0}
isLocked={false}
/>
)
})
})

View file

@ -0,0 +1,9 @@
import * as React from 'react'
import { renderWithSvg } from '+test-utils'
import { Brush } from './brush'
describe('brush', () => {
test('mounts component', () => {
renderWithSvg(<Brush />)
})
})

View file

@ -0,0 +1,17 @@
import * as React from 'react'
import { mockDocument, renderWithContext } from '+test-utils'
import { Canvas } from './canvas'
describe('page', () => {
test('mounts component', () => {
renderWithContext(
<Canvas
page={mockDocument.page}
pageState={mockDocument.pageState}
hideBounds={false}
hideIndicators={false}
hideHandles={false}
/>
)
})
})

View file

@ -8,10 +8,10 @@ import {
useCameraCss,
} from '+hooks'
import type { TLBinding, TLPage, TLPageState, TLShape } from '+types'
import { ErrorFallback } from './error-fallback'
import { Brush } from './brush'
import { Defs } from './defs'
import { Page } from './page'
import { ErrorFallback } from '+components/error-fallback'
import { Brush } from '+components/brush'
import { Defs } from '+components/defs'
import { Page } from '+components/page'
function resetError() {
void null

View file

@ -0,0 +1 @@
export * from './canvas'

View file

@ -0,0 +1,9 @@
import * as React from 'react'
import { renderWithSvg } from '+test-utils'
import { Defs } from './defs'
describe('defs', () => {
test('mounts component', () => {
renderWithSvg(<Defs zoom={1} />)
})
})

View file

@ -0,0 +1 @@
export * from './defs'

View file

@ -0,0 +1,9 @@
import * as React from 'react'
import { renderWithContext } from '+test-utils'
import { ErrorFallback } from './error-fallback'
describe('error fallback', () => {
test('mounts component', () => {
renderWithContext(<ErrorFallback error={new Error()} resetErrorBoundary={() => void null} />)
})
})

View file

@ -1,5 +1,5 @@
import * as React from 'react'
import { useTLContext } from '../hooks'
import { useTLContext } from '+hooks'
interface ErrorFallbackProps {
error: Error
@ -11,7 +11,6 @@ export const ErrorFallback = React.memo(({ error, resetErrorBoundary }: ErrorFal
React.useEffect(() => {
callbacks.onError?.(error)
console.error(error)
}, [error, resetErrorBoundary, callbacks])
return null

View file

@ -0,0 +1 @@
export * from './error-fallback'

View file

@ -0,0 +1,9 @@
import * as React from 'react'
import { mockUtils, renderWithContext } from '+test-utils'
import { Handles } from './handles'
describe('handles', () => {
test('mounts component', () => {
renderWithContext(<Handles zoom={1} shape={mockUtils.box.create({})} />)
})
})

View file

@ -0,0 +1 @@
export * from './page'

View file

@ -0,0 +1,17 @@
import * as React from 'react'
import { mockDocument, renderWithContext } from '+test-utils'
import { Page } from './page'
describe('page', () => {
test('mounts component', () => {
renderWithContext(
<Page
page={mockDocument.page}
pageState={mockDocument.pageState}
hideBounds={false}
hideIndicators={false}
hideHandles={false}
/>
)
})
})

View file

@ -1,11 +1,11 @@
import * as React from 'react'
import type { TLBinding, TLPage, TLPageState, TLShape } from '+types'
import { useSelection, useShapeTree, useHandles, useRenderOnResize, useTLContext } from '+hooks'
import { Bounds } from './bounds'
import { BoundsBg } from './bounds/bounds-bg'
import { Handles } from './handles'
import { ShapeIndicator } from './shape-indicator'
import { ShapeNode } from './shape'
import { Bounds } from '+components/bounds'
import { BoundsBg } from '+components/bounds/bounds-bg'
import { Handles } from '+components/handles'
import { ShapeNode } from '+components/shape'
import { ShapeIndicator } from '+components/shape-indicator'
interface PageProps<T extends TLShape> {
page: TLPage<T, TLBinding>

View file

@ -0,0 +1 @@
export * from './renderer'

View file

@ -0,0 +1,17 @@
import * as React from 'react'
import { mockDocument } from '+test-utils/mockDocument'
import { mockUtils } from '+test-utils/mockUtils'
import { render } from '@testing-library/react'
import { Renderer } from './renderer'
describe('context menu', () => {
test('mounts component', () => {
render(
<Renderer
shapeUtils={mockUtils}
page={mockDocument.page}
pageState={mockDocument.pageState}
/>
)
})
})

View file

@ -9,9 +9,9 @@ import type {
TLTheme,
TLBounds,
TLBinding,
} from '../types'
import { Canvas } from '../components/canvas'
import { useTLTheme, TLContext } from '../hooks'
} from '../../types'
import { Canvas } from '../canvas'
import { useTLTheme, TLContext } from '../../hooks'
export interface RendererProps<T extends TLShape>
extends Partial<TLSettings>,

View file

@ -0,0 +1 @@
export * from './shape-indicator'

View file

@ -0,0 +1,9 @@
import * as React from 'react'
import { mockUtils, renderWithSvg } from '+test-utils'
import { ShapeIndicator } from './shape-indicator'
describe('shape indicator', () => {
test('mounts component', () => {
renderWithSvg(<ShapeIndicator shape={mockUtils.box.create({})} variant={'selected'} />)
})
})

View file

@ -0,0 +1,17 @@
import * as React from 'react'
import { mockUtils, renderWithSvg } from '+test-utils'
import { Shape } from './shape'
describe('handles', () => {
test('mounts component', () => {
renderWithSvg(
<Shape
shape={mockUtils.box.create({})}
isEditing={false}
isBinding={false}
isDarkMode={false}
isCurrentParent={false}
/>
)
})
})

View file

@ -1,7 +0,0 @@
import { ExampleShape } from './example-shape'
describe('example shape', () => {
it('should create an instance', () => {
expect(new ExampleShape()).toBeTruthy()
})
})

View file

@ -0,0 +1,7 @@
import { Box } from './box'
describe('example shape', () => {
it('should create an instance', () => {
expect(new Box()).toBeTruthy()
})
})

View file

@ -3,36 +3,41 @@ import * as React from 'react'
import { TLShapeUtil, TLShape, TLBounds, TLRenderInfo, TLTransformInfo } from '+types'
import Utils, { Intersect } from '+utils'
export class ExampleShape extends TLShapeUtil<TLShape> {
type = 'shape-type'
export interface BoxShape extends TLShape {
size: number[]
}
export class Box extends TLShapeUtil<BoxShape> {
type = 'box'
defaultProps = {
id: 'example',
type: 'shape-type',
id: 'example1',
type: 'box',
parentId: 'page',
childIndex: 0,
name: 'Example Shape',
point: [0, 0],
size: [100, 100],
rotation: 0,
}
create(props: Partial<TLShape>) {
create(props: Partial<BoxShape>) {
return { ...this.defaultProps, ...props }
}
render(shape: TLShape, info: TLRenderInfo): JSX.Element {
render(shape: BoxShape, info: TLRenderInfo): JSX.Element {
return <rect width={100} height={100} fill="none" stroke="black" />
}
renderIndicator(shape: TLShape) {
renderIndicator(shape: BoxShape) {
return <rect width={100} height={100} />
}
shouldRender(prev: TLShape, next: TLShape): boolean {
shouldRender(prev: BoxShape, next: BoxShape): boolean {
return true
}
getBounds(shape: TLShape): TLBounds {
getBounds(shape: BoxShape): TLBounds {
return Utils.getFromCache(this.boundsCache, shape, () => ({
minX: 0,
minY: 0,
@ -43,19 +48,19 @@ export class ExampleShape extends TLShapeUtil<TLShape> {
}))
}
getRotatedBounds(shape: TLShape) {
getRotatedBounds(shape: BoxShape) {
return Utils.getBoundsFromPoints(Utils.getRotatedCorners(this.getBounds(shape), shape.rotation))
}
getCenter(shape: TLShape): number[] {
getCenter(shape: BoxShape): number[] {
return Utils.getBoundsCenter(this.getBounds(shape))
}
hitTest(shape: TLShape, point: number[]) {
hitTest(shape: BoxShape, point: number[]) {
return Utils.pointInBounds(point, this.getBounds(shape))
}
hitTestBounds(shape: TLShape, bounds: TLBounds) {
hitTestBounds(shape: BoxShape, bounds: TLBounds) {
const rotatedCorners = Utils.getRotatedCorners(this.getBounds(shape), shape.rotation)
return (
@ -64,11 +69,11 @@ export class ExampleShape extends TLShapeUtil<TLShape> {
)
}
transform(shape: TLShape, bounds: TLBounds, _info: TLTransformInfo<TLShape>): TLShape {
transform(shape: BoxShape, bounds: TLBounds, _info: TLTransformInfo<BoxShape>): BoxShape {
return { ...shape, point: [bounds.minX, bounds.minY] }
}
transformSingle(shape: TLShape, bounds: TLBounds, info: TLTransformInfo<TLShape>): TLShape {
transformSingle(shape: BoxShape, bounds: TLBounds, info: TLTransformInfo<BoxShape>): BoxShape {
return this.transform(shape, bounds, info)
}
}

View file

@ -0,0 +1,20 @@
import * as React from 'react'
import type { TLPageState, TLBounds } from '../types'
import { mockDocument } from './mockDocument'
import { mockUtils } from './mockUtils'
import { useTLTheme, TLContext } from '../hooks'
export const ContextWrapper: React.FC = ({ children }) => {
useTLTheme()
const rScreenBounds = React.useRef<TLBounds>(null)
const rPageState = React.useRef<TLPageState>(mockDocument.pageState)
const [context] = React.useState(() => ({
callbacks: {},
shapeUtils: mockUtils,
rScreenBounds,
rPageState,
}))
return <TLContext.Provider value={context}>{children}</TLContext.Provider>
}

View file

@ -0,0 +1,5 @@
export * from './box'
export * from './mockDocument'
export * from './mockUtils'
export * from './renderWithContext'
export * from './renderWithSvg'

View file

@ -0,0 +1,19 @@
import type { TLBinding, TLPage, TLPageState } from '+types'
import type { BoxShape } from './box'
export const mockDocument: { page: TLPage<BoxShape, TLBinding>; pageState: TLPageState } = {
page: {
id: 'page1',
shapes: {},
bindings: {},
},
pageState: {
id: 'page1',
selectedIds: [],
currentParentId: 'page1',
camera: {
point: [0, 0],
zoom: 1,
},
},
}

View file

@ -0,0 +1,6 @@
import type { TLShapeUtils } from '+types'
import { Box, BoxShape } from './box'
export const mockUtils: TLShapeUtils<BoxShape> = {
box: new Box(),
}

View file

@ -0,0 +1,7 @@
import * as React from 'react'
import { render } from '@testing-library/react'
import { ContextWrapper } from './context-wrapper'
export const renderWithContext = (children: JSX.Element) => {
return render(<ContextWrapper>{children}</ContextWrapper>)
}

View file

@ -0,0 +1,11 @@
import * as React from 'react'
import { render } from '@testing-library/react'
import { ContextWrapper } from './context-wrapper'
export const renderWithSvg = (children: JSX.Element) => {
return render(
<ContextWrapper>
<svg>{children}</svg>
</ContextWrapper>
)
}

View file

@ -0,0 +1,22 @@
{
"extends": "../../tsconfig.base.json",
"include": ["src"],
"exclude": [
"node_modules",
"**/*.test.tsx",
"**/*.test.ts",
"**/*.spec.tsx",
"**/*.spec.ts",
"src/test-utils",
"dist"
],
"compilerOptions": {
"declaration": true,
"rootDir": "src",
"outDir": "./dist/types",
"baseUrl": "src",
"paths": {
"+*": ["./*"]
}
}
}

View file

@ -1,7 +1,7 @@
{
"extends": "../../tsconfig.base.json",
"include": ["src"],
"exclude": ["node_modules", "**/*.test.ts", "**/*.spec.ts", "dist"],
"exclude": ["node_modules", "dist"],
"compilerOptions": {
"rootDir": "src",
"outDir": "./dist/types",

View file

@ -16,7 +16,7 @@
"typings": "./dist/types/index.d.ts",
"scripts": {
"start": "node scripts/dev & tsc --watch --incremental --emitDeclarationOnly --declarationMap --outDir dist/types",
"build": "yarn clean && node scripts/build && tsc --emitDeclarationOnly --outDir dist/types",
"build": "yarn clean && node scripts/build && tsc --project tsconfig.build.json --emitDeclarationOnly --outDir dist/types",
"lint": "eslint src/ --ext .ts,.tsx",
"clean": "rm -rf dist",
"ts-node": "ts-node",
@ -59,4 +59,4 @@
"zustand": "^3.5.7"
},
"gitHead": "4a7439ddf81b615ee49fddbe00802699975f9375"
}
}

View file

@ -14,7 +14,7 @@ async function main() {
target: 'esnext',
jsxFactory: 'React.createElement',
jsxFragment: 'React.Fragment',
tsconfig: './tsconfig.json',
tsconfig: './tsconfig.build.json',
external: ['react', 'react-dom'],
watch: {
onRebuild(error) {

View file

@ -0,0 +1,13 @@
import * as React from 'react'
import { ContextMenu } from './context-menu'
import { renderWithContext } from '~test-utils'
describe('context menu', () => {
test('mounts component', () => {
renderWithContext(
<ContextMenu>
<div>Hello</div>
</ContextMenu>
)
})
})

View file

@ -11,12 +11,11 @@ const selectColor = (data: Data) => data.appState.selectedStyle.color
export const QuickColorSelect = React.memo((): JSX.Element => {
const { theme } = useTheme()
const { tlstate, useSelector } = useTLDrawContext()
const color = useSelector(selectColor)
const handleColorChange = React.useCallback(
(color) => {
tlstate.style({ color: color as ColorStyle })
},
(color) => tlstate.style({ color: color as ColorStyle }),
[tlstate]
)

View file

@ -23,12 +23,11 @@ const selectDash = (data: Data) => data.appState.selectedStyle.dash
export const QuickDashSelect = React.memo((): JSX.Element => {
const { tlstate, useSelector } = useTLDrawContext()
const dash = useSelector(selectDash)
const changeDashStyle = React.useCallback(
(dash) => {
tlstate.style({ dash: dash as DashStyle })
},
(dash) => tlstate.style({ dash: dash as DashStyle }),
[tlstate]
)

View file

@ -13,9 +13,7 @@ export const QuickFillSelect = React.memo((): JSX.Element => {
const isFilled = useSelector(isFilledSelector)
const handleIsFilledChange = React.useCallback(
(isFilled: boolean) => {
tlstate.style({ isFilled })
},
(isFilled: boolean) => tlstate.style({ isFilled }),
[tlstate]
)

View file

@ -20,9 +20,7 @@ export const QuickSizeSelect = React.memo((): JSX.Element => {
const size = useSelector(selectSize)
const changeSizeStyle = React.useCallback(
(size: string) => {
tlstate.style({ size: size as SizeStyle })
},
(size: string) => tlstate.style({ size: size as SizeStyle }),
[tlstate]
)

View file

@ -42,6 +42,8 @@ const hasSelectionSelector = (s: Data) => s.pageState.selectedIds.length > 0
const hasMultipleSelectionSelector = (s: Data) => s.pageState.selectedIds.length > 1
export const ShapesFunctions = React.memo(() => {
const ok = useTLDrawContext()
console.log(ok)
const { tlstate, useSelector } = useTLDrawContext()
const isAllLocked = useSelector(isAllLockedSelector)

View file

@ -0,0 +1,9 @@
import * as React from 'react'
import { renderWithContext } from '~test-utils'
import { StylePanel } from './style-panel'
describe('style panel', () => {
test('mounts component', () => {
renderWithContext(<StylePanel />)
})
})

View file

@ -0,0 +1 @@
export * from './tldraw'

View file

@ -0,0 +1,9 @@
import * as React from 'react'
import { render } from '@testing-library/react'
import { TLDraw } from './tldraw'
describe('tldraw', () => {
test('mounts component', () => {
render(<TLDraw />)
})
})

View file

@ -5,10 +5,10 @@ import styled from '~styles'
import type { Data, TLDrawDocument } from '~types'
import { TLDrawState } from '~state'
import { useKeyboardShortcuts, TLDrawContext } from '~hooks'
import { tldrawShapeUtils } from '../shape'
import { ContextMenu } from './context-menu'
import { StylePanel } from './style-panel'
import { ToolsPanel } from './tools-panel'
import { tldrawShapeUtils } from '~shape'
import { ContextMenu } from '~components/context-menu'
import { StylePanel } from '~components/style-panel'
import { ToolsPanel } from '~components/tools-panel'
export interface TLDrawProps {
document?: TLDrawDocument

View file

@ -0,0 +1,9 @@
import * as React from 'react'
import { ToolsPanel } from './tools-panel'
import { renderWithContext } from '~test-utils'
describe('tools panel', () => {
test('mounts component', () => {
renderWithContext(<ToolsPanel />)
})
})

View file

@ -1,5 +1,5 @@
import { TLDrawState } from '~state'
import { mockDocument } from '~state/test-helpers'
import { mockDocument } from '~test-utils'
import { AlignType } from '~types'
describe('Align command', () => {

View file

@ -1,5 +1,5 @@
import { TLDrawState } from '~state'
import { mockDocument } from '~state/test-helpers'
import { mockDocument } from '~test-utils'
describe('Create command', () => {
const tlstate = new TLDrawState()

View file

@ -1,6 +1,6 @@
import { TLDR } from '~state/tldr'
import { TLDrawState } from '~state'
import { mockDocument } from '~state/test-helpers'
import { mockDocument } from '~test-utils'
import type { TLDrawShape } from '~types'
describe('Delete command', () => {

View file

@ -1,5 +1,5 @@
import { TLDrawState } from '~state'
import { mockDocument } from '~state/test-helpers'
import { mockDocument } from '~test-utils'
import { DistributeType } from '~types'
describe('Distribute command', () => {

View file

@ -1,5 +1,5 @@
import { TLDrawState } from '~state'
import { mockDocument } from '~state/test-helpers'
import { mockDocument } from '~test-utils'
describe('Duplicate command', () => {
const tlstate = new TLDrawState()

View file

@ -1,5 +1,5 @@
import { TLDrawState } from '~state'
import { mockDocument } from '~state/test-helpers'
import { mockDocument } from '~test-utils'
import type { RectangleShape } from '~types'
describe('Stretch command', () => {

View file

@ -1,5 +1,5 @@
import { TLDrawState } from '~state'
import { mockDocument } from '~state/test-helpers'
import { mockDocument } from '~test-utils'
import { Utils } from '@tldraw/core'
import type { Data } from '~types'

View file

@ -1,5 +1,5 @@
import { TLDrawState } from '~state'
import { mockDocument } from '~state/test-helpers'
import { mockDocument } from '~test-utils'
describe('Rotate command', () => {
const tlstate = new TLDrawState()

View file

@ -1,6 +1,6 @@
import { StretchType, RectangleShape } from '~types'
import { TLDrawState } from '~state'
import { mockDocument } from '~state/test-helpers'
import { mockDocument } from '~test-utils'
describe('Stretch command', () => {
const tlstate = new TLDrawState()

View file

@ -1,5 +1,5 @@
import { TLDrawState } from '~state'
import { mockDocument } from '~state/test-helpers'
import { mockDocument } from '~test-utils'
import { SizeStyle } from '~types'
describe('Style command', () => {

View file

@ -1,6 +1,6 @@
import { TLDR } from '~state/tldr'
import { TLDrawState } from '~state'
import { mockDocument } from '~state/test-helpers'
import { mockDocument } from '~test-utils'
import { ArrowShape, Decoration, TLDrawShape } from '~types'
describe('Handle command', () => {

View file

@ -1,6 +1,6 @@
import type { RectangleShape } from '~types'
import { TLDrawState } from '~state'
import { mockDocument } from '~state/test-helpers'
import { mockDocument } from '~test-utils'
describe('Toggle command', () => {
const tlstate = new TLDrawState()

View file

@ -1,5 +1,5 @@
import { TLDrawState } from '~state'
import { mockDocument } from '~state/test-helpers'
import { mockDocument } from '~test-utils'
describe('Translate command', () => {
const tlstate = new TLDrawState()

View file

@ -1,5 +1,5 @@
import { TLDrawState } from '~state'
import { mockDocument } from '~state/test-helpers'
import { mockDocument } from '~test-utils'
import { TLDR } from '~state/tldr'
import type { ArrowShape, TLDrawShape } from '~types'

View file

@ -1,5 +1,5 @@
import { TLDrawState } from '~state'
import { mockDocument } from '~state/test-helpers'
import { mockDocument } from '~test-utils'
describe('Brush session', () => {
const tlstate = new TLDrawState()

View file

@ -1,5 +1,5 @@
import { TLDrawState } from '~state'
import { mockDocument } from '~state/test-helpers'
import { mockDocument } from '~test-utils'
import { ColorStyle, DashStyle, SizeStyle, TLDrawShapeType } from '~types'
describe('Transform session', () => {

View file

@ -1,5 +1,5 @@
import { TLDrawState } from '~state'
import { mockDocument } from '~state/test-helpers'
import { mockDocument } from '~test-utils'
import { TLDR } from '~state/tldr'
import type { TLDrawShape } from '~types'

View file

@ -1,5 +1,5 @@
import { TLDrawState } from '~state'
import { mockDocument } from '~state/test-helpers'
import { mockDocument } from '~test-utils'
describe('Brush session', () => {
const tlstate = new TLDrawState()

View file

@ -1,5 +1,5 @@
import { TLDrawState } from '~state'
import { mockDocument } from '~state/test-helpers'
import { mockDocument } from '~test-utils'
import { TLDR } from '~state/tldr'
import { TextShape, TLDrawShape, TLDrawShapeType } from '~types'

View file

@ -1,5 +1,5 @@
import { TLDrawState } from '~state'
import { mockDocument } from '~state/test-helpers'
import { mockDocument } from '~test-utils'
import { TLBoundsCorner } from '@tldraw/core'
describe('Transform single session', () => {

View file

@ -1,5 +1,5 @@
import { TLDrawState } from '~state'
import { mockDocument } from '~state/test-helpers'
import { mockDocument } from '~test-utils'
import { TLBoundsCorner, Utils } from '@tldraw/core'
import { TLDR } from '~state/tldr'

View file

@ -1,6 +1,6 @@
import { TLDR } from '~state/tldr'
import { TLDrawState } from '~state'
import { mockDocument } from '~state/test-helpers'
import { mockDocument } from '~test-utils'
import type { TLDrawShape } from '~types'
describe('Brush session', () => {

View file

@ -1,5 +1,5 @@
import { TLDrawState } from './tlstate'
import { mockDocument, TLStateUtils } from './test-helpers'
import { mockDocument, TLStateUtils } from '~test-utils'
describe('TLDrawState', () => {
const tlstate = new TLDrawState()

View file

@ -0,0 +1,3 @@
export * from './mock-document'
export * from './renderWithContext'
export * from './state-utils'

View file

@ -0,0 +1,66 @@
import { TLDrawDocument, ColorStyle, DashStyle, SizeStyle, TLDrawShapeType } from '~types'
export const mockDocument: TLDrawDocument = {
id: 'doc',
pages: {
page1: {
id: 'page1',
shapes: {
rect1: {
id: 'rect1',
parentId: 'page1',
name: 'Rectangle',
childIndex: 1,
type: TLDrawShapeType.Rectangle,
point: [0, 0],
size: [100, 100],
style: {
dash: DashStyle.Draw,
size: SizeStyle.Medium,
color: ColorStyle.Blue,
},
},
rect2: {
id: 'rect2',
parentId: 'page1',
name: 'Rectangle',
childIndex: 2,
type: TLDrawShapeType.Rectangle,
point: [100, 100],
size: [100, 100],
style: {
dash: DashStyle.Draw,
size: SizeStyle.Medium,
color: ColorStyle.Blue,
},
},
rect3: {
id: 'rect3',
parentId: 'page1',
name: 'Rectangle',
childIndex: 3,
type: TLDrawShapeType.Rectangle,
point: [20, 20],
size: [100, 100],
style: {
dash: DashStyle.Draw,
size: SizeStyle.Medium,
color: ColorStyle.Blue,
},
},
},
bindings: {},
},
},
pageStates: {
page1: {
id: 'page1',
selectedIds: [],
currentParentId: 'page1',
camera: {
point: [0, 0],
zoom: 1,
},
},
},
}

View file

@ -0,0 +1,30 @@
import * as React from 'react'
import { IdProvider } from '@radix-ui/react-id'
import { TLDrawState } from '~state'
import { useKeyboardShortcuts, TLDrawContext } from '~hooks'
import { mockDocument } from './mock-document'
import { render } from '@testing-library/react'
export const Wrapper: React.FC = ({ children }) => {
const [tlstate] = React.useState(() => new TLDrawState())
const [context] = React.useState(() => {
return { tlstate, useSelector: tlstate.store }
})
useKeyboardShortcuts(tlstate)
React.useEffect(() => {
if (!document) return
tlstate.loadDocument(mockDocument)
}, [document, tlstate])
return (
<TLDrawContext.Provider value={context}>
<IdProvider>{children}</IdProvider>
</TLDrawContext.Provider>
)
}
export const renderWithContext = (children: JSX.Element) => {
return render(<Wrapper>{children}</Wrapper>)
}

View file

@ -1,6 +1,5 @@
import { inputs, TLBoundsEdge, TLBoundsCorner } from '@tldraw/core'
import { TLDrawDocument, ColorStyle, DashStyle, SizeStyle, TLDrawShapeType } from '~types'
import type { TLDrawState } from './tlstate'
import type { TLDrawState } from '~state'
interface PointerOptions {
id?: number
@ -99,68 +98,3 @@ export class TLStateUtils {
} as PointerEvent
}
}
export const mockDocument: TLDrawDocument = {
id: 'doc',
pages: {
page1: {
id: 'page1',
shapes: {
rect1: {
id: 'rect1',
parentId: 'page1',
name: 'Rectangle',
childIndex: 1,
type: TLDrawShapeType.Rectangle,
point: [0, 0],
size: [100, 100],
style: {
dash: DashStyle.Draw,
size: SizeStyle.Medium,
color: ColorStyle.Blue,
},
},
rect2: {
id: 'rect2',
parentId: 'page1',
name: 'Rectangle',
childIndex: 2,
type: TLDrawShapeType.Rectangle,
point: [100, 100],
size: [100, 100],
style: {
dash: DashStyle.Draw,
size: SizeStyle.Medium,
color: ColorStyle.Blue,
},
},
rect3: {
id: 'rect3',
parentId: 'page1',
name: 'Rectangle',
childIndex: 3,
type: TLDrawShapeType.Rectangle,
point: [20, 20],
size: [100, 100],
style: {
dash: DashStyle.Draw,
size: SizeStyle.Medium,
color: ColorStyle.Blue,
},
},
},
bindings: {},
},
},
pageStates: {
page1: {
id: 'page1',
selectedIds: [],
currentParentId: 'page1',
camera: {
point: [0, 0],
zoom: 1,
},
},
},
}

View file

@ -0,0 +1,21 @@
{
"extends": "../../tsconfig.base.json",
"include": ["src"],
"exclude": [
"node_modules",
"**/*.test.tsx",
"**/*.test.ts",
"**/*.spec.tsx",
"**/*.spec.ts",
"src/test-utils",
"dist"
],
"compilerOptions": {
"rootDir": "src",
"outDir": "./dist/types",
"baseUrl": "src",
"paths": {
"~*": ["./*"]
}
}
}

View file

@ -1,7 +1,7 @@
{
"extends": "../../tsconfig.base.json",
"include": ["src"],
"exclude": ["node_modules", "**/*.test.ts", "dist"],
"exclude": ["node_modules", "dist"],
"compilerOptions": {
"rootDir": "src",
"outDir": "./dist/types",

1
setupTests.ts Normal file
View file

@ -0,0 +1 @@
import '@testing-library/jest-dom/extend-expect'

108
yarn.lock
View file

@ -9,7 +9,7 @@
dependencies:
"@babel/highlight" "^7.10.4"
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.14.5":
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.14.5":
version "7.14.5"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.14.5.tgz#23b08d740e83f49c5e59945fbf1b43e80bbf4edb"
integrity sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==
@ -376,7 +376,7 @@
dependencies:
regenerator-runtime "^0.13.4"
"@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10":
"@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.9.2":
version "7.15.3"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.15.3.tgz#2e1c2880ca118e5b2f9988322bd8a7656a32502b"
integrity sha512-OvwMLqNXkCXSz1kSm58sEsNuhqOx/fKpnUnKnFB5v8uDda5bLNEHNgKPvhDN6IU0LDcnHQ90LlJ0Q6jnyBSIBA==
@ -2011,11 +2011,53 @@
resolved "https://registry.yarnpkg.com/@stitches/react/-/react-0.2.5.tgz#ad15b4e59ac2a0679542ba002d41253244be7dab"
integrity sha512-RDVn89kW0R/M4q4TdYvsJ7nckFndzRWGGFJnEHbIH9flOpahtNdPsrxVSsZSjFpxeVqCoOxKujlQjiyRrec1VA==
"@testing-library/dom@^8.0.0":
version "8.1.0"
resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.1.0.tgz#f8358b1883844ea569ba76b7e94582168df5370d"
integrity sha512-kmW9alndr19qd6DABzQ978zKQ+J65gU2Rzkl8hriIetPnwpesRaK4//jEQyYh8fEALmGhomD/LBQqt+o+DL95Q==
dependencies:
"@babel/code-frame" "^7.10.4"
"@babel/runtime" "^7.12.5"
"@types/aria-query" "^4.2.0"
aria-query "^4.2.2"
chalk "^4.1.0"
dom-accessibility-api "^0.5.6"
lz-string "^1.4.4"
pretty-format "^27.0.2"
"@testing-library/jest-dom@^5.14.1":
version "5.14.1"
resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-5.14.1.tgz#8501e16f1e55a55d675fe73eecee32cdaddb9766"
integrity sha512-dfB7HVIgTNCxH22M1+KU6viG5of2ldoA5ly8Ar8xkezKHKXjRvznCdbMbqjYGgO2xjRbwnR+rR8MLUIqF3kKbQ==
dependencies:
"@babel/runtime" "^7.9.2"
"@types/testing-library__jest-dom" "^5.9.1"
aria-query "^4.2.2"
chalk "^3.0.0"
css "^3.0.0"
css.escape "^1.5.1"
dom-accessibility-api "^0.5.6"
lodash "^4.17.15"
redent "^3.0.0"
"@testing-library/react@^12.0.0":
version "12.0.0"
resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-12.0.0.tgz#9aeb2264521522ab9b68f519eaf15136148f164a"
integrity sha512-sh3jhFgEshFyJ/0IxGltRhwZv2kFKfJ3fN1vTZ6hhMXzz9ZbbcTgmDYM4e+zJv+oiVKKEWZPyqPAh4MQBI65gA==
dependencies:
"@babel/runtime" "^7.12.5"
"@testing-library/dom" "^8.0.0"
"@tootallnate/once@1":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==
"@types/aria-query@^4.2.0":
version "4.2.2"
resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-4.2.2.tgz#ed4e0ad92306a704f9fb132a0cfcf77486dbe2bc"
integrity sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==
"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14":
version "7.1.15"
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.15.tgz#2ccfb1ad55a02c83f8e0ad327cbc332f55eb1024"
@ -2083,6 +2125,14 @@
dependencies:
"@types/istanbul-lib-report" "*"
"@types/jest@*", "@types/jest@^27.0.1":
version "27.0.1"
resolved "https://registry.yarnpkg.com/@types/jest/-/jest-27.0.1.tgz#fafcc997da0135865311bb1215ba16dba6bdf4ca"
integrity sha512-HTLpVXHrY69556ozYkcq47TtQJXpcWAWfkoqz+ZGz2JnmZhzlRjprCIyFnetSy8gpDWwTTGBcRVv1J1I1vBrHw==
dependencies:
jest-diff "^27.0.0"
pretty-format "^27.0.0"
"@types/jest@^26.0.23", "@types/jest@^26.0.24":
version "26.0.24"
resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.24.tgz#943d11976b16739185913a1936e0de0c4a7d595a"
@ -2091,14 +2141,6 @@
jest-diff "^26.0.0"
pretty-format "^26.0.0"
"@types/jest@^27.0.1":
version "27.0.1"
resolved "https://registry.yarnpkg.com/@types/jest/-/jest-27.0.1.tgz#fafcc997da0135865311bb1215ba16dba6bdf4ca"
integrity sha512-HTLpVXHrY69556ozYkcq47TtQJXpcWAWfkoqz+ZGz2JnmZhzlRjprCIyFnetSy8gpDWwTTGBcRVv1J1I1vBrHw==
dependencies:
jest-diff "^27.0.0"
pretty-format "^27.0.0"
"@types/json-schema@^7.0.7":
version "7.0.9"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d"
@ -2170,6 +2212,13 @@
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c"
integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==
"@types/testing-library__jest-dom@^5.9.1":
version "5.14.1"
resolved "https://registry.yarnpkg.com/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.1.tgz#014162a5cee6571819d48e999980694e2f657c3c"
integrity sha512-Gk9vaXfbzc5zCXI9eYE9BI5BNHEp4D3FWjgqBE/ePGYElLAP+KvxBcsdkwfIVvezs605oiyd/VrpiHe3Oeg+Aw==
dependencies:
"@types/jest" "*"
"@types/yargs-parser@*":
version "20.2.1"
resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.1.tgz#3b9ce2489919d9e4fea439b76916abc34b2df129"
@ -3139,6 +3188,14 @@ chalk@4.0.0:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
chalk@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4"
integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==
dependencies:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
chalk@^4.0.0, chalk@^4.1.0:
version "4.1.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
@ -3624,11 +3681,20 @@ crypto-browserify@3.12.0, crypto-browserify@^3.11.0:
randombytes "^2.0.0"
randomfill "^1.0.3"
css.escape@1.5.1:
css.escape@1.5.1, css.escape@^1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/css.escape/-/css.escape-1.5.1.tgz#42e27d4fa04ae32f931a4b4d4191fa9cddee97cb"
integrity sha1-QuJ9T6BK4y+TGktNQZH6nN3ul8s=
css@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/css/-/css-3.0.0.tgz#4447a4d58fdd03367c516ca9f64ae365cee4aa5d"
integrity sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ==
dependencies:
inherits "^2.0.4"
source-map "^0.6.1"
source-map-resolve "^0.6.0"
cssnano-preset-simple@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/cssnano-preset-simple/-/cssnano-preset-simple-3.0.0.tgz#e95d0012699ca2c741306e9a3b8eeb495a348dbe"
@ -3930,6 +3996,11 @@ doctrine@^3.0.0:
dependencies:
esutils "^2.0.2"
dom-accessibility-api@^0.5.6:
version "0.5.7"
resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.7.tgz#8c2aa6325968f2933160a0b7dbb380893ddf3e7d"
integrity sha512-ml3lJIq9YjUfM9TUnEPvEYWFSwivwIGBPKpewX7tii7fwCazA8yCioGdqQcNsItPpfFvSJ3VIdMQPj60LJhcQA==
domain-browser@4.19.0:
version "4.19.0"
resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-4.19.0.tgz#1093e17c0a17dbd521182fe90d49ac1370054af1"
@ -6676,6 +6747,11 @@ lunr@^2.3.9:
resolved "https://registry.yarnpkg.com/lunr/-/lunr-2.3.9.tgz#18b123142832337dd6e964df1a5a7707b25d35e1"
integrity sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==
lz-string@^1.4.4:
version "1.4.4"
resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.4.4.tgz#c0d8eaf36059f705796e1e344811cf4c498d3a26"
integrity sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY=
macos-release@^2.2.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/macos-release/-/macos-release-2.5.0.tgz#067c2c88b5f3fb3c56a375b2ec93826220fa1ff2"
@ -7950,7 +8026,7 @@ pretty-format@^26.0.0, pretty-format@^26.6.2:
ansi-styles "^4.0.0"
react-is "^17.0.1"
pretty-format@^27.0.0, pretty-format@^27.0.6:
pretty-format@^27.0.0, pretty-format@^27.0.2, pretty-format@^27.0.6:
version "27.0.6"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.0.6.tgz#ab770c47b2c6f893a21aefc57b75da63ef49a11f"
integrity sha512-8tGD7gBIENgzqA+UBzObyWqQ5B778VIFZA/S66cclyd5YkFLYs2Js7gxDKf0MXtTc9zcS7t1xhdfcElJ3YIvkQ==
@ -8868,6 +8944,14 @@ source-map-resolve@^0.5.0:
source-map-url "^0.4.0"
urix "^0.1.0"
source-map-resolve@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.6.0.tgz#3d9df87e236b53f16d01e58150fc7711138e5ed2"
integrity sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==
dependencies:
atob "^2.1.2"
decode-uri-component "^0.2.0"
source-map-support@^0.5.17, source-map-support@^0.5.6:
version "0.5.19"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61"