Protractor (3.0.0)/Webdriver (2.53.0) switching tabs error - javascript

I have the following test with the current versions of webdriver/protractor (see title).
it('checks tabs', () => {
const url1 = 'https://stackoverflow.com/';
const url2 = 'http://programmers.stackexchange.com/';
let windowHandles = {
oldTab: '',
newTab: ''
};
await browser.get(url1);
await browser.getWindowHandle().then(handle => {
windowHandles.oldTab = handle;
});
await browser.executeScript('window.open("' + url2 + '", "whatever")');
await browser.getAllWindowHandles()
.then(handles => {
expect(handles[0]).toEqual(windowHandles.oldTab);
windowHandles.newTab = handles[1];
return browser.driver.switchTo().window(windowHandles.oldTab);
})
.then(() => {
let handle = browser.driver.getWindowHandle();
expect(handle).toEqual(windowHandles.oldTab);
})
.then(() => browser.sleep(6000));
});
The interesting thing is that the assertations work well; they are all green.
But it does not switch back to the first tab.
Am I missing something or it is indeed a bug?
Update
In my FireFox window.open opens a window, not a tab, and switching actually works between the windows.
I can accept the workaround of opening windows instead tabs in Chrome, though I really think that if the current window handle tells you that you have switched while you are still in the same is a bug.
Update 2
Even with opening windows Chrome does not switch while FireFox does. I reported a bug.
This is my new test:
it('checks tabs', async () => {
const url1 = '/login';
const url2 = config.chatLaunchUrl;
let windowHandles = {
oldTab: '',
newTab: ''
};
await browser.get(url1);
await browser.getWindowHandle().then(handle => {
windowHandles.oldTab = handle;
});
// opening new window sending CTRL+N
await browser.actions()
.sendKeys(protractor.Key.chord(protractor.Key.CONTROL, "n"))
.perform();
await browser.getAllWindowHandles()
.then(handles => {
expect(handles[0]).toEqual(windowHandles.oldTab);
windowHandles.newTab = handles[1];
return browser.driver.switchTo().window(windowHandles.newTab);
})
.then(() => {
// this works
return browser.get(url2);
})
.then(() => {
return browser.driver.switchTo()
.window(windowHandles.oldTab)
.then(() => browser.driver.executeScript('window.focus();'));
})
.then(() => {
let handle = browser.driver.getWindowHandle();
expect(handle).toEqual(windowHandles.oldTab);
})
.then(() => browser.sleep(6000));
});
Update 3
The difference between Chrome and Firefox is that if I switch to Firefox the browser window comes into focus while with Chrome it does not. The test can continue without problems in Chrome as well. So it's a lesser bug.
(Related links:
Protractor - switch tabs error - different case
https://github.com/angular/protractor/issues/55 - closed many years ago
https://github.com/angular/protractor/issues/3124 - My new bug report)

Visually, you will see it switch to the second tab, but you won't see it switch back to the first tab (maybe that's a bug in chrome or chromedriver?). The test commands are in fact sent to the correct tab though, and your test will pass or fail appropriately.

Related

Cypress gets 401 error and logs out during the test (session issue probably)

I'm facing an issue which I couldn't solve yet and wanted to get some opinions from you. I've a selector which has two options in total and I'm using select to switch between them. I wasn't sure about the code so I added url check as well, which works successfully.
However, the page loads with the first selection so the api call has already been made, but, in the second part (items section) when I select Items it throws 401 error and logs out which breaks all the following tests.
What can I do/improve here? This flow works perfectly on my local but Cypress fails.
Things I've tried:
selecting using 0 and 1 without value names.
tried with {failOnStatusCode: false}.
couldn't use Cypress.Cookies.preserveOnce (since it's deprecated).
I also tried this one as well here; https://www.youtube.com/watch?v=b8aoVh6IdCg
Thanks in advance!
it('verifies there are only orders, drafts and/or return orders on all orders grid', () => {
ordersPage.ordersSelector().trigger('click')
cy.get('select').select('orders').should('have.value', 'orders');
cy.url()
.should('include', 'orders');
const orderNumberPrefix = ['DRAFT-', 'SO0', 'S0-', 'R0']
cy.get('.ag-center-cols-container div[row-index]')
.each($row =>{
const $col = $row.find('[col-id="orderNumber"]')
const orderNumber = $col.text().trim()
const correctOrderNumberPrefix = orderNumberPrefix.some(prefix => {
return orderNumber.startsWith(prefix)
})
expect(correctOrderNumberPrefix).to.be.true;
});
})
it('verifies there are only orders on items grid', () => {
ordersPage.ordersSelector()
cy.get('select').select('items').should('have.value', 'items'); //fails here
cy.url()
.should('include', 'items');
const orderNumberPrefix = ['SO0']
cy.get('.ag-center-cols-container div[row-index]')
.each($row =>{
const $col = $row.find('[col-id="orderNumber"]')
const orderNumber = $col.text().trim()
const correctOrderNumberPrefix = orderNumberPrefix.some(prefix => {
return orderNumber.startsWith(prefix)
})
expect(correctOrderNumberPrefix).to.be.true;
});
})

