Cypress async issue - reactjs

I have a situation in my test where I click a button and it makes an apollo graphQL call in my reactJS side.
createProductCategory({
variables: {
restaurantID: props.restaurant.id,
name: name
}
});
This is how it looks like in the ReactJS side. This createProductCategory method returns a promise which we wait for and continue with the rest of the code.
This works perfectly fine when I click on the button manually. I can see the graphQL call being made in the network tab and it works perfectly fine. However, if I try to get cypress to click on the button, I can see the button gets clicked, but the graphQL call never gets made. I just cannot understand why it doesn't work and what I am doing wrong.
Can someone please help me out with this. I tried putting wait statements everywhere but it just doesnt "wait" for the promise in the reactJS side to be resolved.
cy.contains("Save")
.click()
.then(() => {
cy.wait(2000)
});
cy.wait(2000)
Thanks for the help in advance.

From what you are describing you should have code that surrounds the button click and waits for the graphql call to complete like so
cy.server()
cy.route('/graphql').as('graphql')
cy.get('buton').contains('abc').click()
cy.wait('#graphql')
More info: alias waits

Related

How can I fix the Axios get request and the React Hooks?

Details about my goal:
I want to create a React App with Material UI that detects gender on the basis of your name.
Summary of the problem:
I am not getting back the result for the name that is entered into the input field
Expected Result:
{name: "Alice" gender: "female", probability: 0.83, count: 3387}
Actual Result:
null
undefined
{data: "Data was undefined"}
Useful resources for this issue:
This is the link to the CodeSandBox for this problem: click here --see what I have tried
Gender.io API link (I used this API to detect gender): click here
Material UI for React: click here
I think your code is a little over-engineered, and doesn't properly handle the asynchronous nature of the request.
What I typically do is return the fetch or axios object so that the calling component can wait for the response and handle it when it's ready.
Forked example
As you can see, I've removed a couple of pieces from your Container.jsx component (which might need a different name fwiw).
Instead of setting a flag for the form being ready to submit, I just have the button directly calling the fetchNameData function.
The checkGender function from your utilities function now directly returns the axios object, which is a promise. The fetchNameData function is async so it can wait for the results from this promise.
The code works fine, if the name starts with a lowercase, it will throw an error, so what you can do is capitalize the first letter of the user input

Clicking a reach dropdown in testcafe

I'm using testcafe in a React app and I'm having some trouble with making testcafe click a dropdown option from a Reach dropdown menu.
I can access the option with Selector after triggering a click on the button that activates the dropdown menu, but clicking the desired option doesn't seem to do anything at all.
However, the action is triggered if I reach the option via keys.
//This works
await t
.click('[testid="menuButton"]')
.pressKey('down')
.pressKey('down')
.pressKey('enter');
//This doesn't
await t
.click('[testid="menuButton"]')
.click('[data-reach-menu-item]:nth-of-type(3)');
I made sure that the selection is made properly in the second case, so that doesn't seem to be the problem.
Any thoughts?
Thanks!
This test is successfully executed on my side:
import { Selector } from 'testcafe';
fixture `fixture 1`
.page `https://reacttraining.com/reach-ui/menu-button/`
test('test', async t => {
await t
.click('[data-reach-menu-button]')
.click('[data-reach-menu-item]:nth-of-type(3)');
})
Perhaps there is more than one menu button on your page, so the '[data-reach-menu-item]:nth-of-type(3)' selector points to an invisible item. To check this, insert .debug() after .click('[testid="menuButton"]') in you code:
await t
.click('[testid="menuButton"]')
.debug()
.click('[data-reach-menu-item]:nth-of-type(3)');
After the test code stops at debug(), open the browser's development console, execute the document.querySelectorAll('[data-reach-menu-item]:nth-of-type(3)') command, and check if the first returned node matches the third element in the menu's dropdown.

ReactJS Function Components object updates on second time

