feat: enforce no-explicit-any in browser tests via oxlint

- Add typescript/no-explicit-any override for browser_tests/**/*.ts

- Fix 9 violations with proper types instead of any

- Add TestGraphAccess interface for typed node access

- Add function overloads to getExportedWorkflow for proper return types

- Fix floating promise in colorPalette.spec.ts

Amp-Thread-ID: https://ampcode.com/threads/T-019c1854-3c3c-723d-8ce6-183ce06fcf1b
Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
Alexander Brown
2026-02-01 01:12:44 -08:00
parent f96a700621
commit 16fec4d45c
8 changed files with 45 additions and 19 deletions

View File

@@ -110,6 +110,12 @@
"rules": {
"no-console": "allow"
}
},
{
"files": ["browser_tests/**/*.ts"],
"rules": {
"typescript/no-explicit-any": "error"
}
}
]
}

View File

@@ -260,7 +260,7 @@ export class ComfyPage {
return await resp.json()
}
async setupSettings(settings: Record<string, any>) {
async setupSettings(settings: Record<string, unknown>) {
const resp = await this.request.post(
`${this.url}/api/devtools/set_settings`,
{

View File

@@ -1,5 +1,9 @@
import { readFileSync } from 'fs'
import type {
ComfyApiWorkflow,
ComfyWorkflowJSON
} from '../../../src/platform/workflow/validation/schemas/workflowSchema'
import type { WorkspaceStore } from '../../types/globals'
import type { ComfyPage } from '../ComfyPage'
@@ -107,7 +111,13 @@ export class WorkflowHelper {
})
}
async getExportedWorkflow(options?: { api?: boolean }): Promise<any> {
async getExportedWorkflow(options: { api: true }): Promise<ComfyApiWorkflow>
async getExportedWorkflow(options?: {
api?: false
}): Promise<ComfyWorkflowJSON>
async getExportedWorkflow(options?: {
api?: boolean
}): Promise<ComfyWorkflowJSON | ComfyApiWorkflow> {
const api = options?.api ?? false
return this.comfyPage.page.evaluate(async (api) => {
return (await window.app!.graphToPrompt())[api ? 'output' : 'workflow']

View File

@@ -1,7 +1,7 @@
import { test as base } from '@playwright/test'
export const webSocketFixture = base.extend<{
ws: { trigger(data: any, url?: string): Promise<void> }
ws: { trigger(data: unknown, url?: string): Promise<void> }
}>({
ws: [
async ({ page }, use) => {

View File

@@ -178,8 +178,8 @@ test.describe('Color Palette', { tag: ['@screenshot', '@settings'] }, () => {
})
test('Can add custom color palette', async ({ comfyPage }) => {
await comfyPage.page.evaluate((p) => {
;(
await comfyPage.page.evaluate(async (p) => {
await (
window.app!.extensionManager as WorkspaceStore
).colorPalette.addCustomColorPalette(p)
}, customColorPalettes.obsidian_dark)

View File

@@ -145,11 +145,11 @@ test.describe('Workflows sidebar', () => {
})
expect(exportedWorkflow).toBeDefined()
for (const node of exportedWorkflow.nodes) {
for (const slot of node.inputs) {
for (const slot of node.inputs ?? []) {
expect(slot.localized_name).toBeUndefined()
expect(slot.label).toBeUndefined()
}
for (const slot of node.outputs) {
for (const slot of node.outputs ?? []) {
expect(slot.localized_name).toBeUndefined()
expect(slot.label).toBeUndefined()
}

View File

@@ -2,6 +2,7 @@ import {
comfyExpect as expect,
comfyPageFixture as test
} from '../../../fixtures/ComfyPage'
import type { TestGraphAccess } from '../../../types/globals'
test.describe('Vue Widget Reactivity', () => {
test.beforeEach(async ({ comfyPage }) => {
@@ -13,21 +14,21 @@ test.describe('Vue Widget Reactivity', () => {
'css=[data-testid="node-body-4"] > .lg-node-widgets > div'
)
await comfyPage.page.evaluate(() => {
const graph = window.graph as { _nodes_by_id: Record<string, any> }
const graph = window.graph as TestGraphAccess
const node = graph._nodes_by_id['4']
node.widgets.push(node.widgets[0])
node.widgets!.push(node.widgets![0])
})
await expect(loadCheckpointNode).toHaveCount(2)
await comfyPage.page.evaluate(() => {
const graph = window.graph as { _nodes_by_id: Record<string, any> }
const graph = window.graph as TestGraphAccess
const node = graph._nodes_by_id['4']
node.widgets[2] = node.widgets[0]
node.widgets![2] = node.widgets![0]
})
await expect(loadCheckpointNode).toHaveCount(3)
await comfyPage.page.evaluate(() => {
const graph = window.graph as { _nodes_by_id: Record<string, any> }
const graph = window.graph as TestGraphAccess
const node = graph._nodes_by_id['4']
node.widgets.splice(0, 0, node.widgets[0])
node.widgets!.splice(0, 0, node.widgets![0])
})
await expect(loadCheckpointNode).toHaveCount(4)
})
@@ -36,21 +37,21 @@ test.describe('Vue Widget Reactivity', () => {
'css=[data-testid="node-body-3"] > .lg-node-widgets > div'
)
await comfyPage.page.evaluate(() => {
const graph = window.graph as { _nodes_by_id: Record<string, any> }
const graph = window.graph as TestGraphAccess
const node = graph._nodes_by_id['3']
node.widgets.pop()
node.widgets!.pop()
})
await expect(loadCheckpointNode).toHaveCount(5)
await comfyPage.page.evaluate(() => {
const graph = window.graph as { _nodes_by_id: Record<string, any> }
const graph = window.graph as TestGraphAccess
const node = graph._nodes_by_id['3']
node.widgets.length--
node.widgets!.length--
})
await expect(loadCheckpointNode).toHaveCount(4)
await comfyPage.page.evaluate(() => {
const graph = window.graph as { _nodes_by_id: Record<string, any> }
const graph = window.graph as TestGraphAccess
const node = graph._nodes_by_id['3']
node.widgets.splice(0, 1)
node.widgets!.splice(0, 1)
})
await expect(loadCheckpointNode).toHaveCount(3)
})

View File

@@ -1,8 +1,17 @@
import type { LGraph } from '@/lib/litegraph/src/LGraph'
import type { LGraphNode } from '@/lib/litegraph/src/LGraphNode'
import type { LiteGraphGlobal } from '@/lib/litegraph/src/LiteGraphGlobal'
import type { ComfyApp } from '@/scripts/app'
import type { useWorkspaceStore } from '@/stores/workspaceStore'
/**
* Helper type for accessing nodes by ID in browser tests.
* Provides typed access to graph internals without requiring `any`.
*/
export interface TestGraphAccess {
_nodes_by_id: Record<string, LGraphNode>
}
interface AppReadiness {
featureFlagsReceived: boolean
apiInitialized: boolean