UNPKG

accessibility-checker

Version:

An automated testing tools for accessibility testing using Puppeteer, Selenium, or Zombie

391 lines (390 loc) 16.8 kB
import * as path from "path"; import * as fs from "fs"; import { ACConfigManager } from "./common/config/ACConfigManager.js"; import { fetch_get_text } from "./common/api-ext/Fetch.js"; import { writeFile } from "fs/promises"; // The following two lines will be modified by sed for cjs vs mjs environments. Look at package.json before modifying import { createRequire } from "module"; const require = createRequire(import.meta.url); let ace; let checker; export class ACEngineManager { static customRulesets = []; static engineContent = null; static async loadEngine(content) { let config = await ACConfigManager.getConfigUnsupported(); let ENGINE_LOAD_MODE = config.engineMode; if (ENGINE_LOAD_MODE === "DEFAULT") { // ENGINE_LOAD_MODE = "REMOTE"; ENGINE_LOAD_MODE = "INJECT"; } if (ENGINE_LOAD_MODE === "INJECT" && !ACEngineManager.engineContent) { ACEngineManager.engineContent = await fetch_get_text(`${config.rulePack}/ace.js`); } if (ACEngineManager.isPuppeteer(content) || ACEngineManager.isPlaywright(content)) { config.DEBUG && console.log("[INFO] aChecker.loadEngine detected Puppeteer/Playwright"); let page = content; if (ENGINE_LOAD_MODE === "REMOTE") { config.DEBUG && console.log("[INFO] engineMode REMOTE"); await page.evaluate((scriptUrl) => { try { var ace_backup_in_ibma; if ('undefined' !== typeof (ace)) { if (!ace || !ace.Checker) ace_backup_in_ibma = ace; ace = null; } if ('undefined' === typeof (ace) || ace === null) { return new Promise((resolve, reject) => { let script = document.createElement('script'); script.setAttribute('type', 'text/javascript'); script.setAttribute('aChecker', 'ACE'); script.setAttribute('src', scriptUrl); script.addEventListener('load', function () { globalThis.ace_ibma = ace; if ('undefined' !== typeof (ace)) { ace = ace_backup_in_ibma; } resolve(); }); script.addEventListener('error', function (evt) { reject(new Error(`Unable to load engine into ${document.location.href}. This can happen if the page server sets a Content-Security-Policy that prevents ${scriptUrl} from loading.`)); }); let heads = document.getElementsByTagName('head'); if (heads.length > 0) { heads[0].appendChild(script); } else if (document.body) { document.body.appendChild(script); } else { Promise.reject("Invalid document"); } }); } } catch (e) { return Promise.reject(e); } }, `${config.rulePack}/ace.js`); } else if (ENGINE_LOAD_MODE === "INJECT") { config.DEBUG && console.log("[INFO] engineMode INJECT"); let aceAlreadyExists = await page.evaluate(() => { try { return 'undefined' !== typeof (ace); } catch (e) { return false; } }); await page.evaluate(({ engineContent, aceAlreadyExists }) => { try { var ace_backup_in_ibma; if (aceAlreadyExists) { if (!ace || !ace.Checker) ace_backup_in_ibma = ace; ace = null; } if (!aceAlreadyExists || ace === null) { return new Promise((resolve, reject) => { eval(engineContent); globalThis.ace_ibma = ace; if (aceAlreadyExists) { ace = ace_backup_in_ibma; } resolve(); }); } } catch (e) { return Promise.reject(e); } }, { engineContent: ACEngineManager.engineContent, aceAlreadyExists }); } return ACEngineManager.loadEngineLocal(); } else if (ACEngineManager.isSelenium(content)) { config.DEBUG && console.log("[INFO] aChecker.loadEngine detected Selenium"); try { let browser = content; let scriptStr; if (ENGINE_LOAD_MODE === "REMOTE") { scriptStr = `let cb = arguments[arguments.length - 1]; try { var ace_backup_in_ibma; if ('undefined' !== typeof(ace)) { if (!ace || !ace.Checker) ace_backup_in_ibma = ace; ace = null; } if ('undefined' === typeof (ace) || ace === null) { let script = document.createElement('script'); script.setAttribute('type', 'text/javascript'); script.setAttribute('aChecker', 'ACE'); script.setAttribute('src', '${config.rulePack}/ace.js'); script.addEventListener('load', function() { globalThis.ace_ibma = ace; if ('undefined' !== typeof(ace)) { ace = ace_backup_in_ibma; } cb(); }); let heads = document.getElementsByTagName('head'); if (heads.length > 0) { heads[0].appendChild(script); } else { document.body.appendChild(script); } } else { cb(); } } catch (e) { cb(e); } `; } else if (ENGINE_LOAD_MODE === "INJECT") { // Selenium scriptStr = `let cb = arguments[arguments.length - 1]; try { var ace_backup_in_ibma; if ('undefined' !== typeof(ace)) { if (!ace || !ace.Checker) ace_backup_in_ibma = ace; ace = null; } if ('undefined' === typeof (ace) || ace === null) { eval(${JSON.stringify(ACEngineManager.engineContent)}) globalThis.ace_ibma = ace; if ('undefined' !== typeof ace) { ace = ace_backup_in_ibma; } cb(); } else { cb(); } } catch (e) { cb(e); } `; } let manage = browser.manage(); if (manage.timeouts) { manage.timeouts().setScriptTimeout(60000); } else if (manage.setTimeouts) { manage.setTimeouts({ "script": 60000 }); } return browser.executeAsyncScript(scriptStr).then(function (return_success) { return ACEngineManager.loadEngineLocal(); }).catch(function (err) { console.log(err); return Promise.reject(err); }); } catch (e) { console.log(e); return Promise.reject(e); } } else if (ACEngineManager.isWebDriverIO(content)) { config.DEBUG && console.log("[INFO] aChecker.loadEngine detected WebDriverIO"); let page = content; // ENGINE_LOAD_MODE = "REMOTE"; if (ENGINE_LOAD_MODE === "REMOTE") { await page.executeAsync((scriptUrl, done) => { try { var ace_backup_in_ibma; if ('undefined' !== typeof (ace)) { if (!ace || !ace.Checker) ace_backup_in_ibma = ace; ace = null; } if ('undefined' === typeof (ace) || ace === null) { new Promise((resolve, reject) => { let script = document.createElement('script'); script.setAttribute('type', 'text/javascript'); script.setAttribute('aChecker', 'ACE'); script.setAttribute('src', scriptUrl); script.addEventListener('load', function () { globalThis.ace_ibma = ace; if ('undefined' !== typeof (ace)) { ace = ace_backup_in_ibma; } resolve(); }); script.addEventListener('error', function (evt) { reject(new Error(`Unable to load engine into ${document.location.href}. This can happen if the page server sets a Content-Security-Policy that prevents ${scriptUrl} from loading.`)); }); let heads = document.getElementsByTagName('head'); if (heads.length > 0) { heads[0].appendChild(script); } else if (document.body) { document.body.appendChild(script); } else { Promise.reject("Invalid document"); } }).then(done); } } catch (e) { return Promise.reject(e); } }, `${config.rulePack}/ace.js`); } else if (ENGINE_LOAD_MODE === "INJECT") { await page.executeAsync((engineContent, done) => { try { var ace_backup_in_ibma; if ('undefined' !== typeof (ace)) { if (!ace || !ace.Checker) ace_backup_in_ibma = ace; ace = null; } if ('undefined' === typeof (ace) || ace === null) { return new Promise((resolve, reject) => { eval(engineContent); globalThis.ace_ibma = ace; if ('undefined' !== typeof (ace)) { ace = ace_backup_in_ibma; } resolve(); }).then(done); } } catch (e) { return Promise.reject(e); } }, ACEngineManager.engineContent); } return ACEngineManager.loadEngineLocal(); } else { config.DEBUG && console.log("[INFO] aChecker.loadEngine detected local"); if (globalThis.ace_ibma) { return Promise.resolve(); } else { return ACEngineManager.loadEngineLocal(); } } } static localLoadPromise = null; static async loadEngineLocal() { if (globalThis.ace_ibma) { return Promise.resolve(); } if (!ACEngineManager.localLoadPromise) { ACEngineManager.localLoadPromise = new Promise(async (resolve, reject) => { let config = await ACConfigManager.getConfigUnsupported(); const data = await fetch_get_text(`${config.rulePack}/ace-node.js`); let engineDir = path.join(path.resolve(config.cacheFolder), "engine"); if (!fs.existsSync(engineDir)) { fs.mkdirSync(engineDir, { recursive: true }); } let fileSuffix = ""; if (!config.toolVersion) { fileSuffix = config.ruleArchiveVersion; } else { fileSuffix = `${config.toolVersion}-${config.ruleArchiveVersion}`; } fileSuffix = fileSuffix.replace(/\./g, "_"); const nodePath = path.join(engineDir, `ace-node-${fileSuffix}`); if (fs.existsSync(`${nodePath}.js`)) { const ace_ibma = require(nodePath); checker = new ace_ibma.Checker(); return resolve(); } else { try { await writeFile(nodePath + ".js", data, { flush: true }); const ace_ibma = require(nodePath); checker = new ace_ibma.Checker(); resolve(); } catch (err) { console.log(err); reject(err); } } }); } return ACEngineManager.localLoadPromise; } static isPuppeteer(content) { if (content && content.constructor) { return !!content.constructor.toString().match(/Function: Page/) || content.constructor.toString().includes("Puppeteer"); } return false; } static isPlaywright(content) { if (content && content.constructor) { return !!content.constructor.toString().match(/class Page /); } return false; } static isSelenium(content) { if (content && content.constructor) { return content.constructor.toString().indexOf("Driver") !== -1 || // check required for selenium >= 3.0.1 (content.constructor.name && content.constructor.name.indexOf("Driver") !== -1); } return false; } static isWebDriverIO(content) { if (content && content.constructor) { return content.constructor.toString().indexOf("Browser") !== -1; } return false; } static addRuleset = (ruleset) => { ACEngineManager.customRulesets.push(ruleset); }; static getRuleset = async (rsId) => { if (!checker) { await ACEngineManager.loadEngineLocal(); } return ACEngineManager.customRulesets.concat(checker.getGuidelines()).filter((function (rs) { return rs.id === rsId; }))[0]; }; static getRulesets = async function () { if (!checker) { await ACEngineManager.loadEngineLocal(); } return ACEngineManager.customRulesets.concat(checker.getGuidelines()); }; static getChecker() { return checker; } static async loadChecker() { if (!checker) { await ACEngineManager.loadEngineLocal(); } return checker; } static getRules = async function () { if (!checker) { await ACEngineManager.loadEngineLocal(); } let retVal = []; for (const ruleId in checker.engine.ruleMap) { retVal.push(checker.engine.ruleMap[ruleId]); } return retVal; }; static getRulesSync = function () { if (!checker) return null; let retVal = []; for (const ruleId in checker.engine.ruleMap) { retVal.push(checker.engine.ruleMap[ruleId]); } return retVal; }; } //# sourceMappingURL=ACEngineManager.js.map