Overriding navigator.mediaDevices.getDisplayMedia for Screenshare inside electron

I came accross capture screen with electron when rendering a web site when I needed a solution for enabling screenshare inside my electron app;
however the desktopCapturer is always undefined, on my side and the only way I can access;
sources is inside the main process;
I would like to know if there is a way to have sources define when I do something like this
let all_sources = undefined
ipcRenderer.on('SET_SOURCES', (ev, sources) => {
all_sources = sources
console.log("The sources are : ", all_sources)
})
const wait_function = function() {
return new Promise(resolve => {
setTimeout(function() {
resolve(all_sources);
}, 4000);
});
};
contextBridge.exposeInMainWorld("myCustomGetDisplayMedia", async () => {
await ipcRenderer.send('GET_SOURCES')
await wait_function(); // want to make sure all_sources is defined
const selectedSource = all_sources[0]; // take the Entire Screen just for testing purposes
return selectedSource;
});
this is inside the preload js script.
thanks

Execution Context has been Destroyed Puppeteer

"Most likely due to page navigation"
The page I'm trying to use has the following behavior. To get to the content I want, I have to click a button. But on clicking that button, the content I want is loaded on a new tab. The current tab I'm on navigates to a useless ad. When I try to do anything with "page" (page.eval, page.url()), it gives me the above error (the actual browser gives an error about the page having been moved permanently).
How do I get puppeteer to follow the new tab instead of getting stuck on the old one?
I've tried making a separate third tab with puppeteer newPage and goto, which works, kind of, but that runs into other issues down the road. I'm looking for a different way.
Edit:
I followed the answer below and did this:
const [newPage, oldPage] = await Promise.all([getNewPage(), getOldPage()]);
console.log("new page", newPage.url());
console.log("old page", oldPage.url());
function getOldPage() {
return new Promise((resolve) => {
page.evaluate(function () {
let element = document.querySelector("button[class*=OfferCta__]");
element.click();
});
resolve(page);
});
}
function getNewPage() {
return new Promise((resolve) => {
browser.on("targetcreated", checkNewTarget);
function checkNewTarget(target) {
if (target.type() === "page") {
browser.off("targetcreated", checkNewTarget);
resolve(target.page());
}
}
});
}
It didn't work. I got this console:
3:17:40 PM web.1 | new page https://www.nike.com/register?cid=4942550&cp=usns_aff_nike__PID_2210202_WhaleShark+Media%3A+RetailMeNot.com&cjevent=3a020cab18a211eb830d00030a1c0e0c
3:17:40 PM web.1 | old page chrome-error://chromewebdata/
So by the time the Promise checks on the old url that I need, it is already erroring out.
EDIT:
It turns out I was blocking navigation requests when I was trying to block third-party scripts. This caused my button press to fail.
Maybe something like this:
const [newPage] = await Promise.all([
getNewPage(),
page.click(selector),
]);
// ...
function getNewPage() {
return new Promise((resolve) => {
browser.on('targetcreated', checkNewTarget);
function checkNewTarget(target) {
if (target.type() === 'page') {
browser.off('targetcreated', checkNewTarget);
resolve(target.page());
}
}
});
}

Chrome extension detect user added new tab

In a situation where the user reboots his/her pc without closing chrome, the tabs will automatically return when chrome is being re-opened.
What I want to know is how to distinguish that the user opened a new tab.
I have the following function:
const interceptRequests = () => {
chrome.webRequest.onBeforeRequest.addListener(
async details => {
if (requestIsUserInitiated(details)) {
const tabs = await getAllTabs();
console.log('get all the tabs', tabs);
console.log('details', details);
}
},
{urls: ["<all_urls>"]},
["blocking"]
);
};
Where:
const requestIsUserInitiated = details =>
details.type === 'main_frame'
&& !details.initiator // ignoring requests made by the website
&& details.method === 'GET';
The thing is, there doesn't seem to be a straightforward way to distinguish whether the browser initiated the request, or the user, unless there is a property that I'm not seeing:
Of course there is the following listener:
chrome.tabs.onCreated.addListener(function(tab) {
});
However, when Chrome opens all the tabs, then it will probably get triggered anyway.
So how can one make the distinction? I want to trigger a function when it is certain that the user initiated the new tab to make the request.
import { interceptRequests } from './requestInterceptor/index';
import { cleanTabs } from './tabCleaner/index';
let extensionIsInitialized = false;
const startBackgroundProcess = () => {
if (! extensionIsInitialized) {
interceptRequests();
cleanTabs();
extensionIsInitialized = true;
}
};
chrome.runtime.onStartup.addListener(startBackgroundProcess);
chrome.runtime.onInstalled.addListener(startBackgroundProcess);

WebRTC: Determine which TURN server is used in PeerConnection

