https://github.com/userlike/joke
Typesafe mock utility with minimal boilerplate for jest
https://github.com/userlike/joke
babel jest mock typescript
Last synced: 2 months ago
JSON representation
Typesafe mock utility with minimal boilerplate for jest
- Host: GitHub
- URL: https://github.com/userlike/joke
- Owner: userlike
- License: mit
- Created: 2020-02-06T23:32:43.000Z (almost 6 years ago)
- Default Branch: master
- Last Pushed: 2025-02-09T12:16:19.000Z (11 months ago)
- Last Synced: 2025-03-28T13:21:16.616Z (9 months ago)
- Topics: babel, jest, mock, typescript
- Language: TypeScript
- Homepage:
- Size: 1.09 MB
- Stars: 18
- Watchers: 11
- Forks: 1
- Open Issues: 5
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
## 🍭 joke
`joke` is a typesafe, boilerplate free version of `jest.mock`.
## Advantages
- Less boilerplate than `jest.mock`.
- Type-safe imports. No more type-casting.
- TS/JS Language Server recognizes them when moving files around.
- Supports partial mocking (`mockSome`).
## Usage
### Install
```
npm install --saveDev @userlike/joke @userlike/babel-plugin-joke
```
```
yarn add -D @userlike/joke @userlike/babel-plugin-joke
```
### Babel config
Add `@userlike/babel-plugin-joke` to your babel plugins.
If you use [`ts-jest`](https://www.npmjs.com/package/ts-jest), please additionally refer to the "Usage with `ts-jest`" section below.
### And use
```typescript
import { mock } from "@userlike/joke";
const { fetchUser } = mock(import("./service"));
fetchUser.mockReturnValue(Promise.resolve({ id: 1, name: "Jane Doe" }));
```
---
## Full mocking
Auto-mock the whole module.
```typescript
import { mock } from "@userlike/joke";
const { fetchUser } = mock(import("./service"));
fetchUser.mockReturnValue(Promise.resolve({ id: 1, name: "Jane Doe" }));
```
### Full mocking with partial implementation
Use the second argument of `mock` to provide a partial implementation. Behind the scenes, it extends auto-mocked module with the given implementation using `Object.assign`.
```typescript
import { mock } from "@userlike/joke";
const { fetchUser } = mock(import("./service"), () => ({
fetchUser: () => Promise.resolve({ id: 1, name: "Jane Doe" })
}));
```
---
## Partial mocking
When you need to mock a module partially and want to keep the rest of the module unmocked, you can use `mockSome`. Behind the scenes, it uses `jest.requireActual` by extending its actual implementation with the given implementation using `Object.assign`.
```typescript
import { mockSome } from "@userlike/joke";
import { renderUser } from "./my-component";
// fetchUser is mocked, getUserId is the real implementation
const { fetchUser, getUserId } = mockSome(import("./service"), () => ({
fetchUser: jest.fn()
}));
test(async () => {
const user = { id: 1, name: "Jane Doe" };
fetchUser.mockReturnValue(Promise.resolve(user));
await renderUser();
expect(document.getElementById("#user-id").innerText).toBe(getUserId(user));
});
```
---
## Full replacement
When you want to skip auto-mocking, you can use `mockAll`. It's equivalent to `jest.mock(module, moduleFactory)`.
```typescript
import { mockAll } from "@userlike/joke";
import { renderUser } from "./my-component";
const { fetchUser } = mockAll(import("./service"), () => ({
fetchUser: jest.fn()
}));
test(async () => {
const user = { id: 1, name: "Jane Doe" };
fetchUser.mockReturnValue(Promise.resolve(user));
await renderUser();
expect(document.getElementById("#user-id").innerText).toBe(getUserId(user));
});
```
---
## Usage with `ts-jest`
If you use [`ts-jest`](https://www.npmjs.com/package/ts-jest) instead of Babel, you need to additionally ensure each of the following:
- That Babel preprocessing is enabled in your `ts-jest` configuration section.
- That Babel is configured to use `joke` as a plugin.
- That the `module` key of `tsconfig.json`'s `compilerOptions` is set to at least `es2020`, or `esnext` to support dynamic imports. You may also need to set `moduleResolution` to `node` for the general `import` syntax to work properly.
- That the code is transpiled down to the JS syntax `jest` understands (you may use `@babel/preset-env` for that purpose).
**Note**: if you don't want to modify your main `tsconfig.json` file, you can introduce a separate configuration named e.g. `tsconfig.tests.json`.
Example Typescript configuration for tests:
```typescript
{
"extends": "tsconfig.json",
"compilerOptions": {
"module": "ES2020",
"moduleResolution": "node"
}
}
```
To enable Babel preprocessing in `ts-jest`, as well as to configure the `tsconfig` file you want use for tests, add or update the `globals` section in your jest config.
Example with separate Babel and Typescript configuration files:
```typescript
"globals": {
'ts-jest': {
"babelConfig": "true",
"tsConfig": "tsconfig.test.json"
}
}
```
Example with inline Typescript and Babel configuration:
```typescript
"globals": {
'ts-jest': {
"babelConfig": {
"plugins": ["@userlike/babel-plugin-joke"],
"presets": [
[
"@babel/preset-env",
{
"targets": {
"node": 'current'
}
}
]
]
},
"tsConfig": {
"module": "es2020",
"moduleResolution": "node",
}
}
}
```
For details, see [`ts-jest` configuration docs](https://kulshekhar.github.io/ts-jest/user/config/).