Why use beforeEach() when writing javascript tests? - javascript

I'm learning how to write tests for my code and my instructor explained to put the component being rendered in a beforeEach() function like this...
describe('CommentBox', () => {
let component;
beforeEach(() => {
component = renderComponent(CommentBox);
});
it('has the correct class', () => {
expect(component).to.have.class('comment-box');
});
it('has a text area', () => {
expect(component.find('textarea')).to.exist;
});
it('has a button', () => {
expect(component.find('button')).to.exist;
});
});
Why use beforeEach(). Why not just declare the component variable at the top of the describe function like so...
describe('CommentBox', () => {
const component = renderComponent(CommentBox);
it('has the correct class', () => {
expect(component).to.have.class('comment-box');
});
it('has a text area', () => {
expect(component.find('textarea')).to.exist;
});
it('has a button', () => {
expect(component.find('button')).to.exist;
});
});
This would seem to save a couple extra lines of code, and one less function you would have to write?

The beforeEach runs before each test. This means that each test gets fresh data to test with.
If you do it the other way each test could modify the object and then taint the object for the next test.
Its good practice to not create dependencies between tests so that you can more accurately find bugs or ensure your test actually tests the logic you intended.
I assume that your testing renderComponent.

Related

In Jest, how to test a function declared inside a function?

I am trying to test a function that is declared inside another function(Parent). I tried a few things but was not able to test that. I am using react library and JEST testing framework in the project.
Here is the service file (service.ts) function which I am trying to test:
import { useThisHook } from './base-hooks';
export function someFunction(param: string) {
const [
resolveFunction,
,
{ loading, error },
] = useThisHook();
const childFun = (param : number) => {
resolveFunction(someArguments);
}
return{
someValue: childFun
}
}
Here is the spec file code:
import * as SomeHooks from './base-hooks';
import * as Service from './service';
describe('Service function', () => {
beforeEach(() => {
jest.spyOn(SomeHooks, 'useThisHook').mockReturnValue(
{
//Some Value
}
);
});
test('Some function test', () => {
const someFunctionResponse = Service.someFunction('string');
expect(someFunctionResponse).toEqual({
someValue: expect.any(Function),
});
});
});
Till here it is fine. Tests are also getting passed but the problem is that childFn is not getting the coverage and that's what my requirement is. I am new to React and Jest. I am not able to understand how can I achieve that. I tried many things but didn't succeed.
Your childFn is not being called, that's why it's not getting coverage.
You could either refactor the whole childFn to a new hook and test it individually with something like react-hooks-testing-library.
Or you could separate the childFn and declarate it outside the someFunction scope pass the resolveFunction and then test it.
You only get coverage if the code is actually called, not when it is declared.

Updating window object per test

I have some conditional logic in a component that reads window.location.pathname.
To test this I want to shallow render a component without touching the window, asserting, then shallow rendering again but this time with a different window.location.pathname and assert.
It seems like after the first shallow render enzyme locks the window object for all following renders. Ignoring any changes I make to the window object in the current process.
describe('SomeComponent', () => {
describe('render', () => {
it('default render', () => {
const component = <SomeComponent><div>test</div></SomeComponent>;
const wrapper = shallow(component);
expect(toJson(wrapper)).toMatchSnapshot();
});
});
describe('lifecycle', () => {
describe('componentDidMount', () => {
it('calls Foo.bar with the locations pathname', () => {
const pathname = '/test';
Object.defineProperty(window.location, 'pathname', {
writable: true,
value: pathname,
});
const wrapper = shallow(<SomeComponent />);
expect(Foo.bar.mock.calls[0][0]).toBe(pathname);
});
});
});
});
So the second test works when run by itself. But when that first test runs then the second test fails. Apparently enzyme doesn't let you update the window between test.
Is this true or am I missing something. If it is true then what would be an alternative to test this?
Thanks

What is the purpose of Mocha's #beforeEach when you can just run code inside the #describe scope?

