Compare commits

...

13 Commits

Author SHA1 Message Date
bymyself
0f67ca7fdd fix: Simplify cloud auth wait logic 2025-11-18 10:58:36 -08:00
bymyself
33e7c0491c fix: Use correct selectors for cloud login form 2025-11-15 23:51:18 -08:00
bymyself
d6d79a834c feat: Enable cloud workflow on push/PR 2025-11-15 13:23:33 -08:00
bymyself
d0d2789f78 feat: Add CI workflow for cloud E2E tests
- Create ci-tests-e2e-cloud.yaml workflow
- Manual trigger via workflow_dispatch
- Uses CLOUD_TEST_EMAIL and CLOUD_TEST_PASSWORD secrets
- Add CLOUD_TESTS.md documentation
2025-11-13 18:25:13 -08:00
bymyself
14ab045a05 fix: exclude @cloud tests from regular playwright runs, add playwright.config.ts to tsconfig 2025-11-13 14:51:42 -08:00
bymyself
730d8c2292 fix: pass parallelIndex to ComfyPage constructor instead of accessing fixture 2025-11-13 09:58:03 -08:00
bymyself
34d7f4b7df fix: import comfyExpect from ComfyPage in 4-level vueNodes tests 2025-11-11 11:47:42 -08:00
bymyself
c5138692bf fix: import comfyExpect from ComfyPage in all vueNodes tests 2025-11-11 10:56:06 -08:00
bymyself
54597f786e fix: import comfyExpect from ComfyPage not comfyPageFixture 2025-11-07 19:35:05 -08:00
bymyself
24be8d123b fix: resolve circular dependency by removing comfyPageFixture re-export
- Remove comfyPageFixture re-export from ComfyPage.ts
- Update all test imports to use comfyPageFixture from its own file
- Update README.md example to show correct import path
- Fixes: comfyPageFixture → LocalhostComfyPage → ComfyPage circular import
2025-11-06 22:55:25 -07:00
bymyself
c44c3088c0 fix: Break circular dependency with shared constants file
Circular dependency was caused by:
- comfyPageFixture.ts importing testComfySnapToGridGridSize from ComfyPage.ts
- ComfyPage.ts re-exporting comfyPageFixture

Solution:
- Extract testComfySnapToGridGridSize to constants.ts
- Both files import from constants.ts
- Only type-import ComfyPage in comfyPageFixture.ts

Now clean dependency graph with no cycles.
2025-11-06 21:28:41 -07:00
bymyself
f306cc9bcb refactor: Extract comfyPageFixture to separate file
Fixes circular dependency between ComfyPage and LocalhostComfyPage.

Changes:
- Create browser_tests/fixtures/comfyPageFixture.ts with fixture
- Remove fixture from ComfyPage.ts (keep abstract class only)
- Re-export fixture from ComfyPage.ts for backward compatibility

Now properly follows dependency hierarchy:
- ComfyPage.ts (abstract) - no implementation imports
- LocalhostComfyPage.ts → imports ComfyPage
- comfyPageFixture.ts → imports both
- Tests import from ComfyPage.ts (re-exported)
2025-11-06 19:49:48 -07:00
bymyself
ae1617874f feat: Add cloud E2E testing infrastructure
Adds Playwright tests for cloud environment with Firebase auth.

Changes:
- Refactor ComfyPage to abstract base class
- Add LocalhostComfyPage (existing devtools implementation)
- Add CloudComfyPage (cloud settings API, Firebase auth)
- Add cloud fixture with auth state persistence
- Add globalSetupCloud for Firebase login
- Add playwright.cloud.config with 5x timeout
- Add basic cloud tests (load app, canvas interaction, settings)
- Update .gitignore for auth state files
- Update tsconfig to include playwright.cloud.config

Architecture:
- ComfyPage abstract with 3 backend-specific methods
- LocalhostComfyPage uses /api/devtools + multi-user
- CloudComfyPage uses /api/settings + Firebase localStorage
- No code duplication (95% shared)

Setup:
- Requires CLOUD_TEST_EMAIL and CLOUD_TEST_PASSWORD env vars
- globalSetup logs in once, saves auth to browser_tests/.auth/
- Tests reuse saved auth state (no login per test)
2025-11-06 16:23:00 -07:00
82 changed files with 587 additions and 242 deletions

View File

