UNPKG

@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
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."); } }