How do I write test case for a function which uses uuid using jest? - javascript

I'm using jest for writing test cases. One of my function uses uuid and due to which it is not a pure function. The code is something like this:
const myFunc = () => {
const a = uuid();
return a;
}
I'm writing my test case as :
test('should return a unique id value', () => {
const a = uuid();
expect(myFunc()).toEqual(a);
});
Obviously it won't work as it will generate a unique Id every time. How can I write test case for such function.
[EDIT]
I don't want test the uuid function as it will always generate a new id and it is a library function which is already being tested. I want to test another function which uses uuid, generates new object and returns that. This function is used by some other function and so on which makes me not able to test any of that because the initial object has an id which is different that the id which I'm using while testing.

I have found this works really nice.
At the top of test file:
// your regular imports here
jest.mock('uuid', () => ({ v4: () => '00000000-0000-0000-0000-000000000000' }));
// describe('test suite here', () => {
in the actual code:
import { v4 as uuidv4 } from 'uuid';

You can use jest.mock inorder to mock the import of uuid, like that:
const uuidMock = jest.fn().mockImplementation(() => {
return 'my-none-unique-uuid';
});
jest.mock('uuid', () => {
return uuidMock;
});
The only caveat of that approach is that you need to apply the mock in the test file before you are importing your real file.
Then you will even able to assert on the mock.
For more info read jest.mock.

Related

Test set cookies function with Jest

Does someone knows how can I test this function in Jest? I don't have any ideas at this moment, maybe I need to mock Cookies ?
import Cookies from "js-cookie";
import { v4 as uuidv4 } from "uuid";
const setUserCookie = () => {
if (!Cookies.get("UserToken")) {
Cookies.set("UserToken", uuidv4(), { expires: 10 });
}
};
export default setUserCookie;
I tried this for now, but I don't know if this is correct, I don't think it tests the functionality of my function:
import Cookies from 'js-cookie';
import setCookie from './setCookie';
describe("setCookie", () => {
it("should set cookie", () => {
const mockSet = jest.fn();
Cookies.set = mockSet;
Cookies.set('testCookie', 'testValue');
setCookie()
expect(mockSet).toBeCalled();
});
});
Best way to test this is to utilize the actual logic, so I would change your test to the following:
it("should set cookie", () => {
// execute actual logic
setCookie();
// retrieve the result
const resultCookie = Cookies.get();
// expects here
expect(resultCookie["UserToken"]).toBeTruthy();
// expects for other values here...
});
To note, uuidv4() will generate a new value for every new test run, meaning that you cannot expect the same value for the "UserToken" property. Instead, you can use the following approach to tackle this problem:
First set up a spy for it:
import { v4 as uuidv4 } from "uuid";
jest.mock('uuid');
Then add its mock implementation with the expected result into the unit test:
const expectedUUIDV4 = 'testId';
uuidv4.mockImplementation(() => expectedUUIDV4);
// then expecting that in the result
expect(resultCookie["UserToken"]).toEqual(expectedUUIDV4);

Mock uuid in jest - uuid called in service function

I have a jest test that is calling the real function and it compares the result returned with an expected result. The service function called uses uuid. I have all kind of errors while trying to mock uuid and can't seem to succeed.
My code is:
import uuid from 'uuid';
import tinyRuleset from './tiny_ruleset.json';
import { Store } from '../store';
describe('TuningStore test ', () => {
let store;
let db;
beforeEach(async () => {
db = levelup(encode(memdown(), { valueEncoding: 'json' }));
store= new Store(db);
});
test('createObject()', async () => {
jest.spyOn(uuid, 'v4').mockReturnValue('abc22');
const obj = await store.createObject();
expect(obj ).toEqual({
a: expect.any(string),
b: 'tiny_ruleset',
v: expect.any(Function)
});
});
})
I tried several ways, but none of them worked. My current error is: uuid is not a function. Also tried this:
const uuidv4Spy = jest.spyOn(store.$uuid, 'v4').mockReturnValueOnce('fake uuid');
Basically uuid is used inside the store.createObject() function.
Thank you!
As explained here Mock uuid
const uuidMock = jest.fn().mockImplementation(() => {
return 'my-none-unique-uuid';
});
jest.mock('uuid', () => {
return uuidMock;
});
you need to apply the mock in the test file before you are importing your real file.

