I'm using Jest 26.x and I defined a custom testEnvironment as so:
import type { EnvironmentContext } from '#jest/environment';
import { Config } from '#jest/types';
import JSDOMEnvironment from 'jest-environment-jsdom';
declare global {
function expectAndMore<ExpectedObject>(
result: ExpectedObject,
expectedObject: ExpectedObject,
): void;
}
class ApprovalTestEnvironment extends JSDOMEnvironment {
constructor(config: Config.ProjectConfig, context: EnvironmentContext) {
super(config, context);
}
async setup() {
await super.setup();
this.global.expectAndMore = ({ result, expectedObject }) => {
expect(result).toEqual(expectedObject);
};
}
async teardown() {
await super.teardown();
}
getVmContext() {
return super.getVmContext();
}
}
export default ApprovalTestEnvironment;
I then configured a unit test file with these comments at the header of my file so it would use the custom environment defined above:
/**
* #jest-environment ./src/approvals/approvalTestEnvironment.ts
*/
But whenever I'm trying to access the expectAndMoreFunction defined in my custom environment with globalThis.expectObjectForPostRequest(result, expected);, I get the following error:
ReferenceError: expect is not defined
Does anyone what causes this and how to fix it?
Note: I'm also using ts-jest 27.1.4.
Related
When setting up jest mocks for a class what does not work for me with an error of "_TextObj.TextObj is not a constructor" is
import { TextObj, } from "#entities/TextObj";
jest.mock('#entities/TextObj', () => {
return jest.fn().mockImplementation((config: TextObjConfig) => {
return { ...
}
});
});
According to https://jestjs.io/docs/es6-class-mocks#calling-jestmock-with-the-module-factory-parameter I had expected the first version to work too - or not?
however what works is
import { TextObj, } from "#entities/TextObj";
jest.mock('#entities/TextObj');
...
beforeAll(() => {
TextObj.mockImplementation((config: TextObjConfig) => {
return {
..
}
});
});
TextObj is a named export and you're trying to mock default export which is why it is throwing the error _TextObj.TextObj is not a constructor.
For mocking named export, you need to do following the changes i.e return an object that contains TestObj property:
import { TextObj, } from "#entities/TextObj";
jest.mock('#entities/TextObj', () => {
TestObj: jest.fn().mockImplementation((config: TextObjConfig) => {
return { ...
}
});
});
When I run test, it show TypeError: Cannot destructure property 'travelDatas' of '(0 , _GetTravelDatas.getTravelDatas)(...)' as it is undefined.
As you see the screenshot: unit test
There isn't any console error or warning.
Could anyone help please
travelListTest.spec.js
import { mount, shallowMount } from '#vue/test-utils'
import TravelList from '../../src/components/TravelList.vue'
import { getTravelDatas } from '../../src/composables/GetTravelDatas'
import ElementPlus from 'element-plus'
const wrapper = shallowMount(TravelList, {
global: {
plugins: [ElementPlus]
}
})
jest.mock('../../src/composables/GetTravelDatas')
describe('TravelList Test', () => {
test('click more will call GoToTravelDetailPage', () => {
wrapper.vm.GoToTravelDetailPage = jest.fn()
console.log(wrapper.html())
wrapper.find('.el-button').trigger('click')
expect(wrapper.vm.GoToTravelDetailPage).toHaveBeenCalled()
})
})
TravelList.vue
.....
<script>
import { ref } from '#vue/reactivity';
import { useRouter } from "vue-router";
import { getTravelDatas } from '../composables/GetTravelDatas'
export default {
name: 'TravelList',
setup() {
const { travelDatas } = getTravelDatas();
const router = useRouter();
function GoToTravelDetailPage(acctractionId) {
router.push({ path: `/travelDetail/${acctractionId}` })
}
return { travelDatas, GoToTravelDetailPage };
},
};
</script>
GetTravelDatas.js
import axios from "axios";
import { ref } from '#vue/runtime-core';
export function getTravelDatas() {
const travelDatas = ref([])
axios.get('https://localhost:5001/MyTravel/GetTravelData')
.then((response) => {
if (!response.data.success) {
alert(response.data.errorMessage)
}else{
travelDatas.value = response.data.travelDetail
}
}).catch((error) => {
alert('Unexpected Error: ', error.message)
console.log(error)
});
return { travelDatas }
}
You are mocking the GetTravelDatas module with an auto-mock version by calling:
jest.mock('../../src/composables/GetTravelDatas')
That means that all the methods exported from that module will be mocked (the real code of the method will not be called) and the mocked version will return undefined when called.
In the code you are testing you then have:
const { travelDatas } = getTravelDatas();
Reading the travelDatas property from undefined is causing the error you are seeing.
You should mock the getTravelDatas method so that it returns the appropriate data. For example, returning an empty array would look like:
getTravelDatas.mockReturnValue([]);
The code I am trying to test the driver / repository for my nodeJS project:
import { Injectable, OnModuleInit } from '#nestjs/common';
import { mapping, types } from 'cassandra-driver';
import { Products } from './poducts.model';
import { CassandraService } from '../database/cassandra/cassandra.service';
import Uuid = types.Uuid;
#Injectable()
export class ProductsRepository implements OnModuleInit {
constructor(private cassandraService: CassandraService) {}
productsMapper: mapping.ModelMapper<Products>;
onModuleInit() {
const mappingOptions: mapping.MappingOptions = {
models: {
Products: {
tables: ['products'],
mappings: new mapping.UnderscoreCqlToCamelCaseMappings(),
},
},
};
this.productsMapper = this.cassandraService
.createMapper(mappingOptions)
.forModel('Products');
}
async getProducts() {
return (await this.productsMapper.findAll()).toArray(); // <-----Breaks here with findAll()
}
}
I am trying to write something like this:
describe('product repository get all', () => {
it('calls the repository get all', async () => {
const await productsRepository.getProducts();
expect().DoSomething()
});
});
This is the error I am getting:
Cannot read property 'findAll' of undefined
How would I accomplish a meaning-full test with Jest to get proper code coverage?
When I try to use jest to spy on the this.products.Mapper.findAll() it seems to break every time.
My e2e test is returning TypeError: metadata_1.Public is not a function for a controller that is using the custom decorator #Public()
Some code is omitted for clarity
it(`/GET forks`, async () => {
const fork: ForksModel = {
type: 'Full Copy',
};
await request(app.getHttpServer())
.get('/forks')
.expect(200)
.expect({ fork: expectedForks});
});
#Public()
public async getAccountForks(#Req() req: Request) {
const { account } = req;
const fork = await this.service.getAccountForks(account);
return { fork, account };
}
public.decorator.ts
import { SetMetadata } from "#nestjs/common";
export const Public = () => SetMetadata( "isPublic", true );
I don't know what is happening here, it doesn't complain this when running nest
This is imported
import { Public } from '#app/utils/metadata';
So i just forgot to export my metadata files from the root utils index.ts!
But Nest didn't complain and the decorator was functional on my Guard when testing!
With Nodejs, I am calling a function called customFunction which is a mutation from a GrpahQL Resolver. I don't have acces to this.
import { Mutation } from './mutation/Mutation'
export default {
Query,
Mutation,
}
then in Mutation.ts
import { customFunctionMutation } from './customFunctionMutation'
export const Mutation = {
customFunction: customFunctionMutation.customFunction,
}
then in customFunctionMutation.ts
export const customFunctionMutation = {
test() {
console.log('test called')
},
async customFunction(parent: any, args: any, ctx: any, info: any) {
console.log('customFunction init')
console.log('this', this)
this.test()
console.log('customFunction end')
},
}
this is undefined and i cannot called the function test() which is in the same object
You separated the method from the object that has the test method when you did this:
import { customFunction } from './customFunction'
So, then when you try to call customFunction() it will have no association with the object it is declared inside of and thus it can't reference this.test() because this will be undefined.
FYI, giving the same name to the export and a property on the export is hopelessly confusing to your clients. Please don't do that.
I would suggest fixing it by making your module be independent of how it was called by changing it to no longer use this:
const moduleObj = {
test() {
console.log('test called')
},
async customFunction(parent: any, args: any, ctx: any, info: any) {
console.log('customFunction init')
console.log('this', this)
moduleObj.test()
console.log('customFunction end')
},
}
export default moduleObj;
Then, you can use:
import { customFunction } from './customFunction'
And, you can then call:
customFunction()
and it will be able to function properly when called.
Probably one of these could work:
import { customFunction } from './customFunction'
export const Mutation = {
customFunction: customFunction.customFunction.bind(customFunction),
}
or
import { customFunction } from './customFunction'
export const Mutation = customFunction
or
import { customFunction } from './customFunction'
export const Mutation = {
customFunction: function functionName(...parameters) { return customFunction.customFunction(...parameters); },
}