I am using Effect Hook and want to confirm if this implementation is correct. I am not getting any warning in the console but I want to know why this is not going into an infinite loop?
React.useEffect(() => {
setSelections(inputUPC, false);
//console.log(props.uncheckCard);
props.setUncheckCard(false);
}, [props.uncheckCard]);
It's not going into infinite loop because you only set this to false so there is no change in parameter (useEffect only trigger on dependencies values change)
Related
https://docs.cypress.io/api/commands/wait - cy.wait() is used to wait for an arbitrary number of milliseconds.
What's the difference in the following two snippets
// snippet-1
cy.wait(10*1000);
// other code
// snippet - 2
cy.wait(10*1000).then(()=>{
// other code
})
I tried to run the following code to test how it is working and i got the output mentioned in the below image.
cy.wait(10 * 1000).then(() =>
cy.log("This is inside wait()" + new Date().toLocaleTimeString())
);
cy.log("This is after wait()" + new Date().toLocaleTimeString());
These are the log results:
From the above image, it looks like we should add our code inside .then because that will be executed after cy.wait . I also have seen people writing their test cases just like snippet-1
Which one is correct and which one we should use?
If you want a better log, use a custom command to make a version that defers evaluating the value.
By providing a callback, the new Date().toLocaleTimeString() expression evaluates when you expect it to.
Cypress.Commands.add('logLazy', (thingToLog) => {
if (typeof thingToLog === 'function') {
cy.log(thingToLog())
} else {
cy.log(thingToLog)
}
})
cy.wait(3_000).then(() =>
cy.log("This is inside wait()" + new Date().toLocaleTimeString())
);
cy.log("This is after wait()" + new Date().toLocaleTimeString());
cy.wait(3_000).then(() =>
cy.logLazy("This is LAZY LOG inside wait()" + new Date().toLocaleTimeString())
);
cy.logLazy(() => "This is LAZY LOG after wait()" + new Date().toLocaleTimeString());
Cypress commands use the current value of variables and resolve function values when enqueuing commands. So, in your example, the commands are enqueued as .wait() and then the outer .log(). The value of the date string is calculated when the command is enqueued. The inner .log() is enqueued within the .then(), and thus has a later date string.
Either snippet is fine to use, but be aware of how the subsequent commands in your test will react. Are you manipulating some variable during your .wait(), and you would not want the original value to be used for your Cypress command? Probably a good idea to place that command within a .then() or some other Cypress command. Are you just interacting with the website and need to wait 10 seconds? You probably don't need to worry about placing commands inside .then().
I was trying to automate a text submit form using cypress. The 'Create student' button is disabled even after all the fields have been filled
Please see the cypress error
code :
it('should be able to add a new student and update the details, remove from the class and delete the account', function () {
cy.visit(
'https://readingeggs.blake-staging.com/district_ui#/reading/manage-schools/students/195286/new'
)
cy.findByLabelText('First Name').type('ark')
cy.get('#first-name').should('have.value', 'ark')
cy.findByLabelText('Last Name').type('last')
cy.get('#last-name').should('have.value', 'last')
cy.get('[data-test-select-grade]').select('1')
cy.get('#grade-dropdown').should('have.value', '1')
cy.get('[data-test-select-teacher]').select('Lehner, Abbey')
cy.get('#teacher-dropdown').should('have.value', '3068134')
cy.get('[data-test-submit-new-student]').click()
cy.get('#main')
.findByRole('alert')
.should('include.text', `Successfully created a student`)
})
})
Be careful using click({force:true}) as suggested in the error message, there may be another problem that your test will now ignore!
You can first try an assertion that the button is not disabled.
Sometimes the test can run too quickly, and the web page has not yet enabled the button before the test tries to click it.
Adding .should('not.be.disabled') will retry this check for up to 4 seconds, which should be enough time for the page to complete changes.
cy.get('[data-test-submit-new-student]')
.should('not.be.disabled')
.click()
If using .should('not.be.disabled') does not work (I agree, it should be the first thing to try), try adding a trigger event to each input - in case the .type() command is not triggering the validation change.
cy.findByLabelText('First Name').type('ark').trigger('change')
cy.get('#first-name').should('have.value', 'ark')
cy.findByLabelText('Last Name').type('last').trigger('change')
cy.get('#last-name').should('have.value', 'last')
cy.get('[data-test-select-grade]').select('1').trigger('change')
cy.get('#grade-dropdown').should('have.value', '1')
cy.get('[data-test-select-teacher]').select('Lehner, Abbey').trigger('change')
cy.get('#teacher-dropdown').should('have.value', '3068134')
cy.get('[data-test-submit-new-student]').click()
If still no joy, use .click({force:true})
By the way, cy.get('[data-test-select-grade]').select('1') looks a bit suspicious. The select command can take a display value as a string or a position value as a number. The screenshot shows "K" is selected, so I would expect either of these to work
cy.get('[data-test-select-grade]').select(1) // number passed
// or
cy.get('[data-test-select-grade]').select('K') // string passed
One option would be to use {force: true} with click().
it('should be able to add a new student and update the details, remove from the class and delete the account', function () {
cy.visit(
'https://readingeggs.blake-staging.com/district_ui#/reading/manage-schools/students/195286/new'
)
cy.findByLabelText('First Name').type('ark')
cy.get('#first-name').should('have.value', 'ark')
cy.findByLabelText('Last Name').type('last')
cy.get('#last-name').should('have.value', 'last')
cy.get('[data-test-select-grade]').select('1')
cy.get('#grade-dropdown').should('have.value', '1')
cy.get('[data-test-select-teacher]').select('Lehner, Abbey')
cy.get('#teacher-dropdown').should('have.value', '3068134')
cy.get('[data-test-submit-new-student]').click({force: true})
cy.get('#main')
.findByRole('alert')
.should('include.text', 'Successfully created a student')
})
Among many, One of my test looks like
it("Admin is able to edit new group", () => {
cy.intercept("PUT", /\/api\/groups/).as("editGroupAPI");
cy.get("#groups").then(groups => {
const group = groups[0];
// go to edit page cancel and come back to groups page
app.groupsPage.card
.groupActionIcon(group.name, "modify")
.scrollIntoView()
.click();
app.commonElements
.toolBarTitle()
.should("have.text", "Edit Group");
app.groupsPage.groupDetailsForm.cancelButton().click();
app.commonElements.toolBarTitle().should("have.text", "Groups");
// edit group - 1
app.groupsPage.card
.groupActionIcon(group.name, "modify")
.scrollIntoView()
.click();
app.groupsPage.groupDetailsForm
.groupDescription()
.type(" edited");
app.groupsPage.groupDetailsForm.saveButton().click();
cy.wait("#editGroupAPI");
// validate that Groups page have loaded
app.commonElements.toolBarTitle().should("have.text", "Groups");
// validate whether group card description is reflected on card
app.groupsPage.card
.groupDescription(group.name)
.should("have.text", group.description + " edited");
});
});
app is top level parent obj, and this test uses Page Object Model.
One example of POM class is :
class CommonElements {
burgerMenu() {
return cy.get("#widgets-banner-appBanner-sideDrawerButton-content");
}
toolBarTitle() {
return cy.get("h1.app-toolbar__title__main-title");
}
toolBarTitleWithText(text) {
return cy.contains("h1.app-toolbar__title__main-title", text);
}
globalScopeButton() {
return cy.get("#global-scope-switch-toggleSwitch-button");
}
}
So as it is evident that, cy.wait() and then call to pageObjectModel function to grab title element:
cy.wait("#editGroupAPI");
// validate that Groups page have loaded
app.commonElements.toolBarTitle().should("have.text", "Groups");
Now sometimes this fails, so as I have seen in docs, plain js code get executed immediately, but since in this case whole test is wrapped in cy.get("alias"), will it still matter (or execute js immediately)?
This might sound very obvious, but I just want to confirm.
Final question: does mix usage of Page Object Model functions and cy.command contribute to test flakiness?
Short answer: no, mixing Cypress commands with Page Object model functions does not itself contribute to test flakiness.
Explanation: a Cypress command is never executed immediately. It does not matter if a Cypress command is called in any 'external' function (including a POM function) or directly in a test case function. Either way, Cypress commands are only enqueued when statements of a function are executed. And they later will be executed in the same order regardless whether they defined inside 'external' function or test case one.
This is also true for a command that was called inside a cypress synchronous block of code (in a then/should callback). Even in this case the command will not be executed immediately.
In a nutshell, using a POM function to call a Cypress command does not influence on how and when this command is executed and so using POM approach can not itself contribute to any test flakiness.
You can play and see the order of command execution using such a script:
You can either open Dev console to see the console output or use breakpoints to see the execution live.
The gif above shows the debugging directly from IDE (IntelliJ) using the Cypress Support Pro plugin
I want an observable to be delayed depending on its value. For example:
of(someBool).pipe(delay(1000))
skip delay when someBool is false, but wait a sec when it's true.
You can use delayWhen for that:
of(someBool).pipe(
delayWhen(val => val ? interval(1000) : of(undefined))
)
Side note, according to the docs using empty() instead of of() should IMHO work, but doesn't appear to. I believe this might be a bug. I have reported it.
Example. Suppose you are implementing a login page and you want to wait until you get some token to put it in another Observable or Cookies. Then you can wait a value of your Observable (someBool here I used this.authService.isLoggedIn). So you can do something like this:
return this.authService.isLoggedIn
.pipe(
delayWhen(loggedIn => loggedIn ? interval(0) : interval(10000)),
);
And when a state of isLoggedIn is changed a user will be logged in.
Note: In future versions, empty notifiers will no longer re-emit the source value on the output observable.
someBool$.pipe(
delayWhen(val => val ? timer(1000) : timer(0))
)
I want to wait for an element to be visible, and if it is do X without erroring it out. I trying using the nightwatch.js waitForElementVisible but that errors out if the element is not visible. What should I do?
waitForElementVisible takes a param abortOnFailure to control if command should fail or not
http://nightwatchjs.org/api#waitForElementVisible
Possible workaround is to use the function below, but the drawback is that we are setting static timeout,
client.pause(1500).element('css selector', '.css_selector', result => {
if (result.status > -1) {
browser.expect.element('.element_to_check').text.to.contain('YES')
}
})
This way nigtwatch will check your element and won't throw an error if it's not in DOM.