## Summary Document the recommended pattern for adding new domain-specific test helpers as Playwright fixtures via `base.extend()` instead of attaching them to `ComfyPage`. ## Changes - **What**: Added "Creating New Test Helpers" section to `docs/guidance/playwright.md` with fixture extension example and rules ## Review Focus Documentation-only change. Verify the example code matches the existing pattern in `browser_tests/fixtures/ComfyPage.ts`. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-10653-docs-document-Playwright-fixture-injection-pattern-for-new-helpers-3316d73d36508145b402cf02a5c2c696) by [Unito](https://www.unito.io) --------- Co-authored-by: Alexander Brown <drjkl@comfy.org>
4.6 KiB
globs
| globs | |
|---|---|
|
Playwright E2E Test Conventions
See docs/testing/*.md for detailed patterns.
Best Practices
- Follow Playwright Best Practices
- Do NOT use
waitForTimeout— use Locator actions and retrying assertions - Prefer specific selectors (role, label, test-id)
- Test across viewports
Window Globals
Browser tests access window.app, window.graph, and window.LiteGraph which are
optional in the main app types. Use non-null assertions (!) in E2E tests only:
window.app!.graph!.nodes
window.LiteGraph!.registered_node_types
TODO: Consolidate into a central utility (e.g., getApp()) with runtime type checking.
Type Assertions
Use specific type assertions when needed, never as any.
Acceptable:
window.app!.extensionManager
id: 'TestSetting' as TestSettingId
type TestSettingId = keyof Settings
Forbidden:
settings: testData as any
data as unknown as SomeType
Access internal state via page.evaluate and stores directly — don't change public API types to expose internals.
Assertion Best Practices
Assert preconditions explicitly with a custom message so failures point to the broken assumption:
expect(node.widgets, 'Widget count changed — update test fixture').toHaveLength(
4
)
await node.move(100, 200)
expect.soft(menuItem1).toBeVisible()
expect.soft(menuItem2).toBeVisible()
// Bad — bare expect on a precondition gives no context when it fails
expect(node.widgets).toHaveLength(4)
expect(x, 'reason')for precondition checks unrelated to the test's purposeexpect.soft()to verify multiple invariants without aborting on the first failure
Test Structure: Arrange/Act/Assert
- All mock setup, state resets, and fixture arrangement belongs in
test.beforeEach()or Playwright fixtures - Inside
test(), only act (user actions) and assert - Never call
clearAllMocksor reset mock state mid-test
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.workflow.loadWorkflow('test.json')
})
test('should do something', async ({ comfyPage }) => {
await comfyPage.menu.topbar.click()
await expect(comfyPage.menu.nodeLibraryTab.root).toBeVisible()
})
Creating New Test Helpers
New domain-specific test helpers (e.g., AssetHelper, JobHelper) should be
registered as Playwright fixtures via base.extend() rather than attached as
properties on ComfyPage. This enables automatic setup/teardown.
Extend base from Playwright
Keep each fixture self-contained by extending @playwright/test directly.
Compose fixtures together with mergeTests when a test needs multiple helpers.
// browser_tests/fixtures/assetFixture.ts
import { test as base } from '@playwright/test'
export const test = base.extend<{
assetHelper: AssetHelper
}>({
assetHelper: async ({ page }, use) => {
const helper = new AssetHelper(page)
await helper.setup()
await use(helper)
await helper.cleanup() // automatic teardown
}
})
Rules
- Do NOT add new helpers as properties on
ComfyPage - Each fixture gets automatic cleanup via the callback after
use() - Keep fixtures modular — extend
@playwright/testbase, notcomfyPageFixture, so they can be composed viamergeTests
Test Tags
@mobile— Mobile viewport tests@2x— High DPI tests
Test Data
- Check
browser_tests/assets/for fixtures - Use realistic ComfyUI workflows
- When multiple nodes share the same title, use
vueNodes.getNodeByTitle(name).nth(n)— Playwright strict mode will fail on ambiguous locators
Fixture Data & Schemas
When creating test fixture data, import or reference existing Zod schemas and TypeScript
types from src/ instead of inventing ad-hoc shapes. This keeps test data in sync with
production types.
Key schema locations:
src/schemas/apiSchema.ts— API response types (PromptResponse,SystemStats,User,UserDataFullInfo, WebSocket messages)src/schemas/nodeDefSchema.ts— Node definition schema (ComfyNodeDef,InputSpec,ComboInputSpec)src/schemas/nodeDef/nodeDefSchemaV2.ts— V2 node definition schemasrc/platform/remote/comfyui/jobs/jobTypes.ts— Jobs API Zod schemas (zJobDetail,zJobsListResponse,zRawJobListItem)src/platform/workflow/validation/schemas/workflowSchema.ts— Workflow validation (ComfyWorkflowJSON,ComfyApiWorkflow)src/types/metadataTypes.ts— Asset metadata types
Running Tests
pnpm test:browser:local # Run all E2E tests
pnpm test:browser:local -- --ui # Interactive UI mode