I have two functions which I'd like to test with Jest. However, I can't get test coverage to 100% because I can't figure out how to simulate String.prototype.trimLeft being undefined. What can I do?
function trimLeft (str: string): string {
if (String.prototype.trimLeft) {
return str.trimLeft()
} else {
return str.replace(/^[\s\uFEFF\xA0]+/, '')
}
return str
// else something's wrong
}
function trimRight (str: string, type: string): string {
if (String.prototype.trimRight) {
return str.trimRight()
} else {
return str.replace(/[\s\uFEFF\xA0]+$/, '')
}
return str
}
export { trimLeft, trimRight }
First of all, the last statement return str is not reachable in these two methods. After fixing them. Here is the unit test solution:
index.ts:
function trimLeft(str: string): string {
if (String.prototype.trimLeft) {
return str.trimLeft();
} else {
return str.replace(/^[\s\uFEFF\xA0]+/, '');
}
}
function trimRight(str: string): string {
if (String.prototype.trimRight) {
return str.trimRight();
} else {
return str.replace(/[\s\uFEFF\xA0]+$/, '');
}
}
export { trimLeft, trimRight };
index.spec.ts:
import { trimLeft, trimRight } from './';
describe('59430114', () => {
describe('#trimLeft', () => {
it('t1', () => {
expect(trimLeft(' jestjs')).toBe('jestjs');
});
it('t2', () => {
Object.defineProperty(String.prototype, 'trimLeft', { value: undefined });
expect(trimLeft(' jestjs')).toBe('jestjs');
});
});
describe('#trimRight', () => {
it('t1', () => {
expect(trimRight('jestjs ')).toBe('jestjs');
});
it('t2', () => {
Object.defineProperty(String.prototype, 'trimRight', { value: undefined });
expect(trimRight('jestjs ')).toBe('jestjs');
});
});
});
Unit test result with 100% coverage:
PASS src/stackoverflow/59430114/index.spec.ts (8.386s)
59430114
#trimLeft
✓ t1 (4ms)
✓ t2 (1ms)
#trimRight
✓ t1 (1ms)
✓ t2 (1ms)
----------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
index.ts | 100 | 100 | 100 | 100 | |
----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 4 passed, 4 total
Snapshots: 0 total
Time: 10.085s
Source code: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/59430114
Related
I'm struggling to figure out how to do this.
example.js
import Logger from "logging-library";
export default function example() {
Logger.error(new Error("Example Error")):
}
example.test.js
test("will log an error", () => {
expect(Logger.error).toHaveBeenCalledWith(new Error("Example Error");
});
The examples I've found might cover mocking an entire library, but don't seem to cover mocking and also asserting how it was called.
unit test solution:
example.js:
import Logger from 'logging-library';
export default function example() {
Logger.error(new Error('Example Error'));
}
example.test.js:
import Logger from 'logging-library';
import example from './example';
jest.mock(
'logging-library',
() => {
return { error: jest.fn() };
},
{ virtual: true },
);
describe('64858662', () => {
afterAll(() => {
jest.resetAllMocks();
});
test('will log an error', () => {
example();
expect(Logger.error).toHaveBeenCalledWith(new Error('Example Error'));
});
});
unit test result:
PASS src/stackoverflow/64858662/example.test.js
64858662
✓ will log an error (5ms)
------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
------------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
example.js | 100 | 100 | 100 | 100 | |
------------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 4.373s, estimated 12s
I am a beginner with Jest, I am doing a program to study more JS. The tests work, but could this try / catch be replaced by exceptions? I believe that it is still not the best way to do this test with Jest.
import Category from "../app/models/Category.js"
describe("Test for category", () => {
it("error for null category", () => {
try {
new Category(null)
console.log("Error: category was created even as null name")
} catch (err) {
expect(err.message)
}
})
it("Error for empty category", () => {
try {
new Category(" ")
console.log("Error: category was created with an empty field")
} catch (err) {
expect(err.message)
}
})
it("Category registration", () => {
try {
new Category("Devops")
console.log("Category was created successfully!")
} catch (err) {
expect(err.message)
}
})
})
This is my class:
import { isEmpty, isNull } from "../validate.js"
export default class Category {
constructor(name) {
this.name = name
}
set name(name) {
if (isEmpty(name) || isNull(name)) throw new Error(`The category field needs to be filled`)
this._name = name
}
get name() {
return this._name
}
}
validate.js
export const isEmpty = value => !notEmpty(value)
export const isNull = value => value === null
Thanks for any help!
Use .toThrow(error?)
Note: You must wrap the code in a function, otherwise the error will not be caught and the assertion will fail.
Category.js:
import { isEmpty, isNull } from './validate';
export default class Category {
constructor(name) {
this.name = name;
}
set name(name) {
if (isEmpty(name) || isNull(name)) throw new Error(`The category field needs to be filled`);
this._name = name;
}
get name() {
return this._name;
}
}
Category.test.js:
import Category from './Category';
describe('Test for category', () => {
it('error for null category', () => {
expect(() => new Category(null)).toThrowError('The category field needs to be filled');
});
it('Error for empty category', () => {
expect(() => new Category(' ')).toThrowError('The category field needs to be filled');
});
it('Category registration', () => {
const c = new Category('Devops');
expect(c._name).toBe('Devops');
});
});
unit test result with coverage report:
PASS src/stackoverflow/64217332/Category.test.js
Test for category
✓ error for null category (11ms)
✓ Error for empty category (2ms)
✓ Category registration (1ms)
-------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
-------------|----------|----------|----------|----------|-------------------|
All files | 92.31 | 100 | 83.33 | 88.89 | |
Category.js | 85.71 | 100 | 66.67 | 83.33 | 13 |
validate.js | 100 | 100 | 100 | 100 | |
-------------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 3 passed, 3 total
Snapshots: 0 total
Time: 5.502s, estimated 17s
I have a function, lets call it generateName, which as you’ve guessed it, generates a name. The problem is that a new name is generated each time time a test is ran.
In one of my tests, I assert that a function is called with an object containing this name. However, the name keeps on changing. I could just check that the object has property name, but I don’t really want to do that.
My idea is that I can mock the return value of the generateName function and do something like this
Import { generateName } from ‘libs/generateName’
jest.fn(generateName).mockResolvedValue ( ‘hello’ )
expect ( spy ).toHaveBeenCalledWith (
expect.objectContaining ( {
name: 'houses',
} )
)
You can use jest.mock(moduleName, factory, options) to mock libs/generateName module.
E.g.
generateName.ts:
export async function generateName() {
const name = Math.random() + '';
return name;
}
main.ts:
import { generateName } from './generateName';
export function main() {
return generateName();
}
main.test.ts:
import { main } from './main';
import { generateName } from './generateName';
jest.mock('./generateName', () => {
return {
generateName: jest.fn(),
};
});
describe('61350152', () => {
it('should pass', async () => {
(generateName as jest.MockedFunction<typeof generateName>).mockResolvedValueOnce('hello');
const actual = await main();
expect(actual).toBe('hello');
});
});
unit test results with coverage report:
PASS stackoverflow/61350152/main.test.ts (28.524s)
61350152
✓ should pass (6ms)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
main.ts | 100 | 100 | 100 | 100 |
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 31.98s
Hi I wanted to unit test my javascript code using Jest and the click function inside it.
swipe.js
export default class swipe {
constructor() {
this.init();
}
init() {
this.postRender();
}
postRender() {
const jqry = jQuery.noConflict();
(function (jqry) {
jqry(document).ready(() => {
jqry('#buttonID').on('click', () => {
jqry('#navigation').addClass('blue');
});
});
})(jqry);
}
}
Here is the unit test solution:
swipe.js:
import $ from 'jquery';
export default class swipe {
constructor() {
this.init();
}
init() {
this.postRender();
}
postRender() {
$(document).ready(() => {
$('#buttonID').on('click', () => {
$('#navigation').addClass('blue');
});
});
}
}
swipe.test.js:
import Swipe from './swipe';
import $ from 'jquery';
jest.mock(
'jquery',
() => {
const m$ = { on: jest.fn(), ready: jest.fn(), addClass: jest.fn() };
return jest.fn(() => m$);
},
// remove this option if you have installed jquery module
{ virtual: true },
);
describe('60190274', () => {
it('should add class when click the button', () => {
$().ready.mockImplementationOnce((callback) => callback());
$().on.mockImplementationOnce((event, handler) => handler());
new Swipe();
expect($).toBeCalledWith(document);
expect($).toBeCalledWith('#buttonID');
expect($).toBeCalledWith('#navigation');
expect($().ready).toBeCalled();
expect($().on).toBeCalledWith('click', expect.any(Function));
expect($().addClass).toBeCalledWith('blue');
});
});
Unit test results with 100% coverage:
PASS stackoverflow/60190274/swipe.test.js
60190274
✓ should add class when click the button (6ms)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
swipe.js | 100 | 100 | 100 | 100 |
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 4.163s, estimated 5s
source code: https://github.com/mrdulin/react-apollo-graphql-starter-kit/tree/master/stackoverflow/60190274
I try to figure out how to test this kind of method
// Let's say models === null when we instantiate
public initialize(mongodb: MongoDb): this {
if (!this.models) {
this.models = {
users: new models.UserModel(mongodb),
};
}
return this;
}
public getModels(): Models | null {
return this.models || null;
}
My coverage is still staying that I didn't test the if part... This is not really true because when I ask for the getModels I can test its value (so implicitly the if.
Any idea?
Here is the solution:
index.ts:
import * as models from './models';
import { MongoDb, Models } from './interfaces';
export class UserDataSource {
private models: Models | null = null;
public initialize(mongodb: MongoDb): this {
if (!this.models) {
this.models = {
users: new models.UserModel(mongodb)
};
}
return this;
}
public getModels(): Models | null {
return this.models || null;
}
}
Unit test, index.spec.ts:
import { UserDataSource } from './';
import { MongoDb } from './interfaces';
import * as models from './models';
describe('UserDataSource', () => {
const mockedMongodb: MongoDb = {};
describe('#initialize', () => {
it('should initlialize models correctly', () => {
const userDataSource = new UserDataSource();
const actualValue = userDataSource.initialize(mockedMongodb);
expect(userDataSource.getModels()).toEqual(expect.objectContaining({ users: expect.any(models.UserModel) }));
expect(actualValue).toBe(userDataSource);
});
it('should not initialize models', () => {
const userDataSource = new UserDataSource();
// tslint:disable-next-line: no-string-literal
userDataSource['models'] = [];
const actualValue = userDataSource.initialize(mockedMongodb);
expect(actualValue).toBe(userDataSource);
});
});
describe('#getModels', () => {
it('should get models correctly', () => {
const userDataSource = new UserDataSource();
const actualValue = userDataSource.getModels();
expect(actualValue).toEqual(null);
});
it('should get models correctly and not null', () => {
const userDataSource = new UserDataSource();
// tslint:disable-next-line: no-string-literal
userDataSource['models'] = [];
const actualValue = userDataSource.getModels();
expect(actualValue).toEqual([]);
});
});
});
Unit test result with 100% coverage:
PASS src/stackoverflow/52729002/index.spec.ts
UserDataSource
#initialize
✓ should initlialize models correctly (5ms)
✓ should not initialize models (7ms)
#getModels
✓ should get models correctly (1ms)
✓ should get models correctly and not null (1ms)
-----------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
-----------------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
52729002 | 100 | 100 | 100 | 100 | |
index.ts | 100 | 100 | 100 | 100 | |
52729002/models | 100 | 100 | 100 | 100 | |
UserModel.ts | 100 | 100 | 100 | 100 | |
index.ts | 100 | 100 | 100 | 100 | |
-----------------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 4 passed, 4 total
Snapshots: 0 total
Time: 6.157s
Here is the completed demo: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/52729002