forked from excalidraw/excalidraw
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
factor out test helpers (excalidraw#2093)
- Loading branch information
Showing
4 changed files
with
613 additions
and
503 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { ExcalidrawElement } from "../../element/types"; | ||
|
||
const { h } = window; | ||
|
||
export class API { | ||
static getSelectedElements = (): ExcalidrawElement[] => { | ||
return h.elements.filter( | ||
(element) => h.state.selectedElementIds[element.id], | ||
); | ||
}; | ||
|
||
static getSelectedElement = (): ExcalidrawElement => { | ||
const selectedElements = API.getSelectedElements(); | ||
if (selectedElements.length !== 1) { | ||
throw new Error( | ||
`expected 1 selected element; got ${selectedElements.length}`, | ||
); | ||
} | ||
return selectedElements[0]; | ||
}; | ||
|
||
static getStateHistory = () => { | ||
// @ts-ignore | ||
return h.history.stateHistory; | ||
}; | ||
|
||
static clearSelection = () => { | ||
// @ts-ignore | ||
h.app.clearSelection(null); | ||
expect(API.getSelectedElements().length).toBe(0); | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,203 @@ | ||
import { ToolName } from "../queries/toolQueries"; | ||
import { fireEvent, GlobalTestState } from "../test-utils"; | ||
import { KEYS, Key } from "../../keys"; | ||
import { ExcalidrawElement } from "../../element/types"; | ||
import { API } from "./api"; | ||
|
||
const { h } = window; | ||
|
||
let altKey = false; | ||
let shiftKey = false; | ||
let ctrlKey = false; | ||
|
||
export class Keyboard { | ||
static withModifierKeys = ( | ||
modifiers: { alt?: boolean; shift?: boolean; ctrl?: boolean }, | ||
cb: () => void, | ||
) => { | ||
const prevAltKey = altKey; | ||
const prevShiftKey = shiftKey; | ||
const prevCtrlKey = ctrlKey; | ||
|
||
altKey = !!modifiers.alt; | ||
shiftKey = !!modifiers.shift; | ||
ctrlKey = !!modifiers.ctrl; | ||
|
||
try { | ||
cb(); | ||
} finally { | ||
altKey = prevAltKey; | ||
shiftKey = prevShiftKey; | ||
ctrlKey = prevCtrlKey; | ||
} | ||
}; | ||
|
||
static hotkeyDown = (hotkey: Key) => { | ||
const key = KEYS[hotkey]; | ||
if (typeof key !== "string") { | ||
throw new Error("must provide a hotkey, not a key code"); | ||
} | ||
Keyboard.keyDown(key); | ||
}; | ||
|
||
static hotkeyUp = (hotkey: Key) => { | ||
const key = KEYS[hotkey]; | ||
if (typeof key !== "string") { | ||
throw new Error("must provide a hotkey, not a key code"); | ||
} | ||
Keyboard.keyUp(key); | ||
}; | ||
|
||
static keyDown = (key: string) => { | ||
fireEvent.keyDown(document, { | ||
key, | ||
ctrlKey, | ||
shiftKey, | ||
altKey, | ||
keyCode: key.toUpperCase().charCodeAt(0), | ||
which: key.toUpperCase().charCodeAt(0), | ||
}); | ||
}; | ||
|
||
static keyUp = (key: string) => { | ||
fireEvent.keyUp(document, { | ||
key, | ||
ctrlKey, | ||
shiftKey, | ||
altKey, | ||
keyCode: key.toUpperCase().charCodeAt(0), | ||
which: key.toUpperCase().charCodeAt(0), | ||
}); | ||
}; | ||
|
||
static hotkeyPress = (key: Key) => { | ||
Keyboard.hotkeyDown(key); | ||
Keyboard.hotkeyUp(key); | ||
}; | ||
|
||
static keyPress = (key: string) => { | ||
Keyboard.keyDown(key); | ||
Keyboard.keyUp(key); | ||
}; | ||
} | ||
|
||
export class Pointer { | ||
private clientX = 0; | ||
private clientY = 0; | ||
|
||
constructor( | ||
private readonly pointerType: "mouse" | "touch" | "pen", | ||
private readonly pointerId = 1, | ||
) {} | ||
|
||
reset() { | ||
this.clientX = 0; | ||
this.clientY = 0; | ||
} | ||
|
||
getPosition() { | ||
return [this.clientX, this.clientY]; | ||
} | ||
|
||
restorePosition(x = 0, y = 0) { | ||
this.clientX = x; | ||
this.clientY = y; | ||
fireEvent.pointerMove(GlobalTestState.canvas, this.getEvent()); | ||
} | ||
|
||
private getEvent() { | ||
return { | ||
clientX: this.clientX, | ||
clientY: this.clientY, | ||
pointerType: this.pointerType, | ||
pointerId: this.pointerId, | ||
altKey, | ||
shiftKey, | ||
ctrlKey, | ||
}; | ||
} | ||
|
||
move(dx: number, dy: number) { | ||
if (dx !== 0 || dy !== 0) { | ||
this.clientX += dx; | ||
this.clientY += dy; | ||
fireEvent.pointerMove(GlobalTestState.canvas, this.getEvent()); | ||
} | ||
} | ||
|
||
down(dx = 0, dy = 0) { | ||
this.move(dx, dy); | ||
fireEvent.pointerDown(GlobalTestState.canvas, this.getEvent()); | ||
} | ||
|
||
up(dx = 0, dy = 0) { | ||
this.move(dx, dy); | ||
fireEvent.pointerUp(GlobalTestState.canvas, this.getEvent()); | ||
} | ||
|
||
click(dx = 0, dy = 0) { | ||
this.down(dx, dy); | ||
this.up(); | ||
} | ||
|
||
doubleClick(dx = 0, dy = 0) { | ||
this.move(dx, dy); | ||
fireEvent.doubleClick(GlobalTestState.canvas, this.getEvent()); | ||
} | ||
|
||
select( | ||
/** if multiple elements supplied, they're shift-selected */ | ||
elements: ExcalidrawElement | ExcalidrawElement[], | ||
) { | ||
API.clearSelection(); | ||
Keyboard.withModifierKeys({ shift: true }, () => { | ||
elements = Array.isArray(elements) ? elements : [elements]; | ||
elements.forEach((element) => { | ||
this.reset(); | ||
this.click(element.x, element.y); | ||
}); | ||
}); | ||
this.reset(); | ||
} | ||
|
||
clickOn(element: ExcalidrawElement) { | ||
this.reset(); | ||
this.click(element.x, element.y); | ||
this.reset(); | ||
} | ||
} | ||
|
||
const mouse = new Pointer("mouse"); | ||
|
||
export class UI { | ||
static clickTool = (toolName: ToolName) => { | ||
fireEvent.click(GlobalTestState.renderResult.getByToolName(toolName)); | ||
}; | ||
|
||
static createElement( | ||
type: ToolName, | ||
{ | ||
x = 0, | ||
y = x, | ||
size = 10, | ||
}: { | ||
x?: number; | ||
y?: number; | ||
size?: number; | ||
}, | ||
) { | ||
UI.clickTool(type); | ||
mouse.reset(); | ||
mouse.down(x, y); | ||
mouse.reset(); | ||
mouse.up(x + size, y + size); | ||
return h.elements[h.elements.length - 1]; | ||
} | ||
|
||
static group(elements: ExcalidrawElement[]) { | ||
mouse.select(elements); | ||
Keyboard.withModifierKeys({ ctrl: true }, () => { | ||
Keyboard.keyPress("g"); | ||
}); | ||
} | ||
} |
Oops, something went wrong.