diff --git a/src/js/background/actions.js b/src/js/background/actions.js
index fb4496e..1ba918f 100644
--- a/src/js/background/actions.js
+++ b/src/js/background/actions.js
@@ -18,13 +18,14 @@
*/
const readyFunctions = require("./bg_function");
+const {setBadgeText} = require("./utils");
async function playProject() {
if(cba.allowPlay == 0 ) {
return;
}
else if(cba.instructArray.length) {
- browser.browserAction.setBadgeText({"text":"play"});
+ setBadgeText("play");
const [instruction] = cba.instructArray.splice(0, 1);
cba.playingActionIndex = (cba.defInstructArray.length - cba.instructArray.length) - 1;
@@ -45,7 +46,7 @@ async function playProject() {
cba.playingActionIndex = -1;
cba.playingProjectId = null;
cba.allowPlay = 0;
- browser.browserAction.setBadgeText({"text": ""});
+ setBadgeText("");
}
}
@@ -90,7 +91,7 @@ async function actionExecution(instruction)
}
case "pause": {
cba.pause();
- browser.browserAction.setBadgeText({"text":"||"});
+ setBadgeText("||");
break;
}
default: {
diff --git a/src/js/background/main.js b/src/js/background/main.js
index 0a5c00a..8db7a33 100644
--- a/src/js/background/main.js
+++ b/src/js/background/main.js
@@ -21,12 +21,15 @@
/** @global */
globalThis.browser = require("webextension-polyfill");
-require("../analytics");
+if (!process.env.MV3) {
+ require("../analytics");
+}
const {CBA} = require("./CBA");
const {playProject} = require("./actions");
const projectsDb = require("../db/projects");
const customActionsDb = require("../db/customActions");
const {addRpcListener, sendRpcMessageResponse} = require("../rpc/host");
+const {setBadgeText} = require("./utils");
/** @global */
globalThis.cba = new CBA();
@@ -128,7 +131,7 @@ async function storeCurrentUrl() {
async function recordButtonClick(groupId, projectId) {
cba.record(groupId, projectId);
await storeCurrentUrl();
- browser.browserAction.setBadgeText({"text": "rec"});
+ setBadgeText("rec");
}
/*
@@ -136,7 +139,7 @@ async function recordButtonClick(groupId, projectId) {
*/
function stopButtonClick() {
cba.stop();
- browser.browserAction.setBadgeText({"text": ""});
+ setBadgeText("");
}
/*
diff --git a/src/js/background/utils.js b/src/js/background/utils.js
new file mode 100644
index 0000000..0875ad1
--- /dev/null
+++ b/src/js/background/utils.js
@@ -0,0 +1,25 @@
+/*
+ * This file is part of Chromium Browser Automation.
+ * Copyright (C) 2020-present Manvel Saroyan
+ *
+ * Chromium Browser Automation is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chromium Browser Automation is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chromium Browser Automation. If not, see
+ * .
+ */
+
+export function setBadgeText(text) {
+ if (process.env.MV3) {
+ return browser.action.setBadgeText({text});
+ }
+ return browser.browserAction.setBadgeText({text});
+}
\ No newline at end of file
diff --git a/src/js/options.js b/src/js/options.js
index 7fa1aa9..f3176a0 100644
--- a/src/js/options.js
+++ b/src/js/options.js
@@ -24,7 +24,7 @@ require("./ui/tabs");
async function setVersion()
{
- const {version} = await browser.app.getDetails();
+ const {version} = await browser.runtime.getManifest();
document.querySelector("#version").textContent = `v. ${version}`;
}
diff --git a/tests/config.js b/tests/config.js
index 2882a75..e1ce8fd 100644
--- a/tests/config.js
+++ b/tests/config.js
@@ -18,7 +18,6 @@
*/
const tests = [
- {file:"play.js", name: "Testing actions"},
{file:"record.js", name: "Testing recording"},
{file:"generic.js", name: "Running generic Tests"},
{file:"popup.js", name: "Testing popup"},
@@ -27,6 +26,11 @@ const tests = [
{file:"functions.js", name: "Testing functions tab in options page"},
];
+if (!process.env.MV3) {
+ //TODO: Fix this test for MV3.
+ tests.push({file:"play.js", name: "Testing actions"});
+}
+
const server = "http://127.0.0.1:3001";
const closeBrowser = true;
diff --git a/tests/main.js b/tests/main.js
index 273c2c2..851f090 100644
--- a/tests/main.js
+++ b/tests/main.js
@@ -21,9 +21,11 @@ const puppeteer = require("puppeteer");
const extensionPath = "dist";
const {tests, server, closeBrowser} = require("./config");
+/** @type {import("puppeteer").Browser} */
let browser;
/** @type {import("puppeteer").Page} */
let page;
+/** @type {import("puppeteer").Page | import("puppeteer").WebWorker}*/
let backgroundPage;
function run()
@@ -41,12 +43,7 @@ function run()
"--no-sandbox"
]});
page = await browser.newPage();
- const targets = await browser.targets();
- const backgroundPageTarget = targets.find((target) =>
- target.url().startsWith("chrome-extension://") && target.type() === "background_page"
- );
-
- backgroundPage = await backgroundPageTarget.page();
+ backgroundPage = await waitForBackgroundPage();
const [,, extensionID] = backgroundPage.url().split('/');
await page.setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3419.0 Safari/537.36");
@@ -66,6 +63,59 @@ function run()
}
}
+/**
+ * Retries function until it returns truthy value or timeout is reached.
+ * @template T
+ * @param {function(any): T} fn - Function to execute.
+ * @param {number} timeout - Timeout in milliseconds.
+ * @param {number} interval - Interval in milliseconds.
+ * @returns {Promise}
+ */
+function retryUntilTruthy(fn, timeout = 5000, interval = 100)
+{
+ return new Promise((resolve, reject) => {
+ const startTime = Date.now();
+ const intervalId = setInterval(async () => {
+ let res;
+ try {
+ res = await fn();
+ }
+ catch (e) {
+ res = false;
+ }
+ if (res)
+ {
+ clearInterval(intervalId);
+ resolve(res);
+ }
+ else if (Date.now() - startTime > timeout)
+ {
+ clearInterval(intervalId);
+ reject(Error("Timeout"));
+ }
+ }, interval);
+ });
+}
+
+/**
+ * Waits for background page to load.
+ */
+async function waitForBackgroundPage()
+{
+ return retryUntilTruthy(async() => {
+ const targets = await browser.targets();
+ const backgroundPageTarget = targets.find((target) => {
+ return target.url().startsWith("chrome-extension://") && target.type() === "background_page" || target.type() === "service_worker"
+ }
+ );
+ const bgPage = await backgroundPageTarget.page() || await backgroundPageTarget.worker();
+ if (!bgPage) {
+ throw new Error("Background page not found");
+ }
+ return bgPage;
+ })
+}
+
async function navigateTo(path)
{
return page.goto(path);
diff --git a/tests/tests/popup.js b/tests/tests/popup.js
index f27b902..934afce 100644
--- a/tests/tests/popup.js
+++ b/tests/tests/popup.js
@@ -502,7 +502,7 @@ it("Actions are being updated while playing", async() =>
await updateSpecificAction("cba-table-id-4", "", "timer", "200");
await clickPlay();
- await wait(100);
+ await wait(110);
equal((await getSelectedRow(cbaTableQuery)).id, "cba-table-id-2");
await wait(100);
@@ -528,7 +528,7 @@ it("When paused play button becomes 'resume', when clicked resumes playback", as
await clickPlay();
- await wait(100);
+ await wait(110);
equal((await getSelectedRow(cbaTableQuery)).id, "cba-table-id-2");
await wait(100);
diff --git a/tests/tests/utils.js b/tests/tests/utils.js
index 8dd80fd..d989ed0 100644
--- a/tests/tests/utils.js
+++ b/tests/tests/utils.js
@@ -25,7 +25,7 @@ const crypto = require("crypto");
async function getExtensionVersion()
{
- const details = await backgroundPage().evaluate(() => browser.app.getDetails());
+ const details = await backgroundPage().evaluate(() => browser.runtime.getManifest());
return details.version;
}
@@ -491,12 +491,12 @@ async function getActiveElementId()
async function getBackgroundGlobalVar(name)
{
- return backgroundPage().evaluate((name) => window[name] , name);
+ return backgroundPage().evaluate((name) => globalThis[name] , name);
}
async function resetBackgroundGlobalVar(name)
{
- return backgroundPage().evaluate((name) => delete window[name] , name);
+ return backgroundPage().evaluate((name) => delete globalThis[name] , name);
}
async function resetClipboardValue()
@@ -523,11 +523,19 @@ async function resetCbaObject()
async function getBadgeText()
{
- return backgroundPage().evaluate(() => {
- return new Promise((response) => {
- chrome.browserAction.getBadgeText({}, response);
- })
- });
+ if (process.env.MV3) {
+ return backgroundPage().evaluate(() => {
+ return new Promise((response) => {
+ chrome.action.getBadgeText({}, response);
+ })
+ });
+ } else {
+ return backgroundPage().evaluate(() => {
+ return new Promise((response) => {
+ chrome.browserAction.getBadgeText({}, response);
+ })
+ });
+ }
}
// Usage: await setListeners("#id", ["mousedown", "click"], (e) => {});
@@ -575,6 +583,11 @@ async function wait(milliseconds = 200)
return page().waitForTimeout(milliseconds);
}
+async function sleep(milliseconds = 200)
+{
+ return new Promise((resolve) => setTimeout(resolve, milliseconds));
+}
+
async function getPageUrl()
{
return page().url();
@@ -589,18 +602,17 @@ async function focusAndType(query, text)
async function sendCurrentTabRequest(request)
{
return backgroundPage().evaluate((request) => {
- return new Promise((resp) =>
+ return new Promise(async (resp) =>
{
- chrome.tabs.getSelected(null , async (tab) => {
- await browser.tabs.sendMessage(tab.id, request);
- resp();
- });
+ const [tab] = await browser.tabs.query({active: true, currentWindow: true});
+ await browser.tabs.sendMessage(tab.id, request);
+ resp();
});
}, request);
}
module.exports = {playTestProject, getBackgroundGlobalVar,
- resetBackgroundGlobalVar, wait, startTestRecording,
+ resetBackgroundGlobalVar, wait, sleep, startTestRecording,
stopTestRecording, getTestProjectActions, getProjectActions,
getTextContent, getInnerHTML, getValue, setValue, changeValue,
isDisabled, isChecked, addCookie, getCookie,