I've got a method inside the file test.ts:
public async listComponentsDiffer(lastTag: string, workDir: string): Promise<any[]>
This method return me a array like this :
[{ components: "toto", newVersion: "2", oldVersion: "1" }]
I'm trying to use Jest and I'm doing this for check this method:
test("correct array form", () => {
// Given
const lastag = "";
const workDir = ".";
// When
const result = ComponentsService.listComponentsDiffer(lastag, workDir);
// Then
const expected = [{ components: "toto", newVersion: "2", oldVersion: "1" }];
expect(result).toBe(expected);
});
But I've got thsi error :
TypeError: test_1.test.listComponentsDiffer is not a function Jest
How can I do my test ?
This method is an instance method, not a class method. Need to be called from an instance of the class.
This method uses async/await syntax, you need to add async/await to your test case as well.
Instead of using .toBe, you should use .toEqual.
Use .toEqual to compare recursively all properties of object instances (also known as "deep" equality)
E.g.
test.ts:
export class ComponentsService {
public async listComponentsDiffer(lastTag: string, workDir: string): Promise<any[]> {
return [{ components: 'toto', newVersion: '2', oldVersion: '1' }];
}
}
test.test.ts:
import { ComponentsService } from './test';
describe('60667611', () => {
test('correct array form', async () => {
const lastag = '';
const workDir = '.';
const instance = new ComponentsService();
const result = await instance.listComponentsDiffer(lastag, workDir);
const expected = [{ components: 'toto', newVersion: '2', oldVersion: '1' }];
expect(result).toEqual(expected);
});
});
unit test results:
PASS stackoverflow/60667611/test.test.ts (7.968s)
60667611
✓ correct array form (6ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 9.014s
Related
I have a project in Node and Typescript in which I am trying to connect to the mongoose Schema from the property of an object, only if the Schema has the same name as the value of the name property
These are the data:
Schema: const Company = require("../../schemas/companies")
MENU_PROPERTIES:
const MENU_PROPERTIES = [
{
"name":"Company",
"icon":"local_shipping"
},
{
"name":"Client",
"icon":"people"
},
{
"name":"Employee",
"icon":"account_circle"
}
]
MenuActions:
interface MenuActions {
name: string,
icon: string,
total(): Promise<number>
}
This is the first function I've tried:
let menuData: MenuActions[] = [];
for (let menu of MENU_PROPERTIES) {
menuData.push({
name: menu.name,
icon: menu.icon,
get total() {
return SCHEMA_LIST.includes(this.name) ? eval(this.name).find().count() : 0
}
})
}
Result: ERROR
TypeError: Converting circular structure to JSON
--> starting at object with constructor 'Topology'
| property 's' -> object with constructor 'Object'
| property 'sessionPool' -> object with constructor 'ServerSessionPool'
--- property 'topology' closes the circle
at JSON.stringify (<anonymous>)
at stringify (C:\Users\quality\Desktop\proyectoFinal\project-server\node_modules\express\lib\response.js:1123:12)
at ServerResponse.json (C:\Users\quality\Desktop\proyectoFinal\project-server\node_modules\express\lib\response.js:260:14)
at returnHandler (C:\Users\quality\Desktop\proyectoFinal\project-server\build\src\routes.js:148:48)
at C:\Users\quality\Desktop\proyectoFinal\project-server\build\src\routes.js:132:13
This is the second function:
let menuData: MenuActions[] = [];
for (let menu of MENU_PROPERTIES) {
menuData.push({
name: menu.name,
icon: menu.icon,
get total() {
return (async () => {
return SCHEMA_LIST.includes(this.name) ? await eval(this.name).find().count() : 0
});
}
})
}
Result: This function does not return anything, the total property does not appear in the object
[
{
"name":"Company",
"icon":"local_shipping"
},
{
"name":"Client",
"icon":"people"
},
{
"name":"Employee",
"icon":"account_circle"
}
]
I am struggling to mock the delete function in the lists component.
My test looks like this at the moment
describe("delete a todo", () => {
test("should have todo removed", async () => {
const deleteItem = jest.fn();
const items = [{ id: 1, name: "ana", isComplete: false }];
const wrapper = shallowMount(Todo, items);
console.log(wrapper);
const deleteButton = ".delete";
wrapper.find(deleteButton).trigger("click");
expect(deleteItem).toHaveBeenCalledWith("1");
});
currently, when I run the tests the error reads.
Test Error
The application works fine, but I am not mocking the delete function correctly in my test as a "New Note" is still being passed through. What am I doing wrong?
just in case it helps, here is a part of the file I am testing.
methods: {
addItem() {
if (this.newItem.trim() != "") {
this.items.unshift({
// id: createUID(10),
id: uuid.v4(),
completed: false,
name: this.newItem
});
this.newItem = "";
localStorage.setItem("list", JSON.stringify(this.items));
this.itemsLeft = this.itemsFiltered.length;
}
},
removeItem(item) {
const itemIndex = this.items.indexOf(item);
this.items.splice(itemIndex, 1);
localStorage.setItem("list", JSON.stringify(this.items));
this.itemsLeft = this.itemsFiltered.length;
},
Also for more code, you can get it from the following link :
https://github.com/oliseulean/ToDoApp-VueJS
I think you have to make some changes to your original test case
Change jest.fn() to jest.spyOn(Todo.methods, 'deleteItem') since you have to track calls to methods object in Todo component. Refer: https://jestjs.io/docs/jest-object
Wait for the click event to be triggered with await
Use toHaveBeenCalledTimes not toHaveBeenCalledWith("1")
So your final test case will look like this
describe("delete a todo", () => {
test("should have todo removed", async () => {
const removeItem = jest.spyOn(Todo.methods, 'removeItem')
const items = [{ id: 1, name: "ana", isComplete: false }];
const wrapper = shallowMount(Todo, items)
await wrapper.find('.delete').trigger('click')
expect(removeItem).toHaveBeenCalledTimes(1);
});
});
I have a simple function to test. I am using jest, and I am assigning in every it("") statement, an assertion constant, with my ArrayOfObjects.
While the first test passes. All other tests fail, cause they are using the object(assertion) from the first test.
How can I teardown the constant value in every test? Or in general fix it? Here is the code:
describe('Fn: CreateEdges', () => {
it('should RETURN [1 Key]', () => {
const assertion = [
{
identifier: {
name: '1'
}
}
];
const expectation = [
{
key: '1'
}
];
expect(createFn(assertion)).toEqual(expectation);
});
it('should RETURN [2 Keys]', () => {
const assertion = [
{
identifier: {
name: '1',
},
identifier: {
name: '2'
}
}
];
const expectation = [
{
key: '1',
},
{
key: '2',
}
];
expect(createFn(assertion)).toEqual(expectation); // This fails cause it is using the Object from test1
});
});
The createFn below:
import * as R from 'ramda';
function createnFn(array: any[]) {
return R.flatten(
array.map(({ identifier }: any) =>
identifier.key.map((marker: { name: string }) => ({
source: identifier.name,
target: marker.name,
}))
)
);
}
export default R.memoizeWith(R.identity, createFn);
As it was already mentioned, memoization causes the problem, it makes the function stateful. Non-memoized createnFn is local to the module, only memoized version of it is exported. Since it's reused between multiple tests, this results in test cross-contamination.
The solution is to re-import the module. It should be imported in tests not on top level but in tests, re-import is done with jest.isolateModules or jest.resetModules:
beforeEach(() => {
jest.resetModules();
})
it('should RETURN [1 Key]', () => {
const createFn = require('...').default;
...
expect(createFn(assertion)).toEqual(expectation);
});
Ciao, you problem could be related to function memoization.
Basically, Memoization is a technique that stores values in cache to improve performances. Try to remove R.memoizeWith(R.identity, createFn) and problem should disappears.
I am developing new application using Vue.js and axios, to get stock market details based upon company name. At the start of application, I am gathering all the US based S&p 500 company's name into javascript array
<script>
import axios from 'axios'
import StockInfo from './StockInfo.vue'
export default {
name: 'app',
data () {
return {
stockname : "",
resultArrived : false,
fetchStatus: false,
resultDetails: {
Symbol : '',
LastUpdated: '',
Open : '',
Close : '',
High : '',
Low : '',
DividendAmount : 0.0
},
errorMessage : '',
stockdetails : []
}
},
components : {
'stockdetails' : StockInfo
},
created : function() {
this.LoadStockData();
},
methods: {
LoadStockData : function()
{
var basicUrl = "https://api.iextrading.com/1.0/ref-data/symbols";
var self = this;
axios.get(basicUrl).then(result => {
// Make sure that we receive proper result
let smallset = [];
result.data.filter(function(record) {
if(record.type === "cs") {
// Convert string to lower case
let finalvalue = self.GetProperCompanyName(record.name);
let updatedvalue = {
Symbol : record.symbol,
Name : finalvalue
};
smallset.push(updatedvalue);
return updatedvalue;
}
});
this.stockdetails = smallset;
}, error => {
this.errorMessage = error.message;
this.resultArrived = false;
this.fetchStatus = true;
});
},
}
}
</script>
describe('User input Scenario', () => {
jest.mock('axios');
it('App should be mounted',async () => {
const appwrapper = mount(app);
await appwrapper.vm.$nextTick();
expect(axios.get).toHaveBeenCalledWith('https://api.iextrading.com/1.0/ref-data/symbols');
expect(appwrapper.vm.stockdetails.length).toBeGreaterThan(0);
});
});
Now I want to unit test this scenario using jest and testutil, so I written following test case
describe('User input Scenario', () => {
jest.mock('axios');
it('App should be mounted',async () => {
const appwrapper = mount(app);
await appwrapper.vm.$nextTick();
expect(axios.get).toHaveBeenCalledWith('https://api.iextrading.com/1.0/ref-data/symbols');
expect(appwrapper.vm.stockdetails.length).toBeGreaterThan(0);
});
});
But when I ran this test case, I am getting following errors
FAIL ./App.test.js
● User input Scenario › App should be mounted
expect(jest.fn())[.not].toHaveBeenCalledWith()
jest.fn() value must be a mock function or spy.
Received:
function: [Function wrap]
63 | await appwrapper.vm.$nextTick();
64 |
> 65 | expect(axios.get).toHaveBeenCalledWith('https://api.iextrading.com/1.0/ref-data/symbols');
| ^
66 | expect(appwrapper.vm.stockdetails.length).toBeGreaterThan(0);
67 | });
68 |
at toHaveBeenCalledWith (App.test.js:65:27)
at tryCatch (node_modules/regenerator-runtime/runtime.js:62:40)
at Generator.invoke [as _invoke] (node_modules/regenerator-runtime/runtime.js:296:22)
at Generator.prototype.(anonymous function) [as next] (node_modules/regenerator-runtime/runtime.js:114:21)
at step (App.test.js:23:191)
at App.test.js:23:361
Test Suites: 1 failed, 1 passed, 2 total
Tests: 1 failed, 7 passed, 8 total
Snapshots: 0 total
Time: 5.328s
Maybe need import axios in test file also
import axios from 'axios';
And try to mock get method of it
axios.get.mockResolvedValue({data: 'something'});
Example in Jest: https://jestjs.io/docs/en/mock-functions#mocking-modules
Also exist separate npm packages for mock axios during testing jest-mock-axios or similar
Александр Смышляев
Second part of answer did the trick, for axios, it need mocking with expected result value
jest.mock('axios', () => ({
get: jest.fn()
}));
describe("Basic App.vue Layout Verification", () => {
let appwrapper;
beforeEach(() => {
axios.get.mockClear();
axios.get.mockReturnValue(Promise.resolve({}));
});
it('App Mounting verfication',async () => {
// Given
const result = {
data : [{
symbol: "A",
name: "Agilent Technologies Inc.",
date: "2018-12-28",
isEnabled: true,
type: "cs",
iexId: "2"
},
{
symbol: "A",
name: "Agilent Technologies Inc.",
date: "2018-12-28",
isEnabled: true,
type: "cs",
iexId: "2"
},
{
symbol: "A",
name: "Agilent Technologies Inc.",
date: "2018-12-28",
isEnabled: true,
type: "cs",
iexId: "2"
},
{
symbol: "A",
name: "Agilent Technologies Inc.",
date: "2018-12-28",
isEnabled: true,
type: "cs",
iexId: "2"
}
]};
axios.get.mockReturnValue(Promise.resolve(result));
const appwrapper = mount(app);
await appwrapper.vm.$nextTick();
expect(axios.get).toHaveBeenCalledWith('https://api.iextrading.com/1.0/ref-data/symbols');
expect(appwrapper.vm.stockdetails.length).toBeGreaterThan(0);
expect(typeof appwrapper.vm.stockdetails).toEqual("object");
// Now validate actual result parsed by webservice return value
expect(appwrapper.vm.stockdetails[0].Symbol).toEqual("A");
expect(appwrapper.vm.stockdetails[0].Name).toEqual("agilent technologies");
});
});
Ive mocked localStorage as suggested on another threat but i cant get the tests to work i tried multiple times with no success.
This is the mock
class LocalStorageMock {
constructor() {
this.store = {};
}
clear() {
this.store = {};
}
getItem(key) {
return this.store[key] || null;
}
setItem(key, value) {
this.store[key] = value.toString();
}
removeItem(key) {
delete this.store[key];
}
}
This is the function that im trying to test.
const setToLS = (target, value) => {
localStorage.setItem(target, JSON.stringify(value));
};
const saveToLS = (target, item) => {
let items;
if (localStorage.getItem(target)) {
items = utilities.addItem(JSON.parse(localStorage.getItem(target)), item);
} else {
items = utilities.addItem([], item);
}
setToLS(target, items);
};
This the test that i cant get to work.
describe('utilitiesLS', () => {
describe('saveToLS', () => {
it('should save item to LS')', () => {
const target = 'recipes';
const item = { name: 'salat', ingredients: 'spinach', id: 1 };
utilitiesLS.saveToLS(target, item)
expect(localStorage.store).toMatch( '{"recipes": [{"id": 1, "ingredient": "spinach", "recipeName": "salat"}]}'
)
});
});
});
And this is the error.
expect(string)[.not].toMatch(expected)
string value must be a string.
Received: undefined
29 | const item = { recipeName: 'salat', ingredients: 'spinach', id: 1 };
30 | utilitiesLS.saveToLS(target, item)
> 31 | expect(localStorage.store).toMatch( '{"recipes": [{"id": 1, "ingredient": "spinach", "recipe
Name": "salat"}]}'
| ^
32 | )
33 | });
34 | });
The problem is your test.
LocalStorageMock.store is an object, but your test expect(localStorage.store).toMatch( '{"reci... is testing it to see if it's a string. This is why your test is not passing, because objects do not match strings.
To fix this you should test:
expect(localStorage.store).toEqual({"recipes": [{"id": 1, "ingredient": "spinach", "recipeName": "salat"}]})
Noting that localStorage.store is undefined indicates that you are also not getting the constructed instance of your mock that your test is using.
n.b. If you're trying to mock local storage, consider one of the pre-built, tested and documented approaches such as:
https://www.npmjs.com/package/jest-localstorage-mock