@@ -6,194 +6,18 @@ describe('lib/http/util/service-worker-injector', () => {
6
6
it ( 'injects into the service worker' , ( ) => {
7
7
const actual = injectIntoServiceWorker ( Buffer . from ( 'foo' ) )
8
8
9
- const expected = `
9
+ // this regex is used to verify the actual output,
10
+ // it verifies the service worker has the injected __cypressInjectIntoServiceWorker
11
+ // function followed by the contents of the user's service worker (in this case 'foo'),
12
+ // it does not verify the contents of __cypressInjectIntoServiceWorker function
13
+ // as it is subject to change and is not relevant to the test
14
+ const expected = new RegExp ( `
10
15
let __cypressIsScriptEvaluated = false;
11
- (function __cypressInjectIntoServiceWorker() {
12
- let listenerCount = 0;
13
- let eventQueue = [];
14
- const nonCaptureListenersMap = new WeakMap();
15
- const captureListenersMap = new WeakMap();
16
- const targetToWrappedHandleEventMap = new WeakMap();
17
- const targetToOrigHandleEventMap = new WeakMap();
18
- const sendEvent = (event) => {
19
- // if the binding has been created, we can call it
20
- // otherwise, we need to queue the event
21
- if (self.__cypressServiceWorkerClientEvent) {
22
- self.__cypressServiceWorkerClientEvent(JSON.stringify(event));
23
- }
24
- else {
25
- eventQueue.push(event);
26
- }
27
- };
28
- const sendHasFetchEventHandlers = () => {
29
- // @ts-expect-error __cypressIsScriptEvaluated is declared below
30
- // if the script has been evaluated, we can call the CDP binding to inform the backend whether or not the service worker has a handler
31
- if (__cypressIsScriptEvaluated) {
32
- sendEvent({ type: 'hasFetchHandler', payload: { hasFetchHandler: !!(listenerCount > 0 || self.onfetch) } });
33
- }
34
- };
35
- const sendFetchRequest = (payload) => {
36
- // call the CDP binding to inform the backend whether or not the service worker handled the request
37
- sendEvent({ type: 'fetchRequest', payload });
38
- };
39
- // A listener is considered valid if it is a function or an object (with the handleEvent function or the function could be added later)
40
- const isValidListener = (listener) => {
41
- return listener && (typeof listener === 'function' || typeof listener === 'object');
42
- };
43
- // Determine if the event listener was aborted
44
- const isAborted = (options) => {
45
- var _a;
46
- return typeof options === 'object' && ((_a = options.signal) === null || _a === void 0 ? void 0 : _a.aborted);
47
- };
48
- // Get the capture value from the options
49
- const getCaptureValue = (options) => {
50
- return typeof options === 'boolean' ? options : options === null || options === void 0 ? void 0 : options.capture;
51
- };
52
- function wrapListener(listener) {
53
- return (event) => {
54
- // we want to override the respondWith method so we can track if it was called
55
- // to determine if the service worker handled the request
56
- const oldRespondWith = event.respondWith;
57
- let respondWithCalled = false;
58
- event.respondWith = (...args) => {
59
- respondWithCalled = true;
60
- oldRespondWith.call(event, ...args);
61
- };
62
- let returnValue;
63
- try {
64
- // call the original listener
65
- returnValue = listener.call(self, event);
66
- }
67
- catch (_a) {
68
- // if the listener throws an error, we still want to proceed with calling the binding
69
- }
70
- if (returnValue instanceof Promise) {
71
- // if the listener returns a promise, we need to wait for it to resolve
72
- // before we can determine if the service worker handled the request
73
- returnValue.then(() => {
74
- sendFetchRequest({ url: event.request.url, isControlled: respondWithCalled });
75
- });
76
- }
77
- else {
78
- sendFetchRequest({ url: event.request.url, isControlled: respondWithCalled });
79
- }
80
- return returnValue;
81
- };
82
- }
83
- const oldAddEventListener = self.addEventListener;
84
- // Overwrite the addEventListener method so we can determine if the service worker handled the request
85
- // https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
86
- self.addEventListener = (type, listener, options) => {
87
- if (type === 'fetch' && isValidListener(listener) && !isAborted(options)) {
88
- const capture = getCaptureValue(options);
89
- const existingListener = capture ? captureListenersMap.get(listener) : nonCaptureListenersMap.get(listener);
90
- // If the listener is already in the map, we don't need to wrap it again
91
- if (existingListener) {
92
- return oldAddEventListener(type, existingListener, options);
93
- }
94
- let newListener;
95
- // If the listener is a function, we can just wrap it
96
- // Otherwise, we need to wrap the listener in a proxy so we can track and wrap the handleEvent function
97
- if (typeof listener === 'function') {
98
- newListener = wrapListener(listener);
99
- }
100
- else {
101
- // since the handleEvent function could change, we need to use a proxy to wrap it
102
- newListener = new Proxy(listener, {
103
- get(target, key) {
104
- if (key === 'handleEvent') {
105
- const wrappedHandleEvent = targetToWrappedHandleEventMap.get(target);
106
- const origHandleEvent = targetToOrigHandleEventMap.get(target);
107
- // If the handleEvent function has not been wrapped yet, or if it has changed, we need to wrap it
108
- if ((!wrappedHandleEvent && target.handleEvent) || target.handleEvent !== origHandleEvent) {
109
- targetToWrappedHandleEventMap.set(target, wrapListener(target.handleEvent));
110
- targetToOrigHandleEventMap.set(target, target.handleEvent);
111
- }
112
- return targetToWrappedHandleEventMap.get(target);
113
- }
114
- return Reflect.get(target, key);
115
- },
116
- });
117
- }
118
- // call the original addEventListener function prior to doing any additional work since it may fail
119
- const result = oldAddEventListener(type, newListener, options);
120
- // get the capture value so we know which map to add the listener to
121
- // so we can then remove the listener later if requested
122
- getCaptureValue(options) ? captureListenersMap.set(listener, newListener) : nonCaptureListenersMap.set(listener, newListener);
123
- listenerCount++;
124
- sendHasFetchEventHandlers();
125
- return result;
126
- }
127
- return oldAddEventListener(type, listener, options);
128
- };
129
- const oldRemoveEventListener = self.removeEventListener;
130
- // Overwrite the removeEventListener method so we can remove the listener from the map
131
- // https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener
132
- self.removeEventListener = (type, listener, options) => {
133
- if (type === 'fetch' && isValidListener(listener)) {
134
- // get the capture value so we know which map to remove the listener from
135
- const capture = getCaptureValue(options);
136
- const newListener = capture ? captureListenersMap.get(listener) : nonCaptureListenersMap.get(listener);
137
- // call the original removeEventListener function prior to doing any additional work since it may fail
138
- const result = oldRemoveEventListener(type, newListener, options);
139
- capture ? captureListenersMap.delete(listener) : nonCaptureListenersMap.delete(listener);
140
- listenerCount--;
141
- // If the listener is an object with a handleEvent method, we need to remove the wrapped function
142
- if (typeof listener === 'object' && typeof listener.handleEvent === 'function') {
143
- targetToWrappedHandleEventMap.delete(listener);
144
- targetToOrigHandleEventMap.delete(listener);
145
- }
146
- sendHasFetchEventHandlers();
147
- return result;
148
- }
149
- return oldRemoveEventListener(type, listener, options);
150
- };
151
- const originalPropertyDescriptor = Object.getOwnPropertyDescriptor(self, 'onfetch');
152
- if (!originalPropertyDescriptor) {
153
- return;
154
- }
155
- // Overwrite the onfetch property so we can
156
- // determine if the service worker handled the request
157
- Object.defineProperty(self, 'onfetch', {
158
- configurable: originalPropertyDescriptor.configurable,
159
- enumerable: originalPropertyDescriptor.enumerable,
160
- get() {
161
- var _a;
162
- return (_a = originalPropertyDescriptor.get) === null || _a === void 0 ? void 0 : _a.call(this);
163
- },
164
- set(value) {
165
- var _a;
166
- let newHandler;
167
- if (value) {
168
- newHandler = wrapListener(value);
169
- }
170
- (_a = originalPropertyDescriptor.set) === null || _a === void 0 ? void 0 : _a.call(this, newHandler);
171
- sendHasFetchEventHandlers();
172
- },
173
- });
174
- // listen for the activate event so we can inform the
175
- // backend whether or not the service worker has a handler
176
- self.addEventListener('activate', () => {
177
- sendHasFetchEventHandlers();
178
- // if the binding has not been created yet, we need to wait for it
179
- if (!self.__cypressServiceWorkerClientEvent) {
180
- const timer = setInterval(() => {
181
- if (self.__cypressServiceWorkerClientEvent) {
182
- clearInterval(timer);
183
- // send any events that were queued
184
- eventQueue.forEach((event) => {
185
- self.__cypressServiceWorkerClientEvent(JSON.stringify(event));
186
- });
187
- eventQueue = [];
188
- }
189
- }, 5);
190
- }
191
- });
192
- })();
16
+ \\(function __cypressInjectIntoServiceWorker\\(\\) \\{.*\\}\\)\\(\\);
193
17
foo;
194
- __cypressIsScriptEvaluated = true;`
18
+ __cypressIsScriptEvaluated = true;` . replace ( / \s / g , '' ) )
195
19
196
- expect ( actual . replace ( / \s / g, '' ) ) . to . equal ( expected . replace ( / \s / g , '' ) )
20
+ expect ( actual . replace ( / \s / g, '' ) ) . to . match ( expected )
197
21
} )
198
22
} )
199
23
} )
0 commit comments