Skip to content

Commit

Permalink
chore(tests): Add e2e tests for custom filters (#1964)
Browse files Browse the repository at this point in the history
  • Loading branch information
smalluban authored Oct 18, 2024
1 parent 239f5d8 commit c357a91
Show file tree
Hide file tree
Showing 16 changed files with 358 additions and 172 deletions.
23 changes: 17 additions & 6 deletions src/background/adblocker.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,20 @@ async function updateEngines() {

if (enabledEngines.length) {
let updated = false;

// Update engines from the list of enabled engines
for (const id of enabledEngines) {
if (id === engines.CUSTOM_ENGINE) continue;
updated = (await engines.update(id).catch(() => false)) || updated;
}
await Promise.all(
enabledEngines
.filter((id) => id !== engines.CUSTOM_ENGINE)
.map((id) =>
engines.update(id).then(
(v) => {
updated = updated || v;
},
() => {},
),
),
);

// Reload the main engine after all engines are updated
if (updated) await reloadMainEngine();
Expand Down Expand Up @@ -139,14 +148,16 @@ export const setup = asyncSetup([
}

if (options.filtersUpdatedAt < Date.now() - HOUR_IN_MS) {
updateEngines();
await updateEngines();
}
}),
observe('experimentalFilters', async (value, lastValue) => {
engines.setEnv('env_experimental', value);

// Experimental filters changed to enabled
if (lastValue !== undefined && value) updateEngines();
if (lastValue !== undefined && value) {
await updateEngines();
}
}),
]);

Expand Down
11 changes: 11 additions & 0 deletions src/background/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0
*/

import { idleOptionsObservers } from '/store/options.js';

chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
switch (msg.action) {
case 'getCurrentTab':
Expand All @@ -31,6 +33,15 @@ chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
case 'openPrivateWindowWithUrl':
chrome.windows.create({ url: msg.url, incognito: true });
break;
// This is used only by the e2e tests to detect idle state
case 'idleOptionsObservers': {
idleOptionsObservers.then(() => {
sendResponse('done');
console.info('[helpers] "idleOptionsObservers" response...');
});

return true;
}
}

return false;
Expand Down
28 changes: 19 additions & 9 deletions src/pages/settings/components/checkbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,36 @@

import { html } from 'hybrids';

