Skip to content

Commit e891989

Browse files
shakyShaneShane Osbourne
andauthored
messaging: windows special pages (#1216)
* messaging: support `windowsInteropPostMessage` for special pages * fixed tests --------- Co-authored-by: Shane Osbourne <[email protected]>
1 parent 2a88cb0 commit e891989

File tree

4 files changed

+104
-4
lines changed

4 files changed

+104
-4
lines changed

messaging/lib/messaging.types.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ interface UnstableMockCall {
1414

1515
interface Window {
1616
webkit: UnstableWebkit;
17+
windowsInteropPostMessage: Window['postMessage'];
18+
windowsInteropAddEventListener: Window['addEventListener'];
19+
windowsInteropRemoveEventListener: Window['removeEventListener'];
1720
__playwright_01: {
1821
mockResponses: Record<string, import('../index.js').MessageResponse>;
1922
subscriptionEvents: import('../index.js').SubscriptionEvent[];

messaging/lib/test-utils.mjs

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,102 @@ export function mockWindowsMessaging(params) {
117117
* messageCallback: string,
118118
* }} params
119119
*/
120+
export function mockWindowsInteropMessaging(params) {
121+
if (!window.__playwright_01) {
122+
window.__playwright_01 = {
123+
mockResponses: params.responses,
124+
subscriptionEvents: [],
125+
mocks: {
126+
outgoing: [],
127+
},
128+
};
129+
}
130+
const listeners = [];
131+
/**
132+
* @param {AnyWindowsMessage} input
133+
*/
134+
window.windowsInteropPostMessage = (input) => {
135+
// subscription events come through here also
136+
if ('subscriptionName' in input) {
137+
setTimeout(() => {
138+
for (const listener of listeners) {
139+
listener({ origin: window.origin, data: input });
140+
}
141+
}, 0);
142+
return;
143+
}
144+
/** @type {NotificationMessage | RequestMessage} */
145+
let msg = {
146+
context: input.Feature,
147+
featureName: input.SubFeatureName,
148+
params: input.Data,
149+
method: input.Name,
150+
id: undefined,
151+
};
152+
153+
// add the Id if it was a RequestMessage
154+
if ('Id' in input) {
155+
msg = {
156+
...msg,
157+
id: input.Id,
158+
};
159+
}
160+
161+
// record the call
162+
window.__playwright_01.mocks.outgoing.push(
163+
JSON.parse(
164+
JSON.stringify({
165+
payload: msg,
166+
}),
167+
),
168+
);
169+
170+
// if there's no 'id' field, we don't need to respond
171+
if (!('id' in msg)) return;
172+
173+
// If we get here, it needed a response **and** we have a value for it
174+
setTimeout(() => {
175+
// if the mocked response is absent, bail with an error
176+
if (!(msg.method in window.__playwright_01.mockResponses)) {
177+
throw new Error('response not found for ' + msg.method);
178+
}
179+
180+
// now access the response
181+
const response = window.__playwright_01.mockResponses[msg.method];
182+
183+
for (const listener of listeners) {
184+
listener({
185+
origin: window.origin,
186+
/** @type {Omit<MessageResponse, 'error'>} */
187+
data: {
188+
result: response,
189+
context: msg.context,
190+
featureName: msg.featureName,
191+
id: msg.id,
192+
},
193+
});
194+
}
195+
}, 0);
196+
};
197+
window.windowsInteropRemoveEventListener = (_name, _listener) => {
198+
const index = listeners.indexOf(_listener);
199+
if (index > -1) {
200+
listeners.splice(index, 1);
201+
}
202+
};
203+
window.windowsInteropAddEventListener = (_name, listener) => {
204+
listeners.push(listener);
205+
};
206+
}
207+
208+
/**
209+
* Install a mock interface for windows messaging
210+
* @param {{
211+
* messagingContext: import('../index.js').MessagingContext,
212+
* responses: Record<string, any>,
213+
* messageCallback: string,
214+
* }} params
215+
*/
120216
export function mockWebkitMessaging(params) {
121217
if (!window.__playwright_01) {
122218
window.__playwright_01 = {

special-pages/shared/create-special-page-messaging.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@ export function createSpecialPageMessaging(opts) {
2626
const opts = new WindowsMessagingConfig({
2727
methods: {
2828
// @ts-expect-error - not in @types/chrome
29-
postMessage: window.chrome.webview.postMessage,
29+
postMessage: globalThis.windowsInteropPostMessage,
3030
// @ts-expect-error - not in @types/chrome
31-
addEventListener: window.chrome.webview.addEventListener,
31+
addEventListener: globalThis.windowsInteropAddEventListener,
3232
// @ts-expect-error - not in @types/chrome
33-
removeEventListener: window.chrome.webview.removeEventListener,
33+
removeEventListener: globalThis.windowsInteropRemoveEventListener,
3434
},
3535
});
3636
return new Messaging(messageContext, opts);

special-pages/tests/page-objects/mocks.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {
22
mockAndroidMessaging,
33
mockWebkitMessaging,
4+
mockWindowsInteropMessaging,
45
mockWindowsMessaging,
56
readOutgoingMessages,
67
simulateSubscriptionMessage,
@@ -40,7 +41,7 @@ export class Mocks {
4041
async installMessagingMocks() {
4142
await this.build.switch({
4243
windows: async () => {
43-
await this.page.addInitScript(mockWindowsMessaging, {
44+
await this.page.addInitScript(mockWindowsInteropMessaging, {
4445
messagingContext: this.messagingContext,
4546
responses: this._defaultResponses,
4647
messageCallback: 'messageCallback',

0 commit comments

Comments
 (0)