Skip to content

Commit

Permalink
chore: fix runtime error when service worker container is unavailable (
Browse files Browse the repository at this point in the history
…#28678)

* chore: fix runtime error when service worker container is unavailable

* fix flake
  • Loading branch information
ryanthemanuel authored Jan 10, 2024
1 parent c9592bf commit 6ee6544
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 23 deletions.
42 changes: 23 additions & 19 deletions packages/server/lib/browsers/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -434,32 +434,36 @@ const initializeCDP = async (criClient: CriClient, automation: Automation) => {
}

const overrideServiceWorkerRegistration = (binding) => {
const oldRegister = window.ServiceWorkerContainer.prototype.register
// The service worker container won't be available in different situations (like in the placeholder iframes we create
// in open mode). So only override the register function if it exists.
if (window.ServiceWorkerContainer) {
const oldRegister = window.ServiceWorkerContainer.prototype.register

window.ServiceWorkerContainer.prototype.register = function (scriptURL, options) {
const anchor = document.createElement('a')
window.ServiceWorkerContainer.prototype.register = function (scriptURL, options) {
const anchor = document.createElement('a')

let resolvedHref: URL
let resolvedHref: URL

if (typeof scriptURL === 'string') {
anchor.setAttribute('href', scriptURL)
resolvedHref = new URL(anchor.href)
} else {
resolvedHref = scriptURL
}
if (typeof scriptURL === 'string') {
anchor.setAttribute('href', scriptURL)
resolvedHref = new URL(anchor.href)
} else {
resolvedHref = scriptURL
}

anchor.remove()
const resolvedUrl = `${resolvedHref.origin}${resolvedHref.pathname}`
anchor.remove()
const resolvedUrl = `${resolvedHref.origin}${resolvedHref.pathname}`

const serviceWorkerRegistrationEvent = {
type: 'service-worker-registration',
scriptURL: resolvedUrl,
initiatorURL: window.location.href,
}
const serviceWorkerRegistrationEvent = {
type: 'service-worker-registration',
scriptURL: resolvedUrl,
initiatorURL: window.location.href,
}

binding(JSON.stringify(serviceWorkerRegistrationEvent))
binding(JSON.stringify(serviceWorkerRegistrationEvent))

return oldRegister.apply(this, [scriptURL, options])
return oldRegister.apply(this, [scriptURL, options])
}
}
}

Expand Down
4 changes: 4 additions & 0 deletions system-tests/lib/protocol-stubs/protocolStubServiceWorker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export class AppCaptureProtocol implements AppCaptureProtocolInterface {
numberOfResponseStreamReceivedEvents: 0,
correlatedUrls: {},
multipleNetworkRequestEventsForSameRequestId: false,
exceptionThrown: false,
}
private idToUrlAndFrameMap = new Map<string, URLAndFrame>()
private currentRequestWillBeSent: (event) => void
Expand Down Expand Up @@ -63,6 +64,9 @@ export class AppCaptureProtocol implements AppCaptureProtocolInterface {
}

cdpClient.on('Network.requestWillBeSent', this.currentRequestWillBeSent)
cdpClient.on('Runtime.exceptionThrown', (event) => {
this.events.exceptionThrown = true
})
}

addRunnables = (runnables) => {
Expand Down
9 changes: 8 additions & 1 deletion system-tests/projects/e2e/cypress/e2e/service_worker.cy.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
const swReq = (win) => {
return new Promise((resolve) => {
win.addEventListener('service-worker:ready', () => {
win.addEventListener('service-worker:ready', (event) => {
expect(event.detail).to.deep.equal({
example: {
foo: 'bar',
},
cached: 'this response will be used by service worker',
})

resolve(win)
})
})
Expand Down
13 changes: 10 additions & 3 deletions system-tests/projects/e2e/service-worker-assets/scope/load.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
navigator.serviceWorker?.register('/service-worker-assets/scope/service-worker.js')

navigator.serviceWorker?.ready.then(async () => {
await fetch('/service-worker-assets/example.json')
await fetch('/service-worker-assets/scope/cached-service-worker')
const exampleResponse = await fetch('/service-worker-assets/example.json')
const example = await exampleResponse.json()
const cachedServiceWorkerResults = await fetch('/service-worker-assets/scope/cached-service-worker')
const cached = await cachedServiceWorkerResults.text()

window.dispatchEvent(new Event('service-worker:ready'))
window.dispatchEvent(new CustomEvent('service-worker:ready', {
detail: {
example,
cached,
},
}))
})
5 changes: 5 additions & 0 deletions system-tests/test/service_worker_protocol_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ describe('capture-protocol', () => {
return systemTests.exec(this, {
key: 'f858a2bc-b469-4e48-be67-0876339ee7e1',
project: 'protocol',
// Here we are testing that service worker and non-service worker specs can intermingle properly
// Also, protocol.cy.js is not secure which will cause window.ServiceWorkerContainer to not be available
// in the browser. We test that no exceptions are thrown when this happens.
spec: 'protocol.cy.js,service-worker.cy.js',
record: true,
expectedExitCode: 0,
Expand All @@ -49,6 +52,8 @@ describe('capture-protocol', () => {
'http://localhost:2121/cypress/fixtures/service-worker-assets/scope/load.js': ['frame id'],
'http://localhost:2121/cypress/fixtures/service-worker-assets/scope/service_worker.html': ['frame id', 'no frame id', 'no frame id'],
})

expect(parsedProtocolEvents.exceptionThrown).to.be.false
})
})
})
Expand Down

4 comments on commit 6ee6544

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 6ee6544 Jan 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the linux arm64 version of the Test Runner.

Learn more about this pre-release build at https://on.cypress.io/advanced-installation#Install-pre-release-version

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/13.6.3/linux-arm64/develop-6ee654426dd097dac52c3e08658abbba86783e51/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 6ee6544 Jan 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the linux x64 version of the Test Runner.

Learn more about this pre-release build at https://on.cypress.io/advanced-installation#Install-pre-release-version

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/13.6.3/linux-x64/develop-6ee654426dd097dac52c3e08658abbba86783e51/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 6ee6544 Jan 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the darwin x64 version of the Test Runner.

Learn more about this pre-release build at https://on.cypress.io/advanced-installation#Install-pre-release-version

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/13.6.3/darwin-x64/develop-6ee654426dd097dac52c3e08658abbba86783e51/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 6ee6544 Jan 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the darwin arm64 version of the Test Runner.

Learn more about this pre-release build at https://on.cypress.io/advanced-installation#Install-pre-release-version

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/13.6.3/darwin-arm64/develop-6ee654426dd097dac52c3e08658abbba86783e51/cypress.tgz

Please sign in to comment.