When a certain UI bug appears, an alert pops up with an error message. I fixed that bug, and now I want to write a Cypress test.
How do I write a Cypress test that passes if the alert does not appear?
I realize that I must be careful with negative assertions, so I'll want to make the test as robust as I can.
Related post:
Cypress: Test if element does not exist
How do I write a Cypress test that passes if the alert does not appear?
Spy on the window:alert event.
Wait a few seconds to give the alert time to appear.
Use a positive assertion to make sure the spy is what you're expecting.
Assert that the spy isn't called.
// Typing enter should not produce an alert
let spy = cy.spy(window, 'alert');
cy.get('input[name="MyField"]')
.type('{enter}')
.wait(4000)
.then(() => {
expect(spy).to.haveOwnProperty('callCount');
expect(spy).to.not.be.called;
});
Also make a positive assertion for whatever is supposed to happen when the bug is fixed.
Related
Is there a difference between
expect(screen.queryByText('<something>')).toBeInTheDocument();
And
screen.getByText('<something>');
(The specific getBy* and queryBy* operation are not relevant)
In react-testing-library?
getByText tries to find the node and throws an error when it is not able to find it. This will cause the test to fail immediately.
queryByText on the other hand will return null if it is unable to find the node.
Let's suppose you have text <something> in the component that was rendered, you can assert if it has been rendered or not.
If sure that the text has been rendered, then you can simply use getByText
expect(screen.getByText('<something>')).toBeInTheDocument();
and the test would pass.
If for the scenario the text did not render then the above assertion will thrown an error and fail the test case.
In such cases queryByText text makes the most sense
When has not been rendered
expect(screen.getByText('<something>')).not.toBeInTheDocument(); // throws an error
expect(screen.queryByText('<something>')).not.toBeInTheDocument(); // asserts as true
Output comparison
I am testing a web app that renders some of its errors as HTML and gives no other indication that a problem occurred. After every click, I would like to see if a .error element exists.
I know I could manually add this after every click, but it's going to obfuscate my test and it will be easy to forget some instances. Is there a way to tell testcafe that a certain condition should make the test fail, even if I'm not explicitly checking for it?
I did something like this:
const scriptContent = `
window.addEventListener('click', function () {
if($('.error').length > 0) {
throw new Error($('.error').text());
}
});
`;
fixture`Main test`
.page`../../dist/index.html`.clientScripts(
{ content: scriptContent }
);
This injects a script onto the page I am testing. After every click, it uses jQuery to see if an error class exists. If it does, it throws an error on the page I'm testing. Testcafe reports the message of that error.
I'm hoping there's a better way.
I was making a spec file to test my forms in Cypress when suddenly this pops out:
TypeError: form.submit is not a function
: __cypress/runner/cypress_runner.js:67597:14
This is the code:
cy.get(form).within(($form) => {
cy.root().submit();
});
You can clearly see the part that causes the error is the cy.root().submit(); line.
but then when I check the element on the console, this comes out:
root output on console
So, it's a form!
I've got the code from here https://docs.cypress.io/api/commands/within.html#Forms
Screenshot of the run:
Run test
What am I missing? Am i missing some dependency maybe?
PD: I am using chrome 79
You need to put the wait also before the form submit (the route could still in progress without that).
(You probably can delete then the second wait)
Edit:
cy.server();
cy.route(formRequest.method, formRequest.url).as('form-submit');
cy.wait('#form-submit').its('status').should('eq', 200);
cy.root().submit();
Here's my HTML, which is present and valid. When I break on the testcases using WebStorm, I can inspect the page and see this element just fine...
<a id="privacyPolicy1234" on-tap="goPrivacyPolicy()" class="disable-user-behavior">Privacy Policy</a>
Here is my Jasmine test, which is failing to find the element.
it("should list a privacyPolicy ", function() {
privacyPolicyElement = element(by.id('privacyPolicy1234'));
expect(privacyPolicyElement.getText()).toContain("Privacy Policy");
The error coming back
Message:
NoSuchElementError: No element found using locator: By.id("privacyPolicy1234")
edit:
Also tried to put it in one line, and getting false where I expect true
expect(element(by.id('privacyPolicy1234')).isPresent()).toBe(true);
Instead of a browser.sleep() which makes the test non-reliable and slower, use an explicit wait. For instance, you can wait for the "privacy policy" element to become present:
var EC = protractor.ExpectedConditions,
privacyPolicyElement = element(by.id('privacyPolicy1234'));
browser.wait(EC.presenceOf(privacyPolicyElement), 5000);
expect(privacyPolicyElement.getText()).toContain("Privacy Policy");
It's important to note that in this case protractor would wait up to 5 seconds, checking the presence of the element every 500 ms (by default). Once the condition is met, it stops waiting. If after 5 seconds, the element would still not become present - you'll get a timeout exception.
Turns out, I'm testing the page before it loads..
as a work around I added
it("should list a privacyPolicy ", function() {
browser.sleep(2000);
privacyPolicyElement = element(by.id('privacyPolicy1234'));
Is there a way to get QUnit.js to not run the remaining tests after a single one fails?
Using the following code as an example:
QUnit.test('test1', function(assert) {
assert.equal(1,1);
assert.equal(1,2);
assert.equal(3,3);
});
QUnit.test('test2', function(assert) {
assert.equal(4,4);
assert.equal(5,5);
assert.equal(6,6);
});
Is there some way to get QUnit to stop executing after the assert.equal(1,2)? This means that test2 should never be run.
The best way to stop QUnit after test case fail will be
QUnit.testDone( function( details ) {
if (details.failed>0){
QUnit.config.queue.length = 0;
}
});
Okay, based on my comments above I ran the code below and things to stop as I think you want them to. Again, as I said in the comments, I would really investigate whether this is a good idea. Generally you want your tests to be idempotent such that any one failure does not affect any other test.
Note that we have to set the reorder config option to false here, otherwise QUnit will attempt to run the previously failed test first to "short circuit" things, but you don't want that I'm guessing. I also added a "test0" just to see the fill effect.
QUnit.config.reorder = false;
// This is how we detect the failure and cancel the rest of the tests...
QUnit.testDone(function(details) {
console.log(details);
if (details.name === 'test1' && details.failed) {
throw new Error('Cannot proceed because of failure in test1!');
}
});
QUnit.test('test0', function(assert) {
assert.equal(1,1);
assert.equal(2,2);
assert.equal(3,3);
});
QUnit.test('test1', function(assert) {
assert.equal(1,1);
assert.equal(1,2);
assert.equal(3,3);
});
QUnit.test('test2', function(assert) {
assert.equal(4,4);
assert.equal(5,5);
assert.equal(6,6);
});
You won't get any visual feedback that the tests were canceled because this isn't really interacting with the QUnit UI. However, because we threw an Error object you can open the developer console and see the output there: