Cypress test organization - e2e-testing

I have a question about Cypress test organization.
I wanted to have your feedback on how you divide your tests ?
When you define a test with
it("", function() {})
how much do you test ? Do you limit yourself in assertions ?
I have a dataroom that in which two users can interract. One user can upload files and chat with the other, and the user 2 can only upload the files and chat.
What I need to test is :
List item
Upload of a document by user #1
Removing a document by user #1
Assert that chat gets automatic messages about the file uploaded and deleted
user #2 can upload documents
user #2 can close the dataroom and reopen it
...
The question I'm asking myself is about the number of test I should have.
Should I have one that runs the whole scenario ?
Should I have one for each test I want to make
Should I have multiple grouping by user
...
If you have any suggestions on how you organize your test, I would be happy to hear them !

I like to divide my tests in separate subjects and scenario's. So a definition-file contains only 1 subject, and it contains an it per scenario. This way it is possible to have a failing scenario, without blocking all other scenario's.
For example, if you have a house I would separate them like this:
describe ('Living room', function (){
it('Should have a couch', function(){
// do checks for the couch
})
it('Should have a media table', function (){
// do checks for the media table
})
})
describe ('Kitchen', function (){
it('Should have a stove', function(){
// do checks for the stove
})
it('Should have a kitchen table', function (){
// do checks for the kitchen table
})
})
describe ('Bathroom', function (){
it('Should have a shower', function(){
// do checks for the shower
})
it('Should have a sink', function (){
// do checks for the sink
})
})

Related

How to stop jest describe without throw all the test

I want to stop a whole describe of JEST without throwing an error or stoping the other describes.
Im writing e2e test for my app with JEST and PUPPETEER, I write the test in a way every DESCRIBE its a flow of the path and every IT its a step, inside a IT I want to stop the flow if the pages dont match some conditions.
describe('Book a Room', ()=> {
it ('enter on main page' async() => await mainPage.navigateToMainPage())
it('go to book room page', async() => await bookRoomPage.navigateToBookRoomPage())
// The function its inside the "bookRoomPage"
it('check if the user can book room', () => {
if (!page.userCanOpenARoom()) {
// DONT EXECUTE THE NEXT IT BUT CONTINUE WITH THE OTHER DESCRIBE
}
})
it('go to book preview...', async() => bookRoomPreviewPage.navigateToBookRoomPreviewPage());
// REMAINING FLOW
})
I already try with process.exit(0) but exit the whole process
You can try out what this blog says here its for sharing specs in your test suites which is pretty handy. But for your case specifically you could extract your page cases in separate suites and then dynamically include the test case on runtime if a condition is met.
Something like:
Include Spec function shared_specs/index.js
const includeSpec = (sharedExampleName, args) => {
require(`./${sharedExampleName}`)(args);
};
exports.includeSpec = includeSpec;
Test A shared_specs/test_a.js
describe('some_page', () => {
it...
})
Test B shared_specs/test_b.js
describe('some_other_page', () => {
it...
})
and then in your test case
// Something like this would be your path I guess
import {includeSpec} from '../shared_specs/includeSpec.js'
describe('Book a Room', async ()=> {
if (page.userCanOpenARoom()) {
includeSpec('test_a', page);
} else {
includeSpec('test_b', page); // Or dont do anything
}
});
Just make sure that you check the paths since
require(`./${sharedExampleName}`)(args);
will load it dynamically at runtime, and use includeSpec in your describe blocks not it blocks. You should be able to split up your test suites pretty nicely with this.

Populating mongodb in one unit test intereferes with another unit test

