Ran into the issue, where the test code should click the button Process in the iframe. Used npm i cypress-iframe lib, but came up to nothing. Cypress could not find the button.
Tried cy.iframe('[class="resp-iframe"]').find('resp-iframe[id="submit"]')
HTML of the problem
Tried the other ways to click on iframe button:
cy.get('iframe[class="resp-iframe"]').then($element => {
const $body = $element.contents().find('body')
cy.wrap($body).find('resp-iframe[class="btn btn-block btn-primary"]').eq(0).click();
})
also
cy.get('[class="resp-iframe"]').then($element => {
const $body = $element.contents().find('body')
let stripe = cy.wrap($body)
stripe.find('[class="resp-iframe"]').click(150,150)
})
and
cy.iframe('#resp-iframe').find('[name="submitButton"]')
Error
Error 2
Updated FYI:
The first part of code - clicking the Google button in bottom-right:
const getIframeBody = () => {
// get the iframe > document > body
// and retry until the body element is not empty
return cy
.get('[id="popup-contentIframe"]')
.its('0.contentDocument.body')
// wraps "body" DOM element to allow
// chaining more Cypress commands, like ".find(...)"
// https://on.cypress.io/wrap
.then(cy.wrap)
}
getIframeBody().find('[id="payWithout3DS"]').click()
Then, waiting for secure payment preloader to finish up:
cy.wait(20000)
Then, trying to catch the Process button by suggestions:
cy.iframe('[name="AcsFrame"]').find('#submit').click()
or
cy.iframe('[class="resp-iframe"]').find('[id="submit"]')
whole code part looks:
const getIframeBody = () => {
// get the iframe > document > body
// and retry until the body element is not empty
return cy
.get('[id="popup-contentIframe"]')
.its('0.contentDocument.body')
// wraps "body" DOM element to allow
// chaining more Cypress commands, like ".find(...)"
// https://on.cypress.io/wrap
.then(cy.wrap)
}
getIframeBody().find('[id="payWithout3DS"]').click()
cy.wait(20000)
cy.iframe('[name="AcsFrame"]').find('#submit').click()
But still, getting:
Maybe anyone had something like that?
Thanks.
How about you try this:
cy.iframe('[name="AcsFrame"]').find('#submit').click()
You don't need to repeat the resp-iframe inside the .find().
The selector .find('resp-iframe[id="submit"]') means look for HTML like this: <resp-iframe id="submit"> but the element you want is <input id="submit">.
Everything else looks ok
cy.iframe('[class="resp-iframe"]').find('[id="submit"]')
Related
So I am writing a test that will add a card to a container(payment-card-container) and I want to confirm an element was added later by seeing if the children have increased by 1. But I am having issues when we try to count the children length when there isnt any. I am currently using the below:
cy.get('[data-test-id="payment-card-container"]')
.children()
.its('length')
.then(length => {
const childrenLength = length;
})
But Cypress seems to get an error because it cant find the children (Error below).
Timed out retrying: Expected to find element: ``, but never found it.
Is there a way this can work when there isnt any children and it returns the value of 0?
The problem with using a jQuery expression like
Cypress.$('[data-test-id="payment-card-container"]').children().length
is you don't get the Cypress retry for async updates.
If adding a payment card calls an API, the above expression will falsely report 0 children instead of waiting for the DOM to update.
There's really no good way to handle the no-cards situation,
Except
set up your test scenario such that there are no cards initially
add a card
confirm that there is now exactly one card
If you must test for zero children, a trailing .should() will remove the error message.
cy.get('[data-test-id="payment-card-container"]')
.children()
.should('have.length', 0); // no error when should expression passes
// Add card here
cy.get('[data-test-id="payment-card-container"]')
.children()
.should('have.length', 1); // waits for async add-card operation
Tested with
<body>
<div data-test-id="payment-card-container"></div>
<script>
setTimeout(() => {
const div = document.querySelector('[data-test-id="payment-card-container"]');
const p = document.createElement('p')
div.appendChild(p)
}, 2000)
</script>
</body>
One hacky way that I could think of is this. You can use the jQuery length and children() property to check the length:
cy.get('body').then(() = > {
if (Cypress.$('[data-test-id="payment-card-container"]').children().length == 0) {
//Do Something
}
else {
//Do Something
}
})
Hello I am loading a few of data each API call, inside a tag, but when I do the second call this data is appended to the data of the previous call.
The question is how can I clear the content of a div?
I am using this for select that div
this.$refs.data
In order to add contet I am using the following code:
responseJSON.forEach(element => {
let card = Vue.extend(card)
let instance = new card({
propsData: {
ch: element
}
})
instance.$mount()
this.$refs.aaa.appendChild(instance.$el)
this.cards.push(instance)
});
Before running the responseJSON.forEach, you can clear everything in the div first by running
this.$refs.data.innerHTML = ""
I would like to know how to capture and read the URL after a click event on an <a> link.
On the onClick event our javascript does some string manipulation of the actual href of the clicked link and then a window.location.href = myNewReplacebleURL is done on the fly. The original href is not necessarily the location you get to after the onClick.
Here is how I started:
describe("Twitter", function() {
it("Should assert that via value is set correctly in JS", function() {
cy.server();
cy.visit(Cypress.config("appUrl") + "/probes/sha/sha-via.html");
cy.get("#v_test ul.share li a")
.click();
});
});
EDIT: What I would like is to catch the URL located at the "Page Load" step.
You should be able to use cy.on to perform your assertions inside the url:changed event callback:
cy.on("url:changed", (newUrl) => {
expect(newUrl).to.contain("?magic=true")
})
You can use thecy.location() command, example:
cy.get("#v_test ul.share li a")
.click();
cy.location('href').should('eq', 'newUrl');
Also, as an alias to the cy.location('href') command you could use cy.url().
After clicking an element on my webpage, I get the expected behavior from Response.Redirect in the trace, the break point on the expected page gets hit and proceeds to process normally. However when I'd expect the new page to be loaded, the display in the browser is not changed. It looks and behaves like the click brought you back to the same page.
I've moved the redirect call out of a try-catch block, and have tried different combinations of true/false as the second parameter with HttpContext...CompleteRequest()
What might prevent a page from being loaded after a call from Response.Redirect and the Page_Load sub completes?
Edit:
The site uses css and javascript to create a hoverable dropdown menu containing self referencing links, see below. I have tried using Chrome's dev tools to see what the network was processing. As far as I can tell from reading the Network Tab the click was creating the correct call; status 200, type xhr. xhr was the only thing that I found odd, but it looks like this is simply a reference to ajax? This leaves me in the same position. I am telling the site to redirect to new url, and I see the network take a request for that url, but the url in the address bar doesn't change; not the displayed page.
$(document).on('click','.navigation', function () {
loadItems($(this).attr('id'), $(this).attr('itemName'));
return false;
}
);
var loadItems = function (id, itemName) {
var editInfor =
{
"method": "getChildItems",
"id": id
};
$.ajax
(
{
type: "POST",
url: $.url,
dataType: "json",
data: JSON.stringify(editInfor),
success: function (jsonReply) {
$("#chkEnabled").attr('checked', jsonReply.enabled)
if (jsonReply.method == 'getChildItems') {
$("#childrens").html('');
var html = '<table>'
if (jsonReply.successfull) {
$.each(jsonReply.children, function (i, item) {
html += '<tr><td><span class="children">' + item.text + '</span></td><td><a class="moveItemUp btn" href="#" id="moveItemUp' + item.id + '">Move Up <i class="icon-circle-arrow-up"></i></a> <a class="moveItemDown btn" href="#" id="moveItemDown' + item.id + '">Move Down <i class="icon-circle-arrow-down"></i></a></td><td>Remove</td></tr>'
});
}
html += '</table>'
$($.childrens).html(html);
}
}
}
);
Please try this:
$.mobile.changePage( "/Exmaple.aspx", {
transition: "pop"
});
I'm writing tests with Angular Scenario test runner. Within a traditional form, I can enter text into an input, but I need to press enter to execute the query and there is no button to click on. Surely there is some easy way to do this, but I do not know what it is.
input('query').enter('foo bar');
// ... now what?
I tried to simulate a keypress with JQuery, but as this answer indicates JQuery is not loaded in the e2e scenarios scope. So I followed his advice (as well as that of this answer) to simulate the keypress:
element('#search_input').query(function(el, done){
var press = document.createEvent('keypress');
press.which = 13;
press.trigger(evt);
done();
});
But to this Angular replies:
NotSupportedError: DOM Exception 9
Error: The implementation did not support the requested type of object or operation.
Update
I realized that a very easy workaround is to include a hidden submit input in my form:
<input id="search-submit" type="submit" style="display:none;">
Then in the scenario: element('#search-submit').click(); does what is needed.
For a purer solution which doesn't involve modifying the HTML for the sake of testing, #florian-f's answer (as well as this one) provides access to jQuery within the DSL via:
var $ = $window.$;
which can be used there or passed to the callback. However, even with this access when triggering a press of enter I was not able to submit my form in the following manner:
$(selector).trigger($.Event('keypress', { which: 13 }));
This must be another issue all together. But I did find jQuery's submit function to do the trick:
$(#the_form).submit();
You can access to the app (runner in an iframe) instance of jQuery :
angular.scenario.dsl('appElement', function() {
return function(selector, fn) {
return this.addFutureAction('element ' + selector, function($window, $document, done) {
fn.call(this, $window.angular.element(selector));
done();
});
};
});
Then you can call the trigger method of jQuery in your test :
appElement('yourSelector', function(elm) {
elm.trigger('enter');//or keypress
});
There is also another possibility to trigger a key event. While your first approach
element('#search_input').query(function(el, done){
var press = document.createEvent('keypress');
press.which = 13;
press.trigger(evt);
done();
});
will be blocked by angular, this one
element(<selector>).query(function($el, done) {
var event = new CustomEvent('keyup');
event.keyCode = 13;
$el.val(2);
$el.get(0).dispatchEvent(event);
done();
});
will pass and trigger a keyup event on the element specified by the selector (keyCode = 13 = Enter Key). See https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent for further information.