123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205 |
- /* eslint-disable @typescript-eslint/no-non-null-assertion */
- import { Utils } from '@tldraw/core'
- import { TLDrawState } from '~state'
- import { TLDR } from '~state/TLDR'
- import { mockDocument } from '~test'
- import { ArrowShape, SessionType, TLDrawShapeType } from '~types'
-
- describe('Duplicate command', () => {
- const tlstate = new TLDrawState()
-
- beforeEach(() => {
- tlstate.loadDocument(mockDocument)
- })
-
- describe('when no shape is selected', () => {
- it('does nothing', () => {
- const initialState = tlstate.state
- tlstate.duplicate()
- const currentState = tlstate.state
-
- expect(currentState).toEqual(initialState)
- })
- })
-
- it('does, undoes and redoes command', () => {
- tlstate.select('rect1')
-
- expect(Object.keys(tlstate.getPage().shapes).length).toBe(3)
-
- tlstate.duplicate()
-
- expect(Object.keys(tlstate.getPage().shapes).length).toBe(4)
-
- tlstate.undo()
-
- expect(Object.keys(tlstate.getPage().shapes).length).toBe(3)
-
- tlstate.redo()
-
- expect(Object.keys(tlstate.getPage().shapes).length).toBe(4)
- })
-
- describe('when duplicating a shape', () => {
- it.todo('sets the correct props (parent and childIndex)')
- })
-
- describe('when duplicating a bound shape', () => {
- it('removed the binding when the target is not selected', () => {
- tlstate.resetDocument().createShapes(
- {
- id: 'target1',
- type: TLDrawShapeType.Rectangle,
- point: [0, 0],
- size: [100, 100],
- },
- {
- type: TLDrawShapeType.Arrow,
- id: 'arrow1',
- point: [200, 200],
- }
- )
-
- const beforeShapeIds = Object.keys(tlstate.page.shapes)
-
- tlstate
- .select('arrow1')
- .startSession(SessionType.Arrow, [200, 200], 'start')
- .updateSession([50, 50])
- .completeSession()
-
- const beforeArrow = tlstate.getShape<ArrowShape>('arrow1')
-
- expect(beforeArrow.handles.start.bindingId).toBeTruthy()
-
- tlstate.select('arrow1').duplicate()
-
- const afterShapeIds = Object.keys(tlstate.page.shapes)
-
- const newShapeIds = afterShapeIds.filter((id) => !beforeShapeIds.includes(id))
-
- expect(newShapeIds.length).toBe(1)
-
- const duplicatedArrow = tlstate.getShape<ArrowShape>(newShapeIds[0])
-
- expect(duplicatedArrow.handles.start.bindingId).toBeUndefined()
- })
-
- it('duplicates the binding when the target is selected', () => {
- tlstate.resetDocument().createShapes(
- {
- id: 'target1',
- type: TLDrawShapeType.Rectangle,
- point: [0, 0],
- size: [100, 100],
- },
- {
- type: TLDrawShapeType.Arrow,
- id: 'arrow1',
- point: [200, 200],
- }
- )
-
- const beforeShapeIds = Object.keys(tlstate.page.shapes)
-
- tlstate
- .select('arrow1')
- .startSession(SessionType.Arrow, [200, 200], 'start')
- .updateSession([50, 50])
- .completeSession()
-
- const oldBindingId = tlstate.getShape<ArrowShape>('arrow1').handles.start.bindingId
- expect(oldBindingId).toBeTruthy()
-
- tlstate.select('arrow1', 'target1').duplicate()
-
- const afterShapeIds = Object.keys(tlstate.page.shapes)
-
- const newShapeIds = afterShapeIds.filter((id) => !beforeShapeIds.includes(id))
-
- expect(newShapeIds.length).toBe(2)
-
- const newBindingId = tlstate.getShape<ArrowShape>(newShapeIds[0]).handles.start.bindingId
-
- expect(newBindingId).toBeTruthy()
-
- tlstate.undo()
-
- expect(tlstate.getBinding(newBindingId!)).toBeUndefined()
- expect(tlstate.getShape<ArrowShape>(newShapeIds[0])).toBeUndefined()
-
- tlstate.redo()
-
- expect(tlstate.getBinding(newBindingId!)).toBeTruthy()
- expect(tlstate.getShape<ArrowShape>(newShapeIds[0]).handles.start.bindingId).toBe(
- newBindingId
- )
- })
-
- it('duplicates groups', () => {
- tlstate.group(['rect1', 'rect2'], 'newGroup').select('newGroup')
-
- const beforeShapeIds = Object.keys(tlstate.page.shapes)
-
- tlstate.duplicate()
-
- expect(Object.keys(tlstate.page.shapes).length).toBe(beforeShapeIds.length + 3)
-
- tlstate.undo()
-
- expect(Object.keys(tlstate.page.shapes).length).toBe(beforeShapeIds.length)
-
- tlstate.redo()
-
- expect(Object.keys(tlstate.page.shapes).length).toBe(beforeShapeIds.length + 3)
- })
-
- it('duplicates grouped shapes', () => {
- tlstate.group(['rect1', 'rect2'], 'newGroup').select('rect1')
-
- const beforeShapeIds = Object.keys(tlstate.page.shapes)
-
- tlstate.duplicate()
-
- expect(Object.keys(tlstate.page.shapes).length).toBe(beforeShapeIds.length + 1)
-
- tlstate.undo()
-
- expect(Object.keys(tlstate.page.shapes).length).toBe(beforeShapeIds.length)
-
- tlstate.redo()
-
- expect(Object.keys(tlstate.page.shapes).length).toBe(beforeShapeIds.length + 1)
- })
- })
-
- it.todo('Does not delete uneffected bindings.')
- })
-
- describe('when point-duplicating', () => {
- it('duplicates without crashing', () => {
- const tlstate = new TLDrawState()
-
- tlstate
- .loadDocument(mockDocument)
- .group(['rect1', 'rect2'])
- .selectAll()
- .duplicate(tlstate.selectedIds, [200, 200])
- })
-
- it('duplicates in the correct place', () => {
- const tlstate = new TLDrawState()
-
- tlstate.loadDocument(mockDocument).group(['rect1', 'rect2']).selectAll()
-
- const before = tlstate.shapes.map((shape) => shape.id)
-
- tlstate.duplicate(tlstate.selectedIds, [200, 200])
-
- const after = tlstate.shapes.filter((shape) => !before.includes(shape.id))
-
- expect(
- Utils.getBoundsCenter(Utils.getCommonBounds(after.map((shape) => TLDR.getBounds(shape))))
- ).toStrictEqual([200, 200])
- })
- })
|