forked from AtalayaLabs/OxiCloud
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfiles-extra.spec.ts
More file actions
252 lines (216 loc) · 11.8 KB
/
Copy pathfiles-extra.spec.ts
File metadata and controls
252 lines (216 loc) · 11.8 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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
import { test, expect } from './coverage-helpers';
import { apiLogin, apiCreateFolder, apiUploadFile, SAMPLE_FILES } from '../scenarios/helpers';
/**
* Deeper files-page coverage (the largest source file): list/grid view toggle,
* column sorting, group-by lanes, breadcrumb navigation, and copy-via-dialog.
*/
test.beforeEach(async ({ page }) => {
await apiLogin(page);
});
function uniq(p: string): string {
return `${p}-${Date.now()}-${Math.floor(Math.random() * 1e6)}`;
}
test('sort columns and toggle list/grid views', async ({ page }) => {
const folder = await apiCreateFolder(page, uniq('SortHost'));
await apiUploadFile(page, SAMPLE_FILES.text(), folder.id);
await apiUploadFile(page, SAMPLE_FILES.json(), folder.id);
await page.goto(`/files/${folder.id}`);
await expect(page.getByTestId(SAMPLE_FILES.text().name)).toBeVisible({ timeout: 15_000 });
await page.getByTestId('list-toolbar-view-list-btn').click();
// Column sort buttons live in the list-view header.
await page.getByTestId('files-sort-name-btn').click({ timeout: 5_000 }).catch(() => {});
await page.getByTestId('files-sort-size-btn').click({ timeout: 5_000 }).catch(() => {});
await page.getByTestId('files-sort-modified_at-btn').click({ timeout: 5_000 }).catch(() => {});
await page.getByTestId('list-toolbar-view-grid-btn').click();
});
test('sort by every column and group by every dimension', async ({ page }) => {
const folder = await apiCreateFolder(page, uniq('Dims'));
await apiUploadFile(page, SAMPLE_FILES.text(), folder.id);
await apiUploadFile(page, SAMPLE_FILES.png(), folder.id);
await apiUploadFile(page, SAMPLE_FILES.pdf(), folder.id);
await page.goto(`/files/${folder.id}`);
await expect(page.getByTestId(SAMPLE_FILES.text().name)).toBeVisible({ timeout: 15_000 });
// List view exposes the column-sort buttons.
await page.getByTestId('list-toolbar-view-list-btn').click();
for (const col of ['name', 'owner', 'type', 'size', 'modified_at']) {
await page.getByTestId(`files-sort-${col}-btn`).click({ timeout: 3_000 }).catch(() => {});
}
// Flip the sort direction.
await page.getByTestId('list-toolbar-sort-direction-btn').click({ timeout: 3_000 }).catch(() => {});
// Cycle through every group-by dimension.
for (const g of ['type', 'size', 'modifiedAt', 'createdAt']) {
await page.getByTestId('list-toolbar-groupby-btn').click({ timeout: 3_000 }).catch(() => {});
await page.getByTestId(`list-toolbar-groupby-${g}-item`).click({ timeout: 3_000 }).catch(() => {});
}
});
test('group files by type', async ({ page }) => {
const folder = await apiCreateFolder(page, uniq('GroupHost'));
await apiUploadFile(page, SAMPLE_FILES.text(), folder.id);
await apiUploadFile(page, SAMPLE_FILES.png(), folder.id);
await page.goto(`/files/${folder.id}`);
await expect(page.getByTestId(SAMPLE_FILES.text().name)).toBeVisible({ timeout: 15_000 });
await page.getByTestId('list-toolbar-groupby-btn').click();
await page.getByTestId('list-toolbar-groupby-type-item').click();
// The grouped (swimlane) view now renders; items remain visible.
await expect(page.getByTestId(SAMPLE_FILES.text().name)).toBeVisible();
});
test('file context menu: favorite, copy, open-parent', async ({ page }) => {
const folder = await apiCreateFolder(page, uniq('Ctx'));
await apiCreateFolder(page, uniq('CtxDest'));
const f = SAMPLE_FILES.text();
await apiUploadFile(page, f, folder.id);
await page.goto(`/files/${folder.id}`);
await expect(page.getByTestId(f.name)).toBeVisible({ timeout: 15_000 });
// Favorite the file from its context menu.
await page.getByTestId(f.name).click({ button: 'right' });
await page.getByTestId('files-ctx-favorite-item').click();
await expect(page.getByTestId('files-context-menu')).toHaveCount(0);
// Copy → opens the move dialog (copy mode); cancel.
await page.getByTestId(f.name).click({ button: 'right' });
await page.getByTestId('files-ctx-copy-item').click();
await expect(page.getByTestId('move-dialog')).toBeVisible({ timeout: 15_000 });
await page.getByTestId('move-dialog-cancel-btn').click();
// Open-parent navigates to the file's parent folder.
await page.getByTestId(f.name).click({ button: 'right' });
await page.getByTestId('files-ctx-open-parent-item').click();
await expect(page).toHaveURL(/\/files\//, { timeout: 15_000 });
});
test('download a folder as a zip via the context menu', async ({ page }) => {
const folderName = uniq('Zip');
const folder = await apiCreateFolder(page, folderName);
await apiUploadFile(page, SAMPLE_FILES.text(), folder.id);
await page.goto('/files');
await expect(page.getByTestId(folderName)).toBeVisible({ timeout: 15_000 });
await page.getByTestId(folderName).click({ button: 'right' });
const downloadPromise = page.waitForEvent('download', { timeout: 10_000 }).catch(() => null);
await page.getByTestId('files-ctx-download-zip-item').click();
await downloadPromise;
});
test('deep-link ?file= opens the viewer', async ({ page }) => {
const folder = await apiCreateFolder(page, uniq('DeepLink'));
const f = SAMPLE_FILES.markdown();
await apiUploadFile(page, f, folder.id);
await page.goto(`/files/${folder.id}`);
await expect(page.getByTestId(f.name)).toBeVisible({ timeout: 15_000 });
// Extract the file id from a row action button, then deep-link to it.
const tid = await page
.locator('[data-testid^="files-file-share-"]')
.first()
.getAttribute('data-testid');
const fileId = (tid ?? '').replace('files-file-share-', '');
await page.goto(`/files/${folder.id}?file=${fileId}`);
await expect(page.getByTestId('file-viewer-dialog')).toBeVisible({ timeout: 15_000 });
await page.getByTestId('file-viewer-close-btn').click();
});
test('download a file via the context menu', async ({ page }) => {
const folder = await apiCreateFolder(page, uniq('Dl'));
const f = SAMPLE_FILES.text();
await apiUploadFile(page, f, folder.id);
await page.goto(`/files/${folder.id}`);
await expect(page.getByTestId(f.name)).toBeVisible({ timeout: 15_000 });
await page.getByTestId(f.name).click({ button: 'right' });
const downloadPromise = page.waitForEvent('download', { timeout: 10_000 }).catch(() => null);
await page.getByTestId('files-ctx-download-item').click();
const download = await downloadPromise;
if (download) expect(download.suggestedFilename().length).toBeGreaterThan(0);
});
test('upload a folder via the hidden folder input', async ({ page }) => {
const folder = await apiCreateFolder(page, uniq('FolderUp'));
await page.goto(`/files/${folder.id}`);
await expect(page.getByTestId('files-upload-folder-input')).toBeAttached({ timeout: 15_000 });
// webkitdirectory input — set a couple of nested files to exercise the
// folder-upload handler.
await page
.getByTestId('files-upload-folder-input')
.setInputFiles([
{ name: 'up/a.txt', mimeType: 'text/plain', buffer: Buffer.from('a') },
{ name: 'up/b.txt', mimeType: 'text/plain', buffer: Buffer.from('b') },
])
.catch(() => {});
await page.waitForTimeout(1500);
// The page stays functional whether or not the upload fully completes.
await expect(page.getByTestId('files-upload-btn')).toBeVisible();
});
test('drag a file onto a subfolder to move it', async ({ page }) => {
const parent = await apiCreateFolder(page, uniq('DragHost'));
const destName = uniq('DragDest');
await apiCreateFolder(page, destName, parent.id);
const f = SAMPLE_FILES.text();
await apiUploadFile(page, f, parent.id);
await page.goto(`/files/${parent.id}`);
await expect(page.getByTestId(f.name)).toBeVisible({ timeout: 15_000 });
await expect(page.getByTestId(destName)).toBeVisible();
// HTML5 drag-and-drop: the row is draggable and the folder is a drop target.
await page.getByTestId(f.name).dragTo(page.getByTestId(destName));
// The file moved into the destination folder.
await expect(page.getByTestId(f.name)).toHaveCount(0, { timeout: 15_000 });
});
test('open a folder with the keyboard (focus + Enter)', async ({ page }) => {
const parent = await apiCreateFolder(page, uniq('KeyNav'));
const childName = uniq('KeyChild');
const child = await apiCreateFolder(page, childName, parent.id);
await page.goto(`/files/${parent.id}`);
await expect(page.getByTestId(childName)).toBeVisible({ timeout: 15_000 });
// Focus the folder row and press Enter to open it (covers the keydown path).
await page.getByTestId(childName).focus();
await page.keyboard.press('Enter');
// The URL ends with the child id (nested under the parent path).
await expect(page).toHaveURL(new RegExp(`${child.id}$`), { timeout: 15_000 });
});
test('keyboard select-all and escape in the files list', async ({ page }) => {
const folder = await apiCreateFolder(page, uniq('Keys'));
await apiCreateFolder(page, uniq('k1'), folder.id);
await apiCreateFolder(page, uniq('k2'), folder.id);
await page.goto(`/files/${folder.id}`);
await expect(page.locator('.files-page')).toBeVisible({ timeout: 15_000 });
await page.locator('.files-page').click({ position: { x: 5, y: 5 } });
await page.keyboard.press('Control+a');
await expect(page.getByTestId('files-batch-bar')).toBeVisible({ timeout: 5_000 }).catch(() => {});
await page.keyboard.press('Escape');
});
test('breadcrumb navigates back to home', async ({ page }) => {
const folderName = uniq('Crumb');
const folder = await apiCreateFolder(page, folderName);
await page.goto(`/files/${folder.id}`);
// Breadcrumb home link leaves the subfolder for the root listing. Bare /files
// canonicalizes to the user's drive root, where the just-created folder lives.
await page.getByTestId('files-breadcrumb-home-link').click();
await expect(page).not.toHaveURL(new RegExp(folder.id));
await expect(page.getByTestId(folderName)).toBeVisible({ timeout: 15_000 });
});
test('open an image in the viewer and use the zoom controls', async ({ page }) => {
const folder = await apiCreateFolder(page, uniq('ImgView'));
const img = SAMPLE_FILES.png();
await apiUploadFile(page, img, folder.id);
await page.goto(`/files/${folder.id}`);
await expect(page.getByTestId(img.name)).toBeVisible({ timeout: 15_000 });
await page.getByTestId(img.name).click({ button: 'right' });
await page.getByTestId('files-ctx-file-open-item').click();
await expect(page.getByTestId('file-viewer-dialog')).toBeVisible({ timeout: 15_000 });
// Zoom controls render only for images.
await page.getByTestId('file-viewer-zoom-in-btn').click({ timeout: 3_000 }).catch(() => {});
await page.getByTestId('file-viewer-zoom-out-btn').click({ timeout: 3_000 }).catch(() => {});
await page.getByTestId('file-viewer-zoom-reset-btn').click({ timeout: 3_000 }).catch(() => {});
// The download + open-in-new-tab links are present in the viewer toolbar.
await expect(page.getByTestId('file-viewer-download-link')).toBeVisible();
await expect(page.getByTestId('file-viewer-open-new-tab-link')).toBeVisible();
await page.getByTestId('file-viewer-close-btn').click();
await expect(page.getByTestId('file-viewer-dialog')).toHaveCount(0);
});
test('copy a folder into another (copy mode keeps the source)', async ({ page }) => {
const srcName = uniq('CopySrc');
await apiCreateFolder(page, srcName);
const dest = await apiCreateFolder(page, uniq('CopyDest'));
await page.goto('/files');
await expect(page.getByTestId(srcName)).toBeVisible({ timeout: 15_000 });
await page.getByTestId(srcName).click({ button: 'right' });
await page.getByTestId('files-ctx-copy-item').click();
await expect(page.getByTestId('move-dialog')).toBeVisible();
await page.getByTestId(`move-dialog-folder-${dest.id}`).click();
await page.getByTestId('move-dialog-confirm-btn').click();
// Copy leaves the source in place.
await expect(page.getByTestId(srcName)).toBeVisible({ timeout: 15_000 });
// And a copy now lives in the destination.
await page.goto(`/files/${dest.id}`);
await expect(page.getByTestId(srcName)).toBeVisible({ timeout: 15_000 });
});