Skip to content

Commit

Permalink
Add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
pythongosssss committed Sep 24, 2024
1 parent 440b6fc commit fcbdefc
Show file tree
Hide file tree
Showing 4 changed files with 218 additions and 26 deletions.
123 changes: 98 additions & 25 deletions browser_tests/ComfyPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -571,46 +571,43 @@ export class ComfyPage {
await this.nextFrame()
}

async ctrlC() {
async ctrlSend(keyToPress: string) {
await this.page.keyboard.down('Control')
await this.page.keyboard.press('KeyC')
await this.page.keyboard.press(keyToPress)
await this.page.keyboard.up('Control')
await this.nextFrame()
}

async ctrlA() {
await this.ctrlSend('KeyA')
}

async ctrlB() {
await this.ctrlSend('KeyB')
}

async ctrlC() {
await this.ctrlSend('KeyC')
}

async ctrlV() {
await this.page.keyboard.down('Control')
await this.page.keyboard.press('KeyV')
await this.page.keyboard.up('Control')
await this.nextFrame()
await this.ctrlSend('KeyV')
}

async ctrlZ() {
await this.page.keyboard.down('Control')
await this.page.keyboard.press('KeyZ')
await this.page.keyboard.up('Control')
await this.nextFrame()
await this.ctrlSend('KeyZ')
}

async ctrlY() {
await this.page.keyboard.down('Control')
await this.page.keyboard.press('KeyY')
await this.page.keyboard.up('Control')
await this.nextFrame()
await this.ctrlSend('KeyY')
}

async ctrlArrowUp() {
await this.page.keyboard.down('Control')
await this.page.keyboard.press('ArrowUp')
await this.page.keyboard.up('Control')
await this.nextFrame()
await this.ctrlSend('ArrowUp')
}

async ctrlArrowDown() {
await this.page.keyboard.down('Control')
await this.page.keyboard.press('ArrowDown')
await this.page.keyboard.up('Control')
await this.nextFrame()
await this.ctrlSend('ArrowDown')
}

async closeMenu() {
Expand Down Expand Up @@ -735,6 +732,9 @@ export class ComfyPage {
if (!id) return null
return this.getNodeRefById(id)
}
async moveMouseToEmptyArea() {
await this.page.mouse.move(10, 10)
}
}
class NodeSlotReference {
constructor(
Expand Down Expand Up @@ -786,7 +786,7 @@ class NodeSlotReference {
)
}
}
class NodeReference {
export class NodeReference {
constructor(
readonly id: NodeId,
readonly comfyPage: ComfyPage
Expand All @@ -809,13 +809,39 @@ class NodeReference {
y: pos[1]
}
}
async getBounding(): Promise<Position & Size> {
const [x, y, width, height]: [number, number, number, number] =
await this.comfyPage.page.evaluate((id) => {
const node = window['app'].graph.getNodeById(id)
if (!node) throw new Error('Node not found')
return node.getBounding()
}, this.id)
return {
x,
y,
width,
height
}
}
async getSize(): Promise<Size> {
const size = await this.getProperty<[number, number]>('size')
return {
width: size[0],
height: size[1]
}
}
async getFlags(): Promise<{ collapsed?: boolean; pinned?: boolean }> {
return await this.getProperty('flags')
}
async isPinned() {
return !!(await this.getFlags()).pinned
}
async isCollapsed() {
return !!(await this.getFlags()).collapsed
}
async isBypassed() {
return (await this.getProperty<number | null | undefined>('mode')) === 4
}
async getProperty<T>(prop: string): Promise<T> {
return await this.comfyPage.page.evaluate(
([id, prop]) => {
Expand All @@ -832,22 +858,37 @@ class NodeReference {
async getInput(index: number) {
return new NodeSlotReference('input', index, this)
}
async click(position: 'title', options?: Parameters<Page['click']>[1]) {
async click(
position: 'title' | 'collapse',
options?: Parameters<Page['click']>[1] & { moveMouseToEmptyArea?: boolean }
) {
const nodePos = await this.getPosition()
const nodeSize = await this.getSize()
let clickPos: Position
switch (position) {
case 'title':
clickPos = { x: nodePos.x + nodeSize.width / 2, y: nodePos.y + 15 }
clickPos = { x: nodePos.x + nodeSize.width / 2, y: nodePos.y - 15 }
break
case 'collapse':
clickPos = { x: nodePos.x + 5, y: nodePos.y - 10 }
break
default:
throw new Error(`Invalid click position ${position}`)
}

const moveMouseToEmptyArea = options?.moveMouseToEmptyArea
if (options) {
delete options.moveMouseToEmptyArea
}

await this.comfyPage.canvas.click({
...options,
position: clickPos
})
await this.comfyPage.nextFrame()
if (moveMouseToEmptyArea) {
await this.comfyPage.moveMouseToEmptyArea()
}
}
async connectOutput(
originSlotIndex: number,
Expand Down Expand Up @@ -898,3 +939,35 @@ export const comfyPageFixture = base.extend<{ comfyPage: ComfyPage }>({
await use(comfyPage)
}
})

const makeMatcher = function <T>(
getValue: (node: NodeReference) => Promise<T> | T,
type: string
) {
return async function (
node: NodeReference,
options?: { timeout?: number; intervals?: number[] }
) {
const value = await getValue(node)
let assertion = expect(
value,
'Node is ' + (this.isNot ? '' : 'not ') + type
)
if (this.isNot) {
assertion = assertion.not
}
await expect(async () => {
assertion.toBeTruthy()
}).toPass({ timeout: 250, ...options })
return {
pass: !this.isNot,
message: () => 'Node is ' + (this.isNot ? 'not ' : '') + type
}
}
}

export const comfyExpect = expect.extend({
toBePinned: makeMatcher((n) => n.isPinned(), 'pinned'),
toBeBypassed: makeMatcher((n) => n.isBypassed(), 'bypassed'),
toBeCollapsed: makeMatcher((n) => n.isCollapsed(), 'collapsed')
})
100 changes: 100 additions & 0 deletions browser_tests/changeTracker.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import {
ComfyPage,
comfyPageFixture as test,
comfyExpect as expect
} from './ComfyPage'

async function beforeChange(comfyPage: ComfyPage) {
await comfyPage.page.evaluate(() => {
window['app'].canvas.emitBeforeChange()
})
}
async function afterChange(comfyPage: ComfyPage) {
await comfyPage.page.evaluate(() => {
window['app'].canvas.emitAfterChange()
})
}

test.describe('Change Tracker', () => {
test('Can group multiple change actions into a single transaction', async ({
comfyPage
}) => {
const node = (await comfyPage.getFirstNodeRef())!
expect(node).toBeTruthy()
await expect(node).not.toBeCollapsed()
await expect(node).not.toBeBypassed()

// Make changes outside set
// Bypass + collapse node
await node.click('collapse')
await comfyPage.ctrlB()
await expect(node).toBeCollapsed()
await expect(node).toBeBypassed()

// Undo, undo, ensure both changes undone
await comfyPage.ctrlZ()
await expect(node).not.toBeBypassed()
await expect(node).toBeCollapsed()
await comfyPage.ctrlZ()
await expect(node).not.toBeBypassed()
await expect(node).not.toBeCollapsed()

// Run again, but within a change transaction
beforeChange(comfyPage)

await node.click('collapse')
await comfyPage.ctrlB()
await expect(node).toBeCollapsed()
await expect(node).toBeBypassed()

// End transaction
afterChange(comfyPage)

// Ensure undo reverts both changes
await comfyPage.ctrlZ()
await expect(node).not.toBeBypassed()
await expect(node).not.toBeCollapsed()
})

test('Can group multiple transaction calls into a single one', async ({
comfyPage
}) => {
const node = (await comfyPage.getFirstNodeRef())!
const bypassAndPin = async () => {
await beforeChange(comfyPage)
await comfyPage.ctrlB()
await expect(node).toBeBypassed()
await comfyPage.page.keyboard.press('KeyP')
await comfyPage.nextFrame()
await expect(node).toBePinned()
await afterChange(comfyPage)
}

const collapse = async () => {
await beforeChange(comfyPage)
await node.click('collapse', { moveMouseToEmptyArea: true })
await expect(node).toBeCollapsed()
await afterChange(comfyPage)
}

const multipleChanges = async () => {
await beforeChange(comfyPage)
// Call other actions that uses begin/endChange
await collapse()
await bypassAndPin()
await afterChange(comfyPage)
}

await multipleChanges()

await comfyPage.ctrlZ()
await expect(node).not.toBeBypassed()
await expect(node).not.toBePinned()
await expect(node).not.toBeCollapsed()

await comfyPage.ctrlY()
await expect(node).toBeBypassed()
await expect(node).toBePinned()
await expect(node).toBeCollapsed()
})
})
19 changes: 19 additions & 0 deletions browser_tests/copyPaste.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,23 @@ test.describe('Copy Paste', () => {
await comfyPage.page.keyboard.up('Alt')
await expect(comfyPage.canvas).toHaveScreenshot('drag-copy-copied-node.png')
})

test('Can undo paste multiple nodes as single action', async ({
comfyPage
}) => {
const initialCount = await comfyPage.getGraphNodesCount()
expect(initialCount).toBeGreaterThan(1)
await comfyPage.canvas.click()
await comfyPage.ctrlA()
await comfyPage.page.mouse.move(10, 10)
await comfyPage.ctrlC()
await comfyPage.ctrlV()

const pasteCount = await comfyPage.getGraphNodesCount()
expect(pasteCount).toBe(initialCount * 2)

await comfyPage.ctrlZ()
const undoCount = await comfyPage.getGraphNodesCount()
expect(undoCount).toBe(initialCount)
})
})
2 changes: 1 addition & 1 deletion src/scripts/changeTracker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export class ChangeTracker {
}

checkState() {
if (!this.app.graph) return
if (!this.app.graph || this.changeCount) return

const currentState = this.app.graph.serialize()
if (!this.activeState) {
Expand Down

0 comments on commit fcbdefc

Please sign in to comment.