Mocking node_modules which return a function with Jest?

I am writing a typeScript program which hits an external API. In the process of writing tests for this program, I have been unable to correctly mock-out the dependency on the external API in a way that allows me to inspect the values passed to the API itself.
A simplified version of my code that hits the API is as follows:
const api = require("api-name")();
export class DataManager {
setup_api = async () => {
const email = "email#website.ext";
const password = "password";
try {
return api.login(email, password);
} catch (err) {
throw new Error("Failure to log in: " + err);
}
};
My test logic is as follows:
jest.mock("api-name", () => () => {
return {
login: jest.fn().mockImplementation(() => {
return "200 - OK. Log in successful.";
}),
};
});
import { DataManager } from "../../core/dataManager";
const api = require("api-name")();
describe("DataManager.setup_api", () => {
it("should login to API with correct parameters", async () => {
//Arrange
let manager: DataManager = new DataManager();
//Act
const result = await manager.setup_api();
//Assert
expect(result).toEqual("200 - OK. Log in successful.");
expect(api.login).toHaveBeenCalledTimes(1);
});
});
What I find perplexing is that the test assertion which fails is only expect(api.login).toHaveBeenCalledTimes(1). Which means the API is being mocked, but I don't have access to the original mock. I think this is because the opening line of my test logic is replacing login with a NEW jest.fn() when called. Whether or not that's true, I don't know how to prevent it or to get access to the mock function-which I want to do because I am more concerned with the function being called with the correct values than it returning something specific.
I think my difficulty in mocking this library has to do with the way it's imported: const api = require("api-name")(); where I have to include an opening and closing parenthesis after the require statement. But I don't entirely know what that means, or what the implications of it are re:testing.
I came across an answer in this issue thread for ts-jest. Apparently, ts-jest does NOT "hoist" variables which follow the naming pattern mock*, as regular jest does. As a result, when you try to instantiate a named mock variable before using the factory parameter for jest.mock(), you get an error that you cannot access the mock variable before initialization.
Per the previously mentioned thread, the jest.doMock() method works in the same way as jest.mock(), save for the fact that it is not "hoisted" to the top of the file. Thus, you can create variables prior to mocking out the library.
Thus, a working solution is as follows:
const mockLogin = jest.fn().mockImplementation(() => {
return "Mock Login Method Called";
});
jest.doMock("api-name", () => () => {
return {
login: mockLogin,
};
});
import { DataManager } from "../../core/dataManager";
describe("DataManager.setup_api", () => {
it("should login to API with correct parameters", async () => {
//Arrange
let manager: DataManager = new DataManager();
//Act
const result = await manager.setup_api();
//Assert
expect(result).toEqual("Mock Login Method Called");
expect(mockLogin).toHaveBeenCalledWith("email#website.ext", "password");
});
});
Again, this is really only relevant when using ts-jest, as using babel to transform your jest typescript tests WILL support the correct hoisting behavior. This is subject to change in the future, with updates to ts-jest, but the jest.doMock() workaround seems good enough for the time being.

Jest Mock a function's return value

I have a simple function like this, I would like to mock the return value of authentication.getAccessToken() with a valid accessToken, I am having hard time doing this. Tried different ways but couldn't succeed, Can someone help me on this?
import decodeJWT from "jwt-decode";
import authentication from "#kdpw/msal-b2c-react";
export const testfunction = () => {
const jwt = decodeJWT(authentication.getAccessToken());
var current_time = Date.now() / 1000;
var remaining_time = jwt.exp - current_time;
return "testing done"
}
Following is the unit test which I have been trying, As authentication.getAccessToken() doesn't get any value it is throwing InvalidToken error.
import * as commonUtil from "../commonUtil";
describe('test test function', () => {
it("Mock", () => {
//The following runs but test fails due to null return
const authentication = require("#kdpw/msal-b2c-react");
authentication.getAccessToken = jest.fn().mockReturnValue(false);
expect(commonUtil.testfunction()).toBe(false)
});
});
Error message
Comparing two different types of values. Expected boolean but received null.
You need to import authentication within your test.
See CodeSandbox example. Open with editor to check out the unit tests.
In short, you need to do something like this.
test('test test function', () => {
const resp = { data: '' };
import authentication from "#kdpw/msal-b2c-react";
authentication.getAccessToken = jest.fn().mockReturnValue("eyJ0eXAiOiJKV1QiLCJhbdjhkbE5QNC1jNTdkTzZR...");
expect(commonUtil.testfunction()).toEqual("testing done")
});
Use describe to wrap test cases that uses mocked authentication so the mocked function will only stay local in that specific describe and everything outside it will use the real authentication.getAccessToken().

writing a test case for a function in jest

I am trying to write a unit test case for the following function:
export function exportTableToCSV(data, columns, filename) {
const csv = encode(data, columns);
downloadCsv(csv, filename);
}
And here the test case:
exportTableToCSV = jest.fn();
it('testing exportTableToCSV function', () => {
const data = {
"Linkname": "ATL-HOU",
"Anode": "ATL:pos0/1",
"Aloc": "ATL"
}
const columns = Object.keys(data);
const filename = "data.csv";
exportTableToCSV(data,columns,filename);
expect(exportTableToCSV).toHaveBeenCalledWith(data,columns,filename);
}
this works but when try to add:
expect(encode).toHaveBeenCalledWith(data,columns);
it gives me an error saying it was not called.
can someone please guide me what is the correct way to write testcase for above function
I believe exportTableToCSV which is called is not the real exportTableToCSV, it is a jest.fn(). The real exportTableToCSV will invoked encode(), but you aren't using the real one here, so encode() isn't invoked.
One solution I would try would be to import the real exportTableToCSV() and have encode() as a jest.fn(). Then, when you call exportTableToCSV(), expect encode() to have been called and you will prove that both were invoked.
Here's one way to do that:
import { exportTableToCSV } from './foo'
it('testing exportTableToCSV function', () => {
const mockEncodeResult = 'i am a mock';
const encode = jest.fn((data, columns) => mockEncodeResult);
const downloadCsv = jest.fn((csv, filename) => {});
const testData = {
Linkname: 'ATL-HOU',
Anode: 'ATL:pos0/1',
Aloc: 'ATL',
};
const testColumns = Object.keys(testData);
const testFilename = 'data.csv';
exportTableToCSV(testData, testColumns, testFilename);
expect(encode).toHaveBeenCalledWith(testData, testColumns);
expect(downloadCsv).toHaveBeenCalledWith(mockEncodeResult, testFilename);
});
Please note: In the above example I do not mock exportTableToCSV. jest.fn() is a mock. This unit test imports and tests the real exportTableToCSV function, but it mocks encode() and downloadCsv(). Cheers!
UPDATE ---
Per your comment you state you are seeing an error about createObjectURL, but this is not in the sample code provided. Clearly, then, there is some problematic code in the module you are importing along with exportTableToCSV. The proper way to fix this is to mock and clean that problematic code, but because I want to provide a self-contained solution here, a second-best approach is to mock exportTableToCSV itself. In this case you will not test the original function, but only the mock. Remove the import statement and add the following inside the scope of the test case, after the definition of downloadCsv:
const exportTableToCSV = jest.fn((data, columns, filename) => {
const csv = encode(data, columns);
downloadCsv(csv, filename);
});

Categories

Resources