I'm learning TDD from this article and the author talks about how Mocha's beforeEach will run a code before each assertion for you. But I don't understand why you need to do that when you can just run the code in the describe scope.
describe('Test suite for UserComponent', () => {
beforeEach(() => {
// Prevent duplication
wrapper = shallow(<UserComponent
name={ 'Reign' }
age={ 26 } />);
});
it('UserComponent should exist', () => {
expect(wrapper).to.exist;
});
it('Correctly displays the user name and age in paragraphs wrapped under a parent div', () => {
expect(wrapper.type()).to.equal('div');
// more code...
});
});
But not using the beforeEach would still work -
describe('Test suite for UserComponent', () => {
wrapper = shallow(<UserComponent
name={ 'Reign' }
age={ 26 } />);
it('UserComponent should exist', () => {
expect(wrapper).to.exist;
});
it('Correctly displays the user name and age in paragraphs wrapped under a parent div', () => {
expect(wrapper.type()).to.equal('div');
// more code...
});
});
beforeEach is executed before each test. This iteration is lost when the code is moved from beforeEach to be directly inside the function passed to describe. However, that's not all.
In some cases, code executed directly inside the function passed to describe can perform the same task as a beforeEach hook. For instance, if its function is to initialize a read-only structure that is local to the test in the describe block, then you could skip the beforeEach hook.
However, Mocha executes right away all the callbacks that are passed to describe calls whereas a beforeEach call registers the function passed to it for future execution, and it will be executed only if needed. If the initialization is expensive it is better to use a beforeEach hook because if you make use of --grep to select only some test, or use it.only to run a single test, then Mocha will run the hook only if it pertains to the test it will actually run. If you have the initialization code in describe, Mocha cannot skip it so you'll pay the initialization cost every time. However, if you are going to use a hook and the data is immutable, then before is better than beforeEach because it will run just once instead of before each test.
Then there are cases where running code in directly in the function passed to describe simply won't work. Imagine in the following that sharedResource is a resource that all tests need to use. It could be a third-party library that carries state, for instance. Some tests need it to be set to a certain state. Other tests need it to be in a different state. This does not work:
"use strict";
const assert = require('assert');
let sharedResource;
describe("in condition a", () => {
sharedResource = true;
it("sharedResource is true", () => assert(sharedResource));
});
describe("in condition b", () => {
sharedResource = false;
it("sharedResource is false", () => assert(!sharedResource));
});
The first test will fail because the execution order of the key statements is:
sharedResource = true;
sharedResource = false;
assert(sharedResource);
assert(!sharedResource);
The problem can be easily fixed by using beforeEach. This runs fine:
"use strict";
const assert = require('assert');
let sharedResource;
describe("in condition a", () => {
beforeEach(() => {
sharedResource = true;
});
it("sharedResource is true", () => assert(sharedResource));
});
describe("in condition b", () => {
beforeEach(() => {
sharedResource = false;
});
it("sharedResource is false", () => assert(!sharedResource));
});

Testing a custom method for $state.go

I tried to test this code:
redireccion() {
this.$state.go('modifyLine', {lineId: this.look()._id});
}
look() {
return Entries.findOne({name: this.entry.name});
}
the code above method is ok (look), but for 'redireccion' I tried something like this and i got an error.
this is the code:
describe('redireccion()', () => {
beforeEach( inject(($state) => {
spyOn($state, 'go');
spyOn(controller, 'look');
spyOn(Entries, 'findOne');
}));
it('should be a ... bla bla', () => {
controller.redireccion();
expect($state.go).toHaveBeenCalledWith('modifyLine', {lineId: });
});
});
This is an excerpt, because really I do not know how testing this.
I will try to give you an insight. You should try to make your tests isolated... That means that if you're testing your redirection, you can mock the look method since it's not relevant (for this specific test).
describe('testing redirection()', () => {
beforeEach( inject(($state) => {
//here I'm saying that I'm spying every call to $state.go
spyOn($state, 'go');
//And here I'm that I'm not only spying every call to
//controller.look() but I'm also replacing the original
//implementation with my fake one. Every call will basically
//return an object with id equals 10
spyOn(controller, 'look').and.callFake(() => {
var mockedLine = {
_id: 10
};
return mockedLine;
});
}));
it('should call state.go', () => {
controller.redireccion();
//if you just want to check if the method was called, do the following:
expect($state.go).toHaveBeenCalled();
//if you need to also check the arguments, try:
var args = $state.go.mostRecentCall.args;
expect(args[0]).toBe('modifyLine');
expect(args[1].lineId).toBe(10);
});
});

Jasmine does not reset spy after each test spec

I have the following spec.
describe("SN.ExitHistory", function() {
var exitHistory;
beforeEach(function() {
SN.Utils = jasmine.createSpy("utils").andCallFake(function() {
function readSNCookie(cookieName, key) {
return "google.com";
}
function isUndefinedOrNull(param) {
return (param == null) || (param === "null");
}
function createSNCookie(snCookieName, key, value, lifeTime) {
}
var me = {
readSNCookie : readSNCookie,
isUndefinedOrNull : isUndefinedOrNull,
createSNCookie : createSNCookie
};
return me;
})();
exitHistory = SN.ExitHistory();
});
it("return last exit link", function() {
expect(exitHistory.getLastExitLink()).toEqual("google.com");
});
});
exitHistory.getLastExitLink internally use SN.Utils.
After the test is done Jasmine does not remove the spy object utils. In next test suite also I can see the same utils present. Is there any way to reset the spy object after each test is done?
Instead of creating spy, if I create a new object for utils, behavior is same. Then what is the difference between a spy and actual object in this scenario.
Correct me if I am wrong.
I had the same problem some time ago and after days of struggling I found the solution. If you use the other way your spy will be reseted, so try with
spyOn(SN, 'Utils');
Spies are described here:
https://github.com/pivotal/jasmine/wiki/Spies
Use spyOn and declare your spies within a before block inside of a describe spec block and the spies will be cleaned up when each spec is torn down.
aSpec.js
describe('something', () => {
beforeAll(() => spyOn(someObject, 'someMethod').and.returnValue('foo'));
it('is spied on', () => {
expect(someObject.someMethod()).toEqual('foo');
});
});
anotherSpec.js
describe('something else', () => {
beforeAll(() => spyOn(someObject, 'someMethod').and.returnValue('bar'));
it('is spied on', () => {
expect(someObject.someMethod()).toEqual('bar');
});
});

Categories

Resources