dragAndDrop in selenium javascript - selenium-chromedriver

dragAndDrop()
How to do dragAndDrop in selenium with javascript?
element drag and drop sorting

I hope this works for you.
let actions = driver.actions({async: true, bridge:true});
await driver.findElements(By.css('.box2'))
.then(async(firstBoxes) => {
for (firstBox of firstBoxes) {
await actions.move({async: true, origin:firstBox}).press().perform();
await driver.findElements(By.css('.box1'))
.then(async(boxes) => {
for (secbox of boxes) {
await actions.dragAndDrop(firstBox, secbox).release().perform();
}
});
}
});

Related

Chrome Extension embedding script in active web page, in MV3?

beautiful people on the internet. I am new to chrome extension not new to writing code though. I have implemented webpack to use external packages. One major one in my application is npm package by the name "mark.js".
My application works like this i want some specific words to be highlighted in active webpage using this package. I have written code for this to achieve the functionality but the problem is with loading the script in a web page. I have performed different aspect of loading script but that doesnot work. The new MV3 version have some strict rules.
I want to achieve anything similar of loading script in an active webpage. Please help.
btn.addEventListener("click", async () => {
console.log("BUTTON IS PRESSED!!");
try {
await chrome.tabs.query(
{ active: true, currentWindow: true },
async function (tabs) {
chrome.scripting.executeScript({
target: { tabId: tabs[0].id },
func: highlightText,
args: [arr],
});
}
);
} catch (e) {
console.log("ERROR AT CHROME TAB QUERY : ", e);
}
});
async function highlightText(arr) {
console.log(typeof Mark);
try {
var instance2 = new Mark(document.querySelector("body"));
// instance2.mark("is");
var success = [];
// const instance2 = new Mark(document.querySelector("body"));
await Promise.all(
arr.map(async function (obj) {
console.log("OBJECT TEXT : ", obj.text);
instance2.mark(obj.text, {
element: "span",
each: function (ele) {
console.log("STYLING : ");
ele.setAttribute("style", `background-color: ${obj.color};`);
if (obj.title && obj.title != "") {
ele.setAttribute("title", obj.title);
}
ele.innerHTML = obj.text;
success.push({
status: "Success",
text: obj.text,
});
},
});
})
);
console.log("SUCCESS : ", success);
} catch (error) {
console.log(error);
}
}
There's no need to use chrome.runtime.getURL. Since you use executeScript to run your code all you need is to inject mark.js before injecting the function.
Also, don't load popup.js in content_scripts, it's not a content script (these run in web pages), it's a script for your extension page. Actually, you don't need content_scripts at all.
btn.addEventListener('click', async () => {
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
const target = { tabId: tab.id };
const exec = v => (await chrome.scripting.executeScript({ target, ...v }))[0].result;
if (!await exec({ func: () => !!window.Mark })) {
await exec({files: ['mark.js.min'] });
await exec({func: highlightText, args: [arr] });
}
});
For V3 I assume you will want to use Content Scripts in your manifest to inject the javascript into every webpage it matches. I recently open-sourced TorpedoRead and had to do both V2 and V3, I recommend checking the repo as it sounds like I did something similar to you (Firefox is V2, Chrome is V3).
The code below need to be added to your manifest.json and this will execute on every page based on the matches property. You can read more about content scripts here: https://developer.chrome.com/docs/extensions/mv3/content_scripts/
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["yourscript.js"]
}
],

How to encapsulate 'Role' functionality into page model to log in only once

Currently we are using testcafe to implement our test cases, and we'd like to encapsulate some page models for reusing purpose. In testcafe there is a 'Role' functionality that we want to leverage in our 'log_in' function so that we could log in only once in each test suite. The page model code is like below:
app.js
async _login(url, userName, password) {
const userRole = Role(url, async (t) => {
await t
.typeText(this.user, userName)
.typeText(this.password, password)
.click(this.signIn)
.expect(this.home.exists)
.ok("The file icon should exist after logging on");
}, { preserveUrl: true });
await t.useRole(userRole);
}
async login1stApp() {
await this._login(config.firstUrl, config.user, config.password)
}
async login2ndApp() {
await this._login(config.secondUrl, config.user, config.password,
)
}
And in the test code, we will simply reference this page model and execute login function in beforeEach hook:
test.js
fixture`check ui`.beforeEach(async (t) => {
await app.login1stApp();
});
test(`test a`, async (t) => {
...
});
test(`test b`, async (t) => {
....
});
It seems that the 'Role' does not take effect. Instead of logging in only once, testcafe will log in for each test case every time.
Is there any solution to make the 'Role' work based on current implementation? Thanks!
You need to rewrite your page model class so that the t.useRole(role) method call is placed in the beforeEach hook.
So, the fixed page model implementation will look as follows:
import { Role, t } from 'testcafe';
class App {
constructor() {
this._login1AppRole = Role('https://example.com', async (t) => {
await t.wait(1000);
}, { preserveUrl: true });
}
async login1stApp() {
await t.useRole(this._login1AppRole);
}
}
export default new App();

