mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-23 14:16:00 +00:00
*PR Created by the Glary-Bot Agent* --- ## Summary Consolidated backport of bug fixes from `origin/main` (which feeds `v1.44.16`) onto `cloud/1.43`. Cherry-picks every applicable `fix:` commit identified in the prior backport-gap audit so `cloud/1.43` doesn't keep falling further behind. - **35 fixes cherry-picked** (out of 49 audited; 14 dropped — see "Dropped commits" below). - Verification (run on this branch): `pnpm typecheck` clean, `pnpm knip` clean, `pnpm lint` 0 errors (warning count 2976 vs cloud/1.43 baseline 2877 — delta is from new test files brought in by the picks, not new lint errors), `pnpm test:unit` 7842 passed / 8 skipped. This is a single consolidated PR per request — not a per-fix backport stream. Each commit has the original SHA recorded via `cherry picked from commit ...` so individual reverts remain possible. ## Picked fixes (35) App / runtime stability - `#10995` auto fit-to-view on first subgraph entry - `#11240` re-sync collapsed node slot positions after subgraph fitView - `#10849` store promoted widget values per SubgraphNode instance - `#10361` place cloned node above original in Vue renderer - `#9935` trigger Vue reactivity on output slot type changes in matchType - `#11541` stop duplicate node creation when dropping image on Vue nodes - `#11779` ensure escape key/graph navigation cancels ghost node placement - `#11063` disable pointer events on non-visible DOM widget overlays - `#11295` include focusMode in splitter refresh key to prevent panel resize - `#11487` render edit pencil icon correctly in properties panel header - `#11296` remove hover dimming overlay on image nodes - `#11542` keep finished badge fully opaque in ProgressToastItem - `#11713` search bar layout and autocomplete clipping on Desktop at small sizes - `#11570` dedupe keybinding modifier display - `#11144` fix(vite): hide git rev-parse window on Windows Cloud / subscription / workspace - `#11130` track workspace subscription success on immediate subscribe - `#11622` dedupe pending checkout attempt construction - `#11463` show credits in legacy user popover on non-cloud distributions - `#11636` enable Chrome password autofill on signup form - `#11520` fix(manager): migrate 4 endpoints GET→POST for CSRF hardening (security) - `#11425` remove deleted workflow from search results in sidebar Assets / blueprints - `#11700` route context menu Download through downloadMultipleAssets - `#11502` render asset fixtures in AssetBrowserModal stories - `#11759` hide blueprint node id in search - `#11573` translate blueprint label Telemetry / progress / feature flags - `#11174` guard progress_text before canvas init - `#11384` route progress_text feature flag check through getDevOverride - `#11417` reset file input value after selection to allow same-file reupload Load3D - `#11265` fix(load3d): restore missed hover state when viewer init is async - `#11546` load3d used wrong i18n key, add test - `#11359` chain Load3D node lifecycle callbacks to preserve widget cleanup GLSL preview - `#11010` resolve incorrect GLSL live preview for non-primitive widget types - `#11517` add GLSL live update when custom size is changed Misc - `#10374` consolidate `--color-coral-red` variables into `--color-coral` - `#11283` reduce noise in coverage Slack notifications ## Dropped commits (14) — need separate manual backport These cherry-picks pulled in code that depends on infrastructure not present on `cloud/1.43`, or required permissions a bot account does not hold. Individual backport tickets recommended: | PR | Subject | Blocker | |---|---|---| | #11224 | fix(ci): resolve pnpm version in release workflow for frontend/ checkout path | touches `.github/workflows/release-biweekly-comfyui.yaml` — bot lacks `workflows` permission. Also depends on prerequisite #11223 (patch-release support) not on cloud/1.43. Needs human-authored backport. | | #11329 | prevent duplicate prepareForSave + conflicting is_new telemetry on self-overwrite Save As | depends on `ChangeTracker.prepareForSave` API added by #10816 / #11328 (refactors not on cloud/1.43) | | #11358 | render dates in Secrets panel for timestamps with >3 fractional-second digits | depends on `formatToISOWithSeconds` and other utils in `dateTimeUtil.ts` not on cloud/1.43 | | #11539 | cancel-subscription dialog renders Invalid Date for ISO fractional seconds | depends on `parseIsoDateSafe` from #11358 | | #11480 | avoid escaped secret date labels | builds on #11358's SecretListItem changes | | #11524 | localize secret date labels | builds on #11358's SecretListItem changes | | #11321 | show asset display names in bulk delete confirmation | brings in `useMediaAssetActions.test.ts` requiring `downloadAssets` API not on cloud/1.43 | | #11610 | naming strategy for multi-job asset exports | same `useMediaAssetActions` test infrastructure | | #11737 | report total file count, not job count, in ZIP export toast | same `useMediaAssetActions` test infrastructure | | #11538 | resolve mesh widget thumbnails via asset preview API | depends on `FormDropdownMenuItemProps` type, `useWidgetSelectItems` not on cloud/1.43 | | #11492 | use getAssetFilename in asset browser to avoid showing hashes | same `useWidgetSelectItems` infrastructure | | #11836 | fix(load3d): dispose THREE.Points GPU resources in clearModel() | brings in `SceneModelManager.test.ts` referencing `ModelAdapter` infrastructure not on cloud/1.43 (memory-leak fix — manual backport recommended) | | #11807 | fix(load3d): suppress error toast on 404 when loading output model file | brings in `LoaderManager.ts` rewritten on main with `ModelAdapter` not on cloud/1.43 | | #11164 | enable playwright/no-force-option lint rule | requires oxlint upgrade with playwright plugin not pinned in cloud/1.43 | ## Conflict resolution notes Most picks applied cleanly. Conflicts encountered: - **Test-only / snapshot-only conflicts** — resolved with `-X theirs` (cloud/1.43 just doesn't have those test files yet). - **Modify/delete conflicts** (test file deleted on cloud/1.43, modified by the fix on main) — accepted the incoming version. - **`src/components/searchbox/v2/NodeSearchListItem.test.ts`** — pulled in by #11759 but referenced `ComfyNodeDefImpl` shape only on main. Removed the test file from the backport commit so the runtime fix lands; test should be rewritten/backported separately if desired. - **`browser_tests/tests/vueNodes/glslPreview.spec.ts` and `browser_tests/tests/subgraph/subgraphBreadcrumb.spec.ts`** — pulled in by #11517 / #11573 but reference helpers (`@e2e/fixtures/helpers/ExecutionHelper`, `SubgraphBreadcrumbHelper`) not on cloud/1.43. Removed the spec files from the respective backport commits; runtime fixes preserved. ## Out-of-scope review note Code review flagged a behavioral concern in `subgraphNavigationStore.ts:142-153,173-177` (`restoreViewport()` may auto-fit on first root-graph load even when the workflow already had a viewport). This is **pre-existing on `main`** (the cherry-picked code is identical to `origin/main` for that file region) — not introduced by this PR. Filing a separate ticket is recommended; not in scope for a backport batch. ## How to validate locally ```bash git checkout glary/cloud-1.43-batch-backport-fixes pnpm install --frozen-lockfile pnpm typecheck # clean pnpm knip # clean pnpm lint # 0 errors pnpm test:unit # 7842 passed, 8 skipped ``` ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11926-backport-cloud-1-43-consolidated-bug-fixes-from-main-v1-44-16-3566d73d3650812393d3e0ea79ab9a14) by [Unito](https://www.unito.io) --------- Co-authored-by: Christian Byrne <cbyrne@comfy.org> Co-authored-by: Amp <amp@ampcode.com> Co-authored-by: Terry Jia <terryjia88@gmail.com> Co-authored-by: Dante <bunggl@naver.com> Co-authored-by: Benjamin Lu <benjaminlu1107@gmail.com> Co-authored-by: dante <dante@danteui-MacStudio.local> Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> Co-authored-by: guill <jacob.e.segal@gmail.com> Co-authored-by: GitHub Action <action@github.com> Co-authored-by: pythongosssss <125205205+pythongosssss@users.noreply.github.com> Co-authored-by: Simon Pinfold <synap5e@users.noreply.github.com> Co-authored-by: comfydesigner <alextov@comfy.org> Co-authored-by: Alex <alex@Mac.lan> Co-authored-by: Robin Huang <robin.j.huang@gmail.com> Co-authored-by: Kelly Yang <124ykl@gmail.com> Co-authored-by: jaeone94 <89377375+jaeone94@users.noreply.github.com> Co-authored-by: github-actions <github-actions@github.com> Co-authored-by: Dr.Lt.Data <128333288+ltdrdata@users.noreply.github.com>
432 lines
12 KiB
TypeScript
432 lines
12 KiB
TypeScript
import { expect } from '@playwright/test'
|
|
|
|
import type { AlgoliaNodePack } from '@/types/algoliaTypes'
|
|
import type { components as ManagerComponents } from '@/workbench/extensions/manager/types/generatedManagerTypes'
|
|
import type { components as RegistryComponents } from '@comfyorg/registry-types'
|
|
|
|
import type { ComfyPage } from '@e2e/fixtures/ComfyPage'
|
|
import { comfyPageFixture as test } from '@e2e/fixtures/ComfyPage'
|
|
import { mockSystemStats } from '@e2e/fixtures/data/systemStats'
|
|
|
|
type InstalledPacksResponse =
|
|
ManagerComponents['schemas']['InstalledPacksResponse']
|
|
type RegistryNodePack = RegistryComponents['schemas']['Node']
|
|
|
|
interface AlgoliaSearchResult {
|
|
hits: Partial<AlgoliaNodePack>[]
|
|
nbHits: number
|
|
page: number
|
|
nbPages: number
|
|
hitsPerPage: number
|
|
}
|
|
|
|
interface AlgoliaSearchResponse {
|
|
results: AlgoliaSearchResult[]
|
|
}
|
|
|
|
const MOCK_PACK_A: RegistryNodePack = {
|
|
id: 'test-pack-a',
|
|
name: 'Test Pack A',
|
|
description: 'A test custom node pack',
|
|
downloads: 5000,
|
|
status: 'NodeStatusActive',
|
|
publisher: { id: 'test-publisher', name: 'Test Publisher' },
|
|
latest_version: { version: '1.0.0', status: 'NodeVersionStatusActive' },
|
|
repository: 'https://github.com/test/pack-a',
|
|
tags: ['image', 'processing']
|
|
}
|
|
|
|
const MOCK_PACK_B: RegistryNodePack = {
|
|
id: 'test-pack-b',
|
|
name: 'Test Pack B',
|
|
description: 'Another test custom node pack for testing search',
|
|
downloads: 3000,
|
|
status: 'NodeStatusActive',
|
|
publisher: { id: 'another-publisher', name: 'Another Publisher' },
|
|
latest_version: { version: '2.1.0', status: 'NodeVersionStatusActive' },
|
|
repository: 'https://github.com/test/pack-b',
|
|
tags: ['video', 'generation']
|
|
}
|
|
|
|
const MOCK_PACK_C: RegistryNodePack = {
|
|
id: 'test-pack-c',
|
|
name: 'Test Pack C',
|
|
description: 'Third test pack',
|
|
downloads: 100,
|
|
status: 'NodeStatusActive',
|
|
publisher: { id: 'test-publisher', name: 'Test Publisher' },
|
|
latest_version: { version: '0.5.0', status: 'NodeVersionStatusActive' },
|
|
repository: 'https://github.com/test/pack-c'
|
|
}
|
|
|
|
const MOCK_INSTALLED_PACKS: InstalledPacksResponse = {
|
|
'test-pack-a': {
|
|
ver: '1.0.0',
|
|
cnr_id: 'test-pack-a',
|
|
enabled: true
|
|
},
|
|
'test-pack-c': {
|
|
ver: '0.5.0',
|
|
cnr_id: 'test-pack-c',
|
|
enabled: false
|
|
}
|
|
}
|
|
|
|
const MOCK_HIT_A: Partial<AlgoliaNodePack> = {
|
|
objectID: 'test-pack-a',
|
|
id: 'test-pack-a',
|
|
name: 'Test Pack A',
|
|
description: 'A test custom node pack',
|
|
total_install: 5000,
|
|
status: 'NodeStatusActive',
|
|
publisher_id: 'test-publisher',
|
|
latest_version: '1.0.0',
|
|
latest_version_status: 'NodeVersionStatusActive',
|
|
repository_url: 'https://github.com/test/pack-a',
|
|
comfy_nodes: ['TestNodeA1', 'TestNodeA2'],
|
|
create_time: '2024-01-01T00:00:00Z',
|
|
update_time: '2024-06-01T00:00:00Z',
|
|
license: 'MIT',
|
|
tags: ['image', 'processing']
|
|
}
|
|
|
|
const MOCK_HIT_B: Partial<AlgoliaNodePack> = {
|
|
objectID: 'test-pack-b',
|
|
id: 'test-pack-b',
|
|
name: 'Test Pack B',
|
|
description: 'Another test custom node pack for testing search',
|
|
total_install: 3000,
|
|
status: 'NodeStatusActive',
|
|
publisher_id: 'another-publisher',
|
|
latest_version: '2.1.0',
|
|
latest_version_status: 'NodeVersionStatusActive',
|
|
repository_url: 'https://github.com/test/pack-b',
|
|
comfy_nodes: ['TestNodeB1'],
|
|
create_time: '2024-02-01T00:00:00Z',
|
|
update_time: '2024-07-01T00:00:00Z',
|
|
license: 'Apache-2.0',
|
|
tags: ['video', 'generation']
|
|
}
|
|
|
|
const MOCK_HIT_C: Partial<AlgoliaNodePack> = {
|
|
objectID: 'test-pack-c',
|
|
id: 'test-pack-c',
|
|
name: 'Test Pack C',
|
|
description: 'Third test pack',
|
|
total_install: 100,
|
|
status: 'NodeStatusActive',
|
|
publisher_id: 'test-publisher',
|
|
latest_version: '0.5.0',
|
|
latest_version_status: 'NodeVersionStatusActive',
|
|
repository_url: 'https://github.com/test/pack-c',
|
|
comfy_nodes: ['TestNodeC1'],
|
|
create_time: '2024-03-01T00:00:00Z',
|
|
update_time: '2024-05-01T00:00:00Z',
|
|
license: 'MIT'
|
|
}
|
|
|
|
const MOCK_ALGOLIA_RESPONSE: AlgoliaSearchResponse = {
|
|
results: [
|
|
{
|
|
hits: [MOCK_HIT_A, MOCK_HIT_B, MOCK_HIT_C],
|
|
nbHits: 3,
|
|
page: 0,
|
|
nbPages: 1,
|
|
hitsPerPage: 20
|
|
}
|
|
]
|
|
}
|
|
|
|
const MOCK_ALGOLIA_PACK_B_ONLY: AlgoliaSearchResponse = {
|
|
results: [
|
|
{
|
|
hits: [MOCK_HIT_B],
|
|
nbHits: 1,
|
|
page: 0,
|
|
nbPages: 1,
|
|
hitsPerPage: 20
|
|
}
|
|
]
|
|
}
|
|
|
|
const MOCK_ALGOLIA_EMPTY: AlgoliaSearchResponse = {
|
|
results: [
|
|
{
|
|
hits: [],
|
|
nbHits: 0,
|
|
page: 0,
|
|
nbPages: 0,
|
|
hitsPerPage: 20
|
|
}
|
|
]
|
|
}
|
|
|
|
test.describe('ManagerDialog', { tag: '@ui' }, () => {
|
|
test.beforeEach(async ({ comfyPage }) => {
|
|
const statsWithManager = {
|
|
...mockSystemStats,
|
|
system: {
|
|
...mockSystemStats.system,
|
|
argv: ['main.py', '--enable-manager']
|
|
}
|
|
}
|
|
await comfyPage.page.route('**/system_stats**', async (route) => {
|
|
await route.fulfill({ json: statsWithManager })
|
|
})
|
|
|
|
await comfyPage.page.route(
|
|
'**/v2/customnode/installed**',
|
|
async (route) => {
|
|
await route.fulfill({ json: MOCK_INSTALLED_PACKS })
|
|
}
|
|
)
|
|
|
|
await comfyPage.page.route(
|
|
'**/v2/manager/queue/status**',
|
|
async (route) => {
|
|
await route.fulfill({
|
|
json: {
|
|
history: {},
|
|
running_queue: [],
|
|
pending_queue: [],
|
|
installed_packs: {}
|
|
}
|
|
})
|
|
}
|
|
)
|
|
|
|
await comfyPage.page.route(
|
|
'**/v2/manager/queue/history**',
|
|
async (route) => {
|
|
await route.fulfill({ json: {} })
|
|
}
|
|
)
|
|
|
|
await comfyPage.page.route('**/*.algolia.net/**', async (route) => {
|
|
await route.fulfill({ json: MOCK_ALGOLIA_RESPONSE })
|
|
})
|
|
|
|
await comfyPage.page.route('**/*.algolianet.com/**', async (route) => {
|
|
await route.fulfill({ json: MOCK_ALGOLIA_RESPONSE })
|
|
})
|
|
|
|
// Mock Comfy Registry API (fallback when Algolia credentials are unavailable)
|
|
const registryListResponse = {
|
|
total: 3,
|
|
nodes: [MOCK_PACK_A, MOCK_PACK_B, MOCK_PACK_C],
|
|
page: 1,
|
|
limit: 64,
|
|
totalPages: 1
|
|
}
|
|
|
|
await comfyPage.page.route(
|
|
'**/api.comfy.org/nodes/search**',
|
|
async (route) => {
|
|
await route.fulfill({ json: registryListResponse })
|
|
}
|
|
)
|
|
|
|
await comfyPage.page.route(
|
|
(url) => url.hostname === 'api.comfy.org' && url.pathname === '/nodes',
|
|
async (route) => {
|
|
await route.fulfill({ json: registryListResponse })
|
|
}
|
|
)
|
|
|
|
await comfyPage.page.route(
|
|
'**/v2/customnode/getmappings**',
|
|
async (route) => {
|
|
await route.fulfill({ json: {} })
|
|
}
|
|
)
|
|
|
|
await comfyPage.page.route(
|
|
'**/v2/customnode/import_fail_info**',
|
|
async (route) => {
|
|
await route.fulfill({ json: {} })
|
|
}
|
|
)
|
|
|
|
await comfyPage.setup()
|
|
|
|
// Seed manager-ready server feature flags AFTER setup so the WebSocket
|
|
// feature_flags payload can't overwrite them. mockServerFeatures (on
|
|
// /api/features) does not populate the serverFeatureFlags ref; direct
|
|
// reactive-ref mutation is the only reliable approach.
|
|
// See shareWorkflowDialog.spec.ts:34-48 for the canonical pattern.
|
|
await comfyPage.page.evaluate(() => {
|
|
const api = window.app!.api
|
|
api.serverFeatureFlags.value = {
|
|
...api.serverFeatureFlags.value,
|
|
extension: {
|
|
manager: {
|
|
supports_v4: true,
|
|
supports_csrf_post: true
|
|
}
|
|
}
|
|
}
|
|
})
|
|
})
|
|
|
|
async function openManagerDialog(comfyPage: ComfyPage) {
|
|
await comfyPage.command.executeCommand('Comfy.OpenManagerDialog')
|
|
}
|
|
|
|
test('Opens the manager dialog via command', async ({ comfyPage }) => {
|
|
await openManagerDialog(comfyPage)
|
|
|
|
const dialog = comfyPage.page.getByRole('dialog')
|
|
await expect(dialog).toBeVisible()
|
|
})
|
|
|
|
test('Displays pack cards from search results', async ({ comfyPage }) => {
|
|
await openManagerDialog(comfyPage)
|
|
|
|
const dialog = comfyPage.page.getByRole('dialog')
|
|
await expect(dialog).toBeVisible()
|
|
|
|
await expect(dialog.getByText('Test Pack A')).toBeVisible()
|
|
await expect(dialog.getByText('Test Pack B')).toBeVisible()
|
|
await expect(dialog.getByText('Test Pack C')).toBeVisible()
|
|
})
|
|
|
|
test('Search filters displayed packs', async ({ comfyPage }) => {
|
|
await comfyPage.page.route('**/*.algolia.net/**', async (route) => {
|
|
await route.fulfill({ json: MOCK_ALGOLIA_PACK_B_ONLY })
|
|
})
|
|
await comfyPage.page.route('**/*.algolianet.com/**', async (route) => {
|
|
await route.fulfill({ json: MOCK_ALGOLIA_PACK_B_ONLY })
|
|
})
|
|
await comfyPage.page.route(
|
|
'**/api.comfy.org/nodes/search**',
|
|
async (route) => {
|
|
await route.fulfill({
|
|
json: {
|
|
total: 1,
|
|
nodes: [MOCK_PACK_B],
|
|
page: 1,
|
|
limit: 64,
|
|
totalPages: 1
|
|
}
|
|
})
|
|
}
|
|
)
|
|
|
|
await openManagerDialog(comfyPage)
|
|
|
|
const dialog = comfyPage.page.getByRole('dialog')
|
|
await expect(dialog).toBeVisible()
|
|
|
|
const searchInput = dialog.getByPlaceholder(/search/i)
|
|
await searchInput.fill('Test Pack B')
|
|
|
|
await expect(dialog.getByText('Test Pack B')).toBeVisible()
|
|
await expect(dialog.getByText('Test Pack A')).toBeHidden()
|
|
})
|
|
|
|
test('Clicking a pack card opens the info panel', async ({ comfyPage }) => {
|
|
await comfyPage.page.route(
|
|
'**/api.comfy.org/nodes/test-pack-a',
|
|
async (route) => {
|
|
await route.fulfill({ json: MOCK_PACK_A })
|
|
}
|
|
)
|
|
|
|
await openManagerDialog(comfyPage)
|
|
|
|
const dialog = comfyPage.page.getByRole('dialog')
|
|
await expect(dialog).toBeVisible()
|
|
|
|
await dialog.getByText('Test Pack A').first().click()
|
|
|
|
await expect(dialog.getByText('Test Publisher').first()).toBeVisible()
|
|
})
|
|
|
|
test('Left side panel navigation tabs exist', async ({ comfyPage }) => {
|
|
await openManagerDialog(comfyPage)
|
|
|
|
const dialog = comfyPage.page.getByRole('dialog')
|
|
await expect(dialog).toBeVisible()
|
|
|
|
const nav = dialog.locator('nav')
|
|
await expect(nav.getByText('All Extensions')).toBeVisible()
|
|
await expect(nav.getByText('Not Installed')).toBeVisible()
|
|
await expect(nav.getByText('All Installed')).toBeVisible()
|
|
await expect(nav.getByText('Updates Available')).toBeVisible()
|
|
})
|
|
|
|
test('Switching tabs changes the content view', async ({ comfyPage }) => {
|
|
await openManagerDialog(comfyPage)
|
|
|
|
const dialog = comfyPage.page.getByRole('dialog')
|
|
await expect(dialog).toBeVisible()
|
|
|
|
const nav = dialog.locator('nav')
|
|
await nav.getByText('All Installed').click()
|
|
|
|
await expect(dialog.getByText('Test Pack A')).toBeVisible()
|
|
})
|
|
|
|
test('Closes via Escape key', async ({ comfyPage }) => {
|
|
await openManagerDialog(comfyPage)
|
|
|
|
const dialog = comfyPage.page.getByRole('dialog')
|
|
await expect(dialog).toBeVisible()
|
|
|
|
await comfyPage.page.keyboard.press('Escape')
|
|
await expect(dialog).toBeHidden()
|
|
})
|
|
|
|
test('Empty search shows no results message', async ({ comfyPage }) => {
|
|
await comfyPage.page.route('**/*.algolia.net/**', async (route) => {
|
|
await route.fulfill({ json: MOCK_ALGOLIA_EMPTY })
|
|
})
|
|
await comfyPage.page.route('**/*.algolianet.com/**', async (route) => {
|
|
await route.fulfill({ json: MOCK_ALGOLIA_EMPTY })
|
|
})
|
|
await comfyPage.page.route(
|
|
'**/api.comfy.org/nodes/search**',
|
|
async (route) => {
|
|
await route.fulfill({
|
|
json: {
|
|
total: 0,
|
|
nodes: [],
|
|
page: 1,
|
|
limit: 64,
|
|
totalPages: 0
|
|
}
|
|
})
|
|
}
|
|
)
|
|
|
|
await openManagerDialog(comfyPage)
|
|
|
|
const dialog = comfyPage.page.getByRole('dialog')
|
|
await expect(dialog).toBeVisible()
|
|
|
|
const searchInput = dialog.getByPlaceholder(/search/i)
|
|
await searchInput.fill('nonexistent-pack-xyz-999')
|
|
|
|
await expect(
|
|
dialog.getByText(/no results found|try a different search/i).first()
|
|
).toBeVisible()
|
|
})
|
|
|
|
test('Search mode can be switched between packs and nodes', async ({
|
|
comfyPage
|
|
}) => {
|
|
await openManagerDialog(comfyPage)
|
|
|
|
const dialog = comfyPage.page.getByRole('dialog')
|
|
await expect(dialog).toBeVisible()
|
|
|
|
const modeSelector = dialog.getByText('Node Pack').first()
|
|
await expect(modeSelector).toBeVisible()
|
|
|
|
await modeSelector.click()
|
|
const nodesOption = comfyPage.page.getByRole('option', { name: 'Nodes' })
|
|
await expect(nodesOption).toBeVisible()
|
|
await nodesOption.click()
|
|
})
|
|
})
|