Skip to content

Commit c16688e

Browse files
authored
fix: no-sw error shows for subdomain requests (#491)
* test: enable testing of pages with no service worker loaded * test: add no-sw tests that repro #272 * fix: no-sw error shows for subdomain requests * test: no-service-worker tests target a test file & run in CI
1 parent d50f5bc commit c16688e

File tree

10 files changed

+85
-6
lines changed

10 files changed

+85
-6
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,3 +226,4 @@ playwright-report
226226
.coverage
227227
test-e2e/fixtures/data/test-repo
228228
test-e2e/fixtures/data/gateway-conformance-fixtures
229+
test-results

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
"test:iso": "aegir test -f dist-tsc/test/**/*.spec.js",
2121
"test:browsers": "playwright test -c playwright.config.js",
2222
"test:chrome": "playwright test -c playwright.config.js --project chromium",
23-
"test:firefox": "playwright test -c playwright.config.js --project firefox",
23+
"test:no-sw": "playwright test -c playwright.config.js --project no-service-worker",
24+
"test:firefox": "playwright test -c playwright.config.js --project firefox --project no-service-worker",
2425
"test:deployed": "playwright test -c playwright.config.js --project deployed",
2526
"test:inbrowser-dev": "cross-env BASE_URL='https://inbrowser.dev' playwright test -c playwright.config.js --project deployed",
2627
"test:inbrowser-prod": "cross-env BASE_URL='https://inbrowser.link' playwright test -c playwright.config.js --project deployed",

playwright.config.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,32 @@ export default defineConfig({
5151
...devices['Desktop Firefox'],
5252
baseURL: process.env.BASE_URL
5353
}
54+
},
55+
{
56+
/**
57+
* Test the site with service workers disabled. You need to `import {testNoServiceWorker as test, expect} from './fixtures/config-test-fixtures.js'` to use this project.
58+
* Anything needing a service worker will be skipped when this project is ran.
59+
*/
60+
name: 'no-service-worker',
61+
testMatch: /test-e2e\/no-service-worker\.test\.ts/,
62+
use: {
63+
...devices['Desktop Firefox'],
64+
contextOptions: {
65+
serviceWorkers: 'block'
66+
},
67+
launchOptions: {
68+
firefoxUserPrefs: {
69+
'dom.serviceWorkers.enabled': false
70+
}
71+
},
72+
beforeEach: async ({ page }) => {
73+
await page.addInitScript(() => {
74+
Object.defineProperty(navigator, 'serviceWorker', {
75+
get: () => undefined
76+
})
77+
})
78+
}
79+
}
5480
}
5581
],
5682
// TODO: disable webservers when testing `deployed` project

