I have an Animal class as follows
Animal.js
export default class Animal {
constructor(type) {
this.type = type
}
getAnimalSound(animal) {
if (animal && animal.type == 'dog') return 'woof'
if (animal && animal.type == 'cat') return 'meow'
}
}
I make a zoo module which has a method for getAnimalSound() as follows
zoo.js
import Animal from './Animal'
export default function getAnimalSound(type) {
let animal = new Animal(type)
let animalSound = animal.getAnimalSound(animal)
return animalSound
}
Now how do i make unit testing for zoo module?
zoo.test.js
import sinon from 'sinon'
import Animal from './Animal'
import getAnimalSound from './zoo'
let animalStub = sinon.createStubInstance(Animal)
let a = animalStub.getAnimalSound.returns('woof')
let sound = getAnimalSound('cat')
console.log(sound)
So the problem is that the 'new' has no effect by the way i have stubbed in test.js
Can i achieve this?
Regards
Bobu P
You could use Link Seams to mock your ./animal.js module and Animal class.
E.g.
animal.ts:
export default class Animal {
type: any;
constructor(type) {
this.type = type;
}
getAnimalSound(animal) {
if (animal && animal.type == 'dog') return 'woof';
if (animal && animal.type == 'cat') return 'meow';
}
}
zoo.ts:
import Animal from './animal';
export default function getAnimalSound(type) {
let animal = new Animal(type);
let animalSound = animal.getAnimalSound(animal);
return animalSound;
}
zoo.test.ts:
import sinon from 'sinon';
import proxyquire from 'proxyquire';
import { expect } from 'chai';
describe('61716637', () => {
it('should pass', () => {
const animalInstanceStub = {
getAnimalSound: sinon.stub().returns('stubbed value'),
};
const AnimalStub = sinon.stub().returns(animalInstanceStub);
const getAnimalSound = proxyquire('./zoo', {
'./animal': { default: AnimalStub },
}).default;
const actual = getAnimalSound('bird');
expect(actual).to.be.equal('stubbed value');
sinon.assert.calledWith(AnimalStub, 'bird');
sinon.assert.calledWith(animalInstanceStub.getAnimalSound, animalInstanceStub);
});
});
unit test results with coverage report:
61716637
✓ should pass (2242ms)
1 passing (2s)
-----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
-----------|---------|----------|---------|---------|-------------------
All files | 54.55 | 0 | 33.33 | 66.67 |
animal.ts | 16.67 | 0 | 0 | 25 | 4-8
zoo.ts | 100 | 100 | 100 | 100 |
-----------|---------|----------|---------|---------|-------------------
Related
I just trying to implement a hooks for fetching data from window by useState, I'm tripping up over generics and code as below
interface ApplyData {
//...
}
interface ApplyRouterData {
//...
}
export const useApplyRouterData = () => useWindowData<ApplyRouterData>();
export const useApplyData = () => useWindowData<ApplyData>();
export const useWindowData = <T extends ApplyData | ApplyRouterData>() => {
return useState<T>(() => {
return window.data;
});
};
I also declare type for window.data like this
declare global {
interface Window {
data: ApplyRouterData | ApplyData;
}
}
but I got complier error om my hook
'T' could be instantiated with an arbitrary type which could be unrelated to 'IApplyResp | IApplyRouterResp'.
the type of window.data and generics are same as IApplyResp | IApplyRouterResp in my view, why? Thanks for you answer.
I want to be able to find target.json by passing a path to startingPoint.txt to a function in Node JS, given the following folder structure:
- root
- sub1
- sub2
startingPoint.txt
target.json
I've found a node package for it called find-up, but this is the kind of thing that probably takes no more than 6 lines of code.
export function findUp(start: Path, target: string): Path | undefined {
// this code here
}
const pathToTarget = findUp("root/sub1/sub2/startingPoint.txt", "target.json"/);
console.log(pathToTarget); // "root/target.json"
Old question I know, but I've just had to implement something similar and spent ages trying to find a good solution.
So, for future explorers, heres my solution using path and fs modules.
const PATH = require('path');
const FS = require('fs');
function findInPathAncestry(path, target) {
let current_directory_path = PATH.normalize(path).split(PATH.sep);
let result = false;
while(current_directory_path.length && !result) {
let current_path = current_directory_path.join(PATH.sep)+PATH.sep+target;
if(FS.existsSync(current_path)) {
result = current_path;
}
current_directory_path.pop();
}
return result;
}
usage example:
// example file structure:
// C:\
// | - path\
// | --- to\
// | ----- start\
// | ------- at\
// | ----- findme.txt
let start_location = "C:\path\to\start\at";
let target_file = "findme.txt";
console.log(findInPathAncestry(start_location, target_file));
// expected output:
// C:\path\to\findme.txt
// or false if file doesn't exist in path
the use of PATH.normalize and PATH.sep allows this to work in windows and unix environments
https://nodejs.org/api/path.html#path_path_sep
Here's what I have for now:
import { join, dirname } from 'path';
import { existsSync } from 'fs';
export let MAX_BACK_STEPS = 50;
export function findUp(start: string, target: string, boundary?: {
path: string,
inclusive: boolean,
}): string | null {
let currentDir = dirname(start);
let lastTry = false;
let backSteps = 0;
while (backSteps++) {
if (backSteps >= MAX_BACK_STEPS) {
console.error("Too many back steps");
return null;
}
if (boundary && boundary.path.includes(currentDir)) {
if (boundary.inclusive && lastTry === false) {
lastTry = true;
} else {
return null;
}
}
const targetTestPath = join(currentDir, target);
if (existsSync(targetTestPath)) {
return targetTestPath;
}
currentDir = join(currentDir, "../");
}
}
I am trying to write a test case using Jest. How can I write the test case for below snippets? A is a separate file and Three is a different file. I need to write the test cases as separate files as like unit test cases.
I am stuck in writing the static methods calling and mocking the multiple inputs. See below what I have tried also.
const one = require('../one');
const two = require('../two');
const three = require('../three');
class A {
public static checkTesting(param) {
switch (param) {
case 'one':
return one;
case 'two':
return two;
default:
return three;
}
}
constructor(param) {
this.testing = A.checkTesting(param);
}
}
module.exports = A;
const multiple = require('../multiple')(module);
const config = require('../config');
class Three {
public static sampleTestingWrite() {
return {
b: param => multiple[config.access](param)
};
}
constructor() {
this.sampleTesting = Three.sampleTestingWrite();
}
}
module.exports = Three;
A.test.js:
const One = require('../one');
const Two = require('../two');
const Three = require('../three');
const A = require('..');
jest.mock('../one');
jest.mock('../two');
jest.mock('../three');
describe('A test cases', () => {
test('should initiate the constructor', () => {
const mockStaticFunction = jest.fn();
mockStaticFunction.mockReturnValue('returns an object which does something on Multiple');
const MockA = new A('one');
console.log(MockA);
Console.mockImplementation(() => ({}));
console.log(logMedium);
expect(Console).toHaveBeenCalledTimes(1);
});
});
If you want to test if the constructor of A is called correctly. There is no need to mock one, two, three modules. Only you need to mock/spyOn is
checkTesting static method of A.
Here is the solution, I use typescript
import one from './one';
import two from './two';
import three from './three';
class A {
public static checkTesting(param) {
switch (param) {
case 'one':
return one;
case 'two':
return two;
default:
return three;
}
}
private testing;
constructor(param) {
this.testing = A.checkTesting(param);
}
}
export { A };
Unit test:
import { A } from './a';
describe('A', () => {
describe('checkTesting', () => {
it('should initiate the constructor', () => {
jest.spyOn(A, 'checkTesting').mockReturnValue({ name: 'never mind' });
const param = 'one';
const a = new A(param);
expect(a).toBeInstanceOf(A);
expect(A.checkTesting).toBeCalledWith(param);
});
});
});
Unit test result with coverage:
PASS src/mock-function/57624975/a.spec.ts
A
checkTesting
✓ t1 (8ms)
----------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files | 73.33 | 0 | 66.67 | 73.33 | |
a.ts | 66.67 | 0 | 66.67 | 66.67 | 7,9,11,13 |
one.ts | 100 | 100 | 100 | 100 | |
three.ts | 100 | 100 | 100 | 100 | |
two.ts | 100 | 100 | 100 | 100 | |
----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 1.649s, estimated 3s
I'm stuck trying to mock a class that is passed in through constructor and all the examples I've encountered so far have initialized dependencies inside constructors.
From my understanding jest replaces such dependencies with its overridden constructor but because I'm passing in the dependencies myself I'm in need of a passable instance when initialising UnderTest.
For what it's worth I'm ideally looking for a Mockito-ish behaviour, something along the lines of.
const mockedDependency = ???
const underTest = new UnderTest(mockedDependency)
...
Proceed to write tests for underTest
This is the code I'm trying to test. Please assume that MockedDependency has its own dependencies, passed in to constructor as well.
export default class UnderTest {
private mockedDependency : MockedDependency
constructor(mockedDependency: MockedDependency) {
this.mockedDependency = mockedDependency
}
public methodUnderTest(parameter: string) {
const mockedResult = this.mockedDependency.returnSomething(parameter)
return this.doSomethingElse(mockedResult)
}
public methodUnderTest2(parameter1: string, parameter2: string) {
const mockedResult = this.mockedDependency.returnSomething2(parameter1, parameter2)
return this.doSomethingElse(mockedResult)
}
private doSomethingElse(mockedResult: string) {
return mockedResult
}
}
How would you go about unit testing UnderTest class?
Bonus points for a way to set the result of mockedDependency methods either in each test or by input.
Edit:
A possible solution to those who stumble upon the same issue:
It's possible to cast variable as the desired object and override the methods like so:
const mockedDependency = {
returnSomething(parameter: string) {
return parameter
}
} as MockedDependency
const underTest = new UnderTest(mockedDependency)
It's far from perfect but will do for simpler cases.
Thanks in advance!
Here is the solution:
UnderTest.ts:
export interface MockedDependency {
returnSomething(...args: any[]): any;
returnSomething2(...args: any[]): any;
}
export default class UnderTest {
private mockedDependency: MockedDependency;
constructor(mockedDependency: MockedDependency) {
this.mockedDependency = mockedDependency;
}
public methodUnderTest(parameter: string) {
const mockedResult = this.mockedDependency.returnSomething(parameter);
return this.doSomethingElse(mockedResult);
}
public methodUnderTest2(parameter1: string, parameter2: string) {
const mockedResult = this.mockedDependency.returnSomething2(parameter1, parameter2);
return this.doSomethingElse(mockedResult);
}
private doSomethingElse(mockedResult: string) {
return mockedResult;
}
}
UnderTest.spec.ts:
import UnderTest, { MockedDependency } from './UnderTest';
const mockedDeps: jest.Mocked<MockedDependency> = {
returnSomething: jest.fn(),
returnSomething2: jest.fn()
};
const underTest = new UnderTest(mockedDeps);
describe('UnderTest', () => {
afterEach(() => {
jest.resetAllMocks();
});
describe('#methodUnderTest', () => {
it('should correctly', () => {
mockedDeps.returnSomething.mockReturnValueOnce('mocked result');
const actualValue = underTest.methodUnderTest('1');
expect(actualValue).toBe('mocked result');
expect(mockedDeps.returnSomething).toBeCalledWith('1');
});
});
describe('#methodUnderTest2', () => {
it('should correctly', () => {
mockedDeps.returnSomething2.mockReturnValueOnce('mocked result');
const actualValue = underTest.methodUnderTest2('2', '3');
expect(actualValue).toBe('mocked result');
expect(mockedDeps.returnSomething2).toBeCalledWith('2', '3');
});
});
});
Unit test result with 100% coverage report:
PASS src/stackoverflow/55966013/UnderTest.spec.ts
UnderTest
#methodUnderTest
✓ should correctly (5ms)
#methodUnderTest2
✓ should correctly (1ms)
--------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
--------------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
UnderTest.ts | 100 | 100 | 100 | 100 | |
--------------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 3.597s, estimated 8s
Here is the completed demo: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/55966013
I am trying to set a variable in a parent function to a imported and nested function in Node.
Parent
const child = require('./child')
function init() {
second()
let def = abc
console.log(def) // Expected log: 15
// Actual log: abc is not defined
}
function second() {
return child.third()
}
init()
Child
exports.third = () => {
let abc = 15
return abc
}
How do I properly return the value of abc so it can be set and logged in init()?
simply do abc = second() in your init() block
Maybe I don't get your question but in order to include anything you need first export it.
function third() {
let abc = 15
return abc
}
module.exports = {
third
};
Now, you just need to import the file and invoke the function
const child = require('child')
function init() {
let def = second();
console.log(def) // Expected log: 15
}
function second() {
return child.third()
}
init()