So I have these 2 cases in my tests. First one works fine, in the second one I try to extract the beforeEach declaration outside and it fails but I don't understand why. This is a simple case, basically I try to define an array and make a loop on that in order to run the tests multimple time with different beforeEach params declaration.
CASE 1
var params;
describe('When initializing', function () {
beforeEach(function () {
params = {
name: 'test 1'
};
});
it('should ..', function () {
params.name = 'test 2';
expect(...); => success
});
it('should ..', function () {
expect(...); => success because it expects params.name to be 'test 1' and it is 'test 1'
});
});
CASE 2
var params;
var test = {
name: 'test 1'
};
describe('When initializing', function () {
beforeEach(function () {
params = test;
});
it('should ..', function () {
params.name = 'test 2';
expect(...); => success
});
it('should ..', function () {
expect(...); => fails because it expects params.name to be 'test 1' and it is 'test 2'
});
});
In the second test if I console.log(test.name) inside the describe I will get test 2, somehow it got overriden even though the previous it did just params.name = 'test 2'; and not test.name = 'test 2';
The difference is that in case 1 you're creating a new object every time beforeEach is called, while in case 2 you're not.
Combined with that is the fact that your first test mutates the object. If all the tests are referring to the same object (ie, case 2) then that mutation will affect any code that runs after the first test. If instead the object is overwritten before each test (case 1), then the mutation won't affect other tests.
There are a few options for how to address this. One is to just to keep case 1; by resetting to a known state each time, you can have a clean state for all the tests to work off of. Another option is to not mutate the object. Perhaps the tests could copy the object and then modify that copy.
Related
Can we run a dynamical loop test in mocha when we obtain the dynamic array from one of the test cases something like below?
describe('test', () {
var array = [];
it('test 1', function(done) {
// get the array
// assume JSON = [ {number : 1, value : 1}, {number : 2, value : 2}]
}
// run loop test base on the array from test 1
array.forEach() {
it(`test {array.number}`, function(done) {
// sample
expect(array.number).to.be.equal(array.value)
}
}
it('test 3', function(done) {
// another test
}
}
So far, it seems to work fine if I ran in a separate js file instead of just one js file by passing the result of the JSON array (callback) to another test js file. What if I want it in one js file?
Reference: https://mochajs.org/#dynamically-generating-tests
createUserPatch is an API custom command to create a new User.
You can see that I have created a variable "A" inside it.
The variable is used in the body emails part [a]+'freddie.doe#example.com','type': 'work','primary': true}]
I want to find a way to automatically increase the variable "A" whenever I call the command createUserPatch.
Cypress.Commands.add('createUserPatch', (user) => {
var A = 1;
cy.request({
method: 'POST',
url: '/scim/v2/users',
qs: {
key : Cypress.env('apiKey')
},
body :{
schemas: user.schemas,
userName: user.userName,
emails: [{ 'value': [A]+'freddie.doe#example.com','type': 'work','primary': true}],
name : 'Maurice'
}
}).then(res => {
return res.body;
});
});
I use this command in the test below in a before each.
let user = {
schemas:'["urn:ietf:params:scim:schemas:core:2.0:User"]',
userName: 'John',
userId: null,
groupID: null
};
describe('Deactivating a user ', () => {
beforeEach(() => {
cy.createUserPatch(user).then((newUser) => {
return user.userId = newUser.id;
});
});
....
Each time I run this test.
I want the value of the email to be increased.
First test -> 0freddie.doe#example.com
Second test -> 1freddie.doe#example.com
Third test -> 2freddie.doe#example.com
etc...
Cypress clears variables between tests, but a few ways to preserve data have been suggested in other questions (e.g write data to file).
Since you already use Cypress.env(name) to access environment variables you could use Cypress.env(name, value) to track the prefix.
Cypress.Commands.add('createUserPatch', (user) => {
let prefix = Cypress.env('emailprefix') || 0; // first time it may be undefined
// so "|| 0" initializes it
Cypress.env('emailprefix', ++prefix); // increment and save
cy.request({
...
emails: [{ 'value': prefix+'freddie.doe#example.com','type': 'work','primary': true}],
Note, the prefix value will be preserved between runs, which may or may not be what you want.
To clear it between runs, add a before() which resets the value
before(() => Cypress.env('emailprefix', 0) );
beforeEach(() => {
cy.createUserPatch().then(console.log)
})
I am new to Jest, and I am trying to figure out how to to reset the test object after each test.
Current Code
describe.only('POST request - missing entry', () => {
// newBlog is the "test" object
let newBlog = {
title: 'Test Title',
author: 'Foo Bar',
url: 'www.google.com',
likes: 100
}
test('sets "likes" field to 0 when missing', async () => {
delete newBlog.likes // propagates to next test
console.log(newBlog)
})
test('returns 400 error when "title" and "url" fields are missing', async () => {
console.log(newBlog)
})
})
Objective: I am writing test using jest to test for bad POST request. i.e. my POST request will intentionally have missing fields for each test.
likes field will be omitted from first test while title, url field will be missing from second test. Goal is to write newBlog object only once rather than rewriting objects for each tests.
Problem Main issue here is that the result of first test propagates to next test, i.e. when removing likes field for first test, it stays like that and starts the second test without having likes field.
I want to know how I can reset the content of object for each test.
Attempts So far, I tried few things:
I used BeforeEach to reset the newBlog in following manner:
beforeEach(() => {
let newBlog = {
title: 'Test Title',
author: 'Foo Bar',
url: 'www.google.com',
likes: 100
}
return newBlog
})
However, above code does not work since newBlog is in different scope so each test does not recognize newBlog variable.
I also used AfterEach to reset in following manner:
afterEach(() => {
jest.clearAllMocks()
})
This time, it ran but gave me the same results as first code snippet.
I would like to know how to reset objects for each test as many of the solution discussed in stackoverflow seems to focus on resetting functions rather than objects.
Thank you for your help in advance.
Try something like this, declare the variable in the describe and reset it in the beforeEach:
describe.only('POST request - missing entry', () => {
// newBlog is the "test" object
let newBlog;
beforeEach(() => {
newBlog = {
title: 'Test Title',
author: 'Foo Bar',
url: 'www.google.com',
likes: 100
}
});
test('sets "likes" field to 0 when missing', async () => {
delete newBlog.likes // propagates to next test
console.log(newBlog)
})
test('returns 400 error when "title" and "url" fields are missing', async () => {
console.log(newBlog)
})
})
You were correct in needing to use Jest's beforeEach() function; however, the only things that are returnable from beforeEach() are promises and generators—returning newBlog from beforeEach() does nothing. What I would do is create a local variable in the describe function and have beforeEach() reassign that variable before each test runs as seen below.
fdescribe('POST request - missing entry', () => {
let newBlog;
beforeEach(() => {
newBlog = {
title: 'Test Title',
author: 'Foo Bar',
url: 'www.google.com',
likes: 100
}
});
test('sets "likes" field to 0 when missing', async () => {
delete newBlog.likes; // remove likes key from copied object
console.log(newBlog);
});
test('returns 400 error when "title" and "url" fields are missing', async () => {
delete newBlog.title;
delete newBlog.url;
console.log(newBlog);
});
})
Additionally, jest.clearAllMocks() clears all calls and instances of a mocked function which will not reset the newBlog variable in the way you want to use it here.
I usually deep copy the test object in this kind of scenarios. So I have a helper function (you can use e.g. Lodash's deepClone function too)
const deepCopy = (obj: Object) => JSON.parse(JSON.stringify(obj));
In your tests you create a new deep copy of the wanted test object instead of mutating it's state like this:
test('sets "likes" field to 0 when missing', async () => {
let testObj = deepCopy(newBlog)
delete testObj.likes // propagates to next test
console.log(testObj)
})
i want to implement jasmine test with the next code:
This is my filter-service.js
function FilterService() {
}
FilterService.prototype.filter = function (companies, filter) {
return companies;
};
And my filter-service-spec.js is
describe("Filter service filter(...) tests", function() {
var filterService = new FilterService();
var allTestCompanies= [
{ id: 1, name: "company1 Test", admin: "Test Admin" },
{ id: 2, name: "company2", admin: "Test Admin", country: 'London' },
{ id: 3, name: "company3", admin: "Mery Phill" }
];
it('returns original collection if called with undefined filter', function() {
var input = [1, 2, 3];
var result = filterService.filter(input, undefined);
expect(result).toEqual(input);
});
it('returns original collection if called with empty filter', function () {
var input = [2, 6, 7];
var result = filterService.filter(input, '');
expect(result).toEqual(input);
});
it('only includes matching companies once', function() {
var result = filterService.filter(allTestCompanies, 'Test');
expect(result.length).toEqual(2);
});
it('matches exact text on company name', function() {
var result = filterService.filter(allTestCompanies, "company1 Test");
expect(result[0]).toEqual(allTestCompanies[0]);
});
it('matches exact text contained in company name', function () {
var result = filterService.filter(allTestCompanies, "Test");
expect(result[0]).toEqual(allTestCompanies[0]);
});
it('matches case invarient text contained in company name', function () {
var result = filterService.filter(allTestCompanies, "test");
expect(result[0]).toEqual(allTestCompanies[0]);
});
it('matches exact text of admin', function() {
var result = filterService.filter(allTestCompanies, 'Mery Phill');
expect(result[0]).toEqual(allTestCompanies[2]);
});
it('matches exact text in admin', function () {
var result = filterService.filter(allTestCompanies, 'Phil');
expect(result[0]).toEqual(allTestCompanies[2]);
});
it('matches case invarient text in admin', function () {
var result = filterService.filter(allTestCompanies, 'PHIl');
expect(result[0]).toEqual(allTestCompanies[2]);
});
});
How i can implement a function in filter-service.js for pass the javascript tests. For now only pass the 2 first.
Sure, this is actually very easy to do, but I will provide just with approach you should take. So lets begin ...
I hope you have an environment where you able to run your tests (Jasmine installed and you able to run your tests against "FilterService" object and "filter" method in particular). You said two first methods are succeeded.
Each Jasmine "it" function has description, for example "matches exact text on company name" (test #4). This is most important part you will be dealing with. We will talk about this test. Ask yourself what this description tells you? This means if you pass into "filter" method exact name of the company, the function should go through array of given companies objects and try to find match for exact company name.
Next you would need to look at implementation of Jasmine "expect" function. You will notice that returned result from the "filter" function call must be equal to the first element of the given array of companies because the name of the company in the filter parameter match to this object's "name".
After you implement this part and test succeeded, you would go to next test and add/change existing implementation to accomplish next "it" description.
This is called TDD (test driven development). Please read a bit on it before you start working.
Finally lets try to implement this test #4. Please note the code provided may not work, but as we agreed you will make it work, I just show the approach ...
function FilterService() {
}
FilterService.prototype.filter = function (companies, filter) {
// this is our result variable which we will return at the end
var result;
// for test #1 the "filter" parameter is undefined and the test description says "returns original collection if called with undefined filter" (#2 will look similar to test #1, add this by yourself)
if (typeof filter === "undefined") {
result = companies;
}
// jump to test #4 we are talking about. "it" says "matches exact text on company name"
companies.forEach( function (companyObj) {
if (companyObj.name === filter) {
result = [companyObj];
return false;
}
});
// continue to modify the function to meet all criteria of every "it" description
// we return our result
return result;
};
I have a simple test, I have a Meteor method on the server side which is basically a variable that contains a collection let's say:
Meteor.methods({
usernames: function() {
var test_users = Meteor.users.find();
test_users.forEach(function (user) {
console.log(user.username);
return 'test output';
});
}
})
If I try to to call this on the client side with Meteor call I can't ever get 'test output' but the console.log will work, I would've expected to get the first 'test output'... is this a asynchronous issue?
If I put a return 'something' after the .forEach loop it will return that..
The return 'test output'; is returning from the anonymous function you pass to forEach and not the usernames function.
Assuming you want to get the list of usernames back, you probably to want use cursor.map like this:
Meteor.methods({
usernames: function() {
var test_users = Meteor.users.find();
return test_users.map(function (user) {
console.log(user.username);
return user.username;
});
}
});