mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-03-15 01:48:06 +00:00
Compare commits
13 Commits
pysssss/dy
...
feat/cloud
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f67ca7fdd | ||
|
|
33e7c0491c | ||
|
|
d6d79a834c | ||
|
|
d0d2789f78 | ||
|
|
14ab045a05 | ||
|
|
730d8c2292 | ||
|
|
34d7f4b7df | ||
|
|
c5138692bf | ||
|
|
54597f786e | ||
|
|
24be8d123b | ||
|
|
c44c3088c0 | ||
|
|
f306cc9bcb | ||
|
|
ae1617874f |
51
.github/workflows/ci-tests-e2e-cloud.yaml
vendored
Normal file
51
.github/workflows/ci-tests-e2e-cloud.yaml
vendored
Normal 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
1
.gitignore
vendored
@@ -58,6 +58,7 @@ coverage/
|
||||
/playwright/.cache/
|
||||
browser_tests/**/*-win32.png
|
||||
browser_tests/local/
|
||||
browser_tests/.auth/
|
||||
|
||||
.env
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
44
browser_tests/fixtures/CloudComfyPage.ts
Normal file
44
browser_tests/fixtures/CloudComfyPage.ts
Normal 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'
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
48
browser_tests/fixtures/ComfyPageCloud.ts
Normal file
48
browser_tests/fixtures/ComfyPageCloud.ts
Normal 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)
|
||||
}
|
||||
})
|
||||
78
browser_tests/fixtures/LocalhostComfyPage.ts
Normal file
78
browser_tests/fixtures/LocalhostComfyPage.ts
Normal 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()}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
56
browser_tests/fixtures/comfyPageFixture.ts
Normal file
56
browser_tests/fixtures/comfyPageFixture.ts
Normal 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)
|
||||
}
|
||||
})
|
||||
4
browser_tests/fixtures/constants.ts
Normal file
4
browser_tests/fixtures/constants.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Shared constants for browser tests
|
||||
*/
|
||||
export const testComfySnapToGridGridSize = 50
|
||||
63
browser_tests/globalSetupCloud.ts
Normal file
63
browser_tests/globalSetupCloud.ts
Normal 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()
|
||||
}
|
||||
}
|
||||
36
browser_tests/tests/CLOUD_TESTS.md
Normal file
36
browser_tests/tests/CLOUD_TESTS.md
Normal 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`
|
||||
@@ -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)
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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 }) => {
|
||||
|
||||
@@ -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', () => {
|
||||
|
||||
@@ -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(() => {
|
||||
|
||||
@@ -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')
|
||||
|
||||
49
browser_tests/tests/cloud.spec.ts
Normal file
49
browser_tests/tests/cloud.spec.ts
Normal 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()
|
||||
})
|
||||
})
|
||||
@@ -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')
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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 }) => {
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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 }) => {
|
||||
|
||||
@@ -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 }) => {
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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 }) => {
|
||||
|
||||
@@ -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 }) => {
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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 }) => {
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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 }) => {
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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', () => {
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { expect } from '@playwright/test'
|
||||
|
||||
import { comfyPageFixture } from '../fixtures/ComfyPage'
|
||||
import { comfyPageFixture } from '../fixtures/comfyPageFixture'
|
||||
|
||||
const test = comfyPageFixture
|
||||
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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 }) => {
|
||||
|
||||
@@ -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 }) => {
|
||||
|
||||
@@ -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 }) => {
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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'
|
||||
|
||||
|
||||
@@ -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 }) => {
|
||||
|
||||
@@ -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 }) => {
|
||||
|
||||
@@ -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'
|
||||
|
||||
|
||||
@@ -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', () => {
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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 }) => {
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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/
|
||||
|
||||
@@ -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 }) => {
|
||||
|
||||
@@ -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 }) => {
|
||||
|
||||
@@ -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/
|
||||
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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"]'
|
||||
|
||||
@@ -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 }) => {
|
||||
|
||||
@@ -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 }) => {
|
||||
|
||||
@@ -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 }) => {
|
||||
|
||||
@@ -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 }) => {
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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 }) => {
|
||||
|
||||
34
playwright.cloud.config.ts
Normal file
34
playwright.cloud.config.ts
Normal 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
|
||||
}
|
||||
]
|
||||
})
|
||||
@@ -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
|
||||
},
|
||||
|
||||
{
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user