Chrome extensions: How to keep badge text from flickering when navigating?

Here's a GIF demo, using a test extension.
I'm using this test extension to test out chrome.browserAction.setBadgeText(). I've noticed that when navigating, the badge text is flickering. All I am doing is clicking any hyperlinks on a webpage, so there's no page refreshing, nor navigating Back.
Is there a way to keep it from flickering? If not, is there a way to keep it persistent for as long as possible?
Code in question:
var SetBadge = function () {
chrome.windows.getCurrent({
populate: true
}, function (win) {
for (let i = 0; i < win.tabs.length; ++i) {
if (win.tabs[i].active) {
chrome.browserAction.setBadgeText({
text: "8",
tabId: win.tabs[i].id
});
}
}
});
};
chrome.webNavigation.onCommitted.addListener(() => {
SetBadge();
});
chrome.webRequest.onSendHeaders.addListener(() => {
SetBadge();
});
chrome.webRequest.onBeforeRedirect.addListener(() => {
SetBadge();
});
chrome.tabs.onActivated.addListener(() => {
SetBadge();
});
chrome.webRequest.onCompleted.addListener(() => {
SetBadge();
});

Chrome.storage.sync.get() seems to be duplicating keys?

I am saving some settings using the following sequence
var getSettings = async function() {
var settings;
try {
settings = await authenticatedGET(server_url + SETTINGS_ENDPOINT);
return settings;
} catch (error) {
console.log("Settings Fetch Failed: " + error);
throw new Error(error);
}
}
const setLocalSettings = function(settings) {
chrome.storage.sync.set({ 'LML_Settings': JSON.parse(settings) }, function() {
console.log("Settings saved locally");
});
}
At the line right after the setLocalSettings function definition, the 'settings' object logs out as
{"email_format":"individual","close_tab":true,"frequency":"DAILY"} (correctly as intended). When I go to fetch the settings using this sequence:
chrome.storage.sync.get('LML_Settings', function(LMLSettingsContainer) {
console.log(LMLSettingsContainer);
if (LMLSettingsContainer.LML_settings.close_tab == "true") {
closeCurrentTab();
}
})
LMLSettingsContainer logs out as
{
"LML_Settings": {
"close_tab": true,
"email_format": "individual",
"frequency": "DAILY"
}
}
accessing my settings with LMLSettingsContainer.LML_Settings["<setting>"] is a bit annoying (and its the whole reason I named the top variable LMLSettingsContainer).
Does anyone know if there's a way to have chrome save/get these values unwrapped?
chrome.storage.sync.get('LML_Settings', ({LML_settings}) => { ... }) works, per #wOxxOm

load data from chrome.storage into vue.js data

I'm building a chrome app and I use Vue.js for the options page.
So I want to load settings from the chrome storage and put it into the vue data.
My problem is, that i can not access the vue compontens from inside the chrome storage callback. Every time i call it inside the callback, all vue elements are undefined.
Is there a way, to let the chrome storage cb function return a value, or give it an extra callback.
Here is my code
name: 'app',
data: function () {
return {
data []
}
},
methods: {
init: function() {
chrome.storage.sync.get('series', function (storageData) {
this.data = storageData //this is not possible, because this.data is undefined
})
});
}
},
created: function () {
this.init();
}
}
If using ES6 and transpiling (preferred approach). Note: arrow functions don't create a new context.
init: function() {
chrome.storage.sync.get('series', storageData => {
this.data = storageData
});
}
ES5 workaround:
init: function() {
var self = this;
chrome.storage.sync.get('series', function (storageData) {
self.data = storageData
});
}