I'm trying to run all of my unit tests asynchronously, but calling a function to populate the database with some dummy data interferes with the other unit tests that run at the same time and that make use of the same data.
collectionSeed.js file:
const {ObjectID} = require('mongodb');
import { CollectionModel } from "../../models/collection";
const collectionOneId = new ObjectID();
const collectionTwoId = new ObjectID();
const collections = [{
_id: collectionOneId
}, {
_id: collectionTwoId
}];
const populateCollections = (done) => {
CollectionModel.remove({}).then(() => {
var collectionOne = new CollectionModel(collections[0]);
collectionOne.save(() =>{
var collectionTwo = new CollectionModel(collections[1]);
collectionTwo.save(() => {
done();
});
});
});
};
unitTest1 file:
beforeEach(populateCollections);
it('Should run', (done) => {
//do something with collection[0]
})
unitTest2 file:
beforeEach(populateCollections);
it('Should run', (done) => {
//do something with collection[0]
})
I'm running unit tests that change, delete, and add data to the database, so using beforeEach is preferable to keep all of the data consistent, but the CollectionModel.remove({}) functions often run in between an it function from one file and a second it function inside the other unit test file, so one unit test is working fine, while the second it is trying to use data that doesn't exist.
Is there anyway to prevent the different unit test files from interfering with each other?
I recommend you create a database per test file, for example adding to the DB name the name of the file. So you just have to take care of tests not interfering inside the same file, but you can forget about tests in other files.
I think that managing fixtures is one the most troublesome parts of unit testing, so with this, creating and fixing unit tests is going to become smoother.
As a trade off, each test file will take more execution time; but in my opinion in most of the cases it is worth enough.
Ideally each test should be independent of the rest, but, in general, that would take way too much overhead, so I recommended the once per test file approach.

Ajax testing with Mocha - Nodejs

I tried using Mocha to write tests for one of my application.
I can able to run different scenarios when page reloads.
Consider the below scenario
1) A user enters value in a text field "Username"
2) Clicks "Save" button
3) This will send ajax call to save user name and response might come back in 1 to 2 seconds
4) A message is shown after response is received
How can i implement test for above scenario?
NOTE : I tried the below code, but the browser isn't waiting at all
describe("Ajax test", function(){
before(function(){
return this.browser.field('save').click()
})
it("Tests save username", function(){
this.browser.wait(6000, function() {
//code to check if success message is shown in body
})
})
})
thanks,
Balan
There is a callback you can make in each test case, and you should wait for a response from the server before making this callback.
The pattern should be something like this:
// Test case. Notice the `done` param
it('Should make an async call', function(done){
// Make an async call, with a callback function
async_call(function(){
// Do whatever you need (test some values)
// Then call done
done();
});
});

VersionError: No matching document found error only on (Mocha) test

I have read the other problems/answers people are having with the version key but for some reason I do not understand why this specifically happens in my case.
So I have the following mocha test:
it('should be able to save one job', function (done) {
Promise.join(user.saveAsync(), company.saveAsync(),
function (savedUser, savedCompany) {
user = savedUser[0];
user.jobs.push(job);
user.saveAsync()
.spread(function (savedUserWithJob) {
user = savedUserWithJob;
user.jobs.should.have.length(1);
done();
})
.catch(function (err) {
done(err);
});
});
});
which is all fine and passes. I did not have any other problems even at runtime.
Now when I try to run the same test again right after the first one i.e.:
it('should be able to save one job', function (done) {
.....
});
it('should be able to save one job again', function (done) {
.....
});
The second one fails with the error:
VersionError: No matching document found.
I really do not understand why that happens as I am already pushing to the array the first time with no versioning problems. Why is it failing the second consecutive time?
Mongoose versionKey saves an version number on document, usually named __v.
This value is atomically incremented whenever a modification to an array potentially changes any array’s elements position. This value is also sent along in the where clause for any updates that require the use of positional notation. If our where clause still matches the document, it ensures that no other operations have changed our array elements position and it is ok to use use positional syntax. (read more here)
In your tests, after first save(), the doc has an incremented __v, that should be updated on your doc to be used by mongoose as part of the where clause on second save().

What is the role of describe() in Mocha?

