In Mocha, why do I want to use only()/skip()? - mocha.js

What is the point of only() and skip()? If I only want to have a single it/describe get executed, why should I keep the other things in the file? If I want to skip something, why shouldn't I just remove that code? When does one want to use those methods?

About only. Imagine that you have 2000 unit tests in some npm module. And you need write 3 more tests for new feature. So you create something.test.js file and write test cases with describe.only()
const assert = require('assert')
describe.only('sample class', () => {
it('constructor works', () => {
assert.deepEqual(true, true)
})
it('1st method works', () => {
assert.deepEqual(true, true)
})
it('2nd method works', () => {
assert.deepEqual(true, true)
})
})
Now if you launch test locally via npm test, you run only your 3 tests, not whole bunch of 2003 tests. Tests are written much faster with only
About skip. Imagine that you need to implement urgent feature in 20mins, you don't have enough time to write tests, but you have time to document your code. As we know unit tests are the best documentation, so you just write test cases how code should works with describe.skip()
describe.skip('urgent feature', () => {
it('should catch thrown error', () => {})
})
Now everyone in your team know about your new functionality and maybe someone write tests for you. Now the knowledge of how your new feature works is not only in your head, the whole team knows about it. It's good for the project and business.
more reasons to use skip

Related

How to programmatically stop a Cypress test

