Skip to content

Commit

Permalink
messaging: windows special pages (#1216)
Browse files Browse the repository at this point in the history
* messaging: support `windowsInteropPostMessage` for special pages

* fixed tests

---------

Co-authored-by: Shane Osbourne <[email protected]>
  • Loading branch information
shakyShane and Shane Osbourne authored Nov 21, 2024
1 parent 2a88cb0 commit e891989
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 4 deletions.
3 changes: 3 additions & 0 deletions messaging/lib/messaging.types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ interface UnstableMockCall {

interface Window {
webkit: UnstableWebkit;
windowsInteropPostMessage: Window['postMessage'];
windowsInteropAddEventListener: Window['addEventListener'];
windowsInteropRemoveEventListener: Window['removeEventListener'];
__playwright_01: {
mockResponses: Record<string, import('../index.js').MessageResponse>;
subscriptionEvents: import('../index.js').SubscriptionEvent[];
Expand Down
96 changes: 96 additions & 0 deletions messaging/lib/test-utils.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,102 @@ export function mockWindowsMessaging(params) {
* messageCallback: string,
* }} params
*/
export function mockWindowsInteropMessaging(params) {
if (!window.__playwright_01) {
window.__playwright_01 = {
mockResponses: params.responses,
subscriptionEvents: [],
mocks: {
outgoing: [],
},
};
}
const listeners = [];
/**
* @param {AnyWindowsMessage} input
*/
window.windowsInteropPostMessage = (input) => {
// subscription events come through here also
if ('subscriptionName' in input) {
setTimeout(() => {
for (const listener of listeners) {
listener({ origin: window.origin, data: input });
}
}, 0);
return;
}
/** @type {NotificationMessage | RequestMessage} */
let msg = {
context: input.Feature,
featureName: input.SubFeatureName,
params: input.Data,
method: input.Name,
id: undefined,
};

// add the Id if it was a RequestMessage
if ('Id' in input) {
msg = {
...msg,
id: input.Id,
};
}

// record the call
window.__playwright_01.mocks.outgoing.push(
JSON.parse(
JSON.stringify({
payload: msg,
}),
),
);

// if there's no 'id' field, we don't need to respond
if (!('id' in msg)) return;

// If we get here, it needed a response **and** we have a value for it
setTimeout(() => {
// if the mocked response is absent, bail with an error
if (!(msg.method in window.__playwright_01.mockResponses)) {
throw new Error('response not found for ' + msg.method);
}

// now access the response
const response = window.__playwright_01.mockResponses[msg.method];

for (const listener of listeners) {
listener({
origin: window.origin,
/** @type {Omit<MessageResponse, 'error'>} */
data: {
result: response,
context: msg.context,
featureName: msg.featureName,
id: msg.id,
},
});
}
}, 0);
};
window.windowsInteropRemoveEventListener = (_name, _listener) => {
const index = listeners.indexOf(_listener);
if (index > -1) {
listeners.splice(index, 1);
}
};
window.windowsInteropAddEventListener = (_name, listener) => {
listeners.push(listener);
};
}

/**
* Install a mock interface for windows messaging
* @param {{
* messagingContext: import('../index.js').MessagingContext,
* responses: Record<string, any>,
* messageCallback: string,
* }} params
*/
export function mockWebkitMessaging(params) {
if (!window.__playwright_01) {
window.__playwright_01 = {
Expand Down
6 changes: 3 additions & 3 deletions special-pages/shared/create-special-page-messaging.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ export function createSpecialPageMessaging(opts) {
const opts = new WindowsMessagingConfig({
methods: {
// @ts-expect-error - not in @types/chrome
postMessage: window.chrome.webview.postMessage,
postMessage: globalThis.windowsInteropPostMessage,
// @ts-expect-error - not in @types/chrome
addEventListener: window.chrome.webview.addEventListener,
addEventListener: globalThis.windowsInteropAddEventListener,
// @ts-expect-error - not in @types/chrome
removeEventListener: window.chrome.webview.removeEventListener,
removeEventListener: globalThis.windowsInteropRemoveEventListener,
},
});
return new Messaging(messageContext, opts);
Expand Down
3 changes: 2 additions & 1 deletion special-pages/tests/page-objects/mocks.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
mockAndroidMessaging,
mockWebkitMessaging,
mockWindowsInteropMessaging,
mockWindowsMessaging,
readOutgoingMessages,
simulateSubscriptionMessage,
Expand Down Expand Up @@ -40,7 +41,7 @@ export class Mocks {
async installMessagingMocks() {
await this.build.switch({
windows: async () => {
await this.page.addInitScript(mockWindowsMessaging, {
await this.page.addInitScript(mockWindowsInteropMessaging, {
messagingContext: this.messagingContext,
responses: this._defaultResponses,
messageCallback: 'messageCallback',
Expand Down

0 comments on commit e891989

Please sign in to comment.