src/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ if ('serviceWorker' in navigator) {
2222

2323
const routes: Route[] = [
2424
{ default: true, component: ErrorPage ?? LazyHelperUi },
25+
{ shouldRender: async () => renderChecks.shouldRenderNoServiceWorkerError(), component: LazyServiceWorkerErrorPage },
2526
{ shouldRender: async () => renderChecks.shouldRenderRedirectsInterstitial(), component: LazyInterstitial },
2627
{ path: '#/ipfs-sw-config', shouldRender: async () => renderChecks.shouldRenderConfigPage(), component: LazyConfig },
2728
{

src/lib/routing-render-checks.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,7 @@ export function shouldRenderRedirectsInterstitial (): boolean {
3131
const heliaSw = url.searchParams.get('helia-sw')
3232
return heliaSw != null
3333
}
34+
35+
export function shouldRenderNoServiceWorkerError (): boolean {
36+
return !('serviceWorker' in navigator)
37+
}

src/pages/errors/no-service-worker.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export default function NoServiceWorkerErrorPage (): React.JSX.Element {
1111
return (
1212
<>
1313
<Header />
14-
<main className='pa4-l bg-red-muted mw7 mb5 center pa4'>
14+
<main className='pa4-l bg-red-muted mw7 mb5 center pa4 e2e-no-service-worker-error'>
1515
<h1>Service Worker Error</h1>
1616
<p>
1717
This page requires a service worker to be available. Please ensure that

test-e2e/fixtures/config-test-fixtures.ts

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ import { test as base, type Page } from '@playwright/test'
22
import { setConfig, setSubdomainConfig } from './set-sw-config.js'
33
import { waitForServiceWorker } from './wait-for-service-worker.js'
44

5+
function isNoServiceWorkerProject <T extends typeof base = typeof base> (test: T): boolean {
6+
return test.info().project.name === 'no-service-worker'
7+
}
8+
59
const rootDomain = async ({ baseURL }, use): Promise<void> => {
610
const url = new URL(baseURL)
711
await use(url.host)
@@ -13,13 +17,20 @@ const baseURLProtocol = async ({ baseURL }, use): Promise<void> => {
1317

1418
export const test = base.extend<{ rootDomain: string, baseURL: string, protocol: string }>({
1519
rootDomain: [rootDomain, { scope: 'test' }],
16-
protocol: [baseURLProtocol, { scope: 'test' }]
20+
protocol: [baseURLProtocol, { scope: 'test' }],
21+
page: async ({ page }, use) => {
22+
if (isNoServiceWorkerProject(test)) {
23+
test.skip()
24+
return
25+
}
26+
await use(page)
27+
}
1728
})
1829

1930
/**
2031
* You should use this fixture instead of the `test` fixture from `@playwright/test` when testing path routing via the service worker.
2132
*/
22-
export const testPathRouting = base.extend<{ rootDomain: string, baseURL: string, protocol: string }>({
33+
export const testPathRouting = test.extend<{ rootDomain: string, baseURL: string, protocol: string }>({
2334
rootDomain: [rootDomain, { scope: 'test' }],
2435
protocol: [baseURLProtocol, { scope: 'test' }],
2536
page: async ({ page, rootDomain }, use) => {
@@ -63,7 +74,7 @@ export const testPathRouting = base.extend<{ rootDomain: string, baseURL: string
6374
* })
6475
* ```
6576
*/
66-
export const testSubdomainRouting = base.extend<{ rootDomain: string, baseURL: string, protocol: string }>({
77+
export const testSubdomainRouting = test.extend<{ rootDomain: string, baseURL: string, protocol: string }>({
6778
rootDomain: [rootDomain, { scope: 'test' }],
6879
protocol: [baseURLProtocol, { scope: 'test' }],
6980
page: async ({ page, baseURL }, use) => {
@@ -108,4 +119,21 @@ export const testSubdomainRouting = base.extend<{ rootDomain: string, baseURL: s
108119
}
109120
})
110121

122+
/**
123+
* A fixture that skips tests that require the service worker. This is needed in order to test handling of requests where the service worker is not present.
124+
*
125+
* @see https://github.com/ipfs/service-worker-gateway/issues/272
126+
*/
127+
export const testNoServiceWorker = base.extend<{ rootDomain: string, baseURL: string, protocol: string }>({
128+
rootDomain: [rootDomain, { scope: 'test' }],
129+
protocol: [baseURLProtocol, { scope: 'test' }],
130+
page: async ({ page }, use) => {
131+
if (!isNoServiceWorkerProject(testNoServiceWorker)) {
132+
testNoServiceWorker.skip()
133+
return
134+
}
135+
await use(page)
136+
}
137+
})
138+
111139
export { expect } from '@playwright/test'

test-e2e/fixtures/locators.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ export const getConfigGatewaysInput: GetLocator = (page) => page.locator('.e2e-c
2121
export const getConfigRoutersInput: GetLocator = (page) => page.locator('.e2e-config-page-input-routers')
2222
export const getConfigAutoReloadInput: GetLocator = (page) => page.locator('.e2e-config-page-input-autoreload')
2323

24+
export const getNoServiceWorkerError: GetLocator = (page) => page.locator('.e2e-no-service-worker-error')
25+
2426
/**
2527
* Iframe page parts
2628
*/

test-e2e/layout.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { test, expect } from '@playwright/test'
1+
import { test, expect } from './fixtures/config-test-fixtures.js'
22
import { getConfigButton, getConfigPage, getConfigPageSaveButton, getConfigPageInput, getHeader, getHeaderTitle } from './fixtures/locators.js'
33

44
test.describe('smoketests', () => {

test-e2e/no-service-worker.test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { testNoServiceWorker as test, expect } from './fixtures/config-test-fixtures.js'
2+
import { getNoServiceWorkerError } from './fixtures/locators.js'
3+
4+
test.describe('no-service-worker', () => {
5+
test('Error renders on landing page', async ({ page }) => {
6+
await page.goto('/')
7+
8+
await expect(getNoServiceWorkerError(page)).toBeVisible()
9+
})
10+
11+
test('Error renders on subdomain page', async ({ page, rootDomain, protocol }) => {
12+
await page.goto(`${protocol ?? 'http'}//bafkqablimvwgy3y.ipfs.${rootDomain}`, { waitUntil: 'networkidle' })
13+
14+
await expect(getNoServiceWorkerError(page)).toBeVisible()
15+
})
16+
})

0 commit comments

Comments
 (0)