Files
Benjamin Woodruff 727a3ffa86 [ci] Skip apt-installed dependencies in playwright install step (#95535)
The hypothesis is that this is just installing some font stuff that
isn't actually needed for Chromium to work:

```
The following additional packages will be installed:
  libnss3-tools xfonts-encodings xfonts-utils
Recommended packages:
  fonts-ipafont-mincho fonts-liberation-sans-narrow fonts-tlwg-loma
The following NEW packages will be installed:
  fonts-freefont-ttf fonts-ipafont-gothic fonts-liberation fonts-tlwg-loma-otf
  fonts-unifont fonts-wqy-zenhei xfonts-cyrillic xfonts-encodings
  xfonts-scalable xfonts-utils
The following packages will be upgraded:
  libnss3 libnss3-tools
2 upgraded, 10 newly installed, 0 to remove and 35 not upgraded.
```

`apt` is very slow, so skipping this step should significantly reduce
setup time per test shard.

It seems like this isn't always true for other browsers, so only skip
this for Chromium (that's fine, that's what most of our jobs use
anyways).

On 16 core arm runners, "Install Playwright Browsers" typically took
18-24 seconds. Now it takes 5-6s.

Let's estimate that saves about 15s per Linux job that installs
Chromium. Claude estimates that there are 73 chromium-only Linux jobs on
this PR:

<img width="891" height="148" alt="Screenshot 2026-07-06 at 10 30 16 PM"
src="https://github.com/user-attachments/assets/725893fa-9f6f-4806-a3b4-9858ab0ebe66"
/>

So that's 15*73/60=18.25 minutes saved per PR push (the average PR gets
many pushes). At the public (before any volume discounts) price of
$0.026/minute for the 16 core arm runners, that comes out to $0.4745 per
PR push saved.

This workflow has had 3,894 runs in the last 30 days, so that could be
$1,847/mo saved, but many of those workflow runs were canceled, and some
likely failed before getting to these jobs, so the actual savings are
probably somewhere around half of that -- scroll through
https://github.com/vercel/next.js/actions/workflows/.github/workflows/build_and_test.yml
and see that a little less than half of the workflow runs end up
canceled.
2026-07-07 09:48:46 +02:00

107 lines
3.5 KiB
TypeScript

/* eslint-env jest */
import { check } from 'next-test-utils'
import path from 'path'
import { nextTestSetup } from 'e2e-utils'
import { expectScrolledTo } from './scroll-position.util'
describe('Client navigation scroll', () => {
const { next } = nextTestSetup({
files: path.join(__dirname, 'fixture'),
env: {
TEST_STRICT_NEXT_HEAD: String(true),
},
})
describe('resets scroll at the correct time', () => {
it('should reset scroll before the new page runs its lifecycles (<Link />)', async () => {
const browser = await next.browser('/nav/long-page-to-snap-scroll')
// Scrolls to item 400 on the page
await browser
.waitForElementByCss('#long-page-to-snap-scroll')
.elementByCss('#scroll-to-item-400')
.click()
await expectScrolledTo(browser, "document.getElementById('item-400')")
// Go to snap scroll page
await browser
.elementByCss('#goto-snap-scroll-position')
.click()
.waitForElementByCss('#scroll-pos-y')
const snappedScrollPosition = await browser.eval(
'document.getElementById("scroll-pos-y").innerText'
)
expect(snappedScrollPosition).toBe('0')
})
it('should reset scroll before the new page runs its lifecycles (Router#push)', async () => {
const browser = await next.browser('/nav/long-page-to-snap-scroll')
// Scrolls to item 400 on the page
await browser
.waitForElementByCss('#long-page-to-snap-scroll')
.elementByCss('#scroll-to-item-400')
.click()
await expectScrolledTo(browser, "document.getElementById('item-400')")
// Go to snap scroll page
await browser
.elementByCss('#goto-snap-scroll-position-imperative')
.click()
.waitForElementByCss('#scroll-pos-y')
const snappedScrollPosition = await browser.eval(
'document.getElementById("scroll-pos-y").innerText'
)
expect(snappedScrollPosition).toBe('0')
})
it('should intentionally not reset scroll before the new page runs its lifecycles (Router#push)', async () => {
const browser = await next.browser('/nav/long-page-to-snap-scroll')
// Scrolls to item 400 on the page
await browser
.waitForElementByCss('#long-page-to-snap-scroll')
.elementByCss('#scroll-to-item-400')
.click()
await expectScrolledTo(browser, "document.getElementById('item-400')")
const scrollPosition = await browser.eval('window.pageYOffset')
// Go to snap scroll page
await browser
.elementByCss('#goto-snap-scroll-position-imperative-noscroll')
.click()
.waitForElementByCss('#scroll-pos-y')
const snappedScrollPosition = await browser.eval(
'document.getElementById("scroll-pos-y").innerText'
)
expect(snappedScrollPosition).not.toBe('0')
expect(Number(snappedScrollPosition)).toBeGreaterThanOrEqual(
scrollPosition
)
})
})
it('should scroll to top when the scroll option is set to true', async () => {
const browser = await next.browser('/nav/shallow-routing')
await browser.eval(() =>
document.querySelector('#increaseWithScroll').scrollIntoView()
)
const scrollPosition = await browser.eval('window.pageYOffset')
expect(scrollPosition).toBeGreaterThan(3000)
await browser.elementByCss('#increaseWithScroll').click()
await check(async () => {
const newScrollPosition = await browser.eval('window.pageYOffset')
return newScrollPosition === 0 ? 'success' : 'fail'
}, 'success')
})
})