diff --git a/packages/designer/src/designer/dragon.ts b/packages/designer/src/designer/dragon.ts index 358af49fb..322a6af8c 100644 --- a/packages/designer/src/designer/dragon.ts +++ b/packages/designer/src/designer/dragon.ts @@ -179,7 +179,7 @@ function makeEventsHandler( } function isDragEvent(e: any): e is DragEvent { - return e?.type?.substr(0, 4) === 'drag'; + return e?.type?.startsWith('drag'); } /** @@ -245,7 +245,7 @@ export class Dragon { const handleEvents = makeEventsHandler(boostEvent, masterSensors); const newBie = !isDragNodeObject(dragObject); const forceCopyState = isDragNodeObject(dragObject) && dragObject.nodes.some((node) => node.isSlot()); - const isBoostFromDragAPI = boostEvent.type.substr(0, 4) === 'drag'; + const isBoostFromDragAPI = isDragEvent(boostEvent); let lastSensor: ISensor | undefined; this._dragging = false; @@ -259,6 +259,7 @@ export class Dragon { let copy = false; const checkcopy = (e: MouseEvent | DragEvent | KeyboardEvent) => { + /* istanbul ignore next */ if (isDragEvent(e) && e.dataTransfer) { if (newBie || forceCopyState) { e.dataTransfer.dropEffect = 'copy'; @@ -272,6 +273,7 @@ export class Dragon { if (e.altKey || e.ctrlKey) { copy = true; this.setCopyState(true); + /* istanbul ignore next */ if (isDragEvent(e) && e.dataTransfer) { e.dataTransfer.dropEffect = 'copy'; } @@ -279,6 +281,7 @@ export class Dragon { copy = false; if (!forceCopyState) { this.setCopyState(false); + /* istanbul ignore next */ if (isDragEvent(e) && e.dataTransfer) { e.dataTransfer.dropEffect = 'move'; } @@ -332,6 +335,7 @@ export class Dragon { // route: drag-move const move = (e: MouseEvent | DragEvent) => { + /* istanbul ignore next */ if (isBoostFromDragAPI) { e.preventDefault(); } @@ -350,6 +354,7 @@ export class Dragon { }; let didDrop = true; + /* istanbul ignore next */ const drop = (e: DragEvent) => { e.preventDefault(); e.stopPropagation(); @@ -358,12 +363,14 @@ export class Dragon { // end-tail drag process const over = (e?: any) => { + /* istanbul ignore next */ if (e && isDragEvent(e)) { e.preventDefault(); } if (lastSensor) { lastSensor.deactiveSensor(); } + /* istanbul ignore next */ if (isBoostFromDragAPI) { if (!didDrop) { designer.clearLocation(); @@ -385,6 +392,7 @@ export class Dragon { designer.clearLocation(); handleEvents((doc) => { + /* istanbul ignore next */ if (isBoostFromDragAPI) { doc.removeEventListener('dragover', move, true); doc.removeEventListener('dragend', over, true); @@ -418,7 +426,7 @@ export class Dragon { if (!sourceDocument || sourceDocument === document) { evt.globalX = e.clientX; evt.globalY = e.clientY; - } else { + } /* istanbul ignore next */ else { // event from simulator sandbox let srcSim: ISimulatorHost | undefined; const lastSim = lastSensor && isSimulatorHost(lastSensor) ? lastSensor : null; @@ -449,6 +457,7 @@ export class Dragon { }; const sourceSensor = getSourceSensor(dragObject); + /* istanbul ignore next */ const chooseSensor = (e: LocateEvent) => { // this.sensors will change on dragstart const sensors: ISensor[] = (masterSensors as ISensor[]).concat(this.sensors); @@ -477,6 +486,7 @@ export class Dragon { return sensor; }; + /* istanbul ignore next */ if (isDragEvent(boostEvent)) { const { dataTransfer } = boostEvent; @@ -496,6 +506,7 @@ export class Dragon { } handleEvents((doc) => { + /* istanbul ignore next */ if (isBoostFromDragAPI) { doc.addEventListener('dragover', move, true); // dragexit diff --git a/packages/designer/tests/designer/dragon.test.ts b/packages/designer/tests/designer/dragon.test.ts index f9774be60..a340f8a70 100644 --- a/packages/designer/tests/designer/dragon.test.ts +++ b/packages/designer/tests/designer/dragon.test.ts @@ -1,14 +1,345 @@ +import '../fixtures/window'; +import { set } from '../utils'; +import { Editor, globalContext } from '@ali/lowcode-editor-core'; +import { Project } from '../../src/project/project'; +import { DocumentModel } from '../../src/document/document-model'; +import { + isRootNode, + Node, + isNode, + comparePosition, + contains, + insertChild, + insertChildren, + PositionNO, +} from '../../src/document/node/node'; +import { Designer } from '../../src/designer/designer'; +import { + Dragon, + isDragNodeObject, + isDragNodeDataObject, + isDragAnyObject, + isLocateEvent, + DragObjectType, + isShaken, + setShaken, +} from '../../src/designer/dragon'; +import formSchema from '../fixtures/schema/form'; +import divMetadata from '../fixtures/component-metadata/div'; +import formMetadata from '../fixtures/component-metadata/form'; +import otherMeta from '../fixtures/component-metadata/other'; +import pageMetadata from '../fixtures/component-metadata/page'; import { fireEvent } from '@testing-library/react'; +import { clearScreenDown } from 'readline'; -it('test', () => { - document.addEventListener('keydown', (e) => { - console.log(e); - }) +describe('Dragon 测试', () => { + let editor: Editor; + let designer: Designer; + let project: Project; + let doc: DocumentModel; + let dragon: Dragon; - fireEvent.keyDown(document, { key: 'Enter', }) + beforeEach(() => { + editor = new Editor(); + !globalContext.has(Editor) && globalContext.register(editor, Editor); + designer = new Designer({ editor }); + project = designer.project; + doc = project.createDocument(formSchema); + dragon = new Dragon(designer); + }); - document.addEventListener('drag', (e) => { - console.log(e); - }) - fireEvent.drag(document, {}) -}) \ No newline at end of file + afterEach(() => { + project.unload(); + project.mountSimulator(undefined); + designer.purge(); + editor = null; + designer = null; + project = null; + dragon = null; + }); + + it.skip('drag NodeData', () => { + const dragStartMockedFn = jest.fn(); + const dragMockedFn = jest.fn(); + const dragEndMockedFn = jest.fn(); + + dragon.onDragstart((e) => { + console.log('start', e, e.originalEvent, e.originalEvent.clientX); + }); + + dragon.onDrag((e) => { + console.log('drag', e, e.originalEvent, e.originalEvent.clientX); + }); + + dragon.onDragend((e) => { + console.log('end', e, e.originalEvent); + }); + + dragon.boost( + { + type: DragObjectType.NodeData, + data: [{ componentName: 'Button' }], + }, + new Event('dragstart', { clientX: 100, clientY: 100 }), + ); + + fireEvent.dragOver(document, { clientX: 108, clientY: 108 }); + fireEvent.dragEnd(document, { clientX: 118, clientY: 118 }); + }); + + it.skip('drag Node', () => { + console.log(new MouseEvent('mousedown', { clientX: 1 }).clientX); + // console.log(new Event('mousedown', { clientX: 1 }).clientX); + // console.log(new Event('drag', { clientX: 1 }).clientX); + // console.log(new CustomEvent('drag', { clientX: 1 }).clientX); + console.log(document.createEvent('dragstart', { clientX: 1 }).clientX); + }); + + it('mouse NodeData', () => { + const dragStartMockedFn = jest.fn(); + const dragMockedFn = jest.fn(); + const dragEndMockedFn = jest.fn(); + + const offDragStart = dragon.onDragstart(dragStartMockedFn); + + const offDrag = dragon.onDrag(dragMockedFn); + + const offDragEnd = dragon.onDragend(dragEndMockedFn); + + dragon.boost( + { + type: DragObjectType.NodeData, + data: [{ componentName: 'Button' }], + }, + new MouseEvent('mousedown', { clientX: 100, clientY: 100 }), + ); + + fireEvent.mouseMove(document, { clientX: 108, clientY: 108 }); + fireEvent.mouseMove(document, { clientX: 110, clientY: 110 }); + fireEvent.mouseUp(document, { clientX: 118, clientY: 118 }); + + expect(dragStartMockedFn).toHaveBeenCalledTimes(1); + expect(dragMockedFn).toHaveBeenCalledTimes(2); + expect(dragEndMockedFn).toHaveBeenCalledTimes(1); + }); + + it('mouse Node', () => { + const dragStartMockedFn = jest.fn(); + const dragMockedFn = jest.fn(); + const dragEndMockedFn = jest.fn(); + + const offDragStart = dragon.onDragstart(dragStartMockedFn); + const offDrag = dragon.onDrag(dragMockedFn); + const offDragEnd = dragon.onDragend(dragEndMockedFn); + + dragon.boost( + { + type: DragObjectType.Node, + nodes: [doc.getNode('node_k1ow3cbn')], + }, + new MouseEvent('mousedown', { clientX: 100, clientY: 100 }), + ); + + // mouseDown 模式正常不会触发 dragStart 事件,除非 shaken 型 + expect(dragStartMockedFn).not.toHaveBeenCalled(); + + fireEvent.mouseMove(document, { clientX: 108, clientY: 108 }); + expect(dragStartMockedFn).toHaveBeenCalledTimes(1); + expect(dragMockedFn).toHaveBeenCalledTimes(1); + fireEvent.mouseMove(document, { clientX: 110, clientY: 110 }); + expect(dragMockedFn).toHaveBeenCalledTimes(2); + expect(dragon.dragging).toBeTruthy(); + + fireEvent.mouseUp(document, { clientX: 118, clientY: 118 }); + + expect(dragEndMockedFn).toHaveBeenCalledTimes(1); + + offDragStart(); + offDrag(); + offDragEnd(); + dragMockedFn.mockClear(); + + dragon.boost( + { + type: DragObjectType.Node, + nodes: [doc.getNode('node_k1ow3cbn')], + }, + new MouseEvent('mousedown', { clientX: 100, clientY: 100 }), + ); + + fireEvent.mouseMove(document, { clientX: 108, clientY: 108 }); + + expect(dragMockedFn).not.toHaveBeenCalled(); + }); + + it('mouse Node & esc', () => { + const dragStartMockedFn = jest.fn(); + const dragMockedFn = jest.fn(); + const dragEndMockedFn = jest.fn(); + + const offDragStart = dragon.onDragstart(dragStartMockedFn); + const offDrag = dragon.onDrag(dragMockedFn); + const offDragEnd = dragon.onDragend(dragEndMockedFn); + + dragon.boost( + { + type: DragObjectType.Node, + nodes: [doc.getNode('node_k1ow3cbn')], + }, + new MouseEvent('mousedown', { clientX: 100, clientY: 100 }), + ); + + fireEvent.keyDown(document, { keyCode: 27 }); + expect(dragon.designer.dropLocation).toBeUndefined(); + }); + + it('mouse Node & copy', () => { + const dragStartMockedFn = jest.fn(); + const dragMockedFn = jest.fn(); + const dragEndMockedFn = jest.fn(); + + const offDragStart = dragon.onDragstart(dragStartMockedFn); + const offDrag = dragon.onDrag(dragMockedFn); + const offDragEnd = dragon.onDragend(dragEndMockedFn); + + dragon.boost( + { + type: DragObjectType.Node, + nodes: [doc.getNode('node_k1ow3cbn')], + }, + new MouseEvent('mousedown', { clientX: 100, clientY: 100 }), + ); + + const mockedFn1 = jest.fn(); + project.mountSimulator({ setCopyState: mockedFn1 }); + expect(dragon.getSimulators().size).toBe(1); + fireEvent.keyDown(document, { ctrlKey: true }); + expect(mockedFn1).toHaveBeenCalled(); + }); + + it('from', () => { + const dragStartMockedFn = jest.fn(); + const dragMockedFn = jest.fn(); + const dragEndMockedFn = jest.fn(); + + const offDragStart = dragon.onDragstart(dragStartMockedFn); + const offDrag = dragon.onDrag(dragMockedFn); + const offDragEnd = dragon.onDragend(dragEndMockedFn); + const mockedBoostFn = jest + .fn((e) => { + return { + type: DragObjectType.Node, + nodes: [doc.getNode('node_k1ow3cbn')], + }; + }) + .mockImplementationOnce(() => null); + + const offFrom = dragon.from(document, mockedBoostFn); + + // 无用 mouseDown,无效的按钮 + fireEvent.mouseDown(document, { button: 2 }); + expect(dragStartMockedFn).not.toHaveBeenCalled(); + + // 无用 mouseDown,无效的 dragObject + fireEvent.mouseDown(document, { clientX: 100, clientY: 100 }); + expect(dragStartMockedFn).not.toHaveBeenCalled(); + + fireEvent.mouseDown(document, { clientX: 100, clientY: 100 }); + expect(dragStartMockedFn).not.toHaveBeenCalled(); + + fireEvent.mouseMove(document, { clientX: 108, clientY: 108 }); + expect(dragStartMockedFn).toHaveBeenCalledTimes(1); + expect(dragMockedFn).toHaveBeenCalledTimes(1); + fireEvent.mouseMove(document, { clientX: 110, clientY: 110 }); + expect(dragMockedFn).toHaveBeenCalledTimes(2); + expect(dragon.dragging).toBeTruthy(); + + fireEvent.mouseUp(document, { clientX: 118, clientY: 118 }); + + expect(dragEndMockedFn).toHaveBeenCalledTimes(1); + + offDragStart(); + offDrag(); + offDragEnd(); + dragMockedFn.mockClear(); + + fireEvent.mouseMove(document, { clientX: 100, clientY: 100 }); + expect(dragMockedFn).not.toHaveBeenCalled(); + + offFrom(); + fireEvent.mouseMove(document, { clientX: 100, clientY: 100 }); + expect(dragMockedFn).not.toHaveBeenCalled(); + }); + + it('addSensor / removeSensor', () => { + const sensor = {}; + dragon.addSensor(sensor); + expect(dragon.sensors.length).toBe(1); + dragon.removeSensor(sensor); + expect(dragon.sensors.length).toBe(0); + }); + + it('has sensor', () => { + const mockedFn1 = jest.fn(); + const mockedDoc = document.createElement('iframe').contentWindow?.document; + dragon.addSensor({ + fixEvent: () => {}, + locate: () => {}, + contentDocument: mockedDoc, + }); + project.mountSimulator({ + setCopyState: mockedFn1, + setNativeSelection: () => {}, + clearState: () => {}, + setDraggingState: () => {}, + }); + + const mockedBoostFn = jest + .fn((e) => { + return { + type: DragObjectType.Node, + nodes: [doc.getNode('node_k1ow3cbn')], + }; + }) + .mockImplementationOnce(() => null); + + const offFrom = dragon.from(document, mockedBoostFn); + + // TODO: 想办法 mock 一个 iframe.currentDocument + fireEvent.mouseDown(document, { clientX: 100, clientY: 100 }); + }); +}); + +describe('导出的其他函数', () => { + it('isDragNodeObject', () => { + expect(isDragNodeObject({ type: DragObjectType.Node, nodes: [] })).toBeTruthy(); + }); + it('isDragNodeDataObject', () => { + expect(isDragNodeDataObject({ type: DragObjectType.NodeData, data: [] })).toBeTruthy(); + }); + it('isDragAnyObject', () => { + expect(isDragAnyObject()).toBeFalsy(); + expect(isDragAnyObject({ type: DragObjectType.Node, nodes: [] })).toBeFalsy(); + expect(isDragAnyObject({ type: DragObjectType.NodeData, data: [] })).toBeFalsy(); + expect(isDragAnyObject({ type: 'others', data: [] })).toBeTruthy(); + }); + it('isLocateEvent', () => { + expect(isLocateEvent({ type: 'LocateEvent' })).toBeTruthy(); + }); + it('isShaken', () => { + expect( + isShaken( + { clientX: 1, clientY: 1, target: {} }, + { clientX: 1, clientY: 1, target: { other: 1 } }, + ), + ).toBeTruthy(); + expect(isShaken({ shaken: true })).toBeTruthy(); + expect(isShaken({ clientX: 1, clientY: 1 }, { clientX: 2, clientY: 2 })).toBeFalsy(); + expect(isShaken({ clientX: 1, clientY: 1 }, { clientX: 3, clientY: 5 })).toBeTruthy(); + }); + it('setShaken', () => { + const e = {}; + setShaken(e); + expect(isShaken(e)).toBeTruthy(); + }); +}); diff --git a/packages/editor-preset-vision/build.json b/packages/editor-preset-vision/build.json index ffd529288..32d1da46c 100644 --- a/packages/editor-preset-vision/build.json +++ b/packages/editor-preset-vision/build.json @@ -1,4 +1,5 @@ { + "sourceMap": true, "plugins": [ [ "build-plugin-component", diff --git a/packages/rax-simulator-renderer/build.json b/packages/rax-simulator-renderer/build.json index 70f118bdf..59f913b34 100644 --- a/packages/rax-simulator-renderer/build.json +++ b/packages/rax-simulator-renderer/build.json @@ -1,4 +1,5 @@ { + "sourceMap": true, "plugins": [ [ "build-plugin-component", diff --git a/packages/rax-simulator-renderer/package.json b/packages/rax-simulator-renderer/package.json index 90e08af37..2d571f5b9 100644 --- a/packages/rax-simulator-renderer/package.json +++ b/packages/rax-simulator-renderer/package.json @@ -57,5 +57,5 @@ "publishConfig": { "registry": "https://registry.npm.alibaba-inc.com" }, - "homepage": "https://unpkg.alibaba-inc.com/@ali/lowcode-rax-simulator-renderer@1.0.24-beta.4/build/index.html" + "homepage": "https://unpkg.alibaba-inc.com/@ali/lowcode-rax-simulator-renderer@1.0.25-beta.1/build/index.html" } diff --git a/packages/react-simulator-renderer/build.json b/packages/react-simulator-renderer/build.json index 12c3c10c6..cc6d56cd4 100644 --- a/packages/react-simulator-renderer/build.json +++ b/packages/react-simulator-renderer/build.json @@ -1,4 +1,5 @@ { + "sourceMap": true, "plugins": [ [ "build-plugin-component",