/fixture-injection

JavaScript test helper to inject fixtures

Primary LanguageTypeScriptMIT LicenseMIT

fixture-injection

CircleCI

Note: fixture-injection is still in alpha stage.

fixture-injection is a test helper tool for Jest and Jasmine to inject fixtures into test functions and beforeAll() by leveraging dependency injection.

  • Test functions use fixtures by declaring the fixture names as arguments.
  • Fixtures can use other fixtures and fixture-injection manages the dependencies.
  • Fixtures can have asynchronous setup and teardown in it.
  • Global fixtures are instantiated in the global scope and shared by multiple test suites (independent workers of Jest) and used as a singleton, whereas local fixtures are instantiated in each local scope.

Usage (Jest/TypeScript)

Define fixtures in __fixtures__.ts:

import { Provide } from 'jest-fixture-injection'

// Example 1) Simple value
export const foo = 'FOO'

// Example 2) Fixture function to provide a value which requires another fixture `foo`
export const bar = (foo: string) => `BAR(${foo})`

// Example 3) Asynchronous fixture function to provide a value
export const baz = async (provide: Provide, bar: string) => { // requires another fixture `bar`
  // Write setup code here
  await provide(`BAZ(${bar}`) // provide the value
  // `await` above waits until the context (test case or suite) finishes
  // Write teardown code here
}

Use fixtures in test functions or beforeAll():

describe('My test suite', () => {
  let fixtures: { foo?: string } = {}

  beforeAll((foo: string) => { // Inject fixtures to *a suite* by beforeAll()
    fixtures.foo = foo
  })

  test('with fixtures', (bar: string, baz: string) => { // Inject fixtures to *a test case*
    // bar and baz are initialized just before this block
    const { foo } = fixtures // Get fixtures from the suite

    expect(foo).toEqual('FOO')
    expect(bar).toEqual('BAR(FOO)')
    expect(baz).toEqual('BAZ(BAR(FOO))')

    // bar and baz are released just after this block
  })

  // foo is released by hidden afterAll() of this block automatically
})

Set environment variable FI_LOGGING=true to print the log.

FI_LOGGING=true yarn tests

Packages

Install/Setup

See the documentation of each test framework extension.

Limitations

  • done() is not available to define asynchronous tests; Use async/await instead
  • Don't use transpiler plugins/settings which modify function arguments such as transform-async-to-generator plugin for Babel because fixture-injection parses the argument names at runtime to determine which fixtures to inject.

FAQ

1) Why not make describe() injectable same as test() and it() instead of manually assigning variables in beforeAll()?

Fixture functions can be asynchronous and fixture objects must be resolved before executing test functions. However describe() does not work asynchronously as expected. So beforeAll() is the only place to share fixture objects between test functions.

Related Work

  • pytest
    • pytest is a popular testing framework for Python. fixture-injection was inspired by its fixtures. pytest fixture has a scope (session/module/function) to manage its lifecycle and can be a generator to have setup/teardown logic in it.