Close Window popup using Protractor - javascript

this.switchWindowByTitle = async function (title) {
await browser.getAllWindowHandles().then(function (handles) {
handles.forEach(function (handle) {
console.log(handle.toString());
browser.switchTo.window(handle);
if (browser.getTitle() == title) {
return true;
}
});
});
I'm using Protractor to work with Chrome browser and try to close window popup by compare title. I get all window handles and for each of this but my code is just only checked with the first value of list handles.
Can anyone help me to fix it?
Here is my issue detail. It just checks first value and then compares the title
Failures:
1) Compare products Compare product should display correctly
Message:
Expected 'MOBILE' to equal 'COMPARE PRODUCTS'.
Stack:
Error: Failed expectation
at UserContext. (E:\Protractor workspace\POM_PROTRACTOR\Testcases\TC_04_CompareProducts.spec.js:17:47)
at C:\Users\tailet\AppData\Roaming\npm\node_modules\protractor\node_modules\jasminewd2\index.js:112:25

Use this method this will close your pop up
closeBrowserPopup: () => {
return new Promise((resolve, reject) => {
closePopup();
resolve("done");
});
};

Related

Open browser window and search for tags

I build something that you can execute in a browser console that searches the site for links and returns an array of links. After that I want to go trough each link, open the linkpage and search for all tags and get the source.
The pages have the same domain and only the part in the end is different. But when I try to execute my code it opens the first window. Returns undefined and closes the window. After that I get this error: VM79:32 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'getVideoSources') at <anonymous>:32:51
The part where I get the links works perfectly and it returns a list of links. Now the part that causes me problems is where I try to open each link.
async function grabLinks(links) {
const videoList = [];
for (const link of links) {
console.log("New link!")
// Go trough each link and get the video sources
const sources = await getVideoSources(link);
videoList.push(...sources);
}
console.log(videoList);
showLinks(videoList)
}
function getVideoSources(link) {
return new Promise((resolve, reject) => {
console.log("Opening Window");
const openedWindow = window.open(link, "_blank");
openedWindow.focus();
openedWindow.addEventListener("DOMContentLoaded", () => {
try {
const videoElements = openedWindow.document.querySelectorAll("div video");
var source = videoElements[0].getVideoSources;
console.log(source)
resolve(source);
} catch (e) {
reject(e);
} finally {
openedWindow.close();
console.log("Closing Window");
}
});
});
}
How would I go about and fix this problem. Should I add a timeout of like 5s and let the page fully load or what exactly goes wrong here.

CHROME-EXTENSION: chrome.runtime.lastError no tab with id error

I am working on a project that creates a google chrome extension and I am using chrome API's in it. Now, I am trying to work my handleTabUpdate function when tab is updated. However, I am getting Unchecked runtime.lastError: No tab with id: 60
How can I fixed that? Here is my code:
chrome.tabs.onUpdated.addListener(handleTabUpdate)
function handleTabUpdate(tabId, info) {
if (info.status === 'loading') {
store.dispatch({ type: 'RESET_TABHOSTS' })
chrome.tabs.get(tabId, (activeTab) => {
if (tabId === store.getState().currentTab['id']) {
store.dispatch({ type: 'ACTIVE_TAB', payload: activeTab })
}
})
}
}
My guess is the tab you are looking for was closed, so when you try to get it by id the operation fails.
To avoid the error, my suggestion is to first query all tabs and see if a tab with a specific id exists in the result. If it does, run chrome.tabs.get() and with your logic.
Just bumped up against this issue in MV3 and I've tooled a solution that allows a bit more ease when working with tabs.
Functions
const handleRuntimeError = () => {
const error = chrome.runtime.lastError;
if (error) {
throw new Error(error);
}
};
const safeGetTab = async (tabId) => {
const tab = await chrome.tabs.get(parseInt(tabId));
try {
handleRuntimeError();
return tab;
} catch (e){
console.log('safeGetTab', e.message);
}
return {};
};
Implementation
(async () => {
// assumes some tabId
const tab = await safeGetTab(tabId);
})()
This will return a value no matter what. It will either return the tab object or an empty object. Then you can can just do some basic checking in your script to decide how you want to handle that. In my case I can simply ignore the action that would have been taken on that tab and move on.

How to populate multiple prompts in a row in Cypress before initial page load

Cypress newbie here.
I'm trying to populate data into 3 different prompts that appear before the page loads completely. These values are then added into session storage. It is my understanding that since the site is not fully loaded I can't chain off cy.visit() so I've been using the onBeforeLoad so I can populate the data for these prompts:
before(function() {
cy.visit(base_url, {
onBeforeLoad(win) {
cy.stub(win, 'prompt').returns('someString').as('stub1')
cy.stub(win, 'prompt').returns('someOtherString').as('stub2')
cy.stub(win, 'prompt').returns('anotherString').as('stub3')
}
})
})
The issue is that when I look under "Spies/Stubs" I only see the stub1 being used 3 times as opposed to 3 different stubs being used once.
I also get the error
TypeError: Attempted to wrap prompt which is already wrapped
Any help will be highly appreciated.
Thank you all in advance.
EDIT:
Doing something like
before(function() {
cy.visit(base_url, {
onBeforeLoad(win) {
demo_site_info.forEach(element => {
cy.stub(win, 'prompt').callsFake(() => {
return element
})
});
}
})
})
yields a TypeError:
Attempted to wrap prompt which is already wrapped
Using callsFake(fn) allows multiple fake values.
it('fakes return values multiple times', () => {
const mod = {
doit: () => 'done'
}
let call = 0
const fakes = ['done1', 'done2', 'done3']
cy.stub(mod, 'doit').callsFake(() => {
return fakes[call++]
})
console.log(mod.doit()) // done1
console.log(mod.doit()) // done2
console.log(mod.doit()) // done3
console.log(mod.doit()) // undefiend
})

