Apollo MockedProvider is throwing error 'Element type is invalid' - apollo

I'm trying to test a React component that uses Apollo userQuery but I'm getting this error:
console.error node_modules/react/cjs/react.development.js:209
Warning: React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite
components) but got: undefined. You likely forgot to export your
component from the file it's defined in, or you might have mixed up
default and named imports.
Here is my test
import { MockedProvider } from '#apollo/client/testing'
import React from 'react'
import { render } from '#testing-library/react'
import { customerList } from '../../mocks'
import { ListCustomers } from '../../queries'
import CustomerListContainer from '../CustomerListContainer'
import '#testing-library/jest-dom'
const mocks = [
{
request: {
query: ListCustomers,
},
result: {
data: customerList,
},
},
]
describe('components: <CustomerListContainer />', () => {
it('renders customer list', () => {
render(
<MockedProvider mocks={mocks} addTypename={false}>
<CustomerListContainer customerRole="ADMIN" />
</MockedProvider>
)
})
})
Here is the component I'm testing:
import React from 'react'
import { useQuery } from '#apollo/client'
import { CustomerList } from '../components'
import { ListCustomers } from '../queries'
const CustomerListContainer = ({ customerRole }: { customerRole: string }) => {
const { data, loading, error } = useQuery(ListCustomers, {
variables: {
filter: {
role: {
eq: customerRole,
},
},
},
})
if (error) return <h1>Something went wrong.</h1>
if (loading) return <h1>Loading...</h1>
return (
<CustomerList customers={data.listCustomers.items} />
)
}
export default CustomerListContainer
From my package.json:
"#apollo/client": "^3.7.1",
"#testing-library/jest-dom": "^5.16.5",
"#testing-library/react": "^13.4.0",
"#testing-library/user-event": "^13.5.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
For context I used Create React App.

I needed to upgrade to the latest version of react-scripts, in my case version 5.0.1.

Related

"ReferenceError: Worker is not defined when running tests in Jest"

I am using Jest to run tests for a React app, and I am seeing the following error when running the tests:
ReferenceError: Worker is not defined
This error is occurring even though the component that is being tested is not using the heic2any library. The error is causing the tests to stop running.
Here is the code for the component that is being tested:
import { Button } from '#material-ui/core';
import { ReactElement } from 'react';
import useBreakpoint from 'src/hooks/useBreakpoint';
interface ActionButtonProps {
isMobileOnly?: boolean;
icon?: ReactElement;
onClick?: () => void;
['data-testid']?: string
}
const ActionButton = ({ isMobileOnly = false, icon, onClick, ...rest }: ActionButtonProps) => {
const { isMobile } = useBreakpoint();
const text = isMobile ? 'Add' : 'Add Photo Description Set';
if ((!isMobile && isMobileOnly) || (isMobile && !isMobileOnly)) {
return null;
}
return (
<Button
data-testid={rest['data-testid']}
startIcon={icon}
variant="outlined"
onClick={onClick}
>
{text}
</Button>
);
};
export default ActionButton;
This is the code of the component where heic2any was imported (which is another file)
import React from 'react';
import { SxProps } from '#material-ui/system';
import { PencilAlt } from 'src/icons';
import heic2any from 'heic2any';
interface FileImageDropzoneProps extends DropzoneOptions {
cardMediaSx?: SxProps;
}
const FileImageDropzone: React.FC<FileImageDropzoneProps> = (props) => {
// component code goes here...
};
export default FileImageDropzone;
Here's my unit test:
import ActionButton from '../ActionButton';
import { render, screen, cleanup, fireEvent } from '#testing-library/react';
import useBreakpoint, { BreakpointHook } from 'src/hooks/useBreakpoint';
import '#testing-library/jest-dom';
afterEach(cleanup)
jest.mock('src/hooks/useBreakpoint');
const mockUseBreakpoint: jest.Mock<BreakpointHook> = useBreakpoint as jest.Mock<BreakpointHook>;
describe('ActionButton', () => {
it('should render the compnent', () => {
render(<ActionButton data-testid='action-button' />);
mockUseBreakpoint.mockReturnValue({
isMobile: true,
isDesktop: false,
})
const { getByTestId } = screen
expect(getByTestId('action-button')).toBeInTheDocument()
});
});
Here's my jest config :
module.exports = {
preset: 'ts-jest',
testEnvironment: 'jsdom',
transform: {
'^.+\\.tsx?$': [
'ts-jest',
{
isolatedModules: true,
},
],
},
testMatch: ['**/src/**/__tests__/**/*.test.ts?(x)'],
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
collectCoverage: true,
coveragePathIgnorePatterns: [
'/node_modules/',
'/__tests__/',
'/dist/',
'/coverage/',
],
setupFilesAfterEnv: [
'#testing-library/jest-dom/extend-expect',
'jest-canvas-mock',
'<rootDir>/jest.setup.ts',
],
moduleNameMapper: {
'^components/(.*)$': '<rootDir>/src/components/$1',
},
testPathIgnorePatterns: ['node_modules'],
moduleNameMapper: {
'^src/(.*)$': '<rootDir>/src',
},
moduleDirectories: ['node_modules'],
coverageThreshold: {
global: {
branches: 80,
functions: 80,
lines: 80,
statements: 80,
},
},
};
I am not sure why this error is occurring or how to fix it. Can anyone help me understand what is causing this issue and how to resolve it? The error even shows even if i commented out the it()

How to mock an inject repository with Jest and NestJS?

In a NestJS project using Jest test the service case. I created a find method and use it in a resolver(GraphQL) function. When test the resolver, it can't find the find method in the service.
src/serivce/post.ts
import { Injectable } from '#nestjs/common';
import { InjectRepository } from '#nestjs/typeorm';
import { AbstractPostRepository } from '#abstractRepository/AbstractPostRepository';
import { PostRepository } from '#repository/PostRepository';
#Injectable()
export class PostService {
constructor(
#InjectRepository(PostRepository)
private postRepo: AbstractPostRepository,
) {}
async findById(id: string) {
const posts = await this.postRepo.findById(id);
......
return posts;
}
}
src/resolver/query/post.ts
import { Args, Query, Resolver } from '#nestjs/graphql';
import { Authorized } from '#lib/auth/authorized';
import { PermissionScope } from '#lib/auth/permissionScope';
import { PostService } from '#service/postService';
#Resolver()
export class PostsResolver {
constructor(private postService: PostService) {}
#PermissionScope()
#Authorized([
PermissionEnum.READ_MANAGEMENT,
])
#Query()
async findPosts() {
return await this.postService.findById(id);
}
}
The unit test for a resolver related this service:
test/unit/resolver/post.spec.ts
import { Test, TestingModule } from '#nestjs/testing';
import { PERMISSION_MANAGER } from '#lib/auth/permissionManager.module';
import { PostsResolver } from '#resolver/query/post';
import { PostService } from '#service/postService';
describe('PostsResolver', () => {
let resolver: PostsResolver;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
PostsResolver,
{
provide: PERMISSION_MANAGER,
useValue: jest.fn(),
},
{
provide: PostService,
useFactory: () => ({
findById: jest.fn(() => [
{
id: '11111111-1111-1111-1111-111111111111',
name: 'name1',
},
]),
}),
},
],
}).compile();
resolver = module.get<PostsResolver>(PostsResolver);
});
describe('findPosts', () => {
it('should return data', async () => {
const posts = await resolver.findPosts({
id: '11111111-1111-1111-1111-111111111111',
});
const expected = [
{
id: '11111111-1111-1111-1111-111111111111',
name: 'name1',
},
];
expect(posts).toEqual(expected);
});
});
});
When run this test got error:
● PostsResolver › findPosts › should return data
TypeError: Cannot read properties of undefined (reading 'findById')
22 | { id }: FindPostsInput,
23 | ) {
> 24 | return await this.postService.findById(
| ^
25 | id,
26 | );
at PostsResolver.findPosts (src/resolver/query/post.ts:24:41)
at Object.<anonymous> (test/unit/resolver/post.spec.ts:59:42)
It seems the mock service findById in the Test.createTestingModule doesn't work. How to mock correctly? Is it related some inject reasons?

Mock objection model dependecy in NestJs with Jest

I'm trying to make unit test with nestjs and objection. The problem I have is that I can't mock the "User" Model that is injected with the decorator "#InjectModel". I searched a lot to find a solution but I didn't find anything.
users.service.ts
import { HttpException, HttpStatus, Inject, Injectable } from '#nestjs/common';
import { CreateUserDto } from './create-user.dto';
import { User } from 'src/app.models';
import { InjectModel } from 'nestjs-objection';
#Injectable()
export class UsersService {
constructor(
#InjectModel(User) private readonly userModel: typeof User,
) {}
async create(createUserDto: CreateUserDto) {
try {
const users = await this.userModel.query().insert(createUserDto);
return users
} catch (err) {
console.log(err)
throw new HttpException(err, HttpStatus.BAD_REQUEST);
}
}
}
users.service.spec.ts
import { Test, TestingModule } from "#nestjs/testing";
import { UsersService } from "../src/users/users.service";
import { CreateUserDto } from "src/users/create-user.dto";
import { User } from "../src/app.models";
import { getObjectionModelToken } from 'nestjs-objection';
describe('userService', () => {
let userService: UsersService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
UsersService,
{
provide: User,
useValue: {}
},
],
}).compile();
userService = module.get<UsersService>(UsersService);
});
it('Should be defined', () => {
expect(userService).toBeDefined();
});
it('Should add pin to a created user', async () => {
const createUserDTO: CreateUserDto = {
email: 'mockEmail#mock.com',
userName: 'user'
}
const res = await userService.create(createUserDTO)
expect(res).toHaveProperty('pin')
});
I tried to use import { getObjectionModelToken } from 'nestjs-objection'; inside provider like this:
providers: [
UsersService,
{
provide: getObjectionModelToken(User),
useValue: {}
},
],
I got this error
It asks for a "connection" but I don't know what to put on it.
I suppose "getObjectionModelToken" is the function to mock the "InjectModel". When I pass an empty string
I got this error:
● Test suite failed to run
Cannot find module 'src/app.models' from '../src/users/users.service.ts'
Require stack:
C:/nestjs-project/nestjs-knex/src/users/users.service.ts
users.repository.spec.ts
1 | import { HttpException, HttpStatus, Inject, Injectable } from '#nestjs/common';
2 | import { CreateUserDto } from './create-user.dto';
> 3 | import { User } from 'src/app.models';
| ^
4 | import {
5 | InjectModel,
6 | synchronize,
at Resolver._throwModNotFoundError (../node_modules/jest-resolve/build/resolver.js:491:11)
at Object.<anonymous> (../src/users/users.service.ts:3:1)
If I change the path it breaks the correct functionality of the app
That looks like an error from jest not understanding what src/* imports are. Either use relative imports rather than absolute (e.g. use import { User } from '../app.models') or tell jest how to resolve src/* imports via the moduleNameMapper in your jest.config.js or package.json
{
"moduleNameMapper": {
"^src/(.*)$": "<rootDir>/path/to/src/$1"
}
}
I think based on the error your /path/to/src should be ../src but I'm not 100% sure, so make sure you set that correctly.

vuejs unit test a component which has a child component

I want to test a TheLogin.vue component that has a child BaseInput.vue component. I tried the code below and also shallowMount but I keep getting the error below.
TheLogin.vue
<template>
<section>
<legend>
Hello Login
</legend>
<BaseInput id="userName"></BaseInput>
</section>
</template>
export default {
name: 'TheLogin',
data() {
return {
userName: null
}
}
}
TheLogin.spec.js
import TheLogin from '#/pages/login/TheLogin.vue';
import BaseInput from '#/components/ui/BaseInput.vue';
import { createLocalVue, mount } from '#vue/test-utils';
describe('TheLogin.vue', () => {
const localVue = createLocalVue();
localVue.use(BaseInput); // no luck
it('renders the title', () => {
const wrapper = mount(TheLogin, {
localVue,
// stubs: {BaseInput: true // no luck either
// stubs: ['base-input'] // no luck again
});
expect(wrapper.find('legend').text()).toEqual(
'Hello Login'
);
});
I import my base components in a separate file which I import into my main.js
import Vue from 'vue';
const components = {
BaseInput: () => import('#/components/ui/BaseInput.vue'),
BaseButton: () => import('#/components/ui/BaseButton.vue'),
//et cetera
};
Object.entries(components).forEach(([name, component]) =>
Vue.component(name, component)
);
The error I'm getting is:
TypeError: Cannot read property 'userName' of undefined
UPDATE
Turned out it was Vuelidate causing the error (the code above was not complete). I also had in my script:
validations: {
userName: {
required,
minLength: minLength(4)
},
password: {
required,
minLength: minLength(4)
}
}
I solved it by adding in my test:
import Vuelidate from 'vuelidate';
import Vue from 'vue';
Vue.use(Vuelidate);
Have you tried to shallow mount the component without using localVue and setting BaseInput as a stub?
Something like:
import TheLogin from '#/pages/login/TheLogin.vue';
import { shallowMount } from '#vue/test-utils';
describe('TheLogin.vue', () => {
it('renders the title', () => {
const wrapper = shallowMount(TheLogin, {
stubs: { BaseInput: true }
});
expect(wrapper.find('legend').text()).toEqual(
'Hello Login'
);
});
});

redux saga put not dispatching action

I'm trying to to do integration tests, by mounting a smart connected component.
The fetch action that is within componentDidMount of my smart components dispatches just fine, and it's taken by my Saga. Although it is supposed to put a success action, it doesn't .
Here is my testing code :
import React from 'react'
import { Provider } from 'react-redux'
import configureMockStore from 'redux-mock-store'
import MockAdapter from 'axios-mock-adapter'
import Enzyme,{ mount,render } from 'enzyme'
import Tasks from '../containers/tasks.jsx'
import createSagaMiddleware from 'redux-saga'
import axios from "axios";
import Adapter from 'enzyme-adapter-react-16';
import mySaga from '../actions/tasksSaga'
import { createStore, combineReducers, applyMiddleware } from 'redux'
import reducer from '../reducers'
Enzyme.configure({ adapter: new Adapter() });
describe('App', () => {
// create the saga middleware
const sagaMiddleware = createSagaMiddleware()
const mock = new MockAdapter(axios)
const state = {
tasksReducer:{
tasks:[]
},
uiReducer :{
}
};
const todos = [
{
id: 1,
title: 'todo1',
description: 'nice'
},
{
id: 2,
title: 'todo2',
description: 'nice'
}
]
beforeAll(() => {
mock.onGet('http://localhost:9001/tasks').reply(200, {tasks:todos})
})
it('renders an App container', () => {
const store = createStore(
reducer,
applyMiddleware(sagaMiddleware),
)
sagaMiddleware.run(mySaga)
const wrapper = mount(
<Provider store={store}>
<Tasks />
</Provider>
)
wrapper.instance().forceUpdate()
expect(wrapper.find('Task')).toHaveLength(3)
})
})
My success action is never called although data is good.