Cypress - Check a user logs in successfully or fails - javascript

In my Cypress code, I want to decide action based upon the response from the backend. Please note, I am not mocking a server, rather wanting to hit & get response from API server & base next commands off the response.
cy.visit("http://localhost:3000/login");
cy.get(".cookieConsent button").click();
cy.get("#email-input").type(userLoginDetail.email);
cy.get("#password-input").type(userLoginDetail.password);
cy.get("form").submit();
cy.wait(3000);
// logic being it user is redirected to homepage, then login was successful. Not happy with this O(
if (cy.url() === "http://localhost:3000/") {
console.log("eeeeeeeeeee");
} else {
console.log(
"aaaaaaaaaaaaaaaaaaa ");
How can I check the response from the form submission & use if condition based off that.

I think the problem is, that you want to do conditional testing. Using cy.wait() is bad practice and is even mentioned in the docs itself.
Anti-Pattern
You almost never need to wait for an arbitrary period of
time. There are always better ways to express this in Cypress.
You should not execute different actions upon response. In cypress testing it is expected, that you know the result of your action beforehand.
If user enters invalid email, you might expect form submisson to fail and an error to be displayed.
cy.get("#email-input").type('invalid_email.com');
cy.get("#password-input").type(userLoginDetail.password);
cy.get("form").submit();
cy.get(".email-error").should('be.visible');
In this case cypress will check them DOM until it finds the error or hits the defaultCommandTimeout from cypress config.
On the other hand, if you want to check if user is redirected correclty, you can simply check for a div on the success/redirected page.
cy.get("#email-input").type('valid#email.com');
cy.get("#password-input").type(userLoginDetail.password);
cy.get("form").submit();
cy.get(".success-page").should('be.visible');
However, if you still decide to execute an action depending on the servers response, cypress enables you to declaratively cy.wait() for requests and their responses.
cy.server()
cy.route({
method: 'POST',
url: '/myApi',
}).as('apiCheck')
cy.visit('/')
cy.wait('#apiCheck').then((xhr) => {
assert.isNotNull(xhr.response.body.data, 'api call successfull')
})

Related

Is there a way I can prevent downloads when testing with Cypress

I'm writing a simple test in Cypress which clicks a button and starts a download. The API's response contains the unformatted contents of the csv file, so I can use that to assert what I want - but the problem is that when you're using Chrome or Firefox to test with, the download still occurs. There is no dialogue prompt - the download happens on click - but I was wondering if maybe there was a way I could prevent it from happening, maybe with cy.window() or cy.stub()?
it('Export list to CSV', () => {
//Click button and assert on the API
cy.findByTestId('btnExport_SystemUsers')
.should('be.visible')
.click()
.wait('#exportToCsv')
.then((xhr) => {
//Assert on some keywords from the response such as Role names, user names, and site group name (that won't change)
expect(xhr.status).to.eq(200)
expect(xhr.response.body.csvFileData).to.contain('CY.User')
expect(xhr.response.body.csvFileData).to.contain('CY.Admin')
expect(xhr.response.body.csvFileData).to.contain('unlockUserAccount')
expect(xhr.response.body.csvFileData).to.contain('CY Administrator')
expect(xhr.response.body.csvFileData).to.contain('Site Group 1')
})
})
Thanks
If your server sends specific disposition headers which cause a browser to prompt for download, you can figure out what URL this request is made to, and use cy.request() to hit that directly. Then you can test that the server send the right response headers.
You can then intercept the response so it doesn't download via cy.intercept. See: https://docs.cypress.io/api/commands/intercept#Intercepted-responses
Reference: https://docs.cypress.io/faq/questions/using-cypress-faq#Is-there-a-way-to-test-that-a-file-got-downloaded-I-want-to-test-that-a-button-click-triggers-a-download

Simple form submission with Firebase; can I detect when offline?

I'm using Firebase perhaps slightly unconventionally -for simple form submission. Submission of my website's contact form simply results in:
ref.push({name:'dr foo', email:'1#2.com', message:'bar'}, myCallback);
The Firebase is hooked up to Zapier to send the site owner an email. All works well, but I'd like to be able to handle the user loosing their connection. When Firebase can't reach the server I'd like to display: "Please check your connection", or a similar message when the user hits the send button. The "Thanks, we'll be in touch"-type message should only be displayed on a successful write.
At first I tried including an if (error) branch in the callback, but of course disconnection is not something that Firebase considers an error as it "catches up" when it can.
I also tried the code in the docs which monitors .info/connected. While this wouldn't display a message on a form submission attempt, I was thinking I could instead display a warning if disconnected. The sample worked intermittently (Chrome 39, Firefox 30, Linux Mint), but the lag between disconnection and the event firing means it's probably not suitable for this case.
Is what I'm trying to do possible?
It indeed seems that the .info/connected values only changes once some other data transfer occurs (and fails).
The only way I can come up with is by using the transaction mechanism with applyLocally set to false. E.g.
function testOnlineStatus() {
var ref = new Firebase('https://your.firebaseio.com/');
ref.child('globalcounter').transaction(function(count) {
return (count || 0) + 1;
}, function(error, committed, snapshot) {
if (error) {
alert('Are you offline?');
}
}, false /* force roundtrip to server */);
}
setInterval(testOnlineStatus, 2000);
This one triggered for me after about 15 seconds.

Generate card_error in stripe.js while testing

I dont know this can be done or not, but i was wondering is there any way to generate card_error on stripe for testing?
To clarify my question here's what I want to do:
Stripe provides varieties of card numbers for testing purposes
(here). Along with this it also provides methods for form
validation(eg. I enter 34/2013 as expiry date and i'll get invalid
date error by validation then and there).
But i want to create a situation where a
user enters an expiry date which is a valid date (say 12/2015) but
its not the real expiry date of the card, so that on sending this
information to stripe, i recieve an error in json form named
card_error. (here)
How can this be done?
There are two approaches you could take to this.
You pass the stripe API call a callback function. This callback is the unit of code that you want to test with the card_error type of response
'test card_error is handled correctly': function() {
var response = {
type: 'card_error',
message: 'The human readable message',
code: 'invalid_cvc'
myStripeCallback(response)
// Make assertions down here about what happened when
// you called the function with the error message
// Maybe it emailed you, maybe it displayed a message
// to the user. I would then probably make another test
// for each `code` that I cared about.
}
The second approach would be to mock out the stripe api call entirely. Check that it was called with the right arguments and then call the provided callback with the error response that you wanted to deal with in that test.
Im sorry, turned out to be stripe already has special codes for this purpose. I over looked that part of the page despite going through the page several times.. stupid me! :-/
Anyways here are the codes:
source: https://stripe.com/docs/testing

Struggling to build a JS/PHP validation function for my app

I have a web service that returns a JSON object when the web service is queried and a match is found, an example of a successful return is below:
{"terms":[{"term":{"termName":"Focus Puller","definition":"A focus puller or 1st assistant camera..."}}]}
If the query does not produce a match it returns:
Errant query: SELECT termName, definition FROM terms WHERE termID = xxx
Now, when I access this through my Win 8 Metro app I parson the JSON notation object using the following code to get a JS object:
var searchTerm = JSON.parse(Result.responseText)
I then have code that processes searchTerm and binds the returned values to the app page control. If I enter in a successful query that finds match in the DB everything works great.
What I can't work out is a way of validating a bad query. I want to test the value that is returned by var searchTerm = JSON.parse(Result.responseText) and continue doing what I'm doing now if it is a successful result, but then handle the result differently on failure. What check should I make to test this? I am happy to implement additional validation either in my app or in the web service, any advice is appreciated.
Thanks!
There are a couple of different ways to approach this.
One approach would be to utilize the HTTP response headers to relay information about the query (i.e. HTTP 200 status for a found record, 404 for a record that is not found, 400 for a bad request, etc.). You could then inspect the response code to determine what you need to do. The pro of this approach is that this would not require any change to the response message format. The con might be that you then have to modify the headers being returned. This is more typical of the approach used with true RESTful services.
Another approach might be to return success/error messaging as part of the structured JSON response. Such that your JSON might look like:
{
"result":"found",
"message":
{
"terms":[{"term":{"termName":"Focus Puller","definition":"A focus puller or 1st assistant camera..."}}]}
}
}
You could obviously change the value of result in the data to return an error and place the error message in message.
The pros here is that you don't have to worry about header modification, and that your returned data would always be parse-able via JSON.parse(). The con is that now you have extra verbosity in your response messaging.

Paypal Embedded Flow not using returnUrl or cancelUrl

I am using Paypals Adaptive Payments and Embedded flow feature to provide checkout via a minibrowser. Everything seems to be working correctly in the sandbox environment except that when the payment is completed successfully, the user is never redirected to my returnUrl set in the PAY API request. Same goes for my cancelUrl.
After the payment is complete, the user is shown an order overview in the minibrowser and a button labelled "close". If a user clicks this button, the minibrowser is closed.
If a user clicks cancel at any time, the minibrowser is closed.
There doesn't seem to be a way to have my page aware of the change besides setting up some polling or something which doesn't make sense, my returnUrl and cancelUrl should be used somewhere, right?
this is my code to get the redirect url (using adaptive payments gem):
pay_request = PaypalAdaptive::Request.new
data = {
'requestEnvelope' => {'errorLanguage' => 'en_US'},
'currencyCode' => 'USD',
'receiverList' =>
{ 'receiver' => [
{'email' => '...', 'amount'=> 10.00}
]},
'actionType' => 'PAY',
'returnUrl' => 'http://www.example.com/paid',
'cancelUrl' => 'http://www.example.com/cancelled',
'ipnNotificationUrl' => 'http://www.example.com/ipn'
}
pay_response = pay_request.pay(data)
redirect_to pay_response.approve_paypal_payment_url "mini"
And here is how I am setting up the paypal js:
var dg = new PAYPAL.apps.DGFlowMini({ trigger: "buyit", expType: "mini" });
It all seems pretty straight forward, not sure what I am missing.
Well - seems to be a bug on our side - just tried it myself and confirmed with our integration teams. :-(
Unfortunately the other short term fix I can think of other than what you've mentioned (checking for the existence of the popup window) is to call the PaymentDetails API from your server side to check the status of the Payment. I've opened the bug on our side but don't have an ETA.
Edit 10/18: Sorry I'm wrong. This is working - it's just that our developer guide is not providing all the required information. In case of the mini-browser flow, you would need to provide a 'callbackFunction' and also name your dgFlow variable as 'dgFlowMini'. (the latter is important - as apdg.js is expecting the 'dgFlowMini' variable to be defined) Here is the code that works:
var returnFromPayPal = function(){
alert("Returned from PayPal");
// Here you would need to pass on the payKey to your server side handle to call the PaymentDetails API to make sure Payment has been successful or not
// based on the payment status- redirect to your success or cancel/failed urls
}
var dgFlowMini = new PAYPAL.apps.DGFlowMini({trigger: 'em_authz_button', expType: 'mini', callbackFunction: 'returnFromPayPal'});
I have a working sample here: https://pp-ap-sample.appspot.com/adaptivesample?action=pay (make sure you select mini as the Experience Type)
We will get our docs updated and also cleanup apdg.js to remove the dependency on the JS variable name.
Looks like the PayPal experience for embedded flows has gotten worse. Now you'll receive an error message after invoking mini or lightbox that says "Payment can't be completed. This feature is currently unavailable."

Categories