0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2025-02-10 22:38:53 -05:00

Makes view transition e2e tests compatible with Firefox (#11093)

This commit is contained in:
Martin Trapp 2024-05-21 12:50:32 +02:00 committed by GitHub
parent bfe9c73536
commit a514bbe992
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 80 additions and 120 deletions

View file

@ -6,7 +6,7 @@ import { ViewTransitions, fade } from 'astro:transitions';
<ViewTransitions />
</head>
<body>
<h1 transition:name="h1" transition:animate={fade({duration:10000})}>Abort</h1>
<h1 transition:name="h1" transition:animate={fade({duration:500})}>Abort</h1>
</body>
</html>
@ -15,11 +15,10 @@ import { ViewTransitions, fade } from 'astro:transitions';
import {navigate } from 'astro:transitions/client';
setTimeout(()=>{
[...document.getAnimations()].forEach((a) => a.addEventListener('cancel',
(e) => console.log("[test]",e.type, a.animationName)));
console.log("[test] navigate to /one")
[...document.getAnimations()].forEach((a) => a.addEventListener('cancel', (e) => console.log("[test]", e.type, a.animationName)));
console.log("[test] navigate to /one");
navigate("/one");
}, 1000);
}, 200);
console.log('[test] navigate to "."')
navigate("/abort2");
</script>

View file

