Skip to content

Commit

Permalink
enable messageBridge on Android + tests (#1395)
Browse files Browse the repository at this point in the history
* enable messageBridge on Android + tests

* fixed tests

* fixing duckplayer special-pages tests

* privacy config
  • Loading branch information
shakyShane authored Jan 28, 2025
1 parent 2145e03 commit 8e76460
Show file tree
Hide file tree
Showing 8 changed files with 113 additions and 5 deletions.
84 changes: 84 additions & 0 deletions injected/integration-test/message-bridge-android.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { test, expect } from '@playwright/test';
import { ResultsCollector } from './page-objects/results-collector.js';
import { readOutgoingMessages } from '@duckduckgo/messaging/lib/test-utils.mjs';

const ENABLED_CONFIG = 'integration-test/test-pages/message-bridge/config/message-bridge-enabled.json';
const DISABLED_CONFIG = 'integration-test/test-pages/message-bridge/config/message-bridge-disabled.json';
const ENABLED_HTML = '/message-bridge/pages/enabled.html';
const DISABLED_HTML = '/message-bridge/pages/disabled.html';

test('message bridge when enabled (android)', async ({ page }, testInfo) => {
const pageWorld = ResultsCollector.create(page, testInfo.project.use);

// seed the request->re
pageWorld.withMockResponse({
sampleData: /** @type {any} */ ({
ghi: 'jkl',
}),
});

pageWorld.withUserPreferences({
messageSecret: 'ABC',
javascriptInterface: 'javascriptInterface',
messageCallback: 'messageCallback',
});

// now load the page
await pageWorld.load(ENABLED_HTML, ENABLED_CONFIG);

// simulate a push event
await pageWorld.simulateSubscriptionMessage('exampleFeature', 'onUpdate', { abc: 'def' });

// get all results
const results = await pageWorld.results();
expect(results['Creating the bridge']).toStrictEqual([
{ name: 'bridge.notify', result: 'function', expected: 'function' },
{ name: 'bridge.request', result: 'function', expected: 'function' },
{ name: 'bridge.subscribe', result: 'function', expected: 'function' },
{ name: 'data', result: [{ abc: 'def' }, { ghi: 'jkl' }], expected: [{ abc: 'def' }, { ghi: 'jkl' }] },
]);

// verify messaging calls
const calls = await page.evaluate(readOutgoingMessages);
expect(calls.length).toBe(2);
const pixel = calls[0].payload;
const request = calls[1].payload;

expect(pixel).toStrictEqual({
context: 'contentScopeScripts',
featureName: 'exampleFeature',
method: 'pixel',
params: {},
});

const { id, ...rest } = /** @type {import("@duckduckgo/messaging").RequestMessage} */ (request);

expect(rest).toStrictEqual({
context: 'contentScopeScripts',
featureName: 'exampleFeature',
method: 'sampleData',
params: {},
});

if (!('id' in request)) throw new Error('unreachable');

expect(typeof request.id).toBe('string');
expect(request.id.length).toBeGreaterThan(10);
});

test('message bridge when disabled (android)', async ({ page }, testInfo) => {
const pageWorld = ResultsCollector.create(page, testInfo.project.use);

// now load the main page
await pageWorld.load(DISABLED_HTML, DISABLED_CONFIG);

// verify no outgoing calls were made
const calls = await page.evaluate(readOutgoingMessages);
expect(calls).toHaveLength(0);

// get all results
const results = await pageWorld.results();
expect(results['Creating the bridge, but it is unavailable']).toStrictEqual([
{ name: 'error', result: 'Did not install Message Bridge', expected: 'Did not install Message Bridge' },
]);
});
5 changes: 5 additions & 0 deletions injected/integration-test/page-objects/duckplayer-overlays.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ export class DuckplayerOverlays {
},
sendDuckPlayerPixel: {},
});
this.collector.withUserPreferences({
messageSecret: 'ABC',
javascriptInterface: 'javascriptInterface',
messageCallback: 'messageCallback',
});
page.on('console', (msg) => {
console.log(msg.type(), msg.text());
});
Expand Down
3 changes: 3 additions & 0 deletions injected/integration-test/page-objects/results-collector.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ export class ResultsCollector {
messagingContext: this.messagingContext('n/a'),
responses: this.#mockResponses,
messageCallback: 'messageCallback',
javascriptInterface: this.#userPreferences.javascriptInterface,
});

const wrapFn = this.build.switch({
Expand Down Expand Up @@ -234,6 +235,8 @@ export class ResultsCollector {
name,
payload,
injectName: this.build.name,
messageCallback: this.#userPreferences.messageCallback,
messageSecret: this.#userPreferences.messageSecret,
});
}

Expand Down
6 changes: 5 additions & 1 deletion injected/playwright.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,11 @@ export default defineConfig({
},
{
name: 'android',
testMatch: ['integration-test/duckplayer-mobile.spec.js', 'integration-test/web-compat-android.spec.js'],
testMatch: [
'integration-test/duckplayer-mobile.spec.js',
'integration-test/web-compat-android.spec.js',
'integration-test/message-bridge-android.spec.js',
],
use: { injectName: 'android', platform: 'android', ...devices['Galaxy S5'] },
},
{
Expand Down
2 changes: 1 addition & 1 deletion injected/src/features.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const otherFeatures = /** @type {const} */ ([
export const platformSupport = {
apple: ['webCompat', ...baseFeatures],
'apple-isolated': ['duckPlayer', 'brokerProtection', 'performanceMetrics', 'clickToLoad', 'messageBridge'],
android: [...baseFeatures, 'webCompat', 'breakageReporting', 'duckPlayer'],
android: [...baseFeatures, 'webCompat', 'breakageReporting', 'duckPlayer', 'messageBridge'],
'android-autofill-password-import': ['autofillPasswordImport'],
windows: ['cookie', ...baseFeatures, 'windowsPermissionUsage', 'duckPlayer', 'brokerProtection', 'breakageReporting'],
firefox: ['cookie', ...baseFeatures, 'clickToLoad'],
Expand Down
15 changes: 13 additions & 2 deletions messaging/lib/test-utils.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ export function mockWebkitMessaging(params) {
* messagingContext: import('../index.js').MessagingContext,
* responses: Record<string, any>,
* messageCallback: string
* javascriptInterface?: string
* }} params
*/
export function mockAndroidMessaging(params) {
Expand All @@ -284,7 +285,8 @@ export function mockAndroidMessaging(params) {
outgoing: [],
},
};
window[params.messagingContext.context] = {
if (!params.javascriptInterface) throw new Error('`javascriptInterface` is required for Android mocking');
window[params.javascriptInterface] = {
/**
* @param {string} jsonString
* @param {string} secret
Expand Down Expand Up @@ -322,7 +324,7 @@ export function mockAndroidMessaging(params) {
id: msg.id,
};

globalThis.messageCallback?.(secret, r);
globalThis[params.messageCallback]?.(secret, r);
},
};
}
Expand Down Expand Up @@ -406,6 +408,8 @@ export function wrapWebkitScripts(js, replacements) {
* @param {string} params.name
* @param {Record<string, any>} params.payload
* @param {NonNullable<ImportMeta['injectName']>} params.injectName
* @param {string} [params.messageCallback] - optional name of a global method where messages can be delivered (android)
* @param {string} [params.messageSecret] - optional message secret for platforms that require it (android)
*/
export function simulateSubscriptionMessage(params) {
const subscriptionEvent = {
Expand All @@ -421,6 +425,13 @@ export function simulateSubscriptionMessage(params) {
fn(subscriptionEvent);
break;
}
case 'android': {
if (!params.messageCallback || !params.messageSecret)
throw new Error('`messageCallback` + `messageSecret` needed to simulate subscription event on Android');

window[params.messageCallback]?.(params.messageSecret, subscriptionEvent);
break;
}
case 'apple':
case 'apple-isolated': {
if (!(params.name in window)) throw new Error('subscription fn not found for: ' + params.injectName);
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions special-pages/shared/mocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export class Mocks {
messagingContext: this.messagingContext,
responses: this._defaultResponses,
messageCallback: 'messageCallback',
javascriptInterface: this.messagingContext.context,
});
},
integration: async () => {
Expand Down

0 comments on commit 8e76460

Please sign in to comment.