- Fecha de publicación
What is a mock? 🤔
- Autores
- Nombre
- x0s3
- @x0s3js
What is a mock?
Following Facebook's(aka jest) definition of mock:
Mock functions allow you to test the links between code by erasing the actual implementation of a function, capturing calls to the function (and the parameters passed in those calls), capturing instances of constructor functions when instantiated with new, and allowing test-time configuration of return values.
This definition can be a bit confusing for someone, but the goal for mocking is to replace something we don't control with something we do.
What can we do with a mock? (with real examples 👨🔧)
Capture calls 👮♂️
e.g With dependency injection 💉
import { screen, render } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
describe('Capture calls onSubmit', () => {
it('captures the `onSubmit` function call', () => {
const onSubmit = jest.fn()
const expectedOnSubmitProps = { name: 'Baki' }
// GIVEN my form is rendered
render(<MyComponent onSubmit={onSubmit} />)
// WHEN submitting the form
userEvent.click(screen.getByText('Submit'))
// THEN the given prop is called
expect(onSubmit).toHaveBeenCalledWith(expectedOnSubmitProps)
})
})
e.g Without dependency injection 💉
TBD
Set return values 🚚
e.g: Static value⚓️
jest.mock('contexts/MediaQueryContext', () => ({
...jest.requireActual('contexts/MediaQueryContext'),
useMedia: () => ({ isLarge: true, isPrint: false }), // will return always these values on each test case
}))
describe('Set return values for useMedia hook', () => {
it('returns `true` for `isLarge` and `false` for `isPrint`', () => {
// ...
})
})
e.g: Dynamic value 🧬
import { useMedia } from 'contexts/MediaQueryContext'
jest.mock('contexts/MediaQueryContext', () => ({
...jest.requireActual('contexts/MediaQueryContext'),
useMedia: jest.fn(), // we need to tell jest that useMedia will be mocked, otherwise it won't be mocked 😢
}))
describe('Set return values for useMedia hook', () => {
const useMediaMocked = useMedia as jest.Mock // in TS we need to cast it to be able to access jest mock utilities, otherwise it will complain about that mock does not contains the expected method 😅
it('returns true for isLarge and false for isPrint', () => {
useMediaMocked.mockImplementation(() => ({
isLarge: true,
isPrint: false,
}))
// ...
})
it('returns false for isLarge and true for isPrint', () => {
useMediaMocked.mockImplementation(() => ({
isLarge: false,
isPrint: true,
}))
// ...
})
})
Change the implementation of a function, module, variable etc. 🧙🏼♂️
TBD
Useful tricks and tips
If your expected mock is not working, make sure that the path that you are mocking is the same path as the component is importing.
e.g:
// MyComponent.tsx import { useMedia } from 'contexts/MediaQueryProvider' function MyComponent() { const { isLarge } = useMedia() return isLarge ? 'Hola' : 'Adios' }
// MyComponent.test.tsx // ❌ WRONG PATH! ❌ /* jest.mock('contexts/MediaQueryContext/MediaQueryContext', () => ({ ...jest.requireActual('contexts/MediaQueryContext/MediaQueryContext'), useMedia: () => ({ isLarge: true }), })); */ // ✅ CORRECT PATH! ✅ jest.mock('contexts/MediaQueryContext', () => ({ ...jest.requireActual('contexts/MediaQueryContext'), useMedia: () => ({ isLarge: true }), })) test('MyComponent', () => { render(<MyComponent />) expect(screen.getByText('Jelou')).toBeInTheDocument() })
Dynamic mock value (in the same test case 🤯) ⚠️ DISCLAIMER: USE IT AT YOUR OWN RISK (prefer to find a better approach to test your scenario) ⚠️
TBD