{"id":15701124,"url":"https://github.com/kettanaito/test-flat","last_synced_at":"2025-05-12T15:35:12.373Z","repository":{"id":54976467,"uuid":"304041003","full_name":"kettanaito/test-flat","owner":"kettanaito","description":"A test framework extension to support resources teardown and cleanup in flat tests.","archived":false,"fork":false,"pushed_at":"2021-01-18T14:29:28.000Z","size":69,"stargazers_count":6,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-05-07T07:21:58.776Z","etag":null,"topics":["test","testing","testing-tools"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kettanaito.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-10-14T14:28:58.000Z","updated_at":"2023-09-08T18:13:37.000Z","dependencies_parsed_at":"2022-08-14T08:00:29.306Z","dependency_job_id":null,"html_url":"https://github.com/kettanaito/test-flat","commit_stats":null,"previous_names":["kettanaito/flat-test"],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kettanaito%2Ftest-flat","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kettanaito%2Ftest-flat/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kettanaito%2Ftest-flat/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kettanaito%2Ftest-flat/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kettanaito","download_url":"https://codeload.github.com/kettanaito/test-flat/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253594540,"owners_count":21933237,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["test","testing","testing-tools"],"created_at":"2024-10-03T20:00:08.368Z","updated_at":"2025-05-12T15:35:12.349Z","avatar_url":"https://github.com/kettanaito.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# `test-flat`\n\nA test framework extension to support resources teardown and cleanup in flat tests.\n\n## What problem does this solve?\n\nWhen writing tests there's often logic that a test needs, which isn't strictly a part of the test itself. That logic is often put into the `beforeAll`/`afterAll` hooks of a testing framework that executes it before and after tests, respectively.\n\nThis package allows to defined a \"before\" and \"after\" logic on a per-test basis. This helps you avoid nesting during your tests and keep them flat.\n\n\u003e Learn more about the topic in \"[Avoid nesting when you're testing](https://kentcdodds.com/blog/avoid-nesting-when-youre-testing)\" by Kent C. Dodds.\n\n## Features\n\n### Immutable shared context\n\nShares context between the `before` and `after` hooks, as well as exposes it in the test suite to prevent variable mutation.\n\n```js\n// BEFORE\n// Exposing `server` at the global test's scope\n// makes it vulnurable to accidental mutation.\nlet server\n\nbeforeAll(() =\u003e {\n  server = createServer(...)\n})\n\nafterAll(() =\u003e server.close())\n```\n\n```js\n// AFTER\ntest(\n  'handles request',\n  ({ server }) =\u003e {/* Your test */},\n  () =\u003e {\n    const server = createServer()\n    // Create a context shared with the test and the \"after\" hook.\n    // The `server` instance is nicely scoped and immutable.\n    return { server }\n  },\n  ({ server }) =\u003e {\n    return server.close()\n  }\n})\n```\n\n### Deterministic cleanup\n\nAs opposed to calling the cleanup (`after`) hook as the last step of the test, this library executes it regardless of the test's passing status.\n\n```js\n// BEFORE\ntest('handles request', () =\u003e {\n  const server = createServer()\n\n  // If this assertion fails,\n  expect(res.status).toBe(200)\n\n  // ...this cleanup is never called.\n  return server.close()\n})\n```\n\n```js\n// AFTER\ntest(\n  'a failing test',\n  () =\u003e {\n    throw new Error('Oops, assertion failed!')\n  },\n  createServer,\n  // Regardless if the test passes or not,\n  // this cleanup function is always called.\n  closeServer\n)\n```\n\n## Getting started\n\n### Install\n\n```bash\n$ npm install test-flat --save-dev\n```\n\n### Extend your testing framework\n\n#### Jest\n\n```js\n// jest.setup.js\nimport 'test-flat'\n```\n\n```js\n// jest.config.js\nmodule.exports = {\n  setupFiles: ['./jest.setup.js'],\n}\n```\n\n## Example\n\nHere's an example of a flat test suite that tears down a Puppeteer browser and cleans up afterwards as a part of a single test suite:\n\n```js\nimport * as puppeteer from 'puppeteer'\n\ntest.flat(\n  'renders the header element on the homepage',\n  (context) =\u003e {\n    await context.page.goto('https://github.com')\n    const headerElement = await context.page.evaluate(() =\u003e {\n      return document.getElementById('header')\n    })\n\n    expect(headerElement).toBeTruthy()\n  },\n  async () =\u003e {\n    // Create a browser and a new page\n    // before the test suite.\n    const browser = await puppeteer.launch()\n    const page = await browser.newPage()\n    return {\n      browser\n      page,\n    }\n  },\n  async (context) =\u003e {\n    // Await until the browser is closed\n    // before finishing the test.\n    return context.browser.close()\n  }\n)\n```\n\n\u003e Both `test.only.flat` and `test.skip.flat` are supported.\n\n## API\n\n```ts\nfunction flatTest\u003cContext\u003e(\n  title: string,\n  suite: (context: Context) =\u003e Promise\u003cany\u003e,\n  before?: () =\u003e Promise\u003cContext\u003e,\n  after?: (context: Context) =\u003e Promise\u003cany\u003e\n): void\n```\n\n### `title`\n\nA test suite title.\n\n### `suite`\n\nA test suite itself.\n\n\u003e Test suite function in `test-flat` is always an asynchronous function and does not support the `done` callback argument.\n\n### `before`\n\nAn optional teardown hook to create any resources necessary for the respective test. Anything returned from this hook will be available as the `context` argument in the `suite` and `after` functions.\n\n### `after`\n\nAn optional cleanup hook executed after the test is finished (passed or failed). Accepts an optional `context` argument to clean up the resources created as a part of the `before` hook.\n\n## FAQ\n\n### This is a huge repetition\n\nIf you notice your before/after logic repeating from test to test, consider abstracting it into a helper function.\n\n```js\n// test/helper.js\nimport express from 'express'\n\nexport function startServer(options) {\n  return () =\u003e {\n    const app = express()\n\n    return new Promise((resolve) =\u003e {\n      app.listen(options?.port || 3000, () =\u003e {\n        resolve({ app })\n      })\n    })\n  }\n}\n\nfunction closeServer({ app }) {\n  return new Promise((resolve) =\u003e {\n    app.close(resolve)\n  })\n}\n```\n\n```js\n// test/checkout.test.js\nimport { startServer, closeServer } from './helpers'\n\ntest(\n  'handles a /checkout route',\n  () =\u003e {\n    /* Your test here */\n  },\n  startServer({ port: 3001 }),\n  closeServer\n)\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkettanaito%2Ftest-flat","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkettanaito%2Ftest-flat","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkettanaito%2Ftest-flat/lists"}