test(front): correct frontend test + end2end tests
This commit is contained in:
@@ -130,6 +130,14 @@
|
|||||||
emptyHint?: string;
|
emptyHint?: string;
|
||||||
/** Empty-state icon-registry name (e.g. "star", "clock", "trash"). */
|
/** Empty-state icon-registry name (e.g. "star", "clock", "trash"). */
|
||||||
emptyIcon?: string;
|
emptyIcon?: string;
|
||||||
|
/**
|
||||||
|
* Call-to-action rendered inside the empty state. Used by
|
||||||
|
* `/files` to surface a "Show hidden files" button when the
|
||||||
|
* folder holds only dotfiles the user has chosen to hide — the
|
||||||
|
* page-specific hint stays in `emptyHint`, the action goes
|
||||||
|
* here. `<EmptyState>` renders it below the hint text.
|
||||||
|
*/
|
||||||
|
emptyAction?: Snippet;
|
||||||
hasMore?: boolean;
|
hasMore?: boolean;
|
||||||
onloadmore?: () => void;
|
onloadmore?: () => void;
|
||||||
/** Show the path/location column (list view only). */
|
/** Show the path/location column (list view only). */
|
||||||
@@ -318,6 +326,7 @@
|
|||||||
emptyText,
|
emptyText,
|
||||||
emptyHint,
|
emptyHint,
|
||||||
emptyIcon,
|
emptyIcon,
|
||||||
|
emptyAction,
|
||||||
hasMore = false,
|
hasMore = false,
|
||||||
onloadmore,
|
onloadmore,
|
||||||
showPath = true,
|
showPath = true,
|
||||||
@@ -1156,7 +1165,9 @@
|
|||||||
icon={emptyIcon}
|
icon={emptyIcon}
|
||||||
title={emptyText ?? t('common.empty', 'Nothing here yet.')}
|
title={emptyText ?? t('common.empty', 'Nothing here yet.')}
|
||||||
hint={emptyHint}
|
hint={emptyHint}
|
||||||
/>
|
>
|
||||||
|
{#if emptyAction}{@render emptyAction()}{/if}
|
||||||
|
</EmptyState>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="files-container" bind:clientWidth={gridWidth}>
|
<div class="files-container" bind:clientWidth={gridWidth}>
|
||||||
{#if grouped && filesStore.viewMode === 'list'}
|
{#if grouped && filesStore.viewMode === 'list'}
|
||||||
|
|||||||
@@ -1615,6 +1615,23 @@
|
|||||||
onitemdragleave={rlOnItemDragLeave}
|
onitemdragleave={rlOnItemDragLeave}
|
||||||
onitemdrop={rlOnItemDrop}
|
onitemdrop={rlOnItemDrop}
|
||||||
>
|
>
|
||||||
|
{#snippet emptyAction()}
|
||||||
|
<!-- Surfaces only when the folder isn't really empty — it's just
|
||||||
|
filtered because the user chose to hide dotfiles. Clicking
|
||||||
|
flips the app-wide `preferences.hideDotfiles` back off,
|
||||||
|
re-populating the list without a hunt through settings. -->
|
||||||
|
{#if hiddenCount > 0}
|
||||||
|
<button
|
||||||
|
class="btn btn-secondary"
|
||||||
|
onclick={() => preferences.setHideDotfiles(false)}
|
||||||
|
data-testid="files-show-hidden-btn"
|
||||||
|
>
|
||||||
|
<Icon name="eye" />
|
||||||
|
{t('files.show_hidden', 'Show hidden files')}
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
|
{/snippet}
|
||||||
|
|
||||||
{#snippet breadcrumb()}
|
{#snippet breadcrumb()}
|
||||||
<nav class="breadcrumb" aria-label="Breadcrumb">
|
<nav class="breadcrumb" aria-label="Breadcrumb">
|
||||||
<!-- Persistent home link → the root listing (bare /files canonicalizes to
|
<!-- Persistent home link → the root listing (bare /files canonicalizes to
|
||||||
|
|||||||
@@ -177,7 +177,7 @@ it('batch-deletes the whole selection after confirmation', async () => {
|
|||||||
m(deleteFolder).mockResolvedValue(undefined);
|
m(deleteFolder).mockResolvedValue(undefined);
|
||||||
m(deleteFile).mockResolvedValue(undefined);
|
m(deleteFile).mockResolvedValue(undefined);
|
||||||
render(FilesPage);
|
render(FilesPage);
|
||||||
await fireEvent.click(await screen.findByTestId('files-select-all-checkbox'));
|
await fireEvent.click(await screen.findByTestId('resource-list-select-all-checkbox'));
|
||||||
await fireEvent.click(await screen.findByTestId('files-batch-delete-btn'));
|
await fireEvent.click(await screen.findByTestId('files-batch-delete-btn'));
|
||||||
await waitFor(() => expect(deleteFolder).toHaveBeenCalledWith('sub1'));
|
await waitFor(() => expect(deleteFolder).toHaveBeenCalledWith('sub1'));
|
||||||
await waitFor(() => expect(deleteFile).toHaveBeenCalledWith('f1'));
|
await waitFor(() => expect(deleteFile).toHaveBeenCalledWith('f1'));
|
||||||
@@ -187,7 +187,7 @@ it('batch-favorites the selection via the favorites batch endpoint', async () =>
|
|||||||
withListing();
|
withListing();
|
||||||
m(apiFetch).mockResolvedValue({ ok: true });
|
m(apiFetch).mockResolvedValue({ ok: true });
|
||||||
render(FilesPage);
|
render(FilesPage);
|
||||||
await fireEvent.click(await screen.findByTestId('files-select-all-checkbox'));
|
await fireEvent.click(await screen.findByTestId('resource-list-select-all-checkbox'));
|
||||||
await fireEvent.click(await screen.findByTestId('files-batch-favorite-btn'));
|
await fireEvent.click(await screen.findByTestId('files-batch-favorite-btn'));
|
||||||
await waitFor(() =>
|
await waitFor(() =>
|
||||||
expect(apiFetch).toHaveBeenCalledWith(
|
expect(apiFetch).toHaveBeenCalledWith(
|
||||||
|
|||||||
@@ -5,12 +5,13 @@ const { confirmDialog, promptDialog } = vi.hoisted(() => ({
|
|||||||
confirmDialog: vi.fn(),
|
confirmDialog: vi.fn(),
|
||||||
promptDialog: vi.fn()
|
promptDialog: vi.fn()
|
||||||
}));
|
}));
|
||||||
vi.mock('$lib/api/endpoints/recent', () => ({ clearRecent: vi.fn(), fetchRecentPage: vi.fn() }));
|
vi.mock('$lib/api/endpoints/recent', () => ({
|
||||||
|
clearRecent: vi.fn(),
|
||||||
|
fetchRecentPage: vi.fn(),
|
||||||
|
removeFromRecent: vi.fn()
|
||||||
|
}));
|
||||||
vi.mock('$lib/api/endpoints/favorites', () => ({
|
vi.mock('$lib/api/endpoints/favorites', () => ({
|
||||||
addFavorite: vi.fn(),
|
|
||||||
dateBucket: () => 'Today',
|
dateBucket: () => 'Today',
|
||||||
fetchFavoritesPage: vi.fn(async () => ({ items: [], next_cursor: null })),
|
|
||||||
removeFavorite: vi.fn(),
|
|
||||||
resolveOwnerName: vi.fn(async () => 'me'),
|
resolveOwnerName: vi.fn(async () => 'me'),
|
||||||
sizeBucket: () => 'Small',
|
sizeBucket: () => 'Small',
|
||||||
typeLabel: () => 'File'
|
typeLabel: () => 'File'
|
||||||
@@ -23,8 +24,7 @@ vi.mock('$lib/api/endpoints/files', () => ({
|
|||||||
vi.mock('$lib/api/endpoints/folders', () => ({ renameFolder: vi.fn(), deleteFolder: vi.fn() }));
|
vi.mock('$lib/api/endpoints/folders', () => ({ renameFolder: vi.fn(), deleteFolder: vi.fn() }));
|
||||||
vi.mock('$lib/stores/dialogs.svelte', () => ({ confirmDialog, promptDialog }));
|
vi.mock('$lib/stores/dialogs.svelte', () => ({ confirmDialog, promptDialog }));
|
||||||
|
|
||||||
import { fetchRecentPage, clearRecent } from '$lib/api/endpoints/recent';
|
import { fetchRecentPage, clearRecent, removeFromRecent } from '$lib/api/endpoints/recent';
|
||||||
import { addFavorite } from '$lib/api/endpoints/favorites';
|
|
||||||
import { deleteFile } from '$lib/api/endpoints/files';
|
import { deleteFile } from '$lib/api/endpoints/files';
|
||||||
import RecentPage from './+page.svelte';
|
import RecentPage from './+page.svelte';
|
||||||
|
|
||||||
@@ -79,13 +79,17 @@ it('clears recent activity after confirmation', async () => {
|
|||||||
await waitFor(() => expect(clearRecent).toHaveBeenCalled());
|
await waitFor(() => expect(clearRecent).toHaveBeenCalled());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('favorites a recent row via the star button', async () => {
|
it('removes a recent row via the broom button', async () => {
|
||||||
|
// Recent no longer surfaces a favorite star (users go to the item's
|
||||||
|
// real home for that). The per-row affordance is now a broom that
|
||||||
|
// calls `DELETE /api/recent/{kind}/{id}` — verified end-to-end via
|
||||||
|
// the `removeFromRecent` mock.
|
||||||
withOneFile();
|
withOneFile();
|
||||||
m(addFavorite).mockResolvedValue(undefined);
|
m(removeFromRecent).mockResolvedValue(undefined);
|
||||||
render(RecentPage);
|
render(RecentPage);
|
||||||
await screen.findByText('notes.txt');
|
await screen.findByText('notes.txt');
|
||||||
await fireEvent.click(screen.getByTestId('resource-list-favorite-r1-btn'));
|
await fireEvent.click(screen.getByTestId('recent-remove-btn-r1'));
|
||||||
await waitFor(() => expect(addFavorite).toHaveBeenCalledWith('file', 'r1'));
|
await waitFor(() => expect(removeFromRecent).toHaveBeenCalledWith('file', 'r1'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('batch-deletes selected recent items after confirmation', async () => {
|
it('batch-deletes selected recent items after confirmation', async () => {
|
||||||
|
|||||||
@@ -25,14 +25,14 @@ async function openFolderWithChildren(
|
|||||||
await apiCreateFolder(page, c2, parent.id);
|
await apiCreateFolder(page, c2, parent.id);
|
||||||
await page.goto(`/files/${parent.id}`);
|
await page.goto(`/files/${parent.id}`);
|
||||||
await expect(page.getByTestId(c1)).toBeVisible({ timeout: 15_000 });
|
await expect(page.getByTestId(c1)).toBeVisible({ timeout: 15_000 });
|
||||||
await page.getByTestId('list-toolbar-view-list-btn').click();
|
await page.getByTestId('display-mode-view-list-btn').click();
|
||||||
return { c1, c2 };
|
return { c1, c2 };
|
||||||
}
|
}
|
||||||
|
|
||||||
test('select-all then batch favorite', async ({ page }) => {
|
test('select-all then batch favorite', async ({ page }) => {
|
||||||
const { c1 } = await openFolderWithChildren(page);
|
const { c1 } = await openFolderWithChildren(page);
|
||||||
await page.getByTestId('files-select-all-checkbox').check();
|
await page.getByTestId('resource-list-select-all-checkbox').check();
|
||||||
await expect(page.getByTestId('files-batch-bar')).toBeVisible();
|
await expect(page.getByTestId('resource-list-batch-close-btn')).toBeVisible();
|
||||||
await page.getByTestId('files-batch-favorite-btn').click();
|
await page.getByTestId('files-batch-favorite-btn').click();
|
||||||
// Items remain in the folder after favoriting.
|
// Items remain in the folder after favoriting.
|
||||||
await expect(page.getByTestId(c1)).toBeVisible({ timeout: 15_000 });
|
await expect(page.getByTestId(c1)).toBeVisible({ timeout: 15_000 });
|
||||||
@@ -40,8 +40,8 @@ test('select-all then batch favorite', async ({ page }) => {
|
|||||||
|
|
||||||
test('select-all then batch copy and download', async ({ page }) => {
|
test('select-all then batch copy and download', async ({ page }) => {
|
||||||
const { c1 } = await openFolderWithChildren(page);
|
const { c1 } = await openFolderWithChildren(page);
|
||||||
await page.getByTestId('files-select-all-checkbox').check();
|
await page.getByTestId('resource-list-select-all-checkbox').check();
|
||||||
await expect(page.getByTestId('files-batch-bar')).toBeVisible();
|
await expect(page.getByTestId('resource-list-batch-close-btn')).toBeVisible();
|
||||||
|
|
||||||
// Copy → the move dialog (copy mode); cancel.
|
// Copy → the move dialog (copy mode); cancel.
|
||||||
await page.getByTestId('files-batch-copy-btn').click();
|
await page.getByTestId('files-batch-copy-btn').click();
|
||||||
@@ -49,8 +49,8 @@ test('select-all then batch copy and download', async ({ page }) => {
|
|||||||
await page.getByTestId('move-dialog-cancel-btn').click();
|
await page.getByTestId('move-dialog-cancel-btn').click();
|
||||||
|
|
||||||
// Re-select and batch-download (a zip).
|
// Re-select and batch-download (a zip).
|
||||||
await page.getByTestId('files-select-all-checkbox').check();
|
await page.getByTestId('resource-list-select-all-checkbox').check();
|
||||||
await expect(page.getByTestId('files-batch-bar')).toBeVisible();
|
await expect(page.getByTestId('resource-list-batch-close-btn')).toBeVisible();
|
||||||
const dl = page.waitForEvent('download', { timeout: 10_000 }).catch(() => null);
|
const dl = page.waitForEvent('download', { timeout: 10_000 }).catch(() => null);
|
||||||
await page.getByTestId('files-batch-download-btn').click();
|
await page.getByTestId('files-batch-download-btn').click();
|
||||||
await dl;
|
await dl;
|
||||||
@@ -59,8 +59,8 @@ test('select-all then batch copy and download', async ({ page }) => {
|
|||||||
|
|
||||||
test('select-all then batch delete', async ({ page }) => {
|
test('select-all then batch delete', async ({ page }) => {
|
||||||
const { c1, c2 } = await openFolderWithChildren(page);
|
const { c1, c2 } = await openFolderWithChildren(page);
|
||||||
await page.getByTestId('files-select-all-checkbox').check();
|
await page.getByTestId('resource-list-select-all-checkbox').check();
|
||||||
await expect(page.getByTestId('files-batch-bar')).toBeVisible();
|
await expect(page.getByTestId('resource-list-batch-close-btn')).toBeVisible();
|
||||||
await page.getByTestId('files-batch-delete-btn').click();
|
await page.getByTestId('files-batch-delete-btn').click();
|
||||||
await page.getByTestId('dialog-host-confirm-btn').click();
|
await page.getByTestId('dialog-host-confirm-btn').click();
|
||||||
|
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ test('toolbar eye toggle hides and re-shows dotfiles in /files', async ({ page }
|
|||||||
// click routes through `preferences.toggleHideDotfiles()` which
|
// click routes through `preferences.toggleHideDotfiles()` which
|
||||||
// does an optimistic local mutation, so the row update should be
|
// does an optimistic local mutation, so the row update should be
|
||||||
// visible before the debounced PATCH lands.
|
// visible before the debounced PATCH lands.
|
||||||
await page.getByTestId('list-toolbar-dotfile-toggle-btn').click();
|
await page.getByTestId('display-mode-dotfile-toggle-btn').click();
|
||||||
|
|
||||||
// Visible row stays; hidden row vanishes.
|
// Visible row stays; hidden row vanishes.
|
||||||
await expect(page.getByTestId(visible)).toBeVisible();
|
await expect(page.getByTestId(visible)).toBeVisible();
|
||||||
@@ -104,7 +104,7 @@ test('toolbar eye toggle hides and re-shows dotfiles in /files', async ({ page }
|
|||||||
|
|
||||||
// Flip it back off — the hidden row must reappear. Same button;
|
// Flip it back off — the hidden row must reappear. Same button;
|
||||||
// its state flips atomically with `preferences.hideDotfiles`.
|
// its state flips atomically with `preferences.hideDotfiles`.
|
||||||
await page.getByTestId('list-toolbar-dotfile-toggle-btn').click();
|
await page.getByTestId('display-mode-dotfile-toggle-btn').click();
|
||||||
await expect(page.getByTestId(hidden)).toBeVisible();
|
await expect(page.getByTestId(hidden)).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -130,7 +130,7 @@ test('empty-state hint appears when a folder holds only dotfiles', async ({ page
|
|||||||
// Turn hide on. Folder becomes visually empty — but not the
|
// Turn hide on. Folder becomes visually empty — but not the
|
||||||
// generic empty state; the "N hidden items" affordance appears
|
// generic empty state; the "N hidden items" affordance appears
|
||||||
// instead, offering a one-click "Show hidden files" escape.
|
// instead, offering a one-click "Show hidden files" escape.
|
||||||
await page.getByTestId('list-toolbar-dotfile-toggle-btn').click();
|
await page.getByTestId('display-mode-dotfile-toggle-btn').click();
|
||||||
|
|
||||||
const showHiddenBtn = page.getByTestId('files-show-hidden-btn');
|
const showHiddenBtn = page.getByTestId('files-show-hidden-btn');
|
||||||
await expect(showHiddenBtn).toBeVisible({ timeout: 15_000 });
|
await expect(showHiddenBtn).toBeVisible({ timeout: 15_000 });
|
||||||
@@ -181,6 +181,6 @@ test('trash always shows dotfiles even when hide is on', async ({ page }) => {
|
|||||||
// we just verify the toolbar toggle reflects the current server
|
// we just verify the toolbar toggle reflects the current server
|
||||||
// state via aria-pressed on /files.
|
// state via aria-pressed on /files.
|
||||||
await page.goto('/files');
|
await page.goto('/files');
|
||||||
const toggle = page.getByTestId('list-toolbar-dotfile-toggle-btn');
|
const toggle = page.getByTestId('display-mode-dotfile-toggle-btn');
|
||||||
await expect(toggle).toHaveAttribute('aria-pressed', 'true');
|
await expect(toggle).toHaveAttribute('aria-pressed', 'true');
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -51,9 +51,9 @@ test('favorites batch select-all then move dialog', async ({ page }) => {
|
|||||||
await page.goto('/favorites');
|
await page.goto('/favorites');
|
||||||
await expect(page.getByTestId(f1)).toBeVisible({ timeout: 15_000 });
|
await expect(page.getByTestId(f1)).toBeVisible({ timeout: 15_000 });
|
||||||
// The select-all checkbox lives in the list-view header.
|
// The select-all checkbox lives in the list-view header.
|
||||||
await page.getByTestId('list-toolbar-view-list-btn').click();
|
await page.getByTestId('display-mode-view-list-btn').click();
|
||||||
await page.getByTestId('resource-list-select-all-checkbox').check();
|
await page.getByTestId('resource-list-select-all-checkbox').check();
|
||||||
await expect(page.getByTestId('resource-list-batch-toolbar')).toBeVisible();
|
await expect(page.getByTestId('resource-list-batch-close-btn')).toBeVisible();
|
||||||
|
|
||||||
// Batch-move opens the move dialog; cancel it.
|
// Batch-move opens the move dialog; cancel it.
|
||||||
await page.getByTestId('favorites-batch-move-btn').click();
|
await page.getByTestId('favorites-batch-move-btn').click();
|
||||||
|
|||||||
@@ -20,12 +20,12 @@ test('sort columns and toggle list/grid views', async ({ page }) => {
|
|||||||
await page.goto(`/files/${folder.id}`);
|
await page.goto(`/files/${folder.id}`);
|
||||||
await expect(page.getByTestId(SAMPLE_FILES.text().name)).toBeVisible({ timeout: 15_000 });
|
await expect(page.getByTestId(SAMPLE_FILES.text().name)).toBeVisible({ timeout: 15_000 });
|
||||||
|
|
||||||
await page.getByTestId('list-toolbar-view-list-btn').click();
|
await page.getByTestId('display-mode-view-list-btn').click();
|
||||||
// Column sort buttons live in the list-view header.
|
// 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-name-btn').click({ timeout: 5_000 }).catch(() => {});
|
||||||
await page.getByTestId('files-sort-size-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('files-sort-modified_at-btn').click({ timeout: 5_000 }).catch(() => {});
|
||||||
await page.getByTestId('list-toolbar-view-grid-btn').click();
|
await page.getByTestId('display-mode-view-grid-btn').click();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('sort by every column and group by every dimension', async ({ page }) => {
|
test('sort by every column and group by every dimension', async ({ page }) => {
|
||||||
@@ -37,17 +37,17 @@ test('sort by every column and group by every dimension', async ({ page }) => {
|
|||||||
await expect(page.getByTestId(SAMPLE_FILES.text().name)).toBeVisible({ timeout: 15_000 });
|
await expect(page.getByTestId(SAMPLE_FILES.text().name)).toBeVisible({ timeout: 15_000 });
|
||||||
|
|
||||||
// List view exposes the column-sort buttons.
|
// List view exposes the column-sort buttons.
|
||||||
await page.getByTestId('list-toolbar-view-list-btn').click();
|
await page.getByTestId('display-mode-view-list-btn').click();
|
||||||
for (const col of ['name', 'owner', 'type', 'size', 'modified_at']) {
|
for (const col of ['name', 'owner', 'type', 'size', 'modified_at']) {
|
||||||
await page.getByTestId(`files-sort-${col}-btn`).click({ timeout: 3_000 }).catch(() => {});
|
await page.getByTestId(`files-sort-${col}-btn`).click({ timeout: 3_000 }).catch(() => {});
|
||||||
}
|
}
|
||||||
// Flip the sort direction.
|
// Flip the sort direction.
|
||||||
await page.getByTestId('list-toolbar-sort-direction-btn').click({ timeout: 3_000 }).catch(() => {});
|
await page.getByTestId('display-mode-sort-direction-btn').click({ timeout: 3_000 }).catch(() => {});
|
||||||
|
|
||||||
// Cycle through every group-by dimension.
|
// Cycle through every group-by dimension.
|
||||||
for (const g of ['type', 'size', 'modifiedAt', 'createdAt']) {
|
for (const g of ['type', 'size', 'modifiedAt', 'createdAt']) {
|
||||||
await page.getByTestId('list-toolbar-groupby-btn').click({ timeout: 3_000 }).catch(() => {});
|
await page.getByTestId('display-mode-groupby-btn').click({ timeout: 3_000 }).catch(() => {});
|
||||||
await page.getByTestId(`list-toolbar-groupby-${g}-item`).click({ timeout: 3_000 }).catch(() => {});
|
await page.getByTestId(`display-mode-groupby-${g}-item`).click({ timeout: 3_000 }).catch(() => {});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -58,8 +58,8 @@ test('group files by type', async ({ page }) => {
|
|||||||
await page.goto(`/files/${folder.id}`);
|
await page.goto(`/files/${folder.id}`);
|
||||||
await expect(page.getByTestId(SAMPLE_FILES.text().name)).toBeVisible({ timeout: 15_000 });
|
await expect(page.getByTestId(SAMPLE_FILES.text().name)).toBeVisible({ timeout: 15_000 });
|
||||||
|
|
||||||
await page.getByTestId('list-toolbar-groupby-btn').click();
|
await page.getByTestId('display-mode-groupby-btn').click();
|
||||||
await page.getByTestId('list-toolbar-groupby-type-item').click();
|
await page.getByTestId('display-mode-groupby-type-item').click();
|
||||||
// The grouped (swimlane) view now renders; items remain visible.
|
// The grouped (swimlane) view now renders; items remain visible.
|
||||||
await expect(page.getByTestId(SAMPLE_FILES.text().name)).toBeVisible();
|
await expect(page.getByTestId(SAMPLE_FILES.text().name)).toBeVisible();
|
||||||
});
|
});
|
||||||
@@ -109,12 +109,15 @@ test('deep-link ?file= opens the viewer', async ({ page }) => {
|
|||||||
|
|
||||||
await page.goto(`/files/${folder.id}`);
|
await page.goto(`/files/${folder.id}`);
|
||||||
await expect(page.getByTestId(f.name)).toBeVisible({ timeout: 15_000 });
|
await expect(page.getByTestId(f.name)).toBeVisible({ timeout: 15_000 });
|
||||||
// Extract the file id from a row action button, then deep-link to it.
|
// Extract the file id straight off the row — ResourceList tags every
|
||||||
const tid = await page
|
// `.file-item` with `data-item-id={item.id}`. The pre-migration
|
||||||
.locator('[data-testid^="files-file-share-"]')
|
// approach read `files-file-share-{id}` off a per-row share button
|
||||||
|
// that no longer exists (Share moved into the context menu).
|
||||||
|
const fileId = await page
|
||||||
|
.locator(`.file-item[data-testid="${f.name}"]`)
|
||||||
.first()
|
.first()
|
||||||
.getAttribute('data-testid');
|
.getAttribute('data-item-id');
|
||||||
const fileId = (tid ?? '').replace('files-file-share-', '');
|
if (!fileId) throw new Error(`could not resolve file id for ${f.name}`);
|
||||||
await page.goto(`/files/${folder.id}?file=${fileId}`);
|
await page.goto(`/files/${folder.id}?file=${fileId}`);
|
||||||
await expect(page.getByTestId('file-viewer-dialog')).toBeVisible({ timeout: 15_000 });
|
await expect(page.getByTestId('file-viewer-dialog')).toBeVisible({ timeout: 15_000 });
|
||||||
await page.getByTestId('file-viewer-close-btn').click();
|
await page.getByTestId('file-viewer-close-btn').click();
|
||||||
@@ -194,7 +197,7 @@ test('keyboard select-all and escape in the files list', async ({ page }) => {
|
|||||||
|
|
||||||
await page.locator('.files-page').click({ position: { x: 5, y: 5 } });
|
await page.locator('.files-page').click({ position: { x: 5, y: 5 } });
|
||||||
await page.keyboard.press('Control+a');
|
await page.keyboard.press('Control+a');
|
||||||
await expect(page.getByTestId('files-batch-bar')).toBeVisible({ timeout: 5_000 }).catch(() => {});
|
await expect(page.getByTestId('resource-list-batch-close-btn')).toBeVisible({ timeout: 5_000 }).catch(() => {});
|
||||||
await page.keyboard.press('Escape');
|
await page.keyboard.press('Escape');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ test('recent shows accessed items, batch selection, and clear', async ({ page })
|
|||||||
await expect(page.getByTestId('appshell-logo-link')).toBeVisible({ timeout: 15_000 });
|
await expect(page.getByTestId('appshell-logo-link')).toBeVisible({ timeout: 15_000 });
|
||||||
|
|
||||||
// Switch to list view (reveals the select-all header) and batch-select.
|
// Switch to list view (reveals the select-all header) and batch-select.
|
||||||
await page.getByTestId('list-toolbar-view-list-btn').click({ timeout: 3_000 }).catch(() => {});
|
await page.getByTestId('display-mode-view-list-btn').click({ timeout: 3_000 }).catch(() => {});
|
||||||
const selectAll = page.getByTestId('resource-list-select-all-checkbox');
|
const selectAll = page.getByTestId('resource-list-select-all-checkbox');
|
||||||
if (await selectAll.isVisible().catch(() => false)) {
|
if (await selectAll.isVisible().catch(() => false)) {
|
||||||
await selectAll.check();
|
await selectAll.check();
|
||||||
@@ -45,16 +45,16 @@ test('recent grouping and sort cycle (ResourceList toolbar)', async ({ page }) =
|
|||||||
await apiRecordRecent(page, 'folder', a.id);
|
await apiRecordRecent(page, 'folder', a.id);
|
||||||
await page.goto('/recent');
|
await page.goto('/recent');
|
||||||
await expect(page.getByTestId('appshell-logo-link')).toBeVisible({ timeout: 15_000 });
|
await expect(page.getByTestId('appshell-logo-link')).toBeVisible({ timeout: 15_000 });
|
||||||
await page.getByTestId('list-toolbar-view-list-btn').click({ timeout: 3_000 }).catch(() => {});
|
await page.getByTestId('display-mode-view-list-btn').click({ timeout: 3_000 }).catch(() => {});
|
||||||
|
|
||||||
// Cycle every group-by dimension exposed by the shared ResourceList toolbar.
|
// Cycle every group-by dimension exposed by the shared ResourceList toolbar.
|
||||||
for (let i = 0; i < 5; i++) {
|
for (let i = 0; i < 5; i++) {
|
||||||
await page.getByTestId('list-toolbar-groupby-btn').click({ timeout: 2_000 }).catch(() => {});
|
await page.getByTestId('display-mode-groupby-btn').click({ timeout: 2_000 }).catch(() => {});
|
||||||
await page
|
await page
|
||||||
.locator('[data-testid^="list-toolbar-groupby-"][data-testid$="-item"]')
|
.locator('[data-testid^="display-mode-groupby-"][data-testid$="-item"]')
|
||||||
.nth(i)
|
.nth(i)
|
||||||
.click({ timeout: 2_000 })
|
.click({ timeout: 2_000 })
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
}
|
}
|
||||||
await page.getByTestId('list-toolbar-sort-direction-btn').click({ timeout: 2_000 }).catch(() => {});
|
await page.getByTestId('display-mode-sort-direction-btn').click({ timeout: 2_000 }).catch(() => {});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user