I have a Cypress test that has only one testing case (using v10.9 with the test GUI):
describe("Basic test", () => {
it.only("First test", () => {
cy.visit("http://localhost:9999");
cy.pause();
//if(cy.get("#importantBox").contains(...) {
//}
//else
{
Cypress.runner.stop();
console.log("Stopping...");
}
console.log("Visiting...");
cy.visit("http://localhost:9999/page1");
If a certain element doesn't exist in the page, I don't want the test to continue, so I try to stop it.
Unfortunately, I can see this in the console:
Stopping...
Visiting...
And the test keeps going without the necessary data...
So, can I somehow stop it without using huge if statements?
Stopping the test is relatively easy, the harder part is the condition check.
Cypress runner is built on the Mocha framework, which has a .skip() method. If you issue it in your else clause and inside the Cypress queue, the test will stop.
Two ways to access skip():
Using a function() callback gives access to this which is the Mocha context
it('stops on skip', function() {
...
cy.then(() => this.skip()) // stop here
})
Use cy.state() internal command (may be removed at some point)
it('stops on skip', () => {
...
cy.then(() => cy.state('test').skip()) // stop here
})
You should be aware that all Cypress commands and queries run on an internal queue which is asynchronous to javascript code in the test like console.log("Visiting..."), so you won't get any useful indication from that line.
To use synchronous javascript on the queue, wrap it in a cy.then() command as shown above with the skip() method, so to console log do
cy.then(() => console.log("Visiting..."))

How to stop a Cypress test but mark it as a success?

I have a Cypress test that clicks a link which runs a method and then brings the user to a new page on different website entirely.
This is the test:
it('Cards', () => {
cy.get('#my-id').click({ force: true })
var itemID= localStorage.getItem('itemID')
expect(itemID).to.eq(null);
cy.get(`a:visible[id*="the_link"]`).first().click()
Cypress.on('fail', (error, runnable) => {
var itemID= localStorage.getItem('itemID')
expect(itemID).to.not.equal(null)
// end test but mark as a success
})
})
The problem is that I get a cross origin error, therefore I added in the Cypress.on('fail') piece of code. So now, the test does not fail but it waits for minutes because it attempting to intercept more data. There is a lot of other stuff going on so I cannot change the intercept logic.
All I want is to end the test and mark it a success on the line that says // end test but mark as a success.
Is this possible?
If you are using chrome based browsers you might wanna try setting chromeWebSecurity to false.
Other browsers (specifically Firefox) might still run into that issue, to which you might wanna properly address the on failure method or split the interaction with another origin to another it statement. The later is pretty simple and should work on all browsers:
it('Cards', () => {
cy.get('#my-id').click({ force: true })
}) //if that gets you to another superdomain, we go to another it
it('Another superdomain', () => {
var itemID= localStorage.getItem('itemID')
expect(itemID).to.eq(null);
cy.get(`a:visible[id*="the_link"]`).first().click()
}) If that is yet another superdomain, we go to another it again
it('Third superdomain', () => {
var itemID= localStorage.getItem('itemID')
expect(itemID).to.not.equal(null)
// test ends by itself
})
The way you describe on failure method, you just provide additional functionality for the failure but do not instruct the method to ignore the test status finalisation.
That can be done by returning false on that specific event:
Cypress.on('fail', () => false);
Mind that you can probably include an assertion before returning false if it is really required.
Cypress.on('fail', () => { // no params are needed tho
var itemID= localStorage.getItem('itemID')
expect(itemID).to.not.equal(null)
// end test but mark as a success
return false
})
That piece of code must be provided right before the potential failure event. This will interrupt the test as it will fail but will mark it as passed.
This is a huge anti-pattern and generalisation, as you use a Cypress.on('fail', ()) event. Better way is to anchor any sort of negative logic to a more specific event, one of those listed here. However, that specific hack above might work for avoiding cross origin error on non-chrome-based browsers if it is for sure the last thing that happens in that test.

is there an equivalent to cypress the dependsonmethods in testNG selenium?

Is there as simple as dependsonmethods used in test annotations in testNG equivalent in cypress?
example if in selenium test annotations it looks like this?
#Test()
public void tc1(){
}
#Test(dependsOnMethods= {"tc1"})
public void tc2(){
}
#Test(dependsOnMethods= {"tc1"})
public void tc3(){
}
if I am not mistaken this is somewhat like a parent function with 2 child functions that when the parent conditions inside is error then the two child functions will be skip.
in cypress I know there is callbacks and promise but depending on the kind of assertion you want it becomes more complex to me. I am new to cypress
please let me know if not too much to ask, can you at least provide an example
thanks
Cypress doesn't have dependsOnMethods like TestNG runner provides as both of them are different. But whatever you want to achieve, you can achieve through hooks provided by Mocha, as Cypress has Mocha as a test framework in itself.
Note: This is what all you can do with hooks and your problem should be solved with below code. If you have any specific requirement, please mention it.
describe('test suite', () => {
before(() => {})
beforeEach(() => { // put tc1() functionality
})
it('tc2 functionality', () => {
// now tc2() depends on beforeEach block where tc1 functionality is done
})
it('tc3 functionality', () => {
// now tc3() depends on beforeEach block where tc1 functionality is done
})
})

How to stub Fluture?

Background
I am trying to convert a code snippet from good old Promises into something using Flutures and Sanctuary:
https://codesandbox.io/embed/q3z3p17rpj?codemirror=1
Problem
Now, usually, using Promises, I can uses a library like sinonjs to stub the promises, i.e. to fake their results, force to resolve, to reject, ect.
This is fundamental, as it helps one test several branch directions and make sure everything works as is supposed to.
With Flutures however, it is different. One cannot simply stub a Fluture and I didn't find any sinon-esque libraries that could help either.
Questions
How do you stub Flutures ?
Is there any specific recommendation to doing TDD with Flutures/Sanctuary?
I'm not sure, but those Flutures (this name! ... nevermind, API looks cool) are plain objects, just like promises. They only have more elaborate API and different behavior.
Moreover, you can easily create "mock" flutures with Future.of, Future.reject instead of doing some real API calls.
Yes, sinon contains sugar helpers like resolves, rejects but they are just wrappers that can be implemented with callsFake.
So, you can easily create stub that creates fluture like this.
someApi.someFun = sinon.stub().callsFake((arg) => {
assert.equals(arg, 'spam');
return Future.of('bar');
});
Then you can test it like any other API.
The only problem is "asynchronicity", but that can be solved like proposed below.
// with async/await
it('spams with async', async () => {
const result = await someApi.someFun('spam).promise();
assert.equals(result, 'bar');
});
// or leveraging mocha's ability to wait for returned thenables
it('spams', async () => {
return someApi.someFun('spam)
.fork(
(result) => { assert.equals(result, 'bar');},
(error) => { /* ???? */ }
)
.promise();
});
As Zbigniew suggested, Future.of and Future.reject are great candidates for mocking using plain old javascript or whatever tools or framework you like.
To answer part 2 of your question, any specific recommendations how to do TDD with Fluture. There is of course not the one true way it should be done. However I do recommend you invest a little time in readability and ease of writing tests if you plan on using Futures all across your application.
This applies to anything you frequently include in tests though, not just Futures.
The idea is that when you are skimming over test cases, you will see developer intention, rather than boilerplate to get your tests to do what you need them to.
In my case I use mocha & chai in the BDD style (given when then).
And for readability I created these helper functions.
const {expect} = require('chai');
exports.expectRejection = (f, onReject) =>
f.fork(
onReject,
value => expect.fail(
`Expected Future to reject, but was ` +
`resolved with value: ${value}`
)
);
exports.expectResolve = (f, onResolve) =>
f.fork(
error => expect.fail(
`Expected Future to resolve, but was ` +
`rejected with value: ${error}`
),
onResolve
);
As you can see, nothing magical going on, I simply fail the unexpected result and let you handle the expected path, to do more assertions with that.
Now some tests would look like this:
const Future = require('fluture');
const {expect} = require('chai');
const {expectRejection, expectResolve} = require('../util/futures');
describe('Resolving function', () => {
it('should resolve with the given value', done => {
// Given
const value = 42;
// When
const f = Future.of(value);
// Then
expectResolve(f, out => {
expect(out).to.equal(value);
done();
});
});
});
describe('Rejecting function', () => {
it('should reject with the given value', done => {
// Given
const value = 666;
// When
const f = Future.of(value);
// Then
expectRejection(f, out => {
expect(out).to.equal(value);
done();
});
});
});
And running should give one pass and one failure.
✓ Resolving function should resolve with the given value: 1ms
1) Rejecting function should reject with the given value
1 passing (6ms)
1 failing
1) Rejecting function
should reject with the given value:
AssertionError: Expected Future to reject, but was resolved with value: 666
Do keep in mind that this should be treated as asynchronous code. Which is why I always accept the done function as an argument in it() and call it at the end of my expected results. Alternatively you could change the helper functions to return a promise and let mocha handle that.

Numerate jasmine tests

Is there a way to automatically numerate "its"/"describes" in Jasmine tests?
It's really confusing when you need to include a lot of tests scripts (200+) and run them all at once from the same file.
And I'm trying to avoid manual numeration, for the obvious reasons.
Thank you in advance.
I'm using a variable and incrementing it inside "it" description:
describe('EntityInfoComponent', () => {
let testNum = 1;
it('should be initialized #' + testNum++, () => {
...
});
it('should call service and show the results #' + testNum++, () => {
...
});
});
Not a great method but it works. I've tried to inserting it on beforeEach() and afterEach() but it seems to be executed inside each iteration function code.
My answer has come 4 years later to this ask but I hope It'll be useful for future searches at least.

Resources