Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: Add README #8

Merged
merged 4 commits into from
Mar 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
204 changes: 204 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
# jest-ctx

Pass context to [Jest](https://jestjs.io) hooks and tests.

## Getting Started

$ npm i -D github:ianpurvis/jest-ctx.git

$ yarn add -D github:ianpurvis/jest-ctx.git

`jest-ctx` exports the same module interface as `@jest/globals`, so it is easy
to drop into your codebase:

import {
afterAll,
afterEach,
beforeAll,
beforeEach,
describe,
expect,
jest,
test // aliases such as `it` are available as well.
} from 'jest-ctx'

If you would like to mimic Jest's
[injectGlobals](https://jestjs.io/docs/configuration#injectglobals-boolean)
option, create a [setup file](https://jestjs.io/docs/configuration#setupfilesafterenv-array) with the
following:

import * as globals from 'jest-ctx'
Object.assign(globalThis, globals)

## Usage

Context can be anything you like including objects, arrays, and primitives. It
is undefined by default. To give some context, use a `beforeAll` or
`beforeEach` hook.

### `beforeAll(fn, timeout)`

You can set the context of any test group (top-level or described) by returning
data from a `beforeAll` hook:

beforeAll(() => '🍐');
it('has group context', (ctx) => expect(ctx).toEqual('🍐'));

`beforeAll` hooks receive context as their first argument, which allows for
accumulation:

beforeAll(() => '🍐');
beforeAll((ctx) => ctx + '🍐');
it('accumulates group context', (ctx) => expect(ctx).toEqual('🍐🍐'));

`beforeAll` hooks of described groups inherit the context of their ancestors:

beforeAll(() => '🍐');

describe('group one', () => {
beforeAll((ctx) => ctx + '🍎');
it('inherits group context', (ctx) => expect(ctx).toEqual('🍐🍎'));
})

describe('group two', () => {
beforeAll((ctx) => ctx + '🍊');
it('inherits group context', (ctx) => expect(ctx).toEqual('🍐🍊'));
})


### `beforeEach(fn, timeout)`

You can set the isolated context of each test in a group by returning data from
a `beforeEach` hook:

const sequence = [...'🍋🍉'];
beforeEach(() => sequence.shift());
it('has test context one', (ctx) => expect(ctx).toEqual('🍋'));
it('has test context two', (ctx) => expect(ctx).toEqual('🍉'));

`beforeEach` hooks can accumlate context:

beforeEach(() => '🍋');
beforeEach((ctx) => ctx + '🍉');
it('accumulates test context', (ctx) => expect(ctx).toEqual('🍋🍉'));

`beforeEach` hooks inherit group context:

beforeAll(() => '🍐');
beforeEach((ctx) => ctx + '🍋');
it('inherits group context' (ctx) => expect(ctx).toEqual('🍐🍋'));

`beforeEach` hooks of described groups inherit context from their ancestors:

beforeEach(() => '🍋');

describe('group one', () => {
beforeEach((ctx) => ctx + '🍉');
it('inherits test context', (ctx) => expect(ctx).toEqual('🍋🍉'));
})

describe('group two', () => {
beforeEach((ctx) => ctx + '🥝');
it('inherits test context', (ctx) => expect(ctx).toEqual('🍋🥝'));
})


### `test(name, fn, timeout)`

`test` hooks receive context as their first argument. Return values do not affect
context.

beforeAll(() => '🍐');
beforeEach((ctx) => ctx + '🍋');
it('has group and test context' (ctx) => expect(ctx).toEqual('🍐🍋'));

### `afterAll(fn, timeout)`

`afterAll` hooks receive context as their first argument. Note that this will
be the context of the group and will not include any isolated test context
created by `beforeEach`. If you need test context, see the `afterEach` hook.
Return values do not affect context.

beforeAll(() => '🍐');
beforeEach((ctx) => ctx + '🍋');
afterAll((ctx) => expect(ctx).toEqual('🍐'));

### `afterEach(fn, timeout)`

`afterEach` hooks receive context as their first argument. Return values do not
affect context.

beforeAll(() => '🍐');
beforeEach((ctx) => ctx + '🍋');
afterEach((ctx) => expect(ctx).toEqual('🍐🍋'));


## Notes

### Accumulation

Context can be accumulated to achieve many different scenarios.
Make sure you have a good grasp of Jest's
[scoping and order of execution](https://jestjs.io/docs/setup-teardown)
when mixing `beforeAll` and `beforeEach`:

beforeAll(() => '🍐');
beforeEach((ctx) => ctx + '🍋');
it('has group and test context', (ctx) => expect(ctx).toEqual('🍐🍋'));

describe('group one', () => {
beforeAll((ctx) => ctx + '🍎');
beforeEach((ctx) => ctx + '🍉');
it('has group and test context', (ctx) => expect(ctx).toEqual('🍐🍎🍋🍉'));
})

describe('group two', () => {
beforeAll((ctx) => ctx + '🍊');
beforeEach((ctx) => ctx + '🥝');
it('has group and test context', (ctx) => expect(ctx).toEqual('🍐🍊🍋🥝'));
})


### Mutability

Any style of data management is allowed, so you are free to mutate your
contexts or keep them immutable, even freeze them, seal them, etc.

Context is only set when a value is returned from `beforeAll` or `beforeEach`.


### Async Code

Async functions, promises, and timeouts work as usual. Note that hooks do not
receive a `done` callback like their native counterparts. As an alternative to
`done`, try using a pattern like this:

it('can be done', (ctx) => new Promise((done) => {
asyncCode(ctx, done)
}))

If it's got to be done with `done`, please open an issue and let's figure it out.


### Each

`test.each` and its variations receive context as the first argument followed
by the usual args for each table row:

beforeAll(() => '🍍')
it.each(['🥥'])(`has context and table data`, (ctx, data) => {
expect(ctx).toEqual('🍍')
expect(data).toEqual('🥥')
})


### Concurrency

`test.concurrent` and its variations are affected by a known issue with
`beforeEach` (https://github.com/facebook/jest/issues/7997)

## License

`jest-ctx` is available as open source under the terms of the [MIT License](LICENSE).

[![https://purvisresearch.com](.logo.svg)](https://purvisresearch.com)