function clickSlottedElement(host, event) {
const target = host.render().querySelector('slot').assignedElements()[0];
if (event.target !== target) {
target.click();
function clickInput(host, event) {
if (host.input && event.target !== host.input) {
event.stopPropagation();
host.input.click();
}
}

export default {
disabled: { value: false, reflect: true },
input: (host) => host.querySelector('input'),
checked: {
value: (host) => host.input?.checked ?? false,
connect: (host, key, invalidate) => {
host.input?.addEventListener('change', invalidate);
return () => {
host.input?.removeEventListener('change', invalidate);
};
},
},
render: () => html`
<template layout="contents">
<label layout="row gap:0.5 items:center" onclick="${clickSlottedElement}">
<template layout="column">
<div layout="row items:center" onclick="${clickInput}">
<slot></slot>
<ui-text type="body-s" color="gray-600">
<ui-text type="body-s" color="gray-600" layout="padding:left:0.5">
<slot name="label"></slot>
</ui-text>
</label>
</div>
</template>
`.css`
:host {
:host, ::slotted(*) {
cursor: pointer;
user-select: none;
}
Expand Down
7 changes: 5 additions & 2 deletions src/pages/settings/components/custom-filters.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export default {
oninput="${html.set(input, 'text')}"
disabled="${!store.ready(input) || disabled}"
defaultValue="${store.ready(input) ? input.text : ''}"
data-qa="textarea:custom-filters"
data-qa="input:custom-filters"
></textarea>
</settings-input>
Expand All @@ -62,7 +62,10 @@ export default {
</ui-button>
${result &&
html`
<div layout="column gap margin:top">
<div
layout="column gap margin:top"
data-qa="component:custom-filters:result"
>
<div layout="column gap:0.5">
<ui-text type="label-s" color="gray-600">
Custom filters has been updated
Expand Down
2 changes: 1 addition & 1 deletion src/pages/settings/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export default {
session: store(Session),
render: ({ stack, session }) => html`
<template layout="contents">
<settings-layout>
<settings-layout data-qa="page:settings">
<a
href="${router.url(Privacy)}"
class="${{ active: router.active(Privacy) }}"
Expand Down
7 changes: 5 additions & 2 deletions src/pages/settings/views/privacy.js
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ export default {
disabled="${globalPause ||
!options.regionalFilters.enabled}"
layout="grow"
data-qa="checkbox:regional-filters:${id}"
>
<input
type="checkbox"
Expand All @@ -220,7 +221,6 @@ export default {
id,
)}"
onchange="${setRegion(id)}"
data-qa="checkbox:regional-filters:${id}"
/>
<span slot="label">
${labels.languages.of(id.toUpperCase())} (${id})
Expand Down Expand Up @@ -335,7 +335,10 @@ export default {
html`
<div layout="column gap">
<div layout="self:start margin:bottom">
<settings-checkbox disabled="${globalPause}">
<settings-checkbox
disabled="${globalPause}"
data-qa="checkbox:custom-filters:trusted-scriptlets"
>
<input
type="checkbox"
disabled="${globalPause}"
Expand Down
18 changes: 12 additions & 6 deletions src/store/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ export const GLOBAL_PAUSE_ID = '<all_urls>';

const observers = new Set();

// The promise is resolved when all observers executed.
// This is used by the e2e tests to detect idle state.
export let idleOptionsObservers = Promise.resolve();

export const SYNC_OPTIONS = [
'blockAds',
'blockTrackers',
Expand Down Expand Up @@ -178,13 +182,15 @@ const Options = {
// Sync if the current memory context get options for the first time
if (!prevOptions) sync(options);

observers.forEach(async (fn) => {
try {
await fn(options, prevOptions);
} catch (e) {
console.error(`[options] Error while observing options: `, e);
idleOptionsObservers = (async () => {
for (const fn of observers) {
try {
await fn(options, prevOptions);
} catch (e) {
console.error(`[options] Error while observing options: `, e);
}
}
});
})();
},
},
};
Expand Down
2 changes: 1 addition & 1 deletion src/utils/engines.js
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ export async function update(name) {

const listURL = `https://${CDN_HOSTNAME}/adblocker/configs/${urlName}/allowed-lists.json`;

console.info(`[engines] Updating engine "${name}...`);
console.info(`[engines] Updating engine "${name}"...`);

const data = await fetch(listURL)
.then(check)
Expand Down
4 changes: 2 additions & 2 deletions tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ On Safari reloading the DNR rules may take up to a few minutes, so after pausing

On the test page, trackers are not blocked or modified, ads are visible.

### Global Pause 🤖
### Global Pause 🤖

> When Global Pause is enabled, the entire extension should turn off its blocking activity on all pages
Expand All @@ -143,7 +143,7 @@ On the test pages, trackers are not blocked or modified, ads are visible.

## Advanced features

### Custom Filters
### Custom Filters 🤖

> Check whether it is possible to add a simple custom filter
Expand Down
9 changes: 9 additions & 0 deletions tests/e2e/page.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,19 @@
<title>E2E Test Page</title>
</head>
<body>
<h1>Test Page</h1>
<!-- Ad-Blocking CSS container -->
<ad-slot style="display: block; height: 100px; background: red"></ad-slot>

<!-- Anti-tracking tracking requests -->
<script src="https://connect.facebook.net/en_US/fbevents.js"></script>
<script src="https://s.pinimg.com/ct/core.js"></script>

<!-- Custom Filters -->
<script src="https://www.exmaple.com/track.js"></script>
<div
id="custom-filter"
style="display: block; height: 100px; background: blue"
></div>
</body>
</html>
16 changes: 8 additions & 8 deletions tests/e2e/spec/_onboarding.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,32 +14,32 @@ import {
getExtensionElement,
getExtensionPageURL,
switchToPanel,
waitForIdleBackgroundTasks,
} from '../utils.js';

describe('Onboarding', function () {
beforeEach(async function () {
await browser.url(await getExtensionPageURL('onboarding'));
});

afterEach(async function () {
await browser.url('about:blank');
});

it('keeps ghostery disabled', async function () {
await browser.url(await getExtensionPageURL('onboarding'));
await getExtensionElement('button:skip').click();
await expect(getExtensionElement('view:skip')).toBeDisplayed();

await switchToPanel(async function () {
await expect(getExtensionElement('button:enable')).toBeDisplayed();
});

await browser.url('about:blank');
});

it('enables ghostery', async function () {
await browser.url(await getExtensionPageURL('onboarding'));
await getExtensionElement('button:enable').click();
await expect(getExtensionElement('view:success')).toBeDisplayed();

await switchToPanel(async function () {
await expect(getExtensionElement('button:enable')).not.toBeDisplayed();
await waitForIdleBackgroundTasks();
});

await browser.url('about:blank');
});
});
104 changes: 104 additions & 0 deletions tests/e2e/spec/advanced.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/**
* Ghostery Browser Extension
* https://www.ghostery.com/
*
* Copyright 2017-present Ghostery GmbH. All rights reserved.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0
*/
import { browser, expect, $ } from '@wdio/globals';
import {
enableExtension,
getExtensionElement,
setPrivacyToggle,
switchToPanel,
} from '../utils.js';

import { PAGE_DOMAIN, PAGE_URL } from '../wdio.conf.js';

async function setCustomFilters(filters) {
await setPrivacyToggle('custom-filters', true);

const checkbox = await getExtensionElement(
'checkbox:custom-filters:trusted-scriptlets',
);

if (!(await checkbox.getProperty('checked'))) {
await checkbox.click();
await expect(checkbox).toHaveElementProperty('checked', true);
}

const input = await getExtensionElement('input:custom-filters');
await input.setValue(filters.join('\n'));

await getExtensionElement('button:custom-filters:save').click();

await expect(
getExtensionElement('component:custom-filters:result'),
).toBeDisplayed();
}

describe('Advanced Features', function () {
before(enableExtension);

describe('Custom Filters', function () {
it('adds custom filters in settings page', async function () {
await setCustomFilters([
`@@connect.facebook.net^`,
`${PAGE_DOMAIN}###custom-filter`,
`${PAGE_DOMAIN}##+js(rpnt, h1, Test Page, "Hello world")`,
]);
});

it('adds custom network filter', async function () {
await browser.url(PAGE_URL);

await switchToPanel(async () => {
await getExtensionElement('button:detailed-view').click();

await expect(
getExtensionElement(`icon:tracker:facebook_connect:blocked`),
).not.toBeDisplayed();
await expect(
getExtensionElement(`icon:tracker:facebook_connect:modified`),
).not.toBeDisplayed();
});
});

it('adds custom cosmetic filter', async function () {
await browser.url(PAGE_URL);
await expect($('#custom-filter')).not.toBeDisplayed();
});

it('adds custom scriptlet filter', async function () {
await browser.url(PAGE_URL);
await expect($('h1')).toHaveText('Hello world');
});

it('disables custom filters', async function () {
// Switching off custom filters requires rebuilding main engine
// and it slows down the update of the DNR rules (it goes after the main engine)
await setPrivacyToggle('custom-filters', false, 5);

await browser.url(PAGE_URL);

await expect($('#custom-filter')).toBeDisplayed();
await expect($('h1')).toHaveText('Test Page');

await switchToPanel(async () => {
await getExtensionElement('button:detailed-view').click();

await expect(
getExtensionElement('icon:tracker:facebook_connect:blocked'),
).toBeDisplayed();
});
});

it('removes custom filters in settings page', async function () {
await setCustomFilters([]);
await setPrivacyToggle('custom-filters', false);
});
});
});
Loading

0 comments on commit c357a91

Please sign in to comment.