Skip to content

Commit 2f4ae9a

Browse files
committed
Updated tests
1 parent 93890ae commit 2f4ae9a

File tree

3 files changed

+135
-17
lines changed

3 files changed

+135
-17
lines changed

injected/integration-test/duckplayer-native.spec.js

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,25 @@ test.describe('Duck Player Native messaging', () => {
1313

1414
// Then Initial Setup should be called
1515
await duckPlayer.didSendInitialHandshake();
16+
17+
// And an onDuckPlayerScriptsReady event should be called
18+
await duckPlayer.didSendDuckPlayerScriptsReady();
19+
});
20+
21+
test('Responds to onUrlChanged', async ({ page }, workerInfo) => {
22+
const duckPlayer = DuckPlayerNative.create(page, workerInfo);
23+
24+
// Given the duckPlayerNative feature is enabled
25+
await duckPlayer.withRemoteConfig();
26+
27+
// When I go to a YouTube page
28+
await duckPlayer.gotoYouTubePage();
29+
30+
// And the frontend receives an onUrlChanged event
31+
await duckPlayer.sendURLChanged('NOCOOKIE');
32+
33+
// Then an onDuckPlayerScriptsReady event should be fired twice
34+
await duckPlayer.didSendDuckPlayerScriptsReady(2);
1635
});
1736

1837
test('Polls timestamp on YouTube', async ({ page }, workerInfo) => {
@@ -27,6 +46,19 @@ test.describe('Duck Player Native messaging', () => {
2746
// Then the current timestamp should be polled back to the browser
2847
await duckPlayer.didSendCurrentTimestamp();
2948
});
49+
50+
test('Polls timestamp on NoCookie page', async ({ page }, workerInfo) => {
51+
const duckPlayer = DuckPlayerNative.create(page, workerInfo);
52+
53+
// Given the duckPlayerNative feature is enabled
54+
await duckPlayer.withRemoteConfig();
55+
56+
// When I go to a NoCookie page
57+
await duckPlayer.gotoNoCookiePage();
58+
59+
// Then the current timestamp should be polled back to the browser
60+
await duckPlayer.didSendCurrentTimestamp();
61+
});
3062
});
3163

3264
test.describe('Duck Player Native thumbnail overlay', () => {
@@ -41,9 +73,31 @@ test.describe('Duck Player Native thumbnail overlay', () => {
4173
await duckPlayer.sendOnMediaControl();
4274

4375
// Then I should see the thumbnail overlay in the page
44-
await duckPlayer.didShowThumbnailOverlay();
76+
await duckPlayer.didShowOverlay();
4577
await duckPlayer.didShowLogoInOverlay();
4678
});
79+
test('Dismisses overlay on click', async ({ page }, workerInfo) => {
80+
const duckPlayer = DuckPlayerNative.create(page, workerInfo);
81+
82+
// Given the duckPlayerNative feature is enabled
83+
await duckPlayer.withRemoteConfig();
84+
85+
// When I go to a YouTube page
86+
await duckPlayer.gotoYouTubePage();
87+
await duckPlayer.sendOnMediaControl();
88+
89+
// And I see the thumbnail overlay in the page
90+
await duckPlayer.didShowOverlay();
91+
92+
// And I click on the overlay
93+
await duckPlayer.clickOnOverlay();
94+
95+
// Then the overlay should be dismissed
96+
await duckPlayer.didDismissOverlay();
97+
98+
// And a didDismissOverlay event should be fired
99+
await duckPlayer.didSendOverlayDismissalMessage();
100+
});
47101
});
48102

49103
test.describe('Duck Player Native custom error view', () => {

injected/integration-test/page-objects/duckplayer-native.js

Lines changed: 76 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,19 @@ import { perPlatform } from '../type-helpers.mjs';
44
import { ResultsCollector } from './results-collector.js';
55

66
/**
7-
* @import { PageType} from '../../src/features/duck-player-native.js'
7+
* @import { PageType } from '../../src/features/duckplayer-native/messages.js'
88
* @typedef {"default" | "incremental-dom" | "age-restricted-error" | "sign-in-error"} PlayerPageVariants
99
*/
1010

1111
// eslint-disable-next-line @typescript-eslint/no-unused-vars
1212
const configFiles = /** @type {const} */ (['native.json']);
1313

14+
const defaultInitialSetup = {
15+
locale: 'en',
16+
};
17+
18+
const featureName = 'duckPlayerNative';
19+
1420
export class DuckPlayerNative {
1521
/** @type {Partial<Record<PageType, string>>} */
1622
pages = {
@@ -29,9 +35,7 @@ export class DuckPlayerNative {
2935
this.platform = platform;
3036
this.collector = new ResultsCollector(page, build, platform);
3137
this.collector.withMockResponse({
32-
initialSetup: {
33-
locale: 'en',
34-
},
38+
initialSetup: defaultInitialSetup,
3539
onCurrentTimestamp: {},
3640
});
3741
this.collector.withUserPreferences({
@@ -79,7 +83,7 @@ export class DuckPlayerNative {
7983
* @param {string} [params.videoID]
8084
*/
8185
async gotoPage(pageType, params = {}) {
82-
await this.pageTypeIs(pageType);
86+
await this.withPageType(pageType);
8387

8488
const { variant = 'default', videoID = '123' } = params;
8589
const urlParams = new URLSearchParams([
@@ -107,14 +111,23 @@ export class DuckPlayerNative {
107111
* @param {PageType} pageType
108112
* @return {Promise<void>}
109113
*/
110-
async pageTypeIs(pageType) {
111-
const initialSetupResponse = {
112-
locale: 'en',
113-
pageType,
114-
};
114+
async withPageType(pageType) {
115+
const initialSetup = this.collector.mockResponses?.initialSetup || defaultInitialSetup;
115116

116117
await this.collector.updateMockResponse({
117-
initialSetup: initialSetupResponse,
118+
initialSetup: { pageType, ...initialSetup },
119+
});
120+
}
121+
122+
/**
123+
* @param {boolean} playbackPaused
124+
* @return {Promise<void>}
125+
*/
126+
async withPlaybackPaused(playbackPaused = true) {
127+
const initialSetup = this.collector.mockResponses.initialSetup || defaultInitialSetup;
128+
129+
await this.collector.updateMockResponse({
130+
initialSetup: { playbackPaused, ...initialSetup },
118131
});
119132
}
120133

@@ -123,7 +136,7 @@ export class DuckPlayerNative {
123136
* @param {Record<string, any>} payload
124137
*/
125138
async simulateSubscriptionMessage(name, payload) {
126-
await this.collector.simulateSubscriptionMessage('duckPlayerNative', name, payload);
139+
await this.collector.simulateSubscriptionMessage(featureName, name, payload);
127140
}
128141

129142
/**
@@ -176,6 +189,13 @@ export class DuckPlayerNative {
176189
await this.simulateSubscriptionMessage('onMuteAudio', options);
177190
}
178191

192+
/**
193+
* @param {PageType} pageType
194+
*/
195+
async sendURLChanged(pageType) {
196+
await this.simulateSubscriptionMessage('onUrlChanged', { pageType });
197+
}
198+
179199
/* Messaging assertions */
180200

181201
async didSendInitialHandshake() {
@@ -184,7 +204,7 @@ export class DuckPlayerNative {
184204
{
185205
payload: {
186206
context: this.collector.messagingContextName,
187-
featureName: 'duckPlayerNative',
207+
featureName,
188208
method: 'initialSetup',
189209
params: {},
190210
},
@@ -198,24 +218,46 @@ export class DuckPlayerNative {
198218
{
199219
payload: {
200220
context: this.collector.messagingContextName,
201-
featureName: 'duckPlayerNative',
221+
featureName,
202222
method: 'onCurrentTimestamp',
203-
params: { timestamp: 0 },
223+
params: { timestamp: "0" },
204224
},
205225
},
206226
]);
207227
}
208228

209229
/* Thumbnail Overlay assertions */
210230

211-
async didShowThumbnailOverlay() {
231+
async didShowOverlay() {
212232
await this.page.locator('ddg-video-thumbnail-overlay-mobile').waitFor({ state: 'visible', timeout: 1000 });
213233
}
214234

215235
async didShowLogoInOverlay() {
216236
await this.page.locator('ddg-video-thumbnail-overlay-mobile .logo').waitFor({ state: 'visible', timeout: 1000 });
217237
}
218238

239+
async clickOnOverlay() {
240+
await this.page.locator('ddg-video-thumbnail-overlay-mobile').click();
241+
}
242+
243+
async didDismissOverlay() {
244+
await this.page.locator('ddg-video-thumbnail-overlay-mobile').waitFor({ state: 'hidden', timeout: 1000 });
245+
}
246+
247+
async didSendOverlayDismissalMessage() {
248+
const messages = await this.collector.waitForMessage('didDismissOverlay');
249+
expect(messages).toMatchObject([
250+
{
251+
payload: {
252+
context: this.collector.messagingContextName,
253+
featureName,
254+
method: 'didDismissOverlay',
255+
params: {},
256+
},
257+
},
258+
]);
259+
}
260+
219261
/* Custom Error assertions */
220262

221263
async didShowGenericError() {
@@ -233,6 +275,24 @@ export class DuckPlayerNative {
233275
- paragraph: If this doesn’t work, you can still watch this video on YouTube, but without the added privacy of Duck Player.
234276
`);
235277
}
278+
279+
/**
280+
* @param {number} numberOfCalls - Number of times the message should be received
281+
*/
282+
async didSendDuckPlayerScriptsReady(numberOfCalls = 1) {
283+
const expectedMessage = {
284+
payload: {
285+
context: this.collector.messagingContextName,
286+
featureName,
287+
method: 'onDuckPlayerScriptsReady',
288+
params: {},
289+
},
290+
};
291+
const expectedMessages = Array(numberOfCalls).fill(expectedMessage);
292+
const actualMessages = await this.collector.waitForMessage('onDuckPlayerScriptsReady');
293+
294+
expect(actualMessages).toMatchObject(expectedMessages);
295+
}
236296
}
237297

238298
/**

injected/integration-test/page-objects/results-collector.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,10 @@ export class ResultsCollector {
244244
return this.build.name === 'apple-isolated' ? 'contentScopeScriptsIsolated' : 'contentScopeScripts';
245245
}
246246

247+
get mockResponses() {
248+
return this.#mockResponses;
249+
}
250+
247251
/**
248252
* @param {string} featureName
249253
* @return {import("@duckduckgo/messaging").MessagingContext}

0 commit comments

Comments
 (0)