How to sort data in JQuery

I'm working on a slider which is showing data from the backend. Using the "push" function it is showing slides in the slider according to date. But I need it to show these slides according to date & status.
Firstly show incomplete status (btn-danger), after it show pending status (btn-success), and then completed status (btn-warning).
screenshot of code https://ibb.co/5KJpdrh
full code:
paste.ofcode.org/hmKSwTvaWrjTj3A6rWh464
code:
function handleSubmit(command) {
if(command === 'meeting') {
let meetingFormValue = getMeetingFormValue('.create-meeting-form');
httpService.post('http://localhost:3000/meeting/create', meetingFormValue)
.then(response => {
meetings.push(response);
setMeetingCarausel();
}).catch(ex => {
console.log('Error');
console.log(ex);
})
// close the form
$('.create-meeting-form').stop().slideToggle();
}else if(command === 'task') {
//attendees
const taskFormValue = getTaskFormValue('#createTaskForm');
httpService.post('http://localhost:3000/meeting/taskList/create', taskFormValue)
.then(response => {
tasks.push(response);
setTasksCarausel();
}).catch(ex => {
console.log(ex);
});
// close the form
$('.create-task-form').stop().slideToggle();
}
}
You want to use Array.prototype.sort().
You should pass a compare function to have sort() use your criteria to sort your entries properly.

Waiting for one event handler before executing another one

I'm writing a Firefox browser extension, and I'm stuck on how to wait for a content script to load before sending a message from the background script.
This is the sequence I'm trying to achieve:
User clicks context menu item (click handler is in background script)
Background script creates new tab
Content script loads fully in new tab
Background script sends message (with data) to content script
Content script uses data
Obviously, the content script needs to be loaded for step 4 to work; otherwise, the message doesn't get received.
I looked at previous similar questions, but most of the answers are incorrect (they wrap the event listener methods in a Promise, which either results in too many listeners or too few Promises), or they seem not-applicable to my scenario (those answers get around the question entirely by putting one callback inside the other; that wouldn't work here).
What I did try so far was to have the content script send a message when it's ready, and that works, but I'm still not sure how to have the click handler (from step 1) wait for a message from the content script (hypothetical step 3.5).
I assume I'd have to define the message handler outside the click handler, as far as I know, unless there's a way to receive the message inside the click handler.
Here's my current code as a minimal working example:
background.js:
let ports = {
'1': null,
'2': null
};
xyz = () => { /*...*/ }
tabHasLoaded = () => { /*...*/ }
browser.runtime.onConnect.addListener(connectHandler);
connectHandler = (p) => {
ports[p.name] = p;
switch (p.name) {
case '1':
ports['1'].addListener(xyz);
break;
case '2':
ports['2'].addListener(tabHasLoaded);
break;
}
};
browser.contextMenus.onClicked.addListener((info, tab) => {
let data, uri;
//...
browser.tabs.create({
url: uri
}).then((tab) => {
// need to wait for tabHasLoaded() to get called
ports['2'].postMessage({
msg: data
})
});
});
1.js (content script for something else):
let myPort = browser.runtime.connect({
name: '1'
});
document.addEventListener("click", (e) => {
myPort.postMessage({
msg: e.target.id
});
});
2.js (content script for new tab, after clicking context menu):
let myPort = browser.runtime.connect({
name: '2'
});
myPort.postMessage({
msg: "READY" // tabHasLoaded() should now get called in background.js
});
myPort.onMessage.addListener((msg) => {
// waiting for background.js to send me data
});
Is there an ideal way to handle this?
i still think promises are the way to go...
update
change code to use your MWE... please note that this is untested/not-optimized code just to outline the idea... it should look something like this:
background.js
let ports = {
'1': null,
'2': null
};
xyz = () => { /*...*/ }
browser.runtime.onConnect.addListener(connectHandler);
connectHandler = (p) => {
ports[p.name] = p;
switch (p.name) {
case '1':
ports['1'].addListener(xyz);
break;
}
};
browser.contextMenus.onClicked.addListener(async (info, tab) => {
let data, uri;
//...
const tab = await LoadAndWaitForPort2(uri)
ports['2'].postMessage({msg: data})
});
function LoadAndWaitForPort2(uri){
return new Promise((resolve, reject)=>{
const tab
const tabHasLoaded = (evt) => {
if(evt.data.msg === "READY"){
ports['2'].removeListener(tabHasLoaded)
resolve(tab)
} else {
reject("error!")
}
}
ports['2'].addListener(tabHasLoaded)
tab = await browser.tabs.create({url: uri})
})
}
2.js
let myPort = browser.runtime.connect({
name: '2'
});
myPort.postMessage({
msg: "READY" // tabHasLoaded() should now get called in background.js
});
myPort.onMessage.addListener((msg) => {
// waiting for background.js to send me data
});

Categories