Scenario: You would like to know if TURN server is being used for a particular call and which one from the array of TURN servers you provided during PeerConnection creation, is being used. Right now there are two options:
Wireshark: But when you are behind a corporate proxy and TURN server is outside that, wireshark would show the Proxy IP as the destination.( also not the mention the inconvenience of running it in the background)
Going through the stats page and finding out, chrome --> chrome://webrtc-internals and Firefox --> about:webrtc
I would like to use a alternative to the above two, programmatically determine this so I do not have to leave my application page.
Update: I've updated the example to follow the latest spec, with maplike getStats.
The following approach follows the specification and currently only works in Firefox, because Chrome implements getStats() incorrectly at the moment. Hopefully, a version of the adapter.js polyfill should be available soon that will make this work in Chrome as well.
When you run this fiddle in Firefox, you'll see:
checking
connected
Does not use TURN
This is because the example provides both a STUN and a TURN server. But when I modify the config to use TURN only with iceTransportPolicy: "relay", I see:
checking
connected
Uses TURN server: 10.252.73.50
Note that the turn server I use is behind a VPN, so it won't work for you, but feel free to modify the fiddle with your own server (just don't save it unless you want the info to become public!)
While I haven't tested with more than one turn server, as you can see the IP address shown matches the turn server configured, so it should be possible to tell which server is used using this approach.
// Turn server is on Mozilla's VPN.
var cfg = { iceTransportPolicy: "all", // set to "relay" to force TURN.
iceServers: [{ urls: "stun:stun.l.google.com:19302" },
{ urls: "turn:10.252.73.50",
username:"webrtc", credential:"firefox" }] };
var pc1 = new RTCPeerConnection(cfg), pc2 = new RTCPeerConnection(cfg);
pc1.onicecandidate = e => pc2.addIceCandidate(e.candidate);
pc2.onicecandidate = e => pc1.addIceCandidate(e.candidate);
pc2.oniceconnectionstatechange = () => log(pc2.iceConnectionState);
pc2.onaddstream = e => v2.srcObject = e.stream;
var findSelected = stats =>
[...stats.values()].find(s => s.type == "candidate-pair" && s.selected);
var start = () => navigator.mediaDevices.getUserMedia({ video: true })
.then(stream => pc1.addStream(v1.srcObject = stream))
.then(() => pc1.createOffer()).then(d => pc1.setLocalDescription(d))
.then(() => pc2.setRemoteDescription(pc1.localDescription))
.then(() => pc2.createAnswer()).then(d => pc2.setLocalDescription(d))
.then(() => pc1.setRemoteDescription(pc2.localDescription))
.then(() => waitUntil(() => pc1.getStats().then(s => findSelected(s))))
.then(() => pc1.getStats())
.then(stats => {
var candidate = stats.get(findSelected(stats).localCandidateId);
if (candidate.candidateType == "relayed") {
log("Uses TURN server: " + candidate.ipAddress);
} else {
log("Does not use TURN (uses " + candidate.candidateType + ").");
}
})
.catch(log);
var waitUntil = f => Promise.resolve(f())
.then(done => done || wait(200).then(() => waitUntil(f)));
var wait = ms => new Promise(resolve => setTimeout(resolve, ms));
var log = msg => div.innerHTML += msg +"<br>";
var failed = e => log(e +", line "+ e.lineNumber);
<video id="v1" width="108" height="81" autoplay></video>
<video id="v2" width="108" height="81" autoplay></video><br>
<button onclick="start()">Start!</button><br><div id="div"></div>
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
I wrote and tested the below piece of code, works in latest versions of both firefox and chrome, getConnectionDetails returns a promise which resolves to connection details:
function getConnectionDetails(peerConnection){
var connectionDetails = {}; // the final result object.
if(window.chrome){ // checking if chrome
var reqFields = [ 'googLocalAddress',
'googLocalCandidateType',
'googRemoteAddress',
'googRemoteCandidateType'
];
return new Promise(function(resolve, reject){
peerConnection.getStats(function(stats){
var filtered = stats.result().filter(function(e){return e.id.indexOf('Conn-audio')==0 && e.stat('googActiveConnection')=='true'})[0];
if(!filtered) return reject('Something is wrong...');
reqFields.forEach(function(e){connectionDetails[e.replace('goog', '')] = filtered.stat(e)});
resolve(connectionDetails);
});
});
}else{ // assuming it is firefox
return peerConnection.getStats(null).then(function(stats){
var selectedCandidatePair = stats[Object.keys(stats).filter(function(key){return stats[key].selected})[0]]
, localICE = stats[selectedCandidatePair.localCandidateId]
, remoteICE = stats[selectedCandidatePair.remoteCandidateId];
connectionDetails.LocalAddress = [localICE.ipAddress, localICE.portNumber].join(':');
connectionDetails.RemoteAddress = [remoteICE.ipAddress, remoteICE.portNumber].join(':');
connectionDetails.LocalCandidateType = localICE.candidateType;
connectionDetails.RemoteCandidateType = remoteICE.candidateType;
return connectionDetails;
});
}
}
I would like point out one thing, all these three methods fail in one scenario: two turn servers running from same machine on different ports, only reliable way I found was looking at the turn server logs.

Categories

Resources