From 74af249c38687be4f6e8cfb1c6747c8352ee0d31 Mon Sep 17 00:00:00 2001 From: Max Schmitt Date: Thu, 26 Sep 2024 18:53:21 +0200 Subject: [PATCH 1/2] feat(webkit): roll to r2083 & have dedicated macOS 15 builds --- .github/workflows/tests_secondary.yml | 9 +++++++-- packages/playwright-core/browsers.json | 2 +- .../playwright-core/src/server/registry/index.ts | 14 ++++++++++++++ packages/playwright-core/src/utils/hostPlatform.ts | 5 +++-- tests/library/browsercontext-cookies.spec.ts | 8 ++++---- tests/library/browsercontext-fetch.spec.ts | 9 +++++++-- 6 files changed, 36 insertions(+), 11 deletions(-) diff --git a/.github/workflows/tests_secondary.yml b/.github/workflows/tests_secondary.yml index 8d4bbd1c7845f..04747ca5c2093 100644 --- a/.github/workflows/tests_secondary.yml +++ b/.github/workflows/tests_secondary.yml @@ -50,10 +50,15 @@ jobs: strategy: fail-fast: false matrix: - # Intel: macos-13, macos-14-large - # Arm64: macos-13-xlarge, macos-14 + # Intel: macos-13, macos-14-large, macos-15-large + # Arm64: macos-13-xlarge, macos-14 macos-15 os: [macos-13, macos-13-xlarge, macos-14-large, macos-14] browser: [chromium, firefox, webkit] + include: + - os: macos-15-large + browser: webkit + - os: macos-15 + browser: webkit runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 diff --git a/packages/playwright-core/browsers.json b/packages/playwright-core/browsers.json index d8605f9ed9a1e..0fb97d68ccb4c 100644 --- a/packages/playwright-core/browsers.json +++ b/packages/playwright-core/browsers.json @@ -27,7 +27,7 @@ }, { "name": "webkit", - "revision": "2082", + "revision": "2083", "installByDefault": true, "revisionOverrides": { "mac10.14": "1446", diff --git a/packages/playwright-core/src/server/registry/index.ts b/packages/playwright-core/src/server/registry/index.ts index 4e942967a48eb..7778d812189e6 100644 --- a/packages/playwright-core/src/server/registry/index.ts +++ b/packages/playwright-core/src/server/registry/index.ts @@ -100,6 +100,8 @@ const DOWNLOAD_PATHS: Record = { 'mac13-arm64': 'builds/chromium/%s/chromium-mac-arm64.zip', 'mac14': 'builds/chromium/%s/chromium-mac.zip', 'mac14-arm64': 'builds/chromium/%s/chromium-mac-arm64.zip', + 'mac15': 'builds/chromium/%s/chromium-mac.zip', + 'mac15-arm64': 'builds/chromium/%s/chromium-mac-arm64.zip', 'win64': 'builds/chromium/%s/chromium-win64.zip', }, 'chromium-tip-of-tree': { @@ -127,6 +129,8 @@ const DOWNLOAD_PATHS: Record = { 'mac13-arm64': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-mac-arm64.zip', 'mac14': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-mac.zip', 'mac14-arm64': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-mac-arm64.zip', + 'mac15': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-mac.zip', + 'mac15-arm64': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-mac-arm64.zip', 'win64': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-win64.zip', }, 'firefox': { @@ -154,6 +158,8 @@ const DOWNLOAD_PATHS: Record = { 'mac13-arm64': 'builds/firefox/%s/firefox-mac-arm64.zip', 'mac14': 'builds/firefox/%s/firefox-mac.zip', 'mac14-arm64': 'builds/firefox/%s/firefox-mac-arm64.zip', + 'mac15': 'builds/firefox/%s/firefox-mac.zip', + 'mac15-arm64': 'builds/firefox/%s/firefox-mac-arm64.zip', 'win64': 'builds/firefox/%s/firefox-win64.zip', }, 'firefox-beta': { @@ -181,6 +187,8 @@ const DOWNLOAD_PATHS: Record = { 'mac13-arm64': 'builds/firefox-beta/%s/firefox-beta-mac-arm64.zip', 'mac14': 'builds/firefox-beta/%s/firefox-beta-mac.zip', 'mac14-arm64': 'builds/firefox-beta/%s/firefox-beta-mac-arm64.zip', + 'mac15': 'builds/firefox-beta/%s/firefox-beta-mac.zip', + 'mac15-arm64': 'builds/firefox-beta/%s/firefox-beta-mac-arm64.zip', 'win64': 'builds/firefox-beta/%s/firefox-beta-win64.zip', }, 'webkit': { @@ -208,6 +216,8 @@ const DOWNLOAD_PATHS: Record = { 'mac13-arm64': 'builds/webkit/%s/webkit-mac-13-arm64.zip', 'mac14': 'builds/webkit/%s/webkit-mac-14.zip', 'mac14-arm64': 'builds/webkit/%s/webkit-mac-14-arm64.zip', + 'mac15': 'builds/webkit/%s/webkit-mac-15.zip', + 'mac15-arm64': 'builds/webkit/%s/webkit-mac-15-arm64.zip', 'win64': 'builds/webkit/%s/webkit-win64.zip', }, 'ffmpeg': { @@ -235,6 +245,8 @@ const DOWNLOAD_PATHS: Record = { 'mac13-arm64': 'builds/ffmpeg/%s/ffmpeg-mac-arm64.zip', 'mac14': 'builds/ffmpeg/%s/ffmpeg-mac.zip', 'mac14-arm64': 'builds/ffmpeg/%s/ffmpeg-mac-arm64.zip', + 'mac15': 'builds/ffmpeg/%s/ffmpeg-mac.zip', + 'mac15-arm64': 'builds/ffmpeg/%s/ffmpeg-mac-arm64.zip', 'win64': 'builds/ffmpeg/%s/ffmpeg-win64.zip', }, 'android': { @@ -262,6 +274,8 @@ const DOWNLOAD_PATHS: Record = { 'mac13-arm64': 'builds/android/%s/android.zip', 'mac14': 'builds/android/%s/android.zip', 'mac14-arm64': 'builds/android/%s/android.zip', + 'mac15': 'builds/android/%s/android.zip', + 'mac15-arm64': 'builds/android/%s/android.zip', 'win64': 'builds/android/%s/android.zip', }, // TODO(bidi): implement downloads. diff --git a/packages/playwright-core/src/utils/hostPlatform.ts b/packages/playwright-core/src/utils/hostPlatform.ts index faf65bd0820d8..9664418e3d885 100644 --- a/packages/playwright-core/src/utils/hostPlatform.ts +++ b/packages/playwright-core/src/utils/hostPlatform.ts @@ -25,6 +25,7 @@ export type HostPlatform = 'win64' | 'mac12' | 'mac12-arm64' | 'mac13' | 'mac13-arm64' | 'mac14' | 'mac14-arm64' | + 'mac15' | 'mac15-arm64' | 'ubuntu18.04-x64' | 'ubuntu18.04-arm64' | 'ubuntu20.04-x64' | 'ubuntu20.04-arm64' | 'ubuntu22.04-x64' | 'ubuntu22.04-arm64' | @@ -47,9 +48,9 @@ function calculatePlatform(): { hostPlatform: HostPlatform, isOfficiallySupporte macVersion = 'mac10.15'; } else { // ver[0] >= 20 - const LAST_STABLE_MAC_MAJOR_VERSION = 14; + const LAST_STABLE_MACOS_MAJOR_VERSION = 15; // Best-effort support for MacOS beta versions. - macVersion = 'mac' + Math.min(ver[0] - 9, LAST_STABLE_MAC_MAJOR_VERSION); + macVersion = 'mac' + Math.min(ver[0] - 9, LAST_STABLE_MACOS_MAJOR_VERSION); // BigSur is the first version that might run on Apple Silicon. if (os.cpus().some(cpu => cpu.model.includes('Apple'))) macVersion += '-arm64'; diff --git a/tests/library/browsercontext-cookies.spec.ts b/tests/library/browsercontext-cookies.spec.ts index f0aabb7139440..41080163dee82 100644 --- a/tests/library/browsercontext-cookies.spec.ts +++ b/tests/library/browsercontext-cookies.spec.ts @@ -143,7 +143,7 @@ it('should get multiple cookies', async ({ context, page, server, defaultSameSit ])); }); -it('should get cookies from multiple urls', async ({ context, browserName, isWindows }) => { +it('should get cookies from multiple urls', async ({ context, browserName, isWindows, platform }) => { await context.addCookies([{ url: 'https://foo.com', name: 'doggo', @@ -178,7 +178,7 @@ it('should get cookies from multiple urls', async ({ context, browserName, isWin expires: -1, httpOnly: false, secure: true, - sameSite: 'None', + sameSite: (browserName === 'webkit' && platform === 'darwin' && parseInt(os.release(), 10) >= 24) ? 'Lax' : 'None', }])); }); @@ -274,7 +274,7 @@ it('should return secure cookies based on HTTP(S) protocol', async ({ context, b }]); }); -it('should add cookies with an expiration', async ({ context }) => { +it('should add cookies with an expiration', async ({ context, browserName, platform }) => { const expires = Math.floor((Date.now() / 1000)) + 3600; await context.addCookies([{ url: 'https://foo.com', @@ -293,7 +293,7 @@ it('should add cookies with an expiration', async ({ context }) => { expires, httpOnly: false, secure: true, - sameSite: 'None', + sameSite: (browserName === 'webkit' && platform === 'darwin' && parseInt(os.release(), 10) >= 24) ? 'Lax' : 'None', }]); { // Rollover to 5-digit year diff --git a/tests/library/browsercontext-fetch.spec.ts b/tests/library/browsercontext-fetch.spec.ts index d10b182cf036b..bc84fda150f4c 100644 --- a/tests/library/browsercontext-fetch.spec.ts +++ b/tests/library/browsercontext-fetch.spec.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +import os from 'os'; import type { LookupAddress } from 'dns'; import formidable from 'formidable'; import fs from 'fs'; @@ -1245,7 +1246,7 @@ it('should work with connectOverCDP', async ({ browserName, browserType, server } }); -it('should support SameSite cookie attribute over https', async ({ contextFactory, httpsServer, browserName, isWindows }) => { +it('should support SameSite cookie attribute over https', async ({ contextFactory, httpsServer, browserName, isWindows, platform }) => { // Cookies with SameSite=None must also specify the Secure attribute. WebKit navigation // to HTTP url will fail if the response contains a cookie with Secure attribute, so // we do HTTPS navigation. @@ -1261,6 +1262,8 @@ it('should support SameSite cookie attribute over https', async ({ contextFactor const [cookie] = await page.context().cookies(); if (browserName === 'webkit' && isWindows) expect(cookie.sameSite).toBe('None'); + else if (browserName === 'webkit' && platform === 'darwin' && value === 'None') + expect(cookie.sameSite).toBe('Lax'); else expect(cookie.sameSite).toBe(value); }); @@ -1290,7 +1293,7 @@ it('fetch should not throw on long set-cookie value', async ({ context, server } expect(cookies.map(c => c.name)).toContain('bar'); }); -it('should support set-cookie with SameSite and without Secure attribute over HTTP', async ({ page, server, browserName, isWindows, isLinux }) => { +it('should support set-cookie with SameSite and without Secure attribute over HTTP', async ({ page, server, browserName, isWindows, isLinux, isMac }) => { for (const value of ['None', 'Lax', 'Strict']) { await it.step(`SameSite=${value}`, async () => { server.setRoute('/empty.html', (req, res) => { @@ -1305,6 +1308,8 @@ it('should support set-cookie with SameSite and without Secure attribute over HT expect(cookie).toBeFalsy(); else if (browserName === 'webkit' && isWindows) expect(cookie.sameSite).toBe('None'); + else if (browserName === 'webkit' && isMac && parseInt(os.release(), 10) >= 24 && value === 'None') + expect(cookie.sameSite).toBe('Lax'); else expect(cookie.sameSite).toBe(value); }); From 90fc8d9b571b047fc06c132c79f1a53c93a9ba0b Mon Sep 17 00:00:00 2001 From: Max Schmitt Date: Thu, 26 Sep 2024 19:21:53 +0200 Subject: [PATCH 2/2] fixture --- .github/actions/enable-microphone-access/action.yml | 4 ++-- tests/config/browserTest.ts | 8 ++++++++ tests/library/browsercontext-cookies.spec.ts | 8 ++++---- tests/library/browsercontext-fetch.spec.ts | 13 ++++++------- 4 files changed, 20 insertions(+), 13 deletions(-) diff --git a/.github/actions/enable-microphone-access/action.yml b/.github/actions/enable-microphone-access/action.yml index b94f48064711f..d706b17544e0c 100644 --- a/.github/actions/enable-microphone-access/action.yml +++ b/.github/actions/enable-microphone-access/action.yml @@ -19,7 +19,7 @@ runs: elif [[ "$version" == "12" || "$version" == "13" ]]; then sqlite3 $HOME/Library/Application\ Support/com.apple.TCC/TCC.db "INSERT OR REPLACE INTO access VALUES('kTCCServiceMicrophone','/usr/local/opt/runner/provisioner/provisioner',1,2,4,1,NULL,NULL,0,'UNUSED',NULL,0,1687786159);" else - echo "macOS version is unsupported. Version is $version, exiting" - exit 1 + echo "Skipping unsupported macOS version $version" + exit 0 fi echo "Successfully allowed microphone access" diff --git a/tests/config/browserTest.ts b/tests/config/browserTest.ts index c301233e07fe9..9880083107f2d 100644 --- a/tests/config/browserTest.ts +++ b/tests/config/browserTest.ts @@ -30,6 +30,7 @@ import type { TestInfo } from '@playwright/test'; export type BrowserTestWorkerFixtures = PageWorkerFixtures & { browserVersion: string; defaultSameSiteCookieValue: string; + sameSiteStoredValueForNone: string; allowsThirdParty: boolean; browserMajorVersion: number; browserType: BrowserType; @@ -86,6 +87,13 @@ const test = baseTest.extend throw new Error('unknown browser - ' + browserName); }, { scope: 'worker' }], + sameSiteStoredValueForNone: [async ({ browserName, isMac }, run) => { + if (browserName === 'webkit' && isMac && parseInt(os.release(), 10) >= 24) + await run('Lax'); + else + await run('None'); + }, { scope: 'worker' }], + browserMajorVersion: [async ({ browserVersion }, run) => { await run(Number(browserVersion.split('.')[0])); }, { scope: 'worker' }], diff --git a/tests/library/browsercontext-cookies.spec.ts b/tests/library/browsercontext-cookies.spec.ts index 41080163dee82..798a840f9d681 100644 --- a/tests/library/browsercontext-cookies.spec.ts +++ b/tests/library/browsercontext-cookies.spec.ts @@ -143,7 +143,7 @@ it('should get multiple cookies', async ({ context, page, server, defaultSameSit ])); }); -it('should get cookies from multiple urls', async ({ context, browserName, isWindows, platform }) => { +it('should get cookies from multiple urls', async ({ context, browserName, isWindows, sameSiteStoredValueForNone }) => { await context.addCookies([{ url: 'https://foo.com', name: 'doggo', @@ -178,7 +178,7 @@ it('should get cookies from multiple urls', async ({ context, browserName, isWin expires: -1, httpOnly: false, secure: true, - sameSite: (browserName === 'webkit' && platform === 'darwin' && parseInt(os.release(), 10) >= 24) ? 'Lax' : 'None', + sameSite: sameSiteStoredValueForNone, }])); }); @@ -274,7 +274,7 @@ it('should return secure cookies based on HTTP(S) protocol', async ({ context, b }]); }); -it('should add cookies with an expiration', async ({ context, browserName, platform }) => { +it('should add cookies with an expiration', async ({ context, sameSiteStoredValueForNone }) => { const expires = Math.floor((Date.now() / 1000)) + 3600; await context.addCookies([{ url: 'https://foo.com', @@ -293,7 +293,7 @@ it('should add cookies with an expiration', async ({ context, browserName, platf expires, httpOnly: false, secure: true, - sameSite: (browserName === 'webkit' && platform === 'darwin' && parseInt(os.release(), 10) >= 24) ? 'Lax' : 'None', + sameSite: sameSiteStoredValueForNone, }]); { // Rollover to 5-digit year diff --git a/tests/library/browsercontext-fetch.spec.ts b/tests/library/browsercontext-fetch.spec.ts index bc84fda150f4c..ae5cf5e7d55cd 100644 --- a/tests/library/browsercontext-fetch.spec.ts +++ b/tests/library/browsercontext-fetch.spec.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -import os from 'os'; import type { LookupAddress } from 'dns'; import formidable from 'formidable'; import fs from 'fs'; @@ -1246,7 +1245,7 @@ it('should work with connectOverCDP', async ({ browserName, browserType, server } }); -it('should support SameSite cookie attribute over https', async ({ contextFactory, httpsServer, browserName, isWindows, platform }) => { +it('should support SameSite cookie attribute over https', async ({ contextFactory, httpsServer, browserName, isWindows, sameSiteStoredValueForNone }) => { // Cookies with SameSite=None must also specify the Secure attribute. WebKit navigation // to HTTP url will fail if the response contains a cookie with Secure attribute, so // we do HTTPS navigation. @@ -1262,8 +1261,8 @@ it('should support SameSite cookie attribute over https', async ({ contextFactor const [cookie] = await page.context().cookies(); if (browserName === 'webkit' && isWindows) expect(cookie.sameSite).toBe('None'); - else if (browserName === 'webkit' && platform === 'darwin' && value === 'None') - expect(cookie.sameSite).toBe('Lax'); + else if (value === 'None') + expect(cookie.sameSite).toBe(sameSiteStoredValueForNone); else expect(cookie.sameSite).toBe(value); }); @@ -1293,7 +1292,7 @@ it('fetch should not throw on long set-cookie value', async ({ context, server } expect(cookies.map(c => c.name)).toContain('bar'); }); -it('should support set-cookie with SameSite and without Secure attribute over HTTP', async ({ page, server, browserName, isWindows, isLinux, isMac }) => { +it('should support set-cookie with SameSite and without Secure attribute over HTTP', async ({ page, server, browserName, isWindows, isLinux, sameSiteStoredValueForNone }) => { for (const value of ['None', 'Lax', 'Strict']) { await it.step(`SameSite=${value}`, async () => { server.setRoute('/empty.html', (req, res) => { @@ -1308,8 +1307,8 @@ it('should support set-cookie with SameSite and without Secure attribute over HT expect(cookie).toBeFalsy(); else if (browserName === 'webkit' && isWindows) expect(cookie.sameSite).toBe('None'); - else if (browserName === 'webkit' && isMac && parseInt(os.release(), 10) >= 24 && value === 'None') - expect(cookie.sameSite).toBe('Lax'); + else if (value === 'None') + expect(cookie.sameSite).toBe(sameSiteStoredValueForNone); else expect(cookie.sameSite).toBe(value); });