Cypress loses test scenario after quitting from iframe - cypress

I have iframe for payments, after successful payment I need to click 'go back to application' button. And here is a problem. Button has a new link in href attribute for the app. After clicking this button, it seems like Cypress loses test scenario, there is no more Cypress steps on the left side of browser window. And it doesn't make further steps.
How to handle this situation ? How to make Cypress keep going by scenario ?

Not sure if this will suit your test, but you can stub the navigation with cy.intercept().
const href = 'url-from-link-href'
cy.location().then(loc => {
cy.intercept({url: href}, (req => {
expect(req.url).to.eq(href) // confirms href seen on intercepted network call
req.url = loc.href // stop navigation, remain at original loc
})).as('redirect')
cy.get(`a[href="${href}"]`)
.click() // click the link
cy.wait('#redirect') // confirms intercept caught the redirect
cy.visit(href)
...
})

Related

How to get the URL of a type 'submit' button during Cypress test?

Below is a submit button on the page I am trying to test.
When you click this button, a pop-up window is displayed. The URL of this pop-up is https://login.microsoftonline.com/........etc.
This sign in uses SSO, but we are having difficulty bypassing the sign-in process using requests.
So we are instead trying to capture the URL of the pop-up during the test.
I have seen examples where people retrieve the href attribute of a button. However, as you can see above, there is no href on this button.
I've searched the HTML for a form element too, but can't find that.
I'm just wondering, is there a way I can get the URL of the pop-up window that clicking the above button generates?
To catch the URL, try adding an intercept before the click
cy.intercept('POST', '*').as('submit')
cy.get('button').click()
cy.wait('#submit').then(interception => {
console.log(interception.request.url)
})
Note this is debugging code only to help find the URL. Don't use it in a long-term test.
Additional notes:
I'm assuming 'POST' as it's most common for submit, but may need 'GET' instead.
using '*' will catch anything, so you may catch so stray requests from the page load with the first cy.wait('#submit'). If so, just add more cy.wait('#submit') or a long cy.wait() before the click.
The new tab is likely to be trigger via javascript. If it is using [window.open][1] the you can stub it to open in the same ta
cy.window().then(win => {
cy.stub(win, 'open').callsFake((url, target) => {
expect(target).to.be.undefined
// call the original `win.open` method
// but pass the `_self` argument
return win.open.wrappedMethod.call(win, url, '_self')
}).as('open')
})
cy.get('a').click()
cy.get('#open').should('have.been.calledOnceWithExactly', 'url')
})
[1]: https://glebbahmutov.com/blog/cypress-tips-and-tricks/#deal-with-windowopen

Laravel dusk coming back to original browser tab or close latest tab but keep original

I have situation where I need to click the link and visit new tab and see if there is that particular text or not and then come back to original tab and perform some work.
this is the code I am using to confirm I am in latest browser tab after clicking view button
$window = collect($this->driver->getWindowHandles())->last();
$this->driver->switchTo()->window($window);
Now I have to come to original tab, How can i do that ? Any help?
is there any way to close recent tab after some time. so that i can come to original tab.
Thanks
You're on the right track.
You can continue with something like this:
$this->browse(function (Browser $browser) {
$browser->visit('/')->click('#some-link');
// switch to the last tab
$window = collect($browser->driver->getWindowHandles())->last();
$browser->driver->switchTo()->window($window);
// make some assertion on that tab
$browser->assertRouteIs('some-route.alias');
// switch back to first tab
$window = collect($browser->driver->getWindowHandles())->first();
$browser->driver->switchTo()->window($window);
// TODO: make further assertions
});

Cypress: Is it possible to extract a URL of a new browser tab that will be opened by a click?

I need to extract a URL of a new browser tab that will be opened by a double click on an element. Element is not a link so there is no any "href" attr. Once we dblclick on this item, we will have a proper url that I need to extract (and parse further).
cy.visit("Runtime/Runtime/Form/Home/");
cy.contains("item").should('be.visible').dblclick();
const url = // to do
I know that cypress does not support multiple tabs testing but I don't need to do any testing on a tab...just what to get that url. Is it possible?
One way to test that is use Chrome and disable Web security in cypres.json:
"chromeWebSecurity": false
Then you could do:
cy.contains("item").should('be.visible').dblclick()
cy.url()
.then((url) => {
expect(url).to.contain('some-string')
})

Switch to another window in Cypress

I want to switch to to a new window on pressing a button, and the new window has dynamic URL, How do we handle this. Is there any workaround. I searched through many articles
Click the add button
cy.get('a[href*="javascript:xxxSearch();"]').click()
It opens a new window
I want to access(search/add the elements in new window and then switch back to previous main window
May be a good idea if you could share the full html of that page. As I understood from the question, may be grab the href and then get the attribute of href to a const and visit to that link as below. Just give a try and let me know if this is working for you.
it('Open a new window',function(){
cy.visit('some_url')
//test code continues....
cy.get('a[href="/some/link"]').then(($href)=>{
const hrefLink = $href.attr('href');
cy.visit(hrefLink);
// rest of you test to grab the search button
})
})

Google Chrome Extension - How can I include a content script more than once?

I've been working on Chrome Extension for a website for the past couple of days. It's coming along really nicely but I've encountered a problem that you might be able to help with.
Here's an outline of what the extension does (this functionality is complete):
A user can enter their username and password into the extensions popup - and verify their user account for the particular website
When a user browses http://twitter.com a content script is dynamically included that manipulates the DOM to include an extra button next to each tweet displayed.
When a user clicks this button they are presented with a dialog box
I've made a lot of progress but here is my problem:
When a user visits Twitter the content script is activated and all tweets on the page get my new button - but if the user then clicks 'More...' and dynamically loads the next 20 tweets... these new additions to the page DOM do not get affected by the content script (because it is already loaded).
I could add an event listener to the 'More...' button so it then triggers the original content script again (and adds the new button) but i would have to predict the length of twitter's ajax request response.
I can't tap into their Ajax request that pulls in more tweets and call my addCurateButton() function once the request is complete.
What do you think is the best solution? (if there is one)
What you want to do is to re-execute your content-script every time the DOM is changed. Luckily there is an event for that. Have a look at the mutation event called DOMNodeInserted.
Rewrite your content script so that it attaches an event listener to the body of the DOM for the DOMNodeInserted event. See the example below:
var isActive = false;
/* Your function that injects your buttons */
var inject = function() {
if (isActive) {
console.log('INFO: Injection already active');
return;
}
try {
isActive = true;
//inject your buttons here
//for the sake of the example I just put an alert here.
alert("Hello. The DOM just changed.");
} catch(e) {
console.error("ERROR: " + e.toString());
} finally {
isActive = false;
}
};
document.body.addEventListener("DOMNodeInserted", inject, false);
The last line will add the event listener. When a page loads the event is triggered quite often so you should define a boolean (e.g. var isActive), that you initialize to false. Whenever the inject function is run check whether isActive == true and then abort the injection to not execute it too often at the same time.
Interacting with Ajax is probably the hardest thing to coax a content script to do, but I think you’re on the right track. There are a couple different approaches I’ve taken to solving this problem. In your case, though, I think a combination of the two approaches (which I’ll explain last) would be best.
Attach event listeners to the DOM to detect relevant changes. This solution is what you’ve suggested and introduces the race condition.
Continuously inspect the DOM for changes from inside a loop (preferably one executed with setInterval). This solution would be effective, but relatively inefficient.
The best-of-both-worlds approach would be to initiate the inspection loop only after the more button is pressed. This solution would both avoid the timing issue and be efficient.
You can attach an event-handler on the button, or link that is used for fetching more results. Then attach a function to it such that whenever the button is clicked, your extension removes all the buttons from DOM and starts over inserting them, or check weather your button exists in that particular class of DOM element or not and attach a button if it doesn't.

Resources