The documentation at the official Mocha site contains this example:
describe('User', function(){
describe('#save()', function(){
it('should save without error', function(done){
var user = new User('Luna');
user.save(function(err){
if (err) throw err;
done();
});
})
})
})
I want to know when I should nest my tests in the describe function and what the basic purpose of describe is. Can I compare the first argument passed to describe to comments in a programming language? Nothing is shown of describe in the output on the console. Is it only for readability purposes, or there is some other use for this function?
Is there anything wrong if I use it like this?
describe('User', function(){
describe('#save()', function(){
var user = new User('Luna');
user.save(function(err){
if (err) throw err;
done();
})
})
})
If I do it this way, the test still passes.
The it call identifies each individual tests but by itself it does not tell Mocha anything about how your test suite is structured. How you use the describe call is what gives structure to your test suite. Here are some of the things that using describe to structure your test suite does for you. Here's an example of a test suite, simplified for the purpose of discussion:
function Foo() {
}
describe("Foo", function () {
var foo;
beforeEach(function () {
foo = new Foo();
});
describe("#clone", function () {
beforeEach(function () {
// Some other hook
});
it("clones the object", function () {
});
});
describe("#equals", function () {
it("returns true when the object passed is the same", function () {
});
it("returns false, when...", function () {
});
});
afterEach(function () {
// Destroy the foo that was created.
// foo.destroy();
});
});
function Bar() {
}
describe("Bar", function () {
describe("#clone", function () {
it("clones the object", function () {
});
});
});
Imagine that Foo and Bar are full-fledged classes. Foo has clone and equals methods. Bar has clone. The structure I have above is one possible way to structure tests for these classes.
(The # notation is used by some systems (like for instance, jsdoc) to indicate an instance field. So when used with a method name, it indicates a method called on an instance of the class (rather than a class method, which is called on the class itself). The test suite would run just as well without the presence of #.)
Provide Banners
Some of Mocha's reporters show the names you give to describe in the reports they produce. For instance, the spec reporter (which you can use by running $ mocha -R spec), would report:
Foo
#clone
✓ clones the object
#equals
✓ returns true when the object passed is the same
✓ returns false, when...
Bar
#clone
✓ clones the object
4 passing (4ms)
Help Select Parts to Run
If you want to run only some of the tests, you can use the --grep option. So if you care only about the Bar class, you can do $ mocha -R spec --grep Bar, and get the output:
Bar
#clone
✓ clones the object
1 passing (4ms)
Or if you care only about the clone methods of all classes, then $ mocha -R spec --grep '\bclone\b' and get the output:
Foo
#clone
✓ clones the object
Bar
#clone
✓ clones the object
2 passing (5ms)
The value given to --grep is interpreted as a regex so when I pass \bclone\b I'm asking only for the word clone, and not things like clones or cloned.
Provide Hooks
In the example above the beforeEach and afterEach calls are hooks. Each hook affects the it calls that are inside the describe call which is the parent of the hook. The various hooks are:
beforeEach which runs before each individual it inside the describe call.
afterEach which runs after each individual it inside the describe call.
before which runs once before any of the individual it inside the describe call is run.
after which runs once after all the individual it inside the describe call are run.
These hooks can be used to acquire resources or create data structures needed for the tests and then release resources or destroy these structures (if needed) after the tests are done.
The snippet you show at the end of your question won't generate an error but it does not actually contain any test, because tests are defined by it.
It's hard to add to Louis' excellent answer. There are a couple of advantages of the describe block that he didn't mention which are the skip and only functions.
describe.skip(...) {
...
}
will skip this describe and all its nested describe and it functions while:
describe.only(...) {
...
}
will only execute that describe and its nested describe and it functions. The skip() and only() modifiers can also be applied to the it() functions.
To my knowledge, describe is really just there for humans... So we can see different areas of the app. You can nest describe n levels deep.
describe('user',function(){
describe('create',function(){}
});
Describe is just used for the sake of understanding the purpose of the tests , it is also used to logically group the tests . Lets say you are testing the database API's , all the database tests could come under the outer describe , so the outer describe logically groups all the database related . Lets say there are 10 database related API's to test , each of the inner describe functions defines what those tests are ....
The particular role of describe is to indicate which component is being tested and which method of that component is also being tested.
for example, lets say we have a User Prototype
var User = function() {
const self = this;
function setName(name) {
self.name = name
}
function getName(name) {
return self.name;
}
return{setName, getName};
}
module.exports = User;
And it needs to be tested, so a spec file is created for unit test
var assert = require('assert');
var User = require("../controllers/user.controller");
describe("User", function() {
describe('setName', function() {
it("should set the name on user", function() {
const pedro = new User();
name = "Pedro"
pedro.setName(name);
assert(pedro.getName(), name);
});
});
});
It is easy to see that the purpose of describe is indicating the component to be tested and the nested describe methods indicate which methods needs to be tested

Resources