From d9b2168172c3b2618602df6560ca131045e634b9 Mon Sep 17 00:00:00 2001 From: Simon Knott Date: Tue, 26 Nov 2024 12:22:21 +0100 Subject: [PATCH] chore(ui): test that UI works behind proxy --- package-lock.json | 62 +++++++++++++++++++++ package.json | 2 + tests/playwright-test/ui-mode-trace.spec.ts | 55 ++++++++++++++++++ 3 files changed, 119 insertions(+) diff --git a/package-lock.json b/package-lock.json index c216b1281c..093e08df01 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,6 +26,7 @@ "@types/babel__core": "^7.20.2", "@types/codemirror": "^5.60.7", "@types/formidable": "^2.0.4", + "@types/http-proxy": "^1.17.15", "@types/immutable": "^3.8.7", "@types/node": "^18.19.39", "@types/react": "^18.0.12", @@ -53,6 +54,7 @@ "eslint-plugin-react": "^7.35.0", "eslint-plugin-react-hooks": "^4.6.2", "formidable": "^2.1.1", + "http-proxy": "^1.18.1", "immutable": "^4.3.7", "license-checker": "^25.0.1", "mime": "^3.0.0", @@ -1831,6 +1833,16 @@ "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", "dev": true }, + "node_modules/@types/http-proxy": { + "version": "1.17.15", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.15.tgz", + "integrity": "sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/immutable": { "version": "3.8.7", "resolved": "https://registry.npmjs.org/@types/immutable/-/immutable-3.8.7.tgz", @@ -3908,6 +3920,13 @@ "node": ">=0.10.0" } }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true, + "license": "MIT" + }, "node_modules/extract-zip": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", @@ -4046,6 +4065,27 @@ "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", "dev": true }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -4527,6 +4567,21 @@ "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", "dev": true }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/http2-wrapper": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", @@ -6107,6 +6162,13 @@ "node": ">=0.10.0" } }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true, + "license": "MIT" + }, "node_modules/resolve": { "version": "2.0.0-next.5", "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", diff --git a/package.json b/package.json index f36e9039e3..f019f6eacc 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,7 @@ "@types/babel__core": "^7.20.2", "@types/codemirror": "^5.60.7", "@types/formidable": "^2.0.4", + "@types/http-proxy": "^1.17.15", "@types/immutable": "^3.8.7", "@types/node": "^18.19.39", "@types/react": "^18.0.12", @@ -92,6 +93,7 @@ "eslint-plugin-react": "^7.35.0", "eslint-plugin-react-hooks": "^4.6.2", "formidable": "^2.1.1", + "http-proxy": "^1.18.1", "immutable": "^4.3.7", "license-checker": "^25.0.1", "mime": "^3.0.0", diff --git a/tests/playwright-test/ui-mode-trace.spec.ts b/tests/playwright-test/ui-mode-trace.spec.ts index eb56204813..863a283d2f 100644 --- a/tests/playwright-test/ui-mode-trace.spec.ts +++ b/tests/playwright-test/ui-mode-trace.spec.ts @@ -16,6 +16,9 @@ import { createImage } from './playwright-test-fixtures'; import { test, expect, retries } from './ui-mode-fixtures'; +import http from 'node:http'; +import httpProxy from 'http-proxy'; +import { ManualPromise } from 'packages/playwright-core/lib/utils/manualPromise'; test.describe.configure({ mode: 'parallel', retries }); @@ -339,3 +342,55 @@ test('should show request source context id', async ({ runUITest, server }) => { await expect(page.getByText('page#2')).toBeVisible(); await expect(page.getByText('api#1')).toBeVisible(); }); + +test('should work behind proxy', async ({ runUITest }, testInfo) => { + const { page } = await runUITest({ + 'a.test.ts': ` + import { test, expect } from '@playwright/test'; + test('trace test', async ({ page }) => { + await page.setContent(''); + await page.getByRole('button').click(); + expect(1).toBe(1); + }); + `, + }); + + const prefix = '/subdir'; + const origin = new URL(page.url()); + const proxy = httpProxy.createProxy({ target: { port: origin.port }, ws: true }); + + const proxyServer = http.createServer((req, res) => { + req.url = req.url!.replace(prefix, ''); + proxy.web(req, res); + }); + proxyServer.on('upgrade', (req, socket, head) => { + req.url = req.url!.replace(prefix, ''); + proxy.ws(req, socket, head); + }); + + const proxyPort = 9010 + testInfo.workerIndex * 4; + await new Promise(resolve => proxyServer.listen(proxyPort, resolve)); + + const proxyURL = new URL(origin); + proxyURL.host = `localhost:${proxyPort}`; + proxyURL.pathname = prefix + proxyURL.pathname; + + await page.goto(proxyURL.toString()); + + await page.getByText('trace test').dblclick(); + + await expect(page.getByTestId('actions-tree')).toMatchAriaSnapshot(` + - tree: + - treeitem /Before Hooks \\d+[hmsp]+/ + - treeitem /page\\.setContent \\d+[hmsp]+/ + - treeitem /locator\\.clickgetByRole\\('button'\\) \\d+[hmsp]+/ + - treeitem /expect\\.toBe \\d+[hmsp]+/ [selected] + - treeitem /After Hooks \\d+[hmsp]+/ + `); + + await expect( + page.frameLocator('iframe.snapshot-visible[name=snapshot]').locator('button'), + ).toHaveText('Submit'); + + proxyServer.close(); +});