import { BaseBoxShapeTool, BaseBoxShapeUtil, Canvas, Editor, HTMLContainer, TLBaseShape, TldrawEditor, createShapeId, createTLStore, noop, } from '@bigbluebutton/editor' import { act, render, screen } from '@testing-library/react' import { defaultTools } from '../lib/defaultTools' import { GeoShapeUtil } from '../lib/shapes/geo/GeoShapeUtil' function checkAllShapes(editor: Editor, shapes: string[]) { expect(Object.keys(editor!.store.schema.types.shape.migrations.subTypeMigrations!)).toStrictEqual( shapes ) expect(Object.keys(editor!.shapeUtils)).toStrictEqual(shapes) } describe('', () => { it('Renders without crashing', () => { render(
) screen.findByTestId('canvas-1') }) it('Creates its own store with core shapes', () => { let editor: Editor render( { editor = e }} initialState="select" tools={defaultTools} autoFocus >
) screen.findByTestId('canvas-1') checkAllShapes(editor!, ['group']) }) it('Can be created with default shapes', () => { let editor: Editor render( { editor = e }} autoFocus >
) screen.findByTestId('canvas-1') expect(editor!).toBeTruthy() checkAllShapes(editor!, ['group']) }) it('Renders with an external store', () => { const store = createTLStore({ shapeUtils: [] }) render( { expect(editor.store).toBe(store) }} autoFocus >
) screen.findByTestId('canvas-1') }) it('throws if the store has different shapes to the ones passed in', () => { const spy = jest.spyOn(console, 'error').mockImplementation(noop) // expect(() => // render( // { // throw error // }, // }} // > //
// // ) // ).toThrowErrorMatchingInlineSnapshot( // `"Editor and store have different shapes: \\"draw\\" was passed into the editor but not the schema"` // ) // expect(() => // render( // { // throw error // }, // }} // > //
// // ) // ).toThrowErrorMatchingInlineSnapshot( // `"Editor and store have different shapes: \\"draw\\" is present in the store schema but not provided to the editor"` // ) spy.mockRestore() }) it('Accepts fresh versions of store and calls `onMount` for each one', () => { const initialStore = createTLStore({ shapeUtils: [] }) const onMount = jest.fn() const rendered = render(
) screen.findByTestId('canvas-1') const initialEditor = onMount.mock.lastCall[0] jest.spyOn(initialEditor, 'dispose') expect(initialEditor.store).toBe(initialStore) // re-render with the same store: rendered.rerender(
) screen.findByTestId('canvas-2') // not called again: expect(onMount).toHaveBeenCalledTimes(1) // re-render with a new store: const newStore = createTLStore({ shapeUtils: [] }) rendered.rerender(
) screen.findByTestId('canvas-3') expect(initialEditor.dispose).toHaveBeenCalledTimes(1) expect(onMount).toHaveBeenCalledTimes(2) expect(onMount.mock.lastCall[0].store).toBe(newStore) }) it('Renders the canvas and shapes', async () => { let editor = {} as Editor render( { editor = editorApp }} >
) screen.findByTestId('canvas-1') expect(editor).toBeTruthy() await act(async () => { editor.updateInstanceState( { screenBounds: { x: 0, y: 0, w: 1080, h: 720 } }, { ephemeral: true, squashing: true } ) }) const id = createShapeId() await act(async () => { editor.createShapes([ { id, type: 'geo', props: { w: 100, h: 100 }, }, ]) }) // Does the shape exist? expect(editor.getShape(id)).toMatchObject({ id, type: 'geo', x: 0, y: 0, opacity: 1, props: { geo: 'rectangle', w: 100, h: 100 }, }) // Is the shape's component rendering? expect(document.querySelectorAll('.tl-shape')).toHaveLength(1) expect(document.querySelectorAll('.tl-shape-indicator')).toHaveLength(0) // Select the shape await act(async () => editor.select(id)) expect(editor.getSelectedShapeIds().length).toBe(1) // Is the shape's component rendering? expect(document.querySelectorAll('.tl-shape-indicator')).toHaveLength(1) // Select the eraser tool... await act(async () => editor.setCurrentTool('eraser')) // Is the editor's current tool correct? expect(editor.getCurrentToolId()).toBe('eraser') }) }) describe('Custom shapes', () => { type CardShape = TLBaseShape< 'card', { w: number h: number } > class CardUtil extends BaseBoxShapeUtil { static override type = 'card' as const override isAspectRatioLocked = (_shape: CardShape) => false override canResize = (_shape: CardShape) => true override canBind = (_shape: CardShape) => true override getDefaultProps(): CardShape['props'] { return { w: 300, h: 300, } } component(shape: CardShape) { return ( {shape.props.w.toFixed()}x{shape.props.h.toFixed()} ) } indicator(shape: CardShape) { return } } class CardTool extends BaseBoxShapeTool { static override id = 'card' static override initial = 'idle' override shapeType = 'card' } const tools = [CardTool] const shapeUtils = [CardUtil] it('Uses custom shapes', async () => { let editor = {} as Editor render( { editor = editorApp }} >
) screen.findByTestId('canvas-1') expect(editor).toBeTruthy() await act(async () => { editor.updateInstanceState( { screenBounds: { x: 0, y: 0, w: 1080, h: 720 } }, { ephemeral: true, squashing: true } ) }) expect(editor.shapeUtils.card).toBeTruthy() checkAllShapes(editor, ['group', 'card']) const id = createShapeId() await act(async () => { editor.createShapes([ { id, type: 'card', props: { w: 100, h: 100 }, }, ]) }) // Does the shape exist? expect(editor.getShape(id)).toMatchObject({ id, type: 'card', x: 0, y: 0, opacity: 1, props: { w: 100, h: 100 }, }) // Is the shape's component rendering? expect(await screen.findByTestId('card-shape')).toBeTruthy() // Select the shape await act(async () => editor.select(id)) // Is the shape's component rendering? expect(await screen.findByTestId('card-indicator')).toBeTruthy() // Select the tool... await act(async () => editor.setCurrentTool('card')) // Is the editor's current tool correct? expect(editor.getCurrentToolId()).toBe('card') }) })