@cliqz/autoconsent
Version:
This is a library of rules for navigating through common consent popups on the web. These rules can be run in a Firefox webextension, or in a puppeteer orchestrated headless browser. Using these rules, opt-in and opt-out options can be selected automatica
123 lines (122 loc) • 4.13 kB
JavaScript
import { waitFor } from '../cmps/base';
import Tools from '../web/consentomatic/tools';
import { matches } from '../web/consentomatic/index';
const DEBUG = false;
export default class Tab {
constructor(page, url, frames) {
// puppeteer doesn't have tab IDs
this.id = 1;
this.page = page;
this.url = url;
this.frames = frames;
}
async elementExists(selector, frameId = 0) {
try {
const elements = await this.frames[frameId].$$(selector);
DEBUG && console.log('[exists]', selector, elements.length > 0);
return elements.length > 0;
}
catch (e) {
console.warn(e);
return false;
}
}
async clickElement(selector, frameId = 0) {
if (await this.elementExists(selector, frameId)) {
try {
const result = await this.frames[frameId].evaluate((s) => {
try {
document.querySelector(s).click();
return true;
}
catch (e) {
return e.toString();
}
}, selector);
DEBUG && console.log('[click]', selector, result);
return result;
}
catch (e) {
console.warn(e);
return false;
}
}
return false;
}
async clickElements(selector, frameId = 0) {
const elements = await this.frames[frameId].$$(selector);
try {
DEBUG && console.log('[click all]', selector);
await this.frames[frameId].evaluate((s) => {
const elem = document.querySelectorAll(s);
elem.forEach(e => e.click());
}, selector);
return true;
}
catch (e) {
console.warn(e);
return false;
}
}
async elementsAreVisible(selector, check, frameId = 0) {
if (!await this.elementExists(selector, frameId)) {
return false;
}
const visible = await this.frames[frameId].$$eval(selector, (nodes) => nodes.map((n) => n.offsetParent !== null || window.getComputedStyle(n).display !== "none"));
DEBUG && console.log('[visible]', selector, check, visible);
if (visible.length === 0) {
return false;
}
else if (check === 'any') {
return visible.some(r => r);
}
else if (check === 'none') {
return visible.every(r => !r);
}
return visible.every(r => r);
}
async getAttribute(selector, attribute, frameId = 0) {
const elem = await this.frames[frameId].$(selector);
if (elem) {
return (await elem.getProperty(attribute)).jsonValue();
}
}
async eval(script, frameId = 0) {
DEBUG && console.log('[eval]', script);
return await this.frames[frameId].evaluate(script);
}
async waitForElement(selector, timeout, frameId = 0) {
const interval = 200;
const times = Math.ceil(timeout / interval);
return waitFor(() => this.elementExists(selector, frameId), times, interval);
}
async waitForThenClick(selector, timeout, frameId = 0) {
await this.waitForElement(selector, timeout, frameId);
await this.clickElement(selector, frameId);
return true;
}
async hideElements(selectors, frameId = 0) {
// TODO implement this
return Promise.resolve(true);
}
async goto(url) {
return this.page.goto(url);
}
wait(ms) {
return new Promise((resolve) => {
setTimeout(() => resolve(true), ms);
});
}
matches(options) {
const script = `(() => {
const Tools = ${Tools.toString()};
const matches = ${matches.toString()};
return matches(${JSON.stringify(options)})
})();
`;
return this.frames[0].evaluate(script);
}
executeAction(config, param) {
throw new Error("Method not implemented.");
}
}