@@ -0,0 +1,51 @@
name: "CI: Tests E2E Cloud"
description: "Cloud E2E testing with Playwright against stagingcloud.comfy.org"
on:
workflow_dispatch:
push:
branches: [cloud/*, main]
pull_request:
branches: [main]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
playwright-tests-cloud:
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v5
- name: Setup frontend
uses: ./.github/actions/setup-frontend
with:
include_build_step: false # Cloud tests don't need build
- name: Setup Playwright
uses: ./.github/actions/setup-playwright
- name: Run Playwright cloud tests
id: playwright
env:
CLOUD_TEST_EMAIL: ${{ secrets.CLOUD_TEST_EMAIL }}
CLOUD_TEST_PASSWORD: ${{ secrets.CLOUD_TEST_PASSWORD }}
run: |
PLAYWRIGHT_JSON_OUTPUT_NAME=playwright-report/report.json \
pnpm exec playwright test --config=playwright.cloud.config.ts \
--reporter=list \
--reporter=html \
--reporter=json
- name: Upload Playwright report
uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report-cloud
path: ./playwright-report/
retention-days: 30

1
.gitignore vendored
View File

@@ -58,6 +58,7 @@ coverage/
/playwright/.cache/
browser_tests/**/*-win32.png
browser_tests/local/
browser_tests/.auth/
.env

View File

@@ -140,7 +140,7 @@ When writing new tests, follow these patterns:
```typescript
// Import the test fixture
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
test.describe('Feature Name', () => {
// Set up test environment if needed

View File

@@ -0,0 +1,44 @@
import type { APIRequestContext, Page } from '@playwright/test'
import { ComfyPage } from './ComfyPage'
import type { FolderStructure } from './ComfyPage'
/**
* Cloud-specific implementation of ComfyPage.
* Uses Firebase auth persistence and cloud API for settings.
*/
export class CloudComfyPage extends ComfyPage {
constructor(
page: Page,
request: APIRequestContext,
parallelIndex: number = 0
) {
super(page, request, parallelIndex)
}
async setupUser(username: string): Promise<string | null> {
// No-op for cloud - user already authenticated via Firebase in globalSetup
// Firebase auth is persisted via storageState in the fixture
return null
}
async setupSettings(settings: Record<string, any>): Promise<void> {
// Cloud uses batch settings API (not devtools)
// Firebase auth token is automatically included from restored localStorage
const resp = await this.request.post(`${this.url}/api/settings`, {
data: settings
})
if (!resp.ok()) {
throw new Error(`Failed to setup cloud settings: ${await resp.text()}`)
}
}
async setupWorkflowsDirectory(structure: FolderStructure): Promise<void> {
// Cloud workflow API not yet implemented
// For initial smoke tests, we can skip this functionality
console.warn(
'setupWorkflowsDirectory: not yet implemented for cloud mode - skipping'
)
}
}

View File

@@ -1,5 +1,5 @@
import type { APIRequestContext, Locator, Page } from '@playwright/test'
import { test as base, expect } from '@playwright/test'
import { expect } from '@playwright/test'
import dotenv from 'dotenv'
import * as fs from 'fs'
@@ -7,10 +7,8 @@ import type { LGraphNode } from '../../src/lib/litegraph/src/litegraph'
import type { NodeId } from '../../src/platform/workflow/validation/schemas/workflowSchema'
import type { KeyCombo } from '../../src/schemas/keyBindingSchema'
import type { useWorkspaceStore } from '../../src/stores/workspaceStore'
import { NodeBadgeMode } from '../../src/types/nodeSource'
import { ComfyActionbar } from '../helpers/actionbar'
import { ComfyTemplates } from '../helpers/templates'
import { ComfyMouse } from './ComfyMouse'
import { VueNodeHelpers } from './VueNodeHelpers'
import { ComfyNodeSearchBox } from './components/ComfyNodeSearchBox'
import { SettingDialog } from './components/SettingDialog'
@@ -94,7 +92,7 @@ class ComfyMenu {
}
}
type FolderStructure = {
export type FolderStructure = {
[key: string]: FolderStructure | string
}
@@ -122,7 +120,11 @@ class ConfirmDialog {
}
}
export class ComfyPage {
/**
* Abstract base class for ComfyUI page objects.
* Subclasses must implement backend-specific methods for different environments (localhost, cloud, etc.)
*/
export abstract class ComfyPage {
private _history: TaskHistory | null = null
public readonly url: string
@@ -156,12 +158,13 @@ export class ComfyPage {
/** Test user ID for the current context */
get id() {
return this.userIds[comfyPageFixture.info().parallelIndex]
return this.userIds[this.parallelIndex]
}
constructor(
public readonly page: Page,
public readonly request: APIRequestContext
public readonly request: APIRequestContext,
public readonly parallelIndex: number = 0
) {
this.url = process.env.PLAYWRIGHT_TEST_URL || 'http://localhost:8188'
this.canvas = page.locator('#graph-canvas')
@@ -215,65 +218,24 @@ export class ComfyPage {
})
}
async setupWorkflowsDirectory(structure: FolderStructure) {
const resp = await this.request.post(
`${this.url}/api/devtools/setup_folder_structure`,
{
data: {
tree_structure: this.convertLeafToContent(structure),
base_path: `user/${this.id}/workflows`
}
}
)
/**
* Setup workflows directory structure. Implementation varies by environment.
* @param structure - Folder structure to create
*/
abstract setupWorkflowsDirectory(structure: FolderStructure): Promise<void>
if (resp.status() !== 200) {
throw new Error(
`Failed to setup workflows directory: ${await resp.text()}`
)
}
/**
* Setup user for testing. Implementation varies by environment.
* @param username - Username to setup
* @returns User ID or null if not applicable
*/
abstract setupUser(username: string): Promise<string | null>
await this.page.evaluate(async () => {
await window['app'].extensionManager.workflow.syncWorkflows()
})
}
async setupUser(username: string) {
const res = await this.request.get(`${this.url}/api/users`)
if (res.status() !== 200)
throw new Error(`Failed to retrieve users: ${await res.text()}`)
const apiRes = await res.json()
const user = Object.entries(apiRes?.users ?? {}).find(
([, name]) => name === username
)
const id = user?.[0]
return id ? id : await this.createUser(username)
}
async createUser(username: string) {
const resp = await this.request.post(`${this.url}/api/users`, {
data: { username }
})
if (resp.status() !== 200)
throw new Error(`Failed to create user: ${await resp.text()}`)
return await resp.json()
}
async setupSettings(settings: Record<string, any>) {
const resp = await this.request.post(
`${this.url}/api/devtools/set_settings`,
{
data: settings
}
)
if (resp.status() !== 200) {
throw new Error(`Failed to setup settings: ${await resp.text()}`)
}
}
/**
* Setup settings for testing. Implementation varies by environment.
* @param settings - Settings object to apply
*/
abstract setupSettings(settings: Record<string, any>): Promise<void>
setupHistory(): TaskHistory {
this._history ??= new TaskHistory(this)
@@ -1628,50 +1590,8 @@ export class ComfyPage {
}
}
export const testComfySnapToGridGridSize = 50
export const comfyPageFixture = base.extend<{
comfyPage: ComfyPage
comfyMouse: ComfyMouse
}>({
comfyPage: async ({ page, request }, use, testInfo) => {
const comfyPage = new ComfyPage(page, request)
const { parallelIndex } = testInfo
const username = `playwright-test-${parallelIndex}`
const userId = await comfyPage.setupUser(username)
comfyPage.userIds[parallelIndex] = userId
try {
await comfyPage.setupSettings({
'Comfy.UseNewMenu': 'Top',
// Hide canvas menu/info/selection toolbox by default.
'Comfy.Graph.CanvasInfo': false,
'Comfy.Graph.CanvasMenu': false,
'Comfy.Canvas.SelectionToolbox': false,
// Hide all badges by default.
'Comfy.NodeBadge.NodeIdBadgeMode': NodeBadgeMode.None,
'Comfy.NodeBadge.NodeSourceBadgeMode': NodeBadgeMode.None,
// Disable tooltips by default to avoid flakiness.
'Comfy.EnableTooltips': false,
'Comfy.userId': userId,
// Set tutorial completed to true to avoid loading the tutorial workflow.
'Comfy.TutorialCompleted': true,
'Comfy.SnapToGrid.GridSize': testComfySnapToGridGridSize,
'Comfy.VueNodes.AutoScaleLayout': false
})
} catch (e) {
console.error(e)
}
await comfyPage.setup()
await use(comfyPage)
},
comfyMouse: async ({ comfyPage }, use) => {
const comfyMouse = new ComfyMouse(comfyPage)
await use(comfyMouse)
}
})
// Re-export shared constants and fixture
export { testComfySnapToGridGridSize } from './constants'
const makeMatcher = function <T>(
getValue: (node: NodeReference) => Promise<T> | T,

View File

@@ -0,0 +1,48 @@
import { test as base } from '@playwright/test'
import { CloudComfyPage } from './CloudComfyPage'
import { ComfyMouse } from './ComfyMouse'
import type { ComfyPage } from './ComfyPage'
/**
* Cloud-specific fixture for ComfyPage.
* Uses Firebase auth persisted from globalSetupCloud.ts.
*/
export const comfyPageCloudFixture = base.extend<{
comfyPage: ComfyPage
comfyMouse: ComfyMouse
}>({
// Use the storageState saved by globalSetupCloud
storageState: 'browser_tests/.auth/cloudUser.json',
comfyPage: async ({ page, request }, use) => {
const comfyPage = new CloudComfyPage(page, request)
// Note: No setupUser needed - Firebase auth persisted via storageState
// Setup cloud-specific settings (optional - can customize per test)
try {
await comfyPage.setupSettings({
'Comfy.UseNewMenu': 'Top',
// Hide canvas menu/info/selection toolbox by default.
'Comfy.Graph.CanvasInfo': false,
'Comfy.Graph.CanvasMenu': false,
'Comfy.Canvas.SelectionToolbox': false,
// Disable tooltips by default to avoid flakiness.
'Comfy.EnableTooltips': false,
// Set tutorial completed to true to avoid loading the tutorial workflow.
'Comfy.TutorialCompleted': true
})
} catch (e) {
console.error('Failed to setup cloud settings:', e)
}
// Don't mock releases for cloud - cloud handles its own releases
await comfyPage.setup({ mockReleases: false })
await use(comfyPage)
},
comfyMouse: async ({ comfyPage }, use) => {
const comfyMouse = new ComfyMouse(comfyPage)
await use(comfyMouse)
}
})

View File

@@ -0,0 +1,78 @@
import type { APIRequestContext, Page } from '@playwright/test'
import { ComfyPage } from './ComfyPage'
import type { FolderStructure } from './ComfyPage'
/**
* Localhost-specific implementation of ComfyPage.
* Uses devtools API and multi-user mode for test isolation.
*/
export class LocalhostComfyPage extends ComfyPage {
constructor(
page: Page,
request: APIRequestContext,
parallelIndex: number = 0
) {
super(page, request, parallelIndex)
}
async setupWorkflowsDirectory(structure: FolderStructure): Promise<void> {
const resp = await this.request.post(
`${this.url}/api/devtools/setup_folder_structure`,
{
data: {
tree_structure: this.convertLeafToContent(structure),
base_path: `user/${this.id}/workflows`
}
}
)
if (resp.status() !== 200) {
throw new Error(
`Failed to setup workflows directory: ${await resp.text()}`
)
}
await this.page.evaluate(async () => {
await window['app'].extensionManager.workflow.syncWorkflows()
})
}
async setupUser(username: string): Promise<string | null> {
const res = await this.request.get(`${this.url}/api/users`)
if (res.status() !== 200)
throw new Error(`Failed to retrieve users: ${await res.text()}`)
const apiRes = await res.json()
const user = Object.entries(apiRes?.users ?? {}).find(
([, name]) => name === username
)
const id = user?.[0]
return id ? id : await this.createUser(username)
}
private async createUser(username: string): Promise<string> {
const resp = await this.request.post(`${this.url}/api/users`, {
data: { username }
})
if (resp.status() !== 200)
throw new Error(`Failed to create user: ${await resp.text()}`)
return await resp.json()
}
async setupSettings(settings: Record<string, any>): Promise<void> {
const resp = await this.request.post(
`${this.url}/api/devtools/set_settings`,
{
data: settings
}
)
if (resp.status() !== 200) {
throw new Error(`Failed to setup settings: ${await resp.text()}`)
}
}
}

View File

@@ -0,0 +1,56 @@
import { test as base } from '@playwright/test'
import { NodeBadgeMode } from '../../src/types/nodeSource'
import type { ComfyPage } from './ComfyPage'
import { ComfyMouse } from './ComfyMouse'
import { testComfySnapToGridGridSize } from './constants'
import { LocalhostComfyPage } from './LocalhostComfyPage'
/**
* Localhost fixture for ComfyPage.
* Creates a test user and sets up default settings for stable testing.
*/
export const comfyPageFixture = base.extend<{
comfyPage: ComfyPage
comfyMouse: ComfyMouse
}>({
comfyPage: async ({ page, request }, use, testInfo) => {
const { parallelIndex } = testInfo
const comfyPage = new LocalhostComfyPage(page, request, parallelIndex)
const username = `playwright-test-${parallelIndex}`
const userId = await comfyPage.setupUser(username)
if (userId) {
comfyPage.userIds[parallelIndex] = userId
}
try {
await comfyPage.setupSettings({
'Comfy.UseNewMenu': 'Top',
// Hide canvas menu/info/selection toolbox by default.
'Comfy.Graph.CanvasInfo': false,
'Comfy.Graph.CanvasMenu': false,
'Comfy.Canvas.SelectionToolbox': false,
// Hide all badges by default.
'Comfy.NodeBadge.NodeIdBadgeMode': NodeBadgeMode.None,
'Comfy.NodeBadge.NodeSourceBadgeMode': NodeBadgeMode.None,
// Disable tooltips by default to avoid flakiness.
'Comfy.EnableTooltips': false,
'Comfy.userId': userId,
// Set tutorial completed to true to avoid loading the tutorial workflow.
'Comfy.TutorialCompleted': true,
'Comfy.SnapToGrid.GridSize': testComfySnapToGridGridSize,
'Comfy.VueNodes.AutoScaleLayout': false
})
} catch (e) {
console.error(e)
}
await comfyPage.setup()
await use(comfyPage)
},
comfyMouse: async ({ comfyPage }, use) => {
const comfyMouse = new ComfyMouse(comfyPage)
await use(comfyMouse)
}
})

View File

@@ -0,0 +1,4 @@
/**
* Shared constants for browser tests
*/
export const testComfySnapToGridGridSize = 50

View File

@@ -0,0 +1,63 @@
import { chromium } from '@playwright/test'
import type { FullConfig } from '@playwright/test'
import dotenv from 'dotenv'
import * as fs from 'fs'
import * as path from 'path'
dotenv.config()
/**
* Global setup for cloud tests.
* Authenticates with Firebase and saves auth state for test reuse.
*/
export default async function globalSetupCloud(config: FullConfig) {
const CLOUD_TEST_EMAIL = process.env.CLOUD_TEST_EMAIL
const CLOUD_TEST_PASSWORD = process.env.CLOUD_TEST_PASSWORD
if (!CLOUD_TEST_EMAIL || !CLOUD_TEST_PASSWORD) {
throw new Error(
'CLOUD_TEST_EMAIL and CLOUD_TEST_PASSWORD must be set in environment variables'
)
}
const browser = await chromium.launch()
const context = await browser.newContext()
const page = await context.newPage()
try {
// Navigate to cloud login page
await page.goto('https://stagingcloud.comfy.org/cloud/login', {
waitUntil: 'networkidle',
timeout: 30000
})
// Fill in email and password
await page.fill('#cloud-sign-in-email', CLOUD_TEST_EMAIL)
await page.fill('#cloud-sign-in-password', CLOUD_TEST_PASSWORD)
// Click login button
await page.click('button[type="submit"]')
// Wait for redirect to main app
await page.waitForURL('**/cloud', { timeout: 30000 })
// Wait a bit for auth tokens to be written to localStorage
await page.waitForTimeout(2000)
// Ensure .auth directory exists
const authDir = path.join(__dirname, '.auth')
if (!fs.existsSync(authDir)) {
fs.mkdirSync(authDir, { recursive: true })
}
// Save authentication state (includes localStorage with Firebase tokens)
await context.storageState({
path: 'browser_tests/.auth/cloudUser.json'
})
} catch (error) {
console.error('❌ Failed to authenticate:', error)
throw error
} finally {
await browser.close()
}
}

View File

@@ -0,0 +1,36 @@
# Cloud E2E Tests
## Setup
Cloud tests run against `https://stagingcloud.comfy.org` with Firebase authentication.
### Required GitHub Secrets
Add these to repository settings → Secrets → Actions:
- `CLOUD_TEST_EMAIL`: Firebase test account email
- `CLOUD_TEST_PASSWORD`: Firebase test account password
### Running Locally
```bash
# Set environment variables
export CLOUD_TEST_EMAIL="your-test-email@example.com"
export CLOUD_TEST_PASSWORD="your-password"
# Run cloud tests
pnpm exec playwright test --config=playwright.cloud.config.ts
```
### Running in CI
Workflow: `.github/workflows/ci-tests-e2e-cloud.yaml`
Trigger manually via Actions tab → "CI: Tests E2E Cloud" → Run workflow
### Test Structure
- Tests tagged with `@cloud` run only in cloud config
- Auth handled once in `globalSetupCloud.ts`
- Auth state saved to `browser_tests/.auth/cloudUser.json`
- Cloud fixture in `fixtures/ComfyPageCloud.ts`

View File

@@ -2,7 +2,7 @@ import type { Response } from '@playwright/test'
import { expect, mergeTests } from '@playwright/test'
import type { StatusWsMessage } from '../../src/schemas/apiSchema.ts'
import { comfyPageFixture } from '../fixtures/ComfyPage.ts'
import { comfyPageFixture } from '../fixtures/comfyPageFixture.ts'
import { webSocketFixture } from '../fixtures/ws.ts'
const test = mergeTests(comfyPageFixture, webSocketFixture)

View File

@@ -1,6 +1,6 @@
import { expect } from '@playwright/test'
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled')

View File

@@ -1,6 +1,6 @@
import { expect } from '@playwright/test'
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
test.describe('Bottom Panel Shortcuts', () => {
test.beforeEach(async ({ comfyPage }) => {

View File

@@ -1,6 +1,6 @@
import { expect } from '@playwright/test'
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
test.describe('Browser tab title', () => {
test.describe('Beta Menu', () => {

View File

@@ -1,8 +1,6 @@
import type { ComfyPage } from '../fixtures/ComfyPage'
import {
comfyExpect as expect,
comfyPageFixture as test
} from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
import { comfyExpect as expect } from '../fixtures/ComfyPage'
async function beforeChange(comfyPage: ComfyPage) {
await comfyPage.page.evaluate(() => {

View File

@@ -1,7 +1,7 @@
import type { Page } from '@playwright/test'
import { expect } from '@playwright/test'
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled')

View File

@@ -0,0 +1,49 @@
/**
* @cloud
* Cloud E2E tests.
* Tests run against stagingcloud.comfy.org with authenticated user.
*/
import { expect } from '@playwright/test'
import { comfyPageCloudFixture as test } from '../fixtures/ComfyPageCloud'
test.describe('Cloud E2E @cloud', () => {
test('loads app with authentication', async ({ comfyPage }) => {
// App should be loaded from setup()
await expect(comfyPage.canvas).toBeVisible()
// Verify we're authenticated (cloud-specific check)
const isAuthenticated = await comfyPage.page.evaluate(() => {
// Check for Firebase auth in localStorage
const keys = Object.keys(localStorage)
return keys.some(
(key) => key.startsWith('firebase:') || key.includes('authUser')
)
})
expect(isAuthenticated).toBe(true)
})
test('can interact with canvas', async ({ comfyPage }) => {
// Basic canvas interaction
await comfyPage.doubleClickCanvas()
await expect(comfyPage.searchBox.input).toBeVisible()
// Close search box
await comfyPage.page.keyboard.press('Escape')
await expect(comfyPage.searchBox.input).not.toBeVisible()
})
test('can access settings dialog', async ({ comfyPage }) => {
// Open settings dialog
await comfyPage.page.click('button[data-testid="settings-button"]', {
timeout: 10000
})
// Settings dialog should be visible
await expect(comfyPage.page.locator('.p-dialog')).toBeVisible()
// Close settings
await comfyPage.closeDialog()
})
})

View File

@@ -1,7 +1,7 @@
import { expect } from '@playwright/test'
import type { Palette } from '../../src/schemas/colorPaletteSchema'
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled')

View File

@@ -1,6 +1,6 @@
import { expect } from '@playwright/test'
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled')

View File

@@ -1,6 +1,6 @@
import { expect } from '@playwright/test'
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled')

View File

@@ -1,7 +1,7 @@
import { expect } from '@playwright/test'
import type { Locator } from '@playwright/test'
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
async function verifyCustomIconSvg(iconElement: Locator) {
const svgVariable = await iconElement.evaluate((element) => {

View File

@@ -2,7 +2,7 @@ import type { Locator } from '@playwright/test'
import { expect } from '@playwright/test'
import type { Keybinding } from '../../src/schemas/keyBindingSchema'
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled')

View File

@@ -1,6 +1,6 @@
import { expect } from '@playwright/test'
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled')

View File

@@ -1,6 +1,6 @@
import { expect } from '@playwright/test'
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled')

View File

@@ -1,7 +1,7 @@
import { expect } from '@playwright/test'
import type { SettingParams } from '../../src/platform/settings/types'
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
test.describe('Topbar commands', () => {
test.beforeEach(async ({ comfyPage }) => {

View File

@@ -1,6 +1,6 @@
import { expect } from '@playwright/test'
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled')

View File

@@ -1,6 +1,6 @@
import { expect } from '@playwright/test'
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled')

View File

@@ -1,6 +1,6 @@
import { expect } from '@playwright/test'
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled')

View File

@@ -1,7 +1,7 @@
import { expect } from '@playwright/test'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
import type { ComfyPage } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
import type { NodeReference } from '../fixtures/utils/litegraphUtils'
test.beforeEach(async ({ comfyPage }) => {

View File

@@ -2,11 +2,9 @@ import type { Locator } from '@playwright/test'
import { expect } from '@playwright/test'
import type { Position } from '@vueuse/core'
import {
comfyPageFixture as test,
testComfySnapToGridGridSize
} from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
import type { ComfyPage } from '../fixtures/ComfyPage'
import { testComfySnapToGridGridSize } from '../fixtures/ComfyPage'
import type { NodeReference } from '../fixtures/utils/litegraphUtils'
test.beforeEach(async ({ comfyPage }) => {

View File

@@ -1,6 +1,6 @@
import { expect } from '@playwright/test'
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled')

View File

@@ -1,6 +1,6 @@
import { expect } from '@playwright/test'
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled')

View File

@@ -1,6 +1,6 @@
import { expect } from '@playwright/test'
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled')

View File

@@ -1,6 +1,6 @@
import { expect } from '@playwright/test'
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled')

View File

@@ -1,6 +1,6 @@
import { expect } from '@playwright/test'
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
test.describe('Menu', () => {
test.beforeEach(async ({ comfyPage }) => {

View File

@@ -1,6 +1,6 @@
import { expect } from '@playwright/test'
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
test.describe('Minimap', () => {
test.beforeEach(async ({ comfyPage }) => {

View File

@@ -2,7 +2,7 @@ import { expect } from '@playwright/test'
import type { ComfyApp } from '../../src/scripts/app'
import { NodeBadgeMode } from '../../src/types/nodeSource'
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled')

View File

@@ -1,6 +1,6 @@
import { expect } from '@playwright/test'
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled')

View File

@@ -1,7 +1,5 @@
import {
comfyExpect as expect,
comfyPageFixture as test
} from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
import { comfyExpect as expect } from '../fixtures/ComfyPage'
// TODO: there might be a better solution for this
// Helper function to pan canvas and select node

View File

@@ -1,7 +1,5 @@
import {
comfyExpect as expect,
comfyPageFixture as test
} from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
import { comfyExpect as expect } from '../fixtures/ComfyPage'
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled')

View File

@@ -1,6 +1,6 @@
import { expect } from '@playwright/test'
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled')

View File

@@ -1,6 +1,6 @@
import { expect } from '@playwright/test'
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
import type { NodeReference } from '../fixtures/utils/litegraphUtils'
test.beforeEach(async ({ comfyPage }) => {

View File

@@ -1,6 +1,6 @@
import { expect } from '@playwright/test'
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled')

View File

@@ -1,6 +1,6 @@
import { expect } from '@playwright/test'
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
test.describe('Release Notifications', () => {
test.beforeEach(async ({ comfyPage }) => {

View File

@@ -1,7 +1,7 @@
import { expect } from '@playwright/test'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
import type { ComfyPage } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
test.describe('Remote COMBO Widget', () => {
const mockOptions = ['d', 'c', 'b', 'a']

View File

@@ -1,6 +1,6 @@
import { expect } from '@playwright/test'
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
import { getMiddlePoint } from '../fixtures/utils/litegraphUtils'
test.describe('Reroute Node', () => {

View File

@@ -1,7 +1,7 @@
import { expect } from '@playwright/test'
import { NodeBadgeMode } from '../../src/types/nodeSource'
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled')

View File

@@ -1,6 +1,6 @@
import { expect } from '@playwright/test'
import { comfyPageFixture } from '../fixtures/ComfyPage'
import { comfyPageFixture } from '../fixtures/comfyPageFixture'
const test = comfyPageFixture

View File

@@ -1,6 +1,6 @@
import { expect } from '@playwright/test'
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled')

View File

@@ -1,6 +1,6 @@
import { expect } from '@playwright/test'
import { comfyPageFixture as test } from '../../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../../fixtures/comfyPageFixture'
test.describe('Node library sidebar', () => {
test.beforeEach(async ({ comfyPage }) => {

View File

@@ -1,6 +1,6 @@
import { expect } from '@playwright/test'
import { comfyPageFixture as test } from '../../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../../fixtures/comfyPageFixture'
test.describe.skip('Queue sidebar', () => {
test.beforeEach(async ({ comfyPage }) => {

View File

@@ -1,6 +1,6 @@
import { expect } from '@playwright/test'
import { comfyPageFixture as test } from '../../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../../fixtures/comfyPageFixture'
test.describe('Workflows sidebar', () => {
test.beforeEach(async ({ comfyPage }) => {

View File

@@ -1,6 +1,6 @@
import { expect } from '@playwright/test'
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
// Constants
const INITIAL_NAME = 'initial_slot_name'

View File

@@ -1,6 +1,6 @@
import { expect } from '@playwright/test'
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
// Constants
const RENAMED_INPUT_NAME = 'renamed_input'

View File

@@ -1,7 +1,7 @@
import type { Page } from '@playwright/test'
import { expect } from '@playwright/test'
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
async function checkTemplateFileExists(
page: Page,

View File

@@ -1,6 +1,6 @@
import { expect } from '@playwright/test'
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled')

View File

@@ -1,7 +1,7 @@
import { expect } from '@playwright/test'
import type { SystemStats } from '../../src/schemas/apiSchema'
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
test.describe('Version Mismatch Warnings', () => {
const ALWAYS_AHEAD_OF_INSTALLED_VERSION = '100.100.100'

View File

@@ -1,7 +1,5 @@
import {
comfyExpect as expect,
comfyPageFixture as test
} from '../../../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../../../fixtures/comfyPageFixture'
import { comfyExpect as expect } from '../../../fixtures/ComfyPage'
const CREATE_GROUP_HOTKEY = 'Control+g'

View File

@@ -1,7 +1,5 @@
import {
comfyExpect as expect,
comfyPageFixture as test
} from '../../../../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../../../../fixtures/comfyPageFixture'
import { comfyExpect as expect } from '../../../../fixtures/ComfyPage'
test.describe('Vue Nodes Canvas Pan', () => {
test.beforeEach(async ({ comfyPage }) => {

View File

@@ -1,7 +1,5 @@
import {
comfyExpect as expect,
comfyPageFixture as test
} from '../../../../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../../../../fixtures/comfyPageFixture'
import { comfyExpect as expect } from '../../../../fixtures/ComfyPage'
test.describe('Vue Nodes Zoom', () => {
test.beforeEach(async ({ comfyPage }) => {

View File

@@ -2,10 +2,8 @@ import type { Locator, Page } from '@playwright/test'
import type { NodeId } from '../../../../../src/platform/workflow/validation/schemas/workflowSchema'
import { getSlotKey } from '../../../../../src/renderer/core/layout/slots/slotIdentifier'
import {
comfyExpect as expect,
comfyPageFixture as test
} from '../../../../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../../../../fixtures/comfyPageFixture'
import { comfyExpect as expect } from '../../../../fixtures/ComfyPage'
import { getMiddlePoint } from '../../../../fixtures/utils/litegraphUtils'
import { fitToViewInstant } from '../../../../helpers/fitToView'

View File

@@ -1,8 +1,6 @@
import {
type ComfyPage,
comfyExpect as expect,
comfyPageFixture as test
} from '../../../../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../../../../fixtures/comfyPageFixture'
import { comfyExpect as expect } from '../../../../fixtures/ComfyPage'
import type { ComfyPage } from '../../../../fixtures/ComfyPage'
import type { Position } from '../../../../fixtures/types'
test.describe('Vue Node Moving', () => {

View File

@@ -1,6 +1,6 @@
import { expect } from '@playwright/test'
import { comfyPageFixture as test } from '../../../../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../../../../fixtures/comfyPageFixture'
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled')

View File

@@ -1,7 +1,5 @@
import {
comfyExpect as expect,
comfyPageFixture as test
} from '../../../../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../../../../fixtures/comfyPageFixture'
import { comfyExpect as expect } from '../../../../fixtures/ComfyPage'
test.describe('Vue Nodes Renaming', () => {
test.beforeEach(async ({ comfyPage }) => {

View File

@@ -1,7 +1,5 @@
import {
comfyExpect as expect,
comfyPageFixture as test
} from '../../../../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../../../../fixtures/comfyPageFixture'
import { comfyExpect as expect } from '../../../../fixtures/ComfyPage'
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled')

View File

@@ -1,7 +1,5 @@
import {
comfyExpect as expect,
comfyPageFixture as test
} from '../../../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../../../fixtures/comfyPageFixture'
import { comfyExpect as expect } from '../../../fixtures/ComfyPage'
const BYPASS_HOTKEY = 'Control+b'
const BYPASS_CLASS = /before:bg-bypass\/60/

View File

@@ -1,7 +1,5 @@
import {
comfyExpect as expect,
comfyPageFixture as test
} from '../../../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../../../fixtures/comfyPageFixture'
import { comfyExpect as expect } from '../../../fixtures/ComfyPage'
test.describe('Vue Node Collapse', () => {
test.beforeEach(async ({ comfyPage }) => {

View File

@@ -1,7 +1,5 @@
import {
comfyExpect as expect,
comfyPageFixture as test
} from '../../../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../../../fixtures/comfyPageFixture'
import { comfyExpect as expect } from '../../../fixtures/ComfyPage'
test.describe('Vue Node Custom Colors', () => {
test.beforeEach(async ({ comfyPage }) => {

View File

@@ -1,7 +1,5 @@
import {
comfyExpect as expect,
comfyPageFixture as test
} from '../../../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../../../fixtures/comfyPageFixture'
import { comfyExpect as expect } from '../../../fixtures/ComfyPage'
const ERROR_CLASS = /border-node-stroke-error/

View File

@@ -1,6 +1,6 @@
import { expect } from '@playwright/test'
import { comfyPageFixture as test } from '../../../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../../../fixtures/comfyPageFixture'
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled')

View File

@@ -1,7 +1,5 @@
import {
comfyExpect as expect,
comfyPageFixture as test
} from '../../../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../../../fixtures/comfyPageFixture'
import { comfyExpect as expect } from '../../../fixtures/ComfyPage'
const MUTE_HOTKEY = 'Control+m'
const MUTE_OPACITY = '0.5'

View File

@@ -1,7 +1,5 @@
import {
comfyExpect as expect,
comfyPageFixture as test
} from '../../../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../../../fixtures/comfyPageFixture'
import { comfyExpect as expect } from '../../../fixtures/ComfyPage'
const PIN_HOTKEY = 'p'
const PIN_INDICATOR = '[data-testid="node-pin-indicator"]'

View File

@@ -1,7 +1,5 @@
import {
comfyExpect as expect,
comfyPageFixture as test
} from '../../../../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../../../../fixtures/comfyPageFixture'
import { comfyExpect as expect } from '../../../../fixtures/ComfyPage'
test.describe('Vue Integer Widget', () => {
test.beforeEach(async ({ comfyPage }) => {

View File

@@ -1,7 +1,5 @@
import {
comfyExpect as expect,
comfyPageFixture as test
} from '../../../../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../../../../fixtures/comfyPageFixture'
import { comfyExpect as expect } from '../../../../fixtures/ComfyPage'
test.describe('Vue Upload Widgets', () => {
test.beforeEach(async ({ comfyPage }) => {

View File

@@ -1,8 +1,6 @@
import {
type ComfyPage,
comfyExpect as expect,
comfyPageFixture as test
} from '../../../../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../../../../fixtures/comfyPageFixture'
import { comfyExpect as expect } from '../../../../fixtures/ComfyPage'
import type { ComfyPage } from '../../../../fixtures/ComfyPage'
test.describe('Vue Multiline String Widget', () => {
test.beforeEach(async ({ comfyPage }) => {

View File

@@ -1,7 +1,5 @@
import {
comfyExpect as expect,
comfyPageFixture as test
} from '../../../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../../../fixtures/comfyPageFixture'
import { comfyExpect as expect } from '../../../fixtures/ComfyPage'
test.describe('Vue Widget Reactivity', () => {
test.beforeEach(async ({ comfyPage }) => {

View File

@@ -1,6 +1,6 @@
import { expect } from '@playwright/test'
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled')

View File

@@ -1,6 +1,7 @@
import { expect } from '@playwright/test'
import { type ComfyPage, comfyPageFixture as test } from '../fixtures/ComfyPage'
import { comfyPageFixture as test } from '../fixtures/comfyPageFixture'
import type { ComfyPage } from '../fixtures/ComfyPage'
test.describe('Workflow Tab Thumbnails', () => {
test.beforeEach(async ({ comfyPage }) => {

View File

@@ -0,0 +1,34 @@
import { defineConfig, devices } from '@playwright/test'
/**
* Playwright configuration for cloud E2E tests.
* Tests run against stagingcloud.comfy.org with authenticated user.
*/
export default defineConfig({
testDir: './browser_tests/tests',
fullyParallel: true,
forbidOnly: !!process.env.CI,
reporter: 'html',
// Cloud tests need more time due to network latency
timeout: 75000, // 5x the default 15000ms
retries: process.env.CI ? 2 : 0,
use: {
trace: 'on-first-retry',
// Cloud URL - can override with PLAYWRIGHT_TEST_URL env var
baseURL: process.env.PLAYWRIGHT_TEST_URL || 'https://stagingcloud.comfy.org'
},
// Authenticate once before all tests
globalSetup: './browser_tests/globalSetupCloud.ts',
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
timeout: 75000,
grep: /@cloud/ // Only run tests tagged with @cloud
}
]
})

View File

@@ -31,7 +31,7 @@ export default defineConfig({
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
timeout: 15000,
grepInvert: /@mobile/ // Run all tests except those tagged with @mobile
grepInvert: /@mobile|@cloud/ // Run all tests except those tagged with @mobile or @cloud
},
{

View File

@@ -55,6 +55,8 @@
"eslint.config.ts",
"global.d.ts",
"knip.config.ts",
"playwright.config.ts",
"playwright.cloud.config.ts",
"src/**/*.vue",
"src/**/*",
"src/types/**/*.d.ts",