@ -13,6 +13,14 @@ test.afterAll(async () => {
await devServer.stop();
});
function collectLoads(page) {
const loads = [];
page.on('load', async () => {
const url = page.url();
if (url !== 'about:blank') loads.push(await page.title());
});
return loads;
}
function scrollToBottom(page) {
return page.evaluate(() => {
window.scrollY = document.documentElement.scrollHeight;
@ -34,12 +42,13 @@ function collectPreloads(page) {
});
}
async function nativeViewTransition(page) {
return page.evaluate(() => document.startViewTransition !== undefined)
}
test.describe('View Transitions', () => {
test('Moving from page 1 to page 2', async ({ page, astro }) => {
const loads = [];
page.addListener('load', (p) => {
loads.push(p.title());
});
const loads = collectLoads(page);
// Go to page 1
await page.goto(astro.resolveUrl('/one'));
@ -55,10 +64,7 @@ test.describe('View Transitions', () => {
});
test('Back button is captured', async ({ page, astro }) => {
const loads = [];
page.addListener('load', (p) => {
loads.push(p.title());
});
const loads = collectLoads(page);
// Go to page 1
await page.goto(astro.resolveUrl('/one'));
@ -79,11 +85,7 @@ test.describe('View Transitions', () => {
});
test('Clicking on a link with nested content', async ({ page, astro }) => {
const loads = [];
page.addListener('load', (p) => {
loads.push(p.title());
});
const loads = collectLoads(page);
// Go to page 4
await page.goto(astro.resolveUrl('/four'));
let p = page.locator('#four');
@ -98,11 +100,7 @@ test.describe('View Transitions', () => {
});
test('Clicking on a link to a page with non-recommended headers', async ({ page, astro }) => {
const loads = [];
page.addListener('load', (p) => {
loads.push(p.title());
});
const loads = collectLoads(page);
// Go to page 4
await page.goto(astro.resolveUrl('/one'));
let p = page.locator('#one');
@ -120,10 +118,7 @@ test.describe('View Transitions', () => {
page,
astro,
}) => {
const loads = [];
page.addListener('load', (p) => {
loads.push(p.title());
});
const loads = collectLoads(page);
// Go to page 1
await page.goto(astro.resolveUrl('/one'));
@ -145,10 +140,7 @@ test.describe('View Transitions', () => {
page,
astro,
}) => {
const loads = [];
page.addListener('load', async (p) => {
loads.push(p.title());
});
const loads = collectLoads(page);
// Go to page 1
await page.goto(astro.resolveUrl('/one'));
let p = page.locator('#one');
@ -176,10 +168,7 @@ test.describe('View Transitions', () => {
});
test('Moving from a page without ViewTransitions w/ back button', async ({ page, astro }) => {
const loads = [];
page.addListener('load', (p) => {
loads.push(p.title());
});
const loads = collectLoads(page);
// Go to page 1
await page.goto(astro.resolveUrl('/one'));
@ -250,7 +239,7 @@ test.describe('View Transitions', () => {
});
test('No page rendering during swap()', async ({ page, astro }) => {
// This has been a problem with theme switchers (e.g. for drakmode)
// This has been a problem with theme switchers (e.g. for darkmode)
// Swap() should not trigger any page renders and give users the chance to
// correct attributes in the astro:after-swap handler before they become visible
@ -258,6 +247,10 @@ test.describe('View Transitions', () => {
// The test succeeds if no additional animation beside those of the
// view transition is triggered during swap()
// Only works for browsers with native view transitions
if (!await nativeViewTransition(page)) return;
await page.goto(astro.resolveUrl('/listener-one'));
let p = page.locator('#totwo');
await expect(p, 'should have content').toHaveText('Go to listener two');
@ -295,10 +288,8 @@ test.describe('View Transitions', () => {
});
test('click self link (w/o hash) does not do navigation', async ({ page, astro }) => {
const loads = [];
page.addListener('load', (p) => {
loads.push(p.title());
});
const loads = collectLoads(page);
// Go to page 1
await page.goto(astro.resolveUrl('/one'));
const p = page.locator('#one');
@ -596,10 +587,8 @@ test.describe('View Transitions', () => {
page,
astro,
}) => {
const loads = [];
page.addListener('load', (p) => {
loads.push(p.title());
});
const loads = collectLoads(page);
// Go to page 1
await page.goto(astro.resolveUrl('/query'));
@ -618,10 +607,8 @@ test.describe('View Transitions', () => {
page,
astro,
}) => {
const loads = [];
page.addListener('load', async (p) => {
loads.push(p);
});
const loads = collectLoads(page);
// Go to the half bakeed page
await page.goto(astro.resolveUrl('/half-baked'));
let p = page.locator('#half-baked');
@ -669,10 +656,8 @@ test.describe('View Transitions', () => {
page,
astro,
}) => {
const loads = [];
page.addListener('load', (p) => {
loads.push(p.title());
});
const loads = collectLoads(page);
// Go to page 4
await page.goto(astro.resolveUrl('/four'));
@ -684,6 +669,9 @@ test.describe('View Transitions', () => {
p = page.locator('#two');
await expect(p, 'should have content').toHaveText('Page 2');
// go to next page
await page.click('#click-longpage');
expect(loads.length, 'There should be 2 page load').toEqual(2);
});
@ -703,10 +691,8 @@ test.describe('View Transitions', () => {
});
test('data-astro-reload not required for non-html content', async ({ page, astro }) => {
const loads = [];
page.addListener('load', (p) => {
loads.push(p.title());
});
const loads = collectLoads(page);
// Go to page 4
await page.goto(astro.resolveUrl('/four'));
let p = page.locator('#four');
@ -765,10 +751,8 @@ test.describe('View Transitions', () => {
});
test('Moving to a page which redirects to another', async ({ page, astro }) => {
const loads = [];
page.addListener('load', (p) => {
loads.push(p.title());
});
const loads = collectLoads(page);
// Go to page 1
await page.goto(astro.resolveUrl('/one'));
@ -792,10 +776,8 @@ test.describe('View Transitions', () => {
});
test('Redirect to external site causes page load', async ({ page, astro }) => {
const loads = [];
page.addListener('load', (p) => {
loads.push(p.title());
});
const loads = collectLoads(page);
// Go to page 1
await page.goto(astro.resolveUrl('/one'));
@ -805,11 +787,9 @@ test.describe('View Transitions', () => {
// go to external page
await page.click('#click-redirect-external');
// doesn't work for playwright when we are too fast
p = page.locator('h1');
await expect(p, 'should have content').toBeVisible();
await page.waitForURL('http://example.com');
await page.waitForFunction((arr) => arr.length === 2, loads);
await expect(page.locator("h1"), 'should have content').toHaveText('Example Domain');
expect(loads.length, 'There should be 2 page loads').toEqual(2);
});
@ -1019,10 +999,8 @@ test.describe('View Transitions', () => {
});
test('form POST that redirects to another page is handled', async ({ page, astro }) => {
const loads = [];
page.addListener('load', async (p) => {
loads.push(p);
});
const loads = collectLoads(page);
await page.goto(astro.resolveUrl('/form-one'));
@ -1048,10 +1026,8 @@ test.describe('View Transitions', () => {
});
test('form GET that redirects to another page is handled', async ({ page, astro }) => {
const loads = [];
page.addListener('load', async (p) => {
loads.push(p);
});
const loads = collectLoads(page);
await page.goto(astro.resolveUrl('/form-one?method=get'));
@ -1070,10 +1046,8 @@ test.describe('View Transitions', () => {
});
test('form POST when there is an error shows the error', async ({ page, astro }) => {
const loads = [];
page.addListener('load', async (p) => {
loads.push(p);
});
const loads = collectLoads(page);
await page.goto(astro.resolveUrl('/form-one?throw'));
@ -1095,11 +1069,8 @@ test.describe('View Transitions', () => {
page,
astro,
}) => {
const loads = [];
const loads = collectLoads(page);
page.addListener('load', async (p) => {
loads.push(p);
});
const postedEncodings = [];
@ -1130,11 +1101,8 @@ test.describe('View Transitions', () => {
});
test('form POST respects enctype attribute', async ({ page, astro }) => {
const loads = [];
const loads = collectLoads(page);
page.addListener('load', async (p) => {
loads.push(p);
});
const postedEncodings = [];
@ -1222,10 +1190,8 @@ test.describe('View Transitions', () => {
});
test('form POST with no action handler', async ({ page, astro }) => {
const loads = [];
page.addListener('load', async (p) => {
loads.push(p);
});
const loads = collectLoads(page);
await page.goto(astro.resolveUrl('/form-two'));
@ -1256,10 +1222,8 @@ test.describe('View Transitions', () => {
});
test('click on an svg anchor should trigger navigation', async ({ page, astro }) => {
const loads = [];
page.addListener('load', (p) => {
loads.push(p.title());
});
const loads = collectLoads(page);
await page.goto(astro.resolveUrl('/non-html-anchor'));
let locator = page.locator('#insidesvga');
@ -1271,10 +1235,8 @@ test.describe('View Transitions', () => {
});
test('click inside an svg anchor should trigger navigation', async ({ page, astro }) => {
const loads = [];
page.addListener('load', (p) => {
loads.push(p.title());
});
const loads = collectLoads(page);
await page.goto(astro.resolveUrl('/non-html-anchor'));
let locator = page.locator('#insidesvga');
await expect(locator, 'should have content').toHaveText('text within a svga');
@ -1285,10 +1247,8 @@ test.describe('View Transitions', () => {
});
test('click on an area in an image map should trigger navigation', async ({ page, astro }) => {
const loads = [];
page.addListener('load', (p) => {
loads.push(p.title());
});
const loads = collectLoads(page);
await page.goto(astro.resolveUrl('/non-html-anchor'));
let locator = page.locator('#area');
await expect(locator, 'should have attribute').toHaveAttribute('shape', 'default');
@ -1328,10 +1288,8 @@ test.describe('View Transitions', () => {
});
test('view transition should also work with 404 page', async ({ page, astro }) => {
const loads = [];
page.addListener('load', (p) => {
loads.push(p.title());
});
const loads = collectLoads(page);
// Go to page 1
await page.goto(astro.resolveUrl('/one'));
@ -1347,10 +1305,8 @@ test.describe('View Transitions', () => {
});
test('custom elements can trigger a view transition', async ({ page, astro }) => {
const loads = [];
page.addListener('load', (p) => {
loads.push(p.title());
});
const loads = collectLoads(page);
await page.goto(astro.resolveUrl('/one'));
await expect(page.locator('#one'), 'should have content').toHaveText('Page 1');
// go to page 2
@ -1361,6 +1317,9 @@ test.describe('View Transitions', () => {
});
test('transition:name should be escaped correctly', async ({ page, astro }) => {
// view-transition-name errors on browser w/o native support
if (!await nativeViewTransition(page)) return;
const expectedAnimations = new Set();
const checkName = async (selector, name) => {
expectedAnimations.add(name);
@ -1518,7 +1477,6 @@ test.describe('View Transitions', () => {
// clicks on slow loading page two
// after short delay clicks on fast loading page one
// even after some delay /two should not show up
await new Promise((resolve) => setTimeout(resolve, 2000)); // wait is part of the test
let p = page.locator('#one');
await expect(p, 'should have content').toHaveText('Page 1');
});
@ -1533,16 +1491,19 @@ test.describe('View Transitions', () => {
// Navigate to self with a 10 second animation
// shortly after starting that, change your mind an navigate to /one
// check that animations got canceled
await new Promise((resolve) => setTimeout(resolve, 1000)); // wait is part of the test
let p = page.locator('#one');
await expect(p, 'should have content').toHaveText('Page 1');
// This test would be more important for a browser without native view transitions
// as those do not have automatic cancelation of transitions.
// For simulated view transitions, the last line would be missing as enter and exit animations
// don't run in parallel.
expect(lines.join('\n')).toBe(
'[test] navigate to "."\n[test] navigate to /one\n[test] cancel astroFadeOut\n[test] cancel astroFadeIn'
);
// For simulated view transitions, the last line would be missing
// as enter and exit animations don't run in parallel.
let expected = '[test] navigate to "."\n[test] navigate to /one\n[test] cancel astroFadeOut';
const native = await nativeViewTransition(page);
if (native) {
expected += '\n[test] cancel astroFadeIn';
}
await page.click('#click-two');
expect(lines.join('\n')).toBe(expected);
});
});

View file

@ -5,7 +5,7 @@ process.stdout.isTTY = false;
const config = {
// TODO: add more tests like view transitions and audits, and fix them. Some of them are failing.
testMatch: ['e2e/css.test.js', 'e2e/prefetch.test.js'],
testMatch: ['e2e/css.test.js', 'e2e/prefetch.test.js', 'e2e/view-transitions.test.js'],
/* Maximum time one test can run for. */
timeout: 40 * 1000,
expect: {