Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions injected/entry-points/integration.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ function generateConfig() {
'cookie',
'webCompat',
'apiManipulation',
'duckPlayer',
],
},
};
Expand Down
192 changes: 192 additions & 0 deletions injected/integration-test/duckplayer-mobile-drawer.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
import { expect, test } from '@playwright/test';
import { DuckplayerOverlays } from './page-objects/duckplayer-overlays.js';

test.describe('Duck Player - Drawer UI variant', () => {
test.describe('Video Player overlays', () => {
test("Selecting 'watch here' on mobile", async ({ page }, workerInfo) => {
const overlays = DuckplayerOverlays.create(page, workerInfo);
await overlays.reducedMotion();

// Given drawer overlay variant is set
await overlays.withRemoteConfig({ json: 'overlays-drawer.json' });

// And my setting is 'always ask'
await overlays.userSettingIs('always ask');
await overlays.gotoPlayerPage();

// watch here = overlays removed
await overlays.mobile.choosesWatchHere();
await overlays.mobile.overlayIsRemoved();
await overlays.pixels.sendsPixels([
{ pixelName: 'overlay', params: {} },
{ pixelName: 'play.do_not_use', params: { remember: '0' } },
]);
});
test("Selecting 'watch here' on mobile + remember", async ({ page }, workerInfo) => {
const overlays = DuckplayerOverlays.create(page, workerInfo);
await overlays.reducedMotion();

// Given drawer overlay variant is set
await overlays.withRemoteConfig({ json: 'overlays-drawer.json' });

// And my setting is 'always ask'
await overlays.userSettingIs('always ask');
await overlays.gotoPlayerPage();

// watch here = overlays removed
await overlays.mobile.selectsRemember();
await overlays.mobile.choosesWatchHere();
await overlays.mobile.overlayIsRemoved();
await overlays.pixels.sendsPixels([
{ pixelName: 'overlay', params: {} },
{ pixelName: 'play.do_not_use', params: { remember: '1' } },
]);
await overlays.userSettingWasUpdatedTo('disabled');
});
test("Selecting 'watch in duckplayer' on mobile", async ({ page }, workerInfo) => {
const overlays = DuckplayerOverlays.create(page, workerInfo);
await overlays.reducedMotion();

// Given drawer overlay variant is set
await overlays.withRemoteConfig({ json: 'overlays-drawer.json' });

// And my setting is 'always ask'
await overlays.userSettingIs('always ask');
await overlays.gotoPlayerPage();

await overlays.mobile.choosesDuckPlayer();
await overlays.pixels.sendsPixels([
{ pixelName: 'overlay', params: {} },
{ pixelName: 'play.use', params: { remember: '0' } },
]);
await overlays.userSettingWasUpdatedTo('always ask');
});
test("Selecting 'watch in duckplayer' on mobile + remember", async ({ page }, workerInfo) => {
const overlays = DuckplayerOverlays.create(page, workerInfo);
await overlays.reducedMotion();

// Given drawer overlay variant is set
await overlays.withRemoteConfig({ json: 'overlays-drawer.json' });

// And my setting is 'always ask'
await overlays.userSettingIs('always ask');
await overlays.gotoPlayerPage();

await overlays.mobile.selectsRemember();
await overlays.mobile.choosesDuckPlayer();
await overlays.pixels.sendsPixels([
{ pixelName: 'overlay', params: {} },
{ pixelName: 'play.use', params: { remember: '1' } },
]);
await overlays.userSettingWasUpdatedTo('enabled');
});
test('Clicking on video thumbnail dismisses overlay', async ({ page }, workerInfo) => {
const overlays = DuckplayerOverlays.create(page, workerInfo);
await overlays.reducedMotion();

// Given drawer overlay variant is set
await overlays.withRemoteConfig({ json: 'overlays-drawer.json' });

// And my setting is 'always ask'
await overlays.userSettingIs('always ask');
await overlays.gotoPlayerPage();

await overlays.mobile.clicksOnVideoThumbnail();
await overlays.pixels.sendsPixels([
{ pixelName: 'overlay', params: {} },
{ pixelName: 'play.do_not_use.thumbnail', params: {} },
]);
await overlays.userSettingWasNotUpdated();
});
test('Clicking on drawer backdrop dismisses overlay', async ({ page }, workerInfo) => {
const overlays = DuckplayerOverlays.create(page, workerInfo);
await overlays.reducedMotion();

// Given drawer overlay variant is set
await overlays.withRemoteConfig({ json: 'overlays-drawer.json' });

// And my setting is 'always ask'
await overlays.userSettingIs('always ask');
await overlays.gotoPlayerPage();

await overlays.mobile.clicksOnDrawerBackdrop();
await overlays.pixels.sendsPixels([
{ pixelName: 'overlay', params: {} },
{ pixelName: 'play.do_not_use', params: {} },
]);
await overlays.userSettingWasNotUpdated();
});
test('opens info', async ({ page }, workerInfo) => {
const overlays = DuckplayerOverlays.create(page, workerInfo);
await overlays.reducedMotion();

// Given drawer overlay variant is set
await overlays.withRemoteConfig({ json: 'overlays-drawer.json' });

// And my setting is 'always ask'
await overlays.userSettingIs('always ask');
await overlays.gotoPlayerPage();
await overlays.mobile.opensInfo();
});
});

/**
* Use this test in `--headed` mode to cycle through every language
*/
test.describe.skip('Translated Overlays', () => {
const items = [
'bg',
'cs',
'da',
'de',
'el',
'en',
'es',
'et',
'fi',
'fr',
'hr',
'hu',
'it',
'lt',
'lv',
'nb',
'nl',
'pl',
'pt',
'ro',
'ru',
'sk',
'sl',
'sv',
'tr',
];
// const items = ['en']
for (const locale of items) {
test(`testing UI ${locale}`, async ({ page }, workerInfo) => {
// console.log(workerInfo.project.use.viewport.height)
// console.log(workerInfo.project.use.viewport.width)
const overlays = DuckplayerOverlays.create(page, workerInfo);
await overlays.withRemoteConfig({ json: 'overlays-drawer.json', locale });
await overlays.userSettingIs('always ask');
await overlays.gotoPlayerPage();
await page.locator('ddg-video-drawer-mobile').nth(0).waitFor();
await page.locator('.html5-video-player').screenshot({ path: `screens/se-2/${locale}.png` });
});
}
});

/**
* Use `npm run playwright-screenshots` to run this test only.
*/
test.describe('Overlay screenshot @screenshots', () => {
test("testing Overlay UI 'en'", async ({ page }, workerInfo) => {
const overlays = DuckplayerOverlays.create(page, workerInfo);
await overlays.withRemoteConfig({ json: 'overlays-drawer.json', locale: 'en' });
await overlays.userSettingIs('always ask');
await overlays.gotoPlayerPage();
await page.locator('ddg-video-drawer-mobile').nth(0).waitFor();
await expect(page.locator('ddg-video-drawer-mobile')).toHaveScreenshot('drawer.png', { maxDiffPixels: 20 });
});
});
});
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 26 additions & 0 deletions injected/integration-test/page-objects/duckplayer-overlays.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
const configFiles = /** @type {const} */ ([
'overlays.json',
'overlays-live.json',
'overlays-drawer.json',
'disabled.json',
'thumbnail-overlays-disabled.json',
'click-interceptions-disabled.json',
Expand Down Expand Up @@ -90,6 +91,10 @@
});
}

async reducedMotion() {
await this.page.emulateMedia({ reducedMotion: 'reduce' });
}

/**
* @param {object} params
* @param {'default' | 'cookie_banner'} [params.variant]
Expand Down Expand Up @@ -472,6 +477,17 @@
]);
}

/**
* @return {Promise<void>}
*/
async userSettingWasNotUpdated() {
const messages = await this.collector.outgoingMessages();
// @ts-expect-error - Subscription is missing method property
const setUserValuesMessages = messages.filter((message) => message.payload?.method === 'setUserValues');

expect(setUserValuesMessages.length).toBe(0);
}

/**
* Helper for creating an instance per platform
* @param {import("@playwright/test").Page} page
Expand Down Expand Up @@ -528,7 +544,7 @@

async choosesWatchHere() {
const { page } = this.overlays;
await page.getByRole('button', { name: 'No Thanks' }).click();

Check failure on line 547 in injected/integration-test/page-objects/duckplayer-overlays.js

View workflow job for this annotation

GitHub Actions / integration

[ios] › integration-test/duckplayer-mobile-drawer.spec.js:6:9 › Duck Player - Drawer UI variant › Video Player overlays › Selecting 'watch here' on mobile

1) [ios] › integration-test/duckplayer-mobile-drawer.spec.js:6:9 › Duck Player - Drawer UI variant › Video Player overlays › Selecting 'watch here' on mobile TimeoutError: locator.click: Timeout 1000ms exceeded. Call log: - waiting for getByRole('button', { name: 'No Thanks' }) - locator resolved to <button type="button" class="button cancel ddg-vpo-cancel">No Thanks</button> - attempting click action - waiting for element to be visible, enabled and stable at integration-test/page-objects/duckplayer-overlays.js:547 545 | async choosesWatchHere() { 546 | const { page } = this.overlays; > 547 | await page.getByRole('button', { name: 'No Thanks' }).click(); | ^ 548 | } 549 | 550 | async choosesDuckPlayer() { at DuckplayerOverlaysMobile.choosesWatchHere (/home/runner/work/content-scope-scripts/content-scope-scripts/injected/integration-test/page-objects/duckplayer-overlays.js:547:63) at /home/runner/work/content-scope-scripts/content-scope-scripts/injected/integration-test/duckplayer-mobile-drawer.spec.js:18:35
}

async choosesDuckPlayer() {
Expand All @@ -536,6 +552,16 @@
await page.getByRole('link', { name: 'Turn On Duck Player' }).click();
}

async clicksOnVideoThumbnail() {
const { page } = this.overlays;
await page.locator('ddg-video-thumbnail-overlay-mobile .bg').click({ force: true });
}

async clicksOnDrawerBackdrop() {
const { page } = this.overlays;
await page.locator('ddg-video-drawer-mobile .ddg-mobile-drawer-background').click({ position: { x: 10, y: 10 } });
}

async selectsRemember() {
const { page } = this.overlays;
await page.getByRole('switch').click();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
{
"unprotectedTemporary": [],
"features": {
"duckPlayer": {
"state": "enabled",
"exceptions": [],
"settings": {
"overlays": {
"youtube": {
"state": "disabled",
"selectors": {
"thumbLink": "a[href^='/watch']",
"excludedRegions": [
"#playlist",
"ytd-movie-renderer",
"ytd-grid-movie-renderer"
],
"videoElement": "#player video",
"videoElementContainer": "#player .html5-video-player",
"hoverExcluded": [".an-overlay-causing-breakage"],
"clickExcluded": [".an-overlay-causing-breakage"],
"allowedEventTargets": [],
"drawerContainer": "body"
},
"thumbnailOverlays": {
"state": "enabled"
},
"clickInterception": {
"state": "enabled"
},
"videoOverlays": {
"state": "enabled"
},
"videoDrawer": {
"state": "enabled"
}
},
"serpProxy": {
"state": "disabled"
}
},
"domains": [
{
"domain": "localhost",
"patchSettings": [
{
"op": "replace",
"path": "/overlays/youtube/state",
"value": "enabled"
},
{
"op": "replace",
"path": "/overlays/serpProxy/state",
"value": "enabled"
}
]
}
]
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -154,13 +154,23 @@
</template>
<script>
(async () => {
settingsFiles = {
default: '/duckplayer/config/overlays.json',
drawer: '/duckplayer/config/overlays-drawer.json',
}

if (!new URLSearchParams(location.search).has('preview')) {
return;
}
const platformName = new URLSearchParams(window.location.search).get('platform') || 'macos';
const locale = new URLSearchParams(window.location.search).get('locale') || 'en';
const settingsId = new URLSearchParams(window.location.search).get('config') || 'default';

await import("/build/contentScope.js").catch(console.error)
const overlays = await fetch('/duckplayer/config/overlays.json').then(x => x.json())

const settingsFile = settingsFiles[settingsId] || settingsFiles.default;
const overlays = await fetch(settingsFile).then(x => x.json())

document.dispatchEvent(new CustomEvent('content-scope-init-args', {
detail: {
debug: true,
Expand Down
3 changes: 2 additions & 1 deletion injected/playwright.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,14 @@ export default defineConfig({
},
{
name: 'ios',
testMatch: ['integration-test/duckplayer-mobile.spec.js'],
testMatch: ['integration-test/duckplayer-mobile.spec.js', 'integration-test/duckplayer-mobile-drawer.spec.js'],
use: { injectName: 'apple-isolated', platform: 'ios', ...devices['iPhone 13'] },
},
{
name: 'android',
testMatch: [
'integration-test/duckplayer-mobile.spec.js',
'integration-test/duckplayer-mobile-drawer.spec.js',
'integration-test/web-compat-android.spec.js',
'integration-test/message-bridge-android.spec.js',
],
Expand Down
10 changes: 10 additions & 0 deletions injected/src/features/duckplayer/assets/info-solid.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading