📝

Writing tests closer to document (Jest)

2021/06/14に公開

package

https://www.npmjs.com/package/jest-simple-template

concept

  • test:code = 1:1
  • easy to read as test document

what I wanted to solve

  • reduce mocking code in a test
  • make closer to code and document
  • more focus to thinking test case

writing your test

import { TestCases } from 'jest-simple-template'

const input = {
// input of test
}

/**
 * Test Case Definition
 *
 * [0]: test description
 * [1]: request(input)
 * [2]: expect(output)
 */
const testCase: TestCases = [
  [
    {
      name: 'NameOfTest',
      description: 'Description of Test'
    },
    input,
    (result, spies) => {
      // todo: write your expectation
      // result: The result of target function
      // spies: Index of jest.SpyInstance if you made some mocks
      expect(result).toBe(xxx)
    }
  ],
  [
    :
  ]
]

mocking

Test runner try to seek mock which has the name of test. (See next section)

import { Mocks } from 'jest-simple-template'

const mocks: Mocks = {
  'NameOfTest': () => {
    const spy1 = jest.spyOn(library, 'hoge').mockImplementation(() => {
      return {}
    })
    
    return { spy1 }

runner

import mocks from './mocks' // should be placed on same root of test file.

// This is test runner. Runner automatically read input, read mock, testcase, execute function, and call your expectation.
describe.each(testCase)('Category of Test', (d, r, e) => {
  beforeEach(() => {
    jest.restoreAllMocks()
  })
  const testMeta = d as TestMetaData
  it(`${testMeta.name}:${testMeta.description}`, async () => {
    const spies = (mocks && mocks[testMeta.name])
      ? mocks[testMeta.name]()
      : undefined

    const request = (typeof r === 'function') ? r() : r
    // @ts-ignore
    const result = await /* call to your target function */
    const expected = e as TestExpectation
    expected(result, spies)
  })
})

vscode snippets

https://github.com/hugtechio/jest-simple-template/blob/master/vscode.snippet.json

{
	"jest-simple-template-template": {
		"scope": "javascript, typescript",
		"prefix": "base",
		"body": [
"/**",
" * Test Case Definition",
" *",
" * [0]: test description",
" * [1]: request(input)",
" * [2]: expect(output)",
" */",
"const testCase: TestCases = [",
"]"
		],
		"description": "test case template"
	},

	"jest-simple-template-case": {
		"scope": "javascript, typescript",
		"prefix": "testcase",
		"body":[
"[",
"  {",
"    name: $1",
"    description: $2",
"  },",
"  $3,",
"  (result, spies) => {",
"    if (spies) {",
"    }",
"  },",
"]"
		],
		"description": "single test case of jest-simple-template"
	},

	"jest-simple-template-file": {
		"scope": "javascript, typescript",
		"prefix": "mocktemplate",
		"body": [
"import { Mocks } from 'jest-simple-template'",
"",
"const mocks: Mocks = {",
"  '$1: () => {",
"    let spy: jest.SpyInstance",
"    return {",
"      spy",
"    }",
"  }",
"}",
"",
"export default mocks"
		],
		"description": "mock template"
	},

	"jest-simple-template-mock": {
		"scope": "javascript, typescript",
		"prefix": "mock",
		"body": [
"'$1': () => {",
"  let spy: jest.SpyInstance",
"  return {",
"    spy",
"  }",
"}",
		],
		"description": "single mock"
	},

	"jest-simple-template-runner": {
		"scope": "javascript, typescript",
		"prefix": "runner",
		"body": [
"describe.each(testCase)('$1', (d, r, e) => {",
"  beforeEach(() => {",
"    jest.restoreAllMocks()",
"  })",
"  const testMeta = d as TestMetaData",
"  it (`${testMeta.name}:${testMeta.description}`, async () => {",
"    const spies = (mocks && mocks[testMeta.name])",
"      ? mocks[testMeta.name]()",
"      : undefined",
"",
"    const request = (typeof r === 'function') ? r() : r",
"    const result = ${2: call target function}",
"    const expected = e as TestExpectation",
"    expected(result, spies)",
"  })",
"})"

		],
		"description": "test runner"
	},

	"jest-simple-template-import": {
		"scope": "javascript, typescript",
		"prefix": "import",
		"body": [
"import { TestCases, TestMetaData, TestExpectation } from 'jest-simple-template",
"import mocks from './mocks'"
		]
	}
}

Feel free to send your any feedback.

Discussion