-
Notifications
You must be signed in to change notification settings - Fork 672
Expand file tree
/
Copy pathvideo-asset-multi-select.spec.ts
More file actions
134 lines (112 loc) · 4.46 KB
/
Copy pathvideo-asset-multi-select.spec.ts
File metadata and controls
134 lines (112 loc) · 4.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/**
* QA test plan "cloud 1.50 → 1.51", Asset Management (#14347, #14765, #14848,
* #14858): shift-click and Ctrl/Cmd-click must multi-select video assets the
* same way they already do for image assets.
*
* Video is the one media kind that needs its own coverage here. A plain click
* on a video card is deliberately swallowed — `MediaAssetCard.handlePreviewClick`
* returns early for `fileKind === 'video'` so the click plays the clip instead
* of selecting it — and that early return is skipped only while a selection
* modifier is held. The modifier paths are therefore the *only* way to build a
* multi-selection on video, and a regression in that guard would silently make
* video assets unselectable while images kept working.
*/
import { readFileSync } from 'node:fs'
import { expect, mergeTests } from '@playwright/test'
import type { Page } from '@playwright/test'
import { comfyPageFixture } from '@e2e/fixtures/ComfyPage'
import {
createRouteMockJob,
jobsRouteFixture,
routeMockJobTimestamp
} from '@e2e/fixtures/jobsRouteFixture'
import { getMimeType } from '@e2e/fixtures/utils/mimeTypeUtil'
import { assetPath } from '@e2e/fixtures/utils/paths'
const test = mergeTests(comfyPageFixture, jobsRouteFixture)
const videoBytes = readFileSync(assetPath('plain_video.mp4'))
/** `getAssetCardByName` matches rendered text, and cards label themselves with
* the base name — passing the full filename here finds nothing. */
const videoBaseNames = [
'output_video-a',
'output_video-b',
'output_video-c'
] as const
const videoFileNames: readonly string[] = videoBaseNames.map(
(baseName) => `${baseName}.mp4`
)
/**
* Staggered timestamps pin the newest-first grid order to a → b → c, which the
* shift-click range assertion below depends on.
*/
const videoJobs = videoFileNames.map((filename, index) =>
createRouteMockJob({
id: `video-${'abc'[index]}`,
create_time: routeMockJobTimestamp - index * 1_000,
execution_start_time: routeMockJobTimestamp - index * 1_000,
execution_end_time: routeMockJobTimestamp,
preview_output: {
filename,
subfolder: '',
type: 'output',
nodeId: '1',
mediaType: 'video'
}
})
)
async function mockVideoViewFiles(page: Page) {
await page.route('**/api/view**', async (route) => {
if (route.request().method().toUpperCase() !== 'GET') {
await route.fallback()
return
}
const filename = new URL(route.request().url()).searchParams.get('filename')
if (!filename || !videoFileNames.includes(filename)) {
await route.fulfill({
status: 404,
json: { error: `Unknown filename: ${filename}` }
})
return
}
await route.fulfill({
body: videoBytes,
contentType: getMimeType(filename)
})
})
}
test.describe('Video asset multi-selection', { tag: ['@ui'] }, () => {
test.beforeEach(async ({ comfyPage, jobsRoutes, page }) => {
await jobsRoutes.mockJobsQueue([])
await jobsRoutes.mockJobsHistory(videoJobs)
await comfyPage.assets.mockInputFiles([])
await mockVideoViewFiles(page)
})
test('shift-click and Ctrl/Cmd-click build a multi-selection of video assets', async ({
comfyPage
}) => {
const tab = comfyPage.menu.assetsTab
await tab.open()
const [videoA, videoB, videoC] = videoBaseNames.map((baseName) =>
tab.getAssetCardByName(baseName)
)
await expect(videoA).toBeVisible()
await expect(videoC).toBeVisible()
// The guard the modifier paths exist for: an unmodified click plays the
// clip instead of selecting it.
await videoA.click()
await expect(tab.selectedCards).toHaveCount(0)
// Ctrl/Cmd-click selects a video and sets the range anchor. A plain click
// cannot do this on video, so it is also how the range below is seeded.
await videoA.click({ modifiers: ['ControlOrMeta'] })
await expect(tab.selectionCountButton).toHaveText(/\b1 selected\b/)
await expect(tab.selectedCards).toHaveCount(1)
await videoC.click({ modifiers: ['Shift'] })
await expect(tab.selectionCountButton).toHaveText(/\b3 selected\b/)
await expect(tab.selectedCards).toHaveCount(3)
await videoB.click({ modifiers: ['ControlOrMeta'] })
await expect(tab.selectionCountButton).toHaveText(/\b2 selected\b/)
await expect(tab.selectedCards).toHaveCount(2)
await expect(videoB).toHaveAttribute('data-selected', 'false')
await expect(tab.deleteSelectedButton).toBeVisible()
await expect(tab.downloadSelectedButton).toBeVisible()
})
})