{"id":22751831,"url":"https://github.com/uid11/clean-tests","last_synced_at":"2026-03-04T08:01:28.004Z","repository":{"id":267554108,"uuid":"888064239","full_name":"uid11/clean-tests","owner":"uid11","description":"A lightweight pure ECMAScript test library with a programmatic API for any ECMAScript/TypeScript environment ✅️️","archived":false,"fork":false,"pushed_at":"2025-12-14T05:38:26.000Z","size":53,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-12-16T07:52:13.642Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/uid11.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-11-13T18:48:16.000Z","updated_at":"2025-12-14T05:38:30.000Z","dependencies_parsed_at":null,"dependency_job_id":"2b4c590d-8efe-4834-b7e1-cec48f286286","html_url":"https://github.com/uid11/clean-tests","commit_stats":null,"previous_names":["uid11/clean-tests"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/uid11/clean-tests","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uid11%2Fclean-tests","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uid11%2Fclean-tests/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uid11%2Fclean-tests/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uid11%2Fclean-tests/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/uid11","download_url":"https://codeload.github.com/uid11/clean-tests/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uid11%2Fclean-tests/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30075909,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-04T05:31:57.858Z","status":"ssl_error","status_checked_at":"2026-03-04T05:31:38.462Z","response_time":59,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":[],"created_at":"2024-12-11T05:07:30.430Z","updated_at":"2026-03-04T08:01:27.998Z","avatar_url":"https://github.com/uid11.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# clean-tests ✅️\n\n[![NPM version][npm-image]][npm-url]\n[![dependencies: none][dependencies-none-image]][dependencies-none-url]\n[![minzipped size][size-image]][size-url]\n[![code style: prettier][prettier-image]][prettier-url]\n[![Conventional Commits][conventional-commits-image]][conventional-commits-url]\n[![License MIT][license-image]][license-url]\n\nA lightweight, zero-overhead pure ECMAScript test library with a programmatic API for any ECMAScript/TypeScript environment.\n\nWe create a `suite` of tests as a regular instance of the `Suite` class,\nfill it with tests using the `suite.addTest` method, possibly export it, and run it using the `suite.run` method.\n\nThe tests are run in the same thread as the `suite.run` call, but in an isolated scope,\nmeaning that variables from the closure will not be available in the tests code.\nTo access the utilities, asserts, and functions being tested in the suite,\nwe explicitly add them as functions to the suite scope using the `suite.addFunctionToScope` method.\n\nA test is considered to have failed if it throws an exception\n(or if the promise it returns is rejected — for example, for asynchronous functions).\n\n## Basic example\n\n```ts\nimport {assertValueIsTrue, Suite} from 'clean-tests';\nimport {sum} from './sum.js';\n\nconst suite = new Suite();\n\nsuite.addFunctionToScope(assertValueIsTrue);\nsuite.addFunctionToScope(sum);\n\nsuite.addTest('adds 1 + 2 to equal 3', () =\u003e {\n  assertValueIsTrue(sum(1, 2) === 3);\n});\n\nconst runResult = await suite.run();\n\nassertValueIsTrue(runResult.runStatus === 'passed');\n```\n\n## Features\n\n### Skipping tests\n\nYou can skip a specific test by giving it the `skip` option:\n\n```ts\nsuite.addTest('skipped', {skip: true}, () =\u003e {\n  // this code will never run\n});\n\nsuite.addTest('skipped with reason', {skip: 'some reason''}, () =\u003e {\n  // this code will never run\n});\n```\n\n### todo tests\n\nThe test can be marked as a `todo` test — in this case it will be run, but will not affect the `runStatus`:\n\n```ts\nsuite.addTest('todo test', {todo: true}, () =\u003e {\n  // some code\n});\n\nsuite.addTest('todo test with reason', {todo: 'some reason''}, () =\u003e {\n  // some code\n});\n```\n\n### only tests\n\nThe test can be marked as an `only` test — in this case, only `only` tests\n(there may be several of them) will be run, regardless of filtering of tests:\n\n```ts\nsuite.addTest('only test', {only: true}, () =\u003e {\n  // some code\n});\n```\n\n### fail tests\n\nThe test can be marked as a `fail` test — in this case the test will be considered `passed` if it throws\n(or rejects the returned promise), and `failed` otherwise:\n\n```ts\nsuite.addTest('fail test', {fail: true}, () =\u003e {\n  throw new Error('should throws');\n});\n```\n\n### Filtering of tests\n\nTests in `suite.run` can be filtered using the `filterTests` function\n(filtering is ignored if there is at least one `only` test in the suite):\n\n```ts\nsuite.addTest('foo', () =\u003e {\n  // some code\n});\n\nsuite.addTest('bar', () =\u003e {\n  // some code\n});\n\n// will run only the test named 'foo'\nconst runResult = await suite.run({filterTests: (_options, test) =\u003e test.name === 'foo'});\n```\n\nThe default filter of tests can be set when creating a suite\n(the filter specified in `suite.run` will override it):\n\n```ts\n// run only tests with retries (i.e. tests that will be rerun if they fail)\nconst suite = new Suite({filterTests: (_options, test) =\u003e test.retries \u003e 0});\n```\n\n### Asynchronous tests\n\nIf a test returns a promise (usually as asynchronous function), `clean-tests` ✅️ waits for it to be fulfilled.\nSuch a test is considered to have failed if the promise is rejected:\n\n```ts\nsuite.addTest('asynchronous test', async () =\u003e {\n  await new Promise((resolve) =\u003e setTimeout(resolve, 1_000));\n});\n```\n\nFor asynchronous tests you can specify a `timeout` in milliseconds, after which they will be considered failed:\n\n```ts\nsuite.addTest('asynchronous test', {timeout: 1_000}, async () =\u003e {\n  await new Promise((resolve) =\u003e setTimeout(resolve, 2_000));\n});\n```\n\nThe default `timeout` for each test can be set when creating the suite\n(the `timeout` specified in `suite.run` will override it):\n\n```ts\nconst suite = new Suite({testTimeout: 3_000});\n```\n\nBy default `testTimeout` is `10_000` (10 seconds).\n\nFor asynchronous tests, you can specify `concurrency` (how many of them can be run at the same time at most):\n\n```ts\nconst runResult = await suite.run({concurrency: 3});\n```\n\nThe default `concurrency` can be set when creating a suite\n(the `concurrency` specified in `suite.run` will override it):\n\n```ts\nconst suite = new Suite({concurrency: 3});\n```\n\nBy default `concurrency` is `1`.\n\n## Install\n\nWorks in any environment that implements the `ECMAScript 2022` standard (or higher):\nmodern browser, [node](https://nodejs.org/en/) (version 16 or higher), [Deno](https://deno.com/), [Bun](https://bun.sh/).\n\n```sh\nnpm install --save-dev clean-tests\n```\n\n## License\n\n[MIT][license-url]\n\n[conventional-commits-image]: https://img.shields.io/badge/Conventional_Commits-1.0.0-yellow.svg 'The Conventional Commits specification'\n[conventional-commits-url]: https://www.conventionalcommits.org/en/v1.0.0/\n[dependencies-none-image]: https://img.shields.io/badge/dependencies-none-success.svg 'No dependencies'\n[dependencies-none-url]: https://github.com/uid11/clean-tests/blob/main/package.json\n[license-image]: https://img.shields.io/badge/license-MIT-blue.svg 'The MIT License'\n[license-url]: LICENSE\n[npm-image]: https://img.shields.io/npm/v/clean-tests.svg 'clean-tests'\n[npm-url]: https://www.npmjs.com/package/clean-tests\n[prettier-image]: https://img.shields.io/badge/code_style-prettier-ff69b4.svg 'Prettier code formatter'\n[prettier-url]: https://prettier.io/\n[size-image]: https://img.shields.io/bundlephobia/minzip/clean-tests 'clean-tests'\n[size-url]: https://bundlephobia.com/package/clean-tests\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuid11%2Fclean-tests","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fuid11%2Fclean-tests","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuid11%2Fclean-tests/lists"}