Skip to content

Commit e52613d

Browse files
committed
updates
1 parent 04c923a commit e52613d

File tree

2 files changed

+144
-81
lines changed

2 files changed

+144
-81
lines changed

packages/driver/cypress/e2e/e2e/service-worker.cy.js

+102-69
Original file line numberDiff line numberDiff line change
@@ -8,56 +8,70 @@ describe('service workers', () => {
88

99
describe('a service worker that handles requests', () => {
1010
it('supports using addEventListener with function', () => {
11+
const script = () => {
12+
self.addEventListener('fetch', function (event) {
13+
event.respondWith(fetch(event.request))
14+
})
15+
}
16+
1117
cy.intercept('/fixtures/service-worker.js', (req) => {
12-
req.reply(`
13-
self.addEventListener('fetch', function (event) {
14-
event.respondWith(fetch(event.request))
15-
})`,
16-
{ 'Content-Type': 'application/javascript' })
18+
req.reply(`(${script})()`,
19+
{ 'Content-Type': 'application/javascript' })
1720
})
1821

1922
cy.visit('fixtures/service-worker.html')
2023
cy.get('#output').should('have.text', 'done')
2124
})
2225

2326
it('supports using addEventListener with object', () => {
27+
const script = () => {
28+
const obj = {
29+
handleEvent (event) {
30+
event.respondWith(fetch(event.request))
31+
},
32+
}
33+
34+
self.addEventListener('fetch', obj)
35+
}
36+
2437
cy.intercept('/fixtures/service-worker.js', (req) => {
25-
req.reply(`
26-
const obj = {
27-
handleEvent: function (event) {
28-
event.respondWith(fetch(event.request))
29-
}
30-
}
31-
self.addEventListener('fetch', obj)`,
32-
{ 'Content-Type': 'application/javascript' })
38+
req.reply(`(${script})()`,
39+
{ 'Content-Type': 'application/javascript' })
3340
})
3441

3542
cy.visit('fixtures/service-worker.html')
3643
cy.get('#output').should('have.text', 'done')
3744
})
3845

3946
it('supports using addEventListener with delayed handleEvent', () => {
47+
const script = () => {
48+
const obj = {}
49+
50+
self.addEventListener('fetch', obj)
51+
obj.handleEvent = function (event) {
52+
event.respondWith(fetch(event.request))
53+
}
54+
}
55+
4056
cy.intercept('/fixtures/service-worker.js', (req) => {
41-
req.reply(`
42-
const obj = {}
43-
self.addEventListener('fetch', obj)
44-
obj.handleEvent = function (event) {
45-
event.respondWith(fetch(event.request))
46-
}`,
47-
{ 'Content-Type': 'application/javascript' })
57+
req.reply(`(${script})()`,
58+
{ 'Content-Type': 'application/javascript' })
4859
})
4960

5061
cy.visit('fixtures/service-worker.html')
5162
cy.get('#output').should('have.text', 'done')
5263
})
5364

5465
it('supports using onfetch', () => {
66+
const script = () => {
67+
self.onfetch = function (event) {
68+
event.respondWith(fetch(event.request))
69+
}
70+
}
71+
5572
cy.intercept('/fixtures/service-worker.js', (req) => {
56-
req.reply(`
57-
self.onfetch = function (event) {
58-
event.respondWith(fetch(event.request))
59-
}`,
60-
{ 'Content-Type': 'application/javascript' })
73+
req.reply(`(${script})()`,
74+
{ 'Content-Type': 'application/javascript' })
6175
})
6276

6377
cy.visit('fixtures/service-worker.html')
@@ -67,25 +81,31 @@ describe('service workers', () => {
6781

6882
describe('a service worker that does not handle requests', () => {
6983
it('supports using addEventListener', () => {
84+
const script = () => {
85+
self.addEventListener('fetch', function (event) {
86+
return
87+
})
88+
}
89+
7090
cy.intercept('/fixtures/service-worker.js', (req) => {
71-
req.reply(`
72-
self.addEventListener('fetch', function (event) {
73-
return
74-
})`,
75-
{ 'Content-Type': 'application/javascript' })
91+
req.reply(`(${script})()`,
92+
{ 'Content-Type': 'application/javascript' })
7693
})
7794

7895
cy.visit('fixtures/service-worker.html')
7996
cy.get('#output').should('have.text', 'done')
8097
})
8198

8299
it('supports using onfetch', () => {
100+
const script = () => {
101+
self.onfetch = function (event) {
102+
return
103+
}
104+
}
105+
83106
cy.intercept('/fixtures/service-worker.js', (req) => {
84-
req.reply(`
85-
self.onfetch = function (event) {
86-
return
87-
}`,
88-
{ 'Content-Type': 'application/javascript' })
107+
req.reply(`(${script})()`,
108+
{ 'Content-Type': 'application/javascript' })
89109
})
90110

91111
cy.visit('fixtures/service-worker.html')
@@ -95,40 +115,50 @@ describe('service workers', () => {
95115

96116
describe('a service worker that removes fetch handlers', () => {
97117
it('supports using addEventListener', () => {
118+
const script = () => {
119+
const handler = function (event) {
120+
return new Response('Network error', {
121+
status: 400,
122+
headers: { 'Content-Type': 'text/plain' },
123+
})
124+
}
125+
126+
self.addEventListener('fetch', handler)
127+
self.removeEventListener('fetch', handler)
128+
129+
self.addEventListener('fetch', function (event) {
130+
return
131+
})
132+
}
133+
98134
cy.intercept('/fixtures/service-worker.js', (req) => {
99-
req.reply(`
100-
const handler = function (event) {
101-
return new Response('Network error', {
102-
status: 400,
103-
headers: { 'Content-Type': 'text/plain' },
104-
})
105-
}
106-
107-
self.addEventListener('fetch', handler)
108-
self.removeEventListener('fetch', handler)
109-
110-
self.addEventListener('fetch', function (event) {
111-
return
112-
})`,
113-
{ 'Content-Type': 'application/javascript' })
135+
req.reply(`(${script})()`,
136+
{ 'Content-Type': 'application/javascript' })
114137
})
115138

116139
cy.visit('fixtures/service-worker.html')
117140
cy.get('#output').should('have.text', 'done')
118141
})
119142

120143
it('supports using onfetch', () => {
144+
const script = () => {
145+
self.onfetch = function (event) {
146+
return new Response('Network error', {
147+
status: 400,
148+
headers: { 'Content-Type': 'text/plain' },
149+
})
150+
}
151+
152+
self.onfetch = undefined
153+
154+
self.onfetch = function (event) {
155+
return
156+
}
157+
}
158+
121159
cy.intercept('/fixtures/service-worker.js', (req) => {
122-
req.reply(`
123-
self.onfetch = function (event) {
124-
event.respondWith(fetch(event.request))
125-
}
126-
self.onfetch = undefined
127-
128-
self.onfetch = function (event) {
129-
event.respondWith(fetch(event.request))
130-
}`,
131-
{ 'Content-Type': 'application/javascript' })
160+
req.reply(`(${script})()`,
161+
{ 'Content-Type': 'application/javascript' })
132162
})
133163

134164
cy.visit('fixtures/service-worker.html')
@@ -138,16 +168,19 @@ describe('service workers', () => {
138168

139169
describe('a service worker with multiple fetch handlers', () => {
140170
it('supports using addEventListener and onfetch', () => {
141-
cy.intercept('/fixtures/service-worker.js', (req) => {
142-
req.reply(`
143-
self.addEventListener('fetch', function (event) {
144-
event.respondWith(fetch(event.request))
145-
})
171+
const script = () => {
172+
self.addEventListener('fetch', function (event) {
173+
event.respondWith(fetch(event.request))
174+
})
146175

147-
self.onfetch = function (event) {
148-
event.respondWith(fetch(event.request))
149-
}`,
150-
{ 'Content-Type': 'application/javascript' })
176+
self.onfetch = function (event) {
177+
event.respondWith(fetch(event.request))
178+
}
179+
}
180+
181+
cy.intercept('/fixtures/service-worker.js', (req) => {
182+
req.reply(`(${script})()`,
183+
{ 'Content-Type': 'application/javascript' })
151184
})
152185

153186
cy.visit('fixtures/service-worker.html')

packages/proxy/lib/http/util/service-worker-rewriter.ts

+42-12
Original file line numberDiff line numberDiff line change
@@ -30,44 +30,74 @@ export const rewriteServiceWorker = (body: Buffer) => {
3030

3131
function __cypressOverwriteAddRemoveEventListener () {
3232
const _listeners = new WeakMap()
33+
const _capturedListeners = new WeakMap()
34+
const _handleEvents = new WeakMap()
35+
36+
const canWrapListener = (listener) => {
37+
return typeof listener === 'function' || listener?.handleEvent || typeof listener === 'object'
38+
}
3339

3440
const oldAddEventListener = self.addEventListener
3541

3642
// Overwrite the addEventListener method so we can
3743
// determine if the service worker handled the request
38-
self.addEventListener = (type, listener, ...args) => {
39-
if (type === 'fetch' && (typeof listener === 'function' || listener?.handleEvent)) {
44+
self.addEventListener = (type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions) => {
45+
if (type === 'fetch' && canWrapListener(listener)) {
4046
let newListener
4147

48+
// If the listener is a function, we can just wrap it
49+
// If the listener is an object with a handleEvent method, we can wrap that method
50+
// Otherwise, we need to wrap the listener in a proxy so we can track and wrap the handleEvent function
4251
if (typeof listener === 'function') {
4352
newListener = __cypressCreateListenerFunction(listener)
44-
} else {
53+
} else if (listener?.handleEvent) {
4554
newListener = __cypressCreateListenerFunction(listener.handleEvent)
4655
listener.handleEvent = newListener
56+
} else {
57+
newListener = new Proxy(listener, {
58+
get (target, key) {
59+
if (key === 'handleEvent') {
60+
if (!_handleEvents.has(target)) {
61+
_handleEvents.set(target, __cypressCreateListenerFunction(target.handleEvent))
62+
}
63+
64+
return _handleEvents.get(target)
65+
}
66+
67+
return Reflect.get(target, key)
68+
},
69+
})
4770
}
4871

49-
_listeners.set(listener, newListener)
72+
const capture = typeof options === 'boolean' ? options : options?.capture
5073

51-
return oldAddEventListener(type, newListener, ...args)
74+
capture ? _capturedListeners.set(listener, newListener) : _listeners.set(listener, newListener)
75+
76+
return oldAddEventListener(type, newListener, options)
5277
}
5378

54-
return oldAddEventListener(type, listener, ...args)
79+
return oldAddEventListener(type, listener, options)
5580
}
5681

5782
const oldRemoveEventListener = self.removeEventListener
5883

5984
// Overwrite the removeEventListener method so we can
6085
// remove the listener from the map
61-
self.removeEventListener = (type, listener, ...args) => {
62-
if (type === 'fetch' && (typeof listener === 'function' || listener?.handleEvent)) {
63-
const newListener = _listeners.get(listener)
86+
self.removeEventListener = (type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions) => {
87+
if (type === 'fetch' && canWrapListener(listener)) {
88+
const capture = typeof options === 'boolean' ? options : options?.capture
89+
const newListener = capture ? _capturedListeners.get(listener) : _listeners.get(listener)
90+
91+
capture ? _capturedListeners.delete(listener) : _listeners.delete(listener)
6492

65-
_listeners.delete(listener)
93+
if (typeof listener === 'object' && typeof listener.handleEvent === 'function') {
94+
_handleEvents.delete(listener)
95+
}
6696

67-
return oldRemoveEventListener(type, newListener, ...args)
97+
return oldRemoveEventListener(type, newListener, options)
6898
}
6999

70-
return oldRemoveEventListener(type, listener, ...args)
100+
return oldRemoveEventListener(type, listener, options)
71101
}
72102
}
73103

0 commit comments

Comments
 (0)