test(documents): E2E smoke + visual snapshots for hub rebuild
Two smoke specs cover the headline flows:
- 04-documents-hub-aggregated: asserts system roots (Clients/Companies/
Yachts) appear in FolderTreeSidebar with lock icons, breadcrumb updates
on selection, and EntityFolderView renders Signing + Files sections.
- 04-documents-hub-upload-into-entity: API-fixture approach (Option B) —
creates a client, uploads via /api/v1/files/upload with clientId, then
asserts the file surfaces in the entity folder view.
Visual baselines: hub-root added to the PAGES table so it snapshots via the
standard loop; hub-entity-folder added as a best-effort standalone test with
explicit skip guards when no entity sub-folders exist. Baselines require a
running dev server to generate (pnpm exec playwright test --project=visual
--update-snapshots).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -24,6 +24,7 @@ const PAGES = [
|
||||
{ name: 'yachts-list', path: '/yachts', requireAuth: true },
|
||||
{ name: 'berths-list', path: '/berths', requireAuth: true },
|
||||
{ name: 'invoices-list', path: '/invoices', requireAuth: true },
|
||||
{ name: 'hub-root', path: '/documents', requireAuth: true },
|
||||
] as const;
|
||||
|
||||
async function settle(page: Page) {
|
||||
@@ -64,4 +65,66 @@ test.describe('Visual regression', () => {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Hub entity-folder visual — click into the Clients system root, then into
|
||||
* the first visible entity sub-folder. This is a best-effort baseline:
|
||||
* if no entity sub-folders exist yet the test skips with a clear message
|
||||
* rather than failing.
|
||||
*/
|
||||
test('hub-entity-folder matches baseline', async ({ page }) => {
|
||||
await login(page, 'super_admin');
|
||||
await navigateTo(page, '/documents');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Expand the Clients system root.
|
||||
const expandBtn = page
|
||||
.locator('aside')
|
||||
.getByRole('button', { name: 'Expand' })
|
||||
.first();
|
||||
const hasExpand = await expandBtn.isVisible({ timeout: 5_000 }).catch(() => false);
|
||||
if (!hasExpand) {
|
||||
test.skip(
|
||||
true,
|
||||
'No expandable folder found in sidebar — hub-entity-folder baseline skipped',
|
||||
);
|
||||
return;
|
||||
}
|
||||
await expandBtn.click();
|
||||
|
||||
// Wait briefly for children to appear.
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
// Find the first entity sub-folder button (deeper indent = child of Clients).
|
||||
// We look for any button in the aside that is NOT one of the fixed pseudo-rows.
|
||||
const pseudoNames = ['All documents', 'Root (no folder)', 'Clients', 'Companies', 'Yachts'];
|
||||
const allFolderBtns = page.locator('aside button[type="button"]');
|
||||
let entityFolderBtn: ReturnType<typeof page.locator> | null = null;
|
||||
|
||||
const count = await allFolderBtns.count();
|
||||
for (let i = 0; i < count; i++) {
|
||||
const btn = allFolderBtns.nth(i);
|
||||
const text = (await btn.textContent())?.trim() ?? '';
|
||||
if (text && !pseudoNames.includes(text) && text !== 'Expand' && text !== 'Collapse') {
|
||||
entityFolderBtn = btn;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!entityFolderBtn) {
|
||||
test.skip(
|
||||
true,
|
||||
'No entity sub-folder visible after expanding — hub-entity-folder baseline skipped',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
await entityFolderBtn.click();
|
||||
await settle(page);
|
||||
|
||||
await expect(page).toHaveScreenshot('hub-entity-folder.png', {
|
||||
fullPage: true,
|
||||
maxDiffPixelRatio: 0.02,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user