I have a login page(Functional Component), When a user tries to login without entering the required fields, I have to show the error message(ex:"Email is required"). When an invalid field exists, I shouldn't make the API call.
But, without entering fields, when I click on login button, API call is done. Again clicking on login button stops the API call.
I have made this demo - https://stackblitz.com/edit/react-pd6vvk?file=login.js which explains the issue.
Steps to follow:
1.Click on login without filling any text values. You can see "API request made" statement when fields are invalid.
2.Again click on login button, "API Request stopped" statement is displayed now.
I am new to React and I don't know, the reason and the solution to fix this issue.
Can somebody please help me out?
Thank you,
Abhilash
Because, setValidFields has async behaviour :
validateLoginForm(); //<--- inside this setValidFieldsis async
console.log(validFields);
if (isFormValid()) { //<---- so,this will still have true value ( means not updated )
// inside validateLoginForm()
// this state change won,t be reflected immediately
setValidFields(validFields => ({
...validFields,
[key]: error.length == 0
}));
I have made few changes as per your code structure, as long as I know you will need useEffect also as shown in working demo.
WORKING DEMO

Test fails because AngularJS has not initialized in time

I'm trying out TestCafe for an AngularJS (v1.6) application.
I have a button then when clicked, opens a modal (from UI bootstrap). This works fine when I try myself in Chrome.
<button class="btn" ng-click="open()">Open</button>
Our application requires user authentication, and the login page is not Angular-based. That phase of my test works fine.
However, when the actual test runs, it "clicks" the button but nothing happens.
I suspect, but can't prove, that it's clicked before AngularJS has properly initialized on the page.
With some research, I found the testcafe-angular-selectors project and a waitForAngular method but that appears to apply only to Angular2+.
import { Role, Selector } from 'testcafe';
const regularAccUser = Role('http://127.0.0.1:8080', async t => {
await t
.typeText('[name=username]', 'abc')
.typeText('[name=password]', '123')
.click('.btn-primary');
});
fixture`Characters Modal`;
test('modal title', async t => {
await t
.useRole(regularAccUser)
.navigateTo('http://127.0.0.1:8080/fake/page')
.click('.btn')
.expect(Selector('.modal-title').innerText).eql('Insert Symbol');
});
Adding .wait(1000) before the click solves the issue. It's not waiting for Angular to load. I'd rather not have waits in every test - is there some other technique I can use?
You can use TestCafe assertions as a mechanism to wait until an element is ready before acting on it.
A typical waiting mechanism would be:
const button = Selector('button.btn')
.with({visibilityCheck: true});
await t
.expect(button.exists) // wait until component is mounted in DOM
.ok({timeout: 10000}) // wait enough time
.hover(button) // move TestCafe cursor over the component
.expect(button.hasAttribute('disabled'))
.notOk({timeout: 10000}) // wait until the button is enabled
.click(button); // now we are sure the button is there and is clickable
This article may also help you in managing all those waiting mechanisms.
As you correctly mentioned, the waitForAngular method is intended for Angular only, not for AngularJS.
I recommend you create your own waitForAngularJS function and call it on the beforeEach hook and after the role was initialized.
In the simplest case, it can be implemented as follows:
function waitForAngularJS (t) {
await t.wait(1000);
}
fixture `App tests`
.page('page with angularjs')
.beforeEach(async t => {
await waitForAngularJS(t);
});
However, the use of the wait method is not a solid solution. I recommend you find a way to detect if AngularJS is loaded on a page on the client side. If it is possible, you can implement the waitForAngularJS method using the TestCafe ClientFunctions mechanism.
This post can be usefulĀ as well: How to check if angular is loaded correctly

Clicking navigation button in Puppeteer returns null response? How to see which function is being clicked?

I'm trying to test clicking a button on a registration app to make sure that the page correctly navigates to the right page.
When I console.log out response in the code it returns an array that looks like this
[undefined, null]
However when I take a screenshot of the page or check the url, the click and navigation worked. It is on the correct page.
I don't understand why this is returning undefined/null. Also, I could not figure out how to test which function was being called when you click on the button.
I wanted to be able to see the actual function that is being called.
I'm using AngularJS 1.6, Mocha, Puppeteer 1.11, and Node 6.4.0
I'm also a junior dev so it could be something simple that I just didn't understand, please help!
it('should rederict to guest_sms_code state when clicking \'I have a guest code\'', async (function () {
var response = await (Promise.all([
page.waitForNavigation({waitUntil: 'domcontentloaded'}),
page.click('[ng-click="enterSmsCode()"]'),
]));
var url = await (page.url());
if (url.indexOf('guest_sms_code') === -1) {
assert.ok(false, 'The URL does not contain \'guest_sms_code\'')
}
}))
I'm not convinced that you can tell which method is called from a UI test. That's something that a JavaScript unit test can prove using, say, something like Mocha or Jest to test your codes behaviour. However an automated UI test, from my experience, won't tell you that. After all, you're trying to hide the inner workings of your app from an external user, right?
As for why the Promise.all([]) call is returning [undefined, null], well I can at least help you with that.
Firstly, you should have a look at the API documentation for both methods you've invoked in your test:
waitForNavigation docs: https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pagewaitfornavigationoptions
click docs: https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pageclickselector-options
In the case of waitForNavigation the response actually returns a Promise which may or may not have a Response value. Whether any data is returned with that Response is dependent on the navigation that occurs in the UI. In your case, you're seeing that undefined value in your array to indicate that there has not been any Response data returned from the navigation.
For the click method, this also just returns a resolved or rejected Promise with no data of any kind returned. So, naturally, you've no actual value returned here at all hence the null value being pushed to the array.

Resources