{"id":20838814,"url":"https://github.com/royalicing/jest-zest","last_synced_at":"2026-03-17T01:45:40.560Z","repository":{"id":72483368,"uuid":"239443586","full_name":"RoyalIcing/jest-zest","owner":"RoyalIcing","description":"Shorter and more readable tests in jest","archived":false,"fork":false,"pushed_at":"2023-12-01T00:51:45.000Z","size":449,"stargazers_count":6,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-05-08T21:29:07.847Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/jest-zest","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/RoyalIcing.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}},"created_at":"2020-02-10T06:31:16.000Z","updated_at":"2024-04-07T13:38:24.000Z","dependencies_parsed_at":"2023-12-01T01:50:17.483Z","dependency_job_id":null,"html_url":"https://github.com/RoyalIcing/jest-zest","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/RoyalIcing/jest-zest","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RoyalIcing%2Fjest-zest","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RoyalIcing%2Fjest-zest/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RoyalIcing%2Fjest-zest/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RoyalIcing%2Fjest-zest/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RoyalIcing","download_url":"https://codeload.github.com/RoyalIcing/jest-zest/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RoyalIcing%2Fjest-zest/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265937375,"owners_count":23852112,"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":[],"created_at":"2024-11-18T01:11:37.329Z","updated_at":"2026-03-17T01:45:40.506Z","avatar_url":"https://github.com/RoyalIcing.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# jest-zest\n\nShorter and more readable tests in jest. Combines TypeScript and `Proxy`.\n\n```tsx\nimport { lazy, freshFn, vary } from 'jest-zest';\nimport { render } from '@testing-library/react';\nimport user from '@testing-library/user-event';\nimport '@testing-library/jest-dom';\n\n// `freshFn` creates many jest.fn() that are mock.mockClear() after every test.\nconst [onAddComment, onEditPost] = freshFn;\n// `vary` lets you redefine a value with nested describes, useful for given-when-then tests.\nconst userKind = vary('normal');\n// `lazy` uses Proxy to lazily perform render() whose result is cached within each test run.\n// We destructure `getByRole` and `queryByRole` which also Proxy to the underlying method.\nconst { getByRole, queryByRole } = lazy(() =\u003e\n  render(\n    \u003cPage\n      userKind={userKind()}\n      onAddComment={onAddComment}\n      onEditPost={onEditPost}\n    /\u003e\n  )\n);\n\nit('shows add comment button', () =\u003e {\n  expect(getByRole('button', { name: 'Add comment' })).toBeVisible();\n});\n\nit('hides edit post button', () =\u003e {\n  expect(queryByRole('button', { name: 'Edit post' })).toBeNull();\n});\n\ndescribe('when add comment is clicked', () =\u003e {\n  beforeEach(() =\u003e {\n    user.click(getByRole('button', { name: 'Add comment' }));\n  });\n\n  it('calls onAddComment', () =\u003e {\n    expect(onAddComment).toHaveBeenCalledTimes(1);\n  });\n});\n\ndescribe('when user is admin', () =\u003e {\n  userKind('admin');\n\n  it('shows edit post button', () =\u003e {\n    expect(getByRole('button', { name: 'Edit post' })).toBeVisible();\n  });\n\n  describe('when edit post is clicked', () =\u003e {\n    beforeEach(() =\u003e {\n      user.click(getByRole('button', { name: 'Edit post' }));\n    });\n\n    it('calls onEditPost', () =\u003e {\n      expect(onEditPost).toHaveBeenCalledTimes(1);\n    });\n  });\n});\n\nuserKind.each(['admin', 'editor'])('when user is %s', () =\u003e {\n  it('shows edit post button', () =\u003e {\n    expect(getByRole('button', { name: 'Edit post' })).toBeInTheDocument();\n  });\n\n  describe('when edit post is clicked', () =\u003e {\n    beforeEach(() =\u003e {\n      user.click(getByRole('button', { name: 'Edit post' }));\n    });\n\n    it('calls onEditPost', () =\u003e {\n      expect(onEditPost).toHaveBeenCalledTimes(1);\n    });\n  });\n});\n```\n\n----\n\n## Documentation\n\n### `lazy(creator: () =\u003e T, cleanup?: (object?: T) =\u003e void)`\n\nPass a creator function that will be called lazily yet only once. Run `cleanup` callback for each test via `afterEach()`.\n\nBefore:\n\n```tsx\nimport { render } from '@testing-library/react';\nimport user from '@testing-library/user-event';\n\nconst subject = () =\u003e render(\u003cCreatePostForm /\u003e);\n\nit('shows a form', () =\u003e {\n  expect(subject().getAllByRole('form')).toHaveLength(1);\n});\n\nit('shows content input', () =\u003e {\n  const { getAllByRole, getByLabelText } = subject();\n  expect(getAllByRole('textbox')).toContain(getByLabelText('Content'));\n});\n\nit('shows post button', () =\u003e {\n  expect(subject().getByRole('button', { name: 'Post' })).toBeInTheDocument();\n});\n\nit('disables post button', () =\u003e {\n  expect(subject().getByRole('button', { name: 'Post' })).toBeDisabled();\n});\n\ndescribe('when user types content', () =\u003e {\n  let result: typeof ReturnType\u003csubject\u003e;\n  beforeEach(() =\u003e {\n    result = subject();\n    return user.type(result.getByLabelText('Content'), 'New content');\n  });\n\n  it('enables the post button', () =\u003e {\n    expect(result.getByRole('button', { name: 'Post' })).toBeEnabled();\n  });\n});\n```\n\nAfter:\n\n```tsx\nimport { render } from '@testing-library/react';\n\nconst { getByRole, getAllByRole, getByLabelText } = lazy(() =\u003e\n  render(\u003cCreatePostForm /\u003e)\n);\nconst postButton = lazy(() =\u003e getByRole('button', { name: 'Post' }));\n\nit('shows a form', () =\u003e {\n  expect(getAllByRole('form')).toHaveLength(1);\n});\n\nit('shows content input', () =\u003e {\n  expect(getAllByRole('textbox')).toContain(getByLabelText('Content'));\n});\n\nit('shows post button', () =\u003e {\n  expect(postButton()).toBeInTheDocument();\n});\n\nit('disables post button', () =\u003e {\n  expect(postButton()).toBeDisabled();\n});\n\ndescribe('when content is added', () =\u003e {\n  beforeEach(() =\u003e user.type(getByLabelText('Content'), 'New content'));\n\n  it('enables the post button', () =\u003e {\n    expect(postButton()).toBeDisabled();\n  });\n});\n```\n\n----\n\n### `freshFn`\n\nCan be called or destructured to create a new `jest.fn()` that is clearer with `mockClear()` after each test run.\n\nBefore:\n\n```ts\nconst onChange = jest.fn();\nconst onFocus = jest.fn();\nconst onBlur = jest.fn();\n\nafterEach(() =\u003e {\n  onChange.mockClear();\n  onFocus.mockClear();\n  onBlur.mockClear();\n});\n\nconst props = {\n  onChange,\n  onFocus,\n  onBlur,\n};\n```\n\nAfter by calling:\n\n```ts\nimport { freshFn } from 'jest-zest';\n\nconst props = {\n  onChange: freshFn(),\n  onFocus: freshFn(),\n  onBlur: freshFn(),\n};\n```\n\nAfter by destructuring:\n\n```ts\nimport { freshFn } from 'jest-zest';\n\nconst [onChange, onFocus, onBlur] = freshFn;\nconst props = {\n  onChange,\n  onFocus,\n  onBlur,\n};\n```\n\n### `fresh(creator: () =\u003e T, refresher: (object: T) =\u003e void)`\n\nCreate multiple of something that must be cleared for each test. Great for spies like `jest.fn()`.\n\nIt accepts two arguments:\n\n1. Pass a function that will be called initially to create your object\n2. A function that clears the object using `afterEach()`\n\nTo then create an instance, either:\n\n- call it to create a single instance\n- destructure it like an array to create multiple instances\n\nBefore:\n\n```ts\nconst onChange = jest.fn();\nconst onFocus = jest.fn();\nconst onBlur = jest.fn();\n\nafterEach(() =\u003e {\n  onChange.mockClear();\n  onFocus.mockClear();\n  onBlur.mockClear();\n});\n```\n\nAfter:\n\n```ts\nimport { fresh } from 'jest-zest';\n\nconst [onChange, onFocus, onBlur] = fresh(jest.fn, mock =\u003e mock.mockClear());\n```\n\n----\n\n### `vary\u003cT\u003e(initialValue: T)`\n\nDefine and redefine a value shared between tests easily.\n\nBefore:\n\n```tsx\nlet variation: string;\n\nfunction subject() {\n  return render(\u003cComponent variation={variation} /\u003e);\n}\n\ndescribe('when variation is orange', () =\u003e {\n  beforeEach(() =\u003e {\n    variation = 'orange';\n  });\n\n  it('shows text orange', () =\u003e {\n    expect(subject().getByText('orange')).toBeInTheDocument();\n  });\n});\n\ndescribe('when variation is blue', () =\u003e {\n  beforeEach(() =\u003e {\n    variation = 'blue';\n  });\n\n  it('shows text blue', () =\u003e {\n    expect(subject().getByText('blue')).toBeInTheDocument();\n  });\n});\n```\n\nAfter:\n\n```tsx\nconst color = vary('');\nconst subject = lazy(() =\u003e render(\u003cComponent color={color()} /\u003e));\n\ndescribe('when color is orange', () =\u003e {\n  color('orange');\n\n  it('shows text orange', () =\u003e {\n    expect(subject.getByText('orange')).toBeInTheDocument();\n  });\n});\n\ndescribe('when color is blue', () =\u003e {\n  color('blue');\n\n  it('shows text blue', () =\u003e {\n    expect(subject.getByText('blue')).toBeInTheDocument();\n  });\n});\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Froyalicing%2Fjest-zest","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Froyalicing%2Fjest-zest","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Froyalicing%2Fjest-zest/lists"}