feat(web): hero view transitions between timeline and asset viewer

Change-Id: I19e0c7385cc38adbc85177ae9706cff06a6a6964

fix(web): fix e2e test failures for view transitions

Change-Id: Ida64f2d509efce0a85a50b89fd4137276a6a6964
Change-Id: I19e0c7385cc38adbc85177ae9706cff06a6a6964
This commit is contained in:
midzelis
2026-04-03 17:04:45 +00:00
parent 3356e81c85
commit 4f33aed350
26 changed files with 901 additions and 61 deletions
+13 -9
View File
@@ -143,8 +143,9 @@ export const timelineUtils = {
return page.locator('#asset-grid');
},
async waitForTimelineLoad(page: Page) {
await expect(timelineUtils.locator(page)).toBeInViewport();
await page.locator('#asset-grid[data-initialized]').waitFor();
await expect.poll(() => thumbnailUtils.locator(page).count()).toBeGreaterThan(0);
await page.locator('#virtual-timeline:not(.invisible)').waitFor();
},
async getScrollTop(page: Page) {
const queryTop = () =>
@@ -163,14 +164,17 @@ export const assetViewerUtils = {
return page.locator('#immich-asset-viewer');
},
async waitForViewerLoad(page: Page, asset: TimelineAssetConfig) {
await page
.locator(
`img[draggable="false"][src="/api/assets/${asset.id}/thumbnail?size=preview&c=${asset.thumbhash}&edited=true"]`,
)
.or(
page.locator(`video[poster="/api/assets/${asset.id}/thumbnail?size=preview&c=${asset.thumbhash}&edited=true"]`),
)
.waitFor();
const imgLocator = page.locator(`[data-viewer-content] img[data-testid="preview"][src*="${asset.id}"]`);
const videoLocator = page.locator(`[data-viewer-content] video[poster*="${asset.id}"]`);
await imgLocator.or(videoLocator).waitFor();
if ((await videoLocator.count()) === 0) {
await expect
.poll(() => imgLocator.evaluate((img: HTMLImageElement) => img.complete && img.naturalWidth > 0))
.toBe(true);
}
await expect(page.locator('#immich-asset-viewer')).not.toHaveAttribute('data-navigating');
},
async expectActiveAssetToBe(page: Page, assetId: string) {
const activeElement = () =>