{"id":17115785,"url":"https://github.com/denisraslov/snappify","last_synced_at":"2025-04-13T02:32:08.255Z","repository":{"id":57364588,"uuid":"125195503","full_name":"denisraslov/snappify","owner":"denisraslov","description":"A generator of Jest snapshot-based tests for React components written with TypeScript 📸","archived":false,"fork":false,"pushed_at":"2023-05-25T08:23:15.000Z","size":273,"stargazers_count":70,"open_issues_count":6,"forks_count":10,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-04-09T15:54:55.118Z","etag":null,"topics":["jest","jest-snapshots","react","react-components","testing","typescript"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","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/denisraslov.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","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}},"created_at":"2018-03-14T10:29:13.000Z","updated_at":"2024-07-06T20:38:23.000Z","dependencies_parsed_at":"2024-11-07T18:04:01.970Z","dependency_job_id":"b14faffb-72d0-464a-9354-8b6c44266237","html_url":"https://github.com/denisraslov/snappify","commit_stats":{"total_commits":88,"total_committers":4,"mean_commits":22.0,"dds":"0.43181818181818177","last_synced_commit":"7c8eec3d14703e3902082c68fb5da92d9085d3c5"},"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/denisraslov%2Fsnappify","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/denisraslov%2Fsnappify/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/denisraslov%2Fsnappify/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/denisraslov%2Fsnappify/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/denisraslov","download_url":"https://codeload.github.com/denisraslov/snappify/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248657793,"owners_count":21140842,"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":["jest","jest-snapshots","react","react-components","testing","typescript"],"created_at":"2024-10-14T17:46:44.992Z","updated_at":"2025-04-13T02:32:07.789Z","avatar_url":"https://github.com/denisraslov.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003e\n  Snappify\n  \u003cbr\u003e\n  \u003cimg src=\"https://emojipedia-us.s3.amazonaws.com/thumbs/120/apple/118/camera-with-flash_1f4f8.png\" alt=\"Snappify logo\" title=\"Snappify logo\" width=\"100\"\u003e\n  \u003cbr\u003e\n  \u003cimg src=\"https://s3.amazonaws.com/media-p.slid.es/uploads/401307/images/4926305/All.png\" alt=\"React + Jest + TypeScript\" title=\"React + Jest + TypeScript\" width=\"400\"\u003e\n  \n\u003c/h1\u003e\n\u003cp align=\"center\" style=\"font-size: 1.2rem;\"\u003e\u003cb\u003eA generator of Jest snapshot-based tests for React components written with TypeScript\u003c/b\u003e\u003c/p\u003e\n\n## Why\n\n[Snapshot testing](https://facebook.github.io/jest/docs/en/snapshot-testing.html) of React components is a useful tool that [Jest](https://facebook.github.io/jest/) provides to make sure your UI does not change unexpectedly. To apply it you have to describe several different states of a component configuring it with different props that this component can have. \n\nHowever, if you write components with [TypeScript](https://www.typescriptlang.org/), you have an interface describing the types of the props. There is no reason to fill props up manually with random values in your tests. It could be done automatically based on the described types. That is what `Snappify` does. \n\n`Snappify` generates files with tests for your React components. You just run them. ✨\n\n## A related blog post\n\n* [Introducing Snappify 📸: A generator of snapshot tests for React + TypeScript](https://medium.com/@denisraslov/introducing-snappify-a-generator-of-snapshot-tests-for-react-typescript-54b3fd1ffa54)\n\n## Quick Overview\n\nInstall `Snappify` globally:\n\n```sh\nnpm install -g snappify\n```\n\nRun `Snappify` inside of a project folder with a configured glob pattern of the React components files and a name of a root folder for generated tests:\n\n```sh\nsnappify components/**/*.tsx --testsRoot=tests\n```\n\nIt will create a directory called `tests` inside the current folder.\n\nInside that directory, it will generate the files with snapshot-based tests for every of the components from the files that matched to `components/**/*.tsx` pattern. \n\n## Folders structure\nThe structure of the included folders with tests will be the same as the structure of the folders with components. The names of the files with tests will be the same as the names of the files with the components.\n\nFor example, if you have this structure of folders:\n```\nmy-app\n├── components\n│   └── Header.tsx\n│   └── Content.tsx\n│   └── Footer.tsx\n│   └── Button\n│       └── index.tsx\n```\n\nYou will get this structure of the folders with the tests (when you run the command above):\n\n```\nmy-app\n├── tests\n│   └── Header.js\n│   └── Content.js\n│   └── Footer.js\n│   └── Button\n│       └── index.js\n```\n\n## How it works\n\n`Snappify` takes a component and its interface, and generates a file with snapshot-based tests with **up to 10 test cases each**. \n\nThe props values for test cases be **generated with uniformly distributed sets of random values based on the types of the props**. That means you get the count of test cases that you can take control of, but they are still cover the details of your components as wide as it possible in this situation. \n\n## An example\n\nHere we have the `Button` component that have the declared interface for its props called `IButtonProps`. \n\n```ts\nimport * as React from 'react';\n\ninterface IButtonProps {\n    children: React.ReactNode;\n    className?: string;\n    isDisabled?: boolean;\n    onClick?: () =\u003e void;\n}\n\nconst Button: React.StatelessComponent\u003cIButtonProps\u003e = (props) =\u003e {\n    const { className, isDisabled, onClick } = props;\n\n    return (\n        \u003cdiv className={className} onClick={!isDisabled \u0026\u0026 onClick}\u003e\n            {props.children}\n        \u003c/div\u003e\n    );\n};\n\nexport default Button;\n```\n\n`Snappify` will generate a file with tests for this component that will looks like:\n\n```jsx\nimport React from 'react';\nimport renderer from 'react-test-renderer';\n\nimport Button from 'components/Button.tsx';\n\ntest('Button case #1', () =\u003e {\n    const tree = renderer.create(\n        \u003cButton\n            // some randomly generated values for props\n            className={'value'}\n            isDisabled={true}\n            onClick={() =\u003e undefined}\n            children={\u003cdiv /\u003e}\n        /\u003e\n    ).toJSON();\n\n    expect(tree).toMatchSnapshot();\n});\n\ntest('Button case #2', () =\u003e {\n    const tree = renderer.create(\n        \u003cButton\n            // another set of randomly generated values for props\n            // (the not required props were skipped)\n            children={\u003cdiv /\u003e}\n        /\u003e\n    ).toJSON();\n\n    expect(tree).toMatchSnapshot();\n});\n\n// Other test cases go here...\n```\n\n## Supported TypeScript types\n\nRight now `Snappify` supports the [basic types of TypeScript](https://www.typescriptlang.org/docs/handbook/basic-types.html). It also supports a few of the React types: `React.ReactNode`, `JSX.Element` and `React.CSSProperties`. \n\nIt **doesn't support** using other declared TypeScript interfaces as types of items of a React component's interface yet.\n\nI condiser increase of the supported types as a future improvement.\n\n## Supported TypeScript syntax\n\nRight now `Snappify` supports **only** the semicolon (`;`) as a delimiter between interface items. See example:\n\n```js\ninterface IButtonProps {\n    children: React.ReactNode;\n    className?: string;\n}\n```\n\nIt also supports only React components declared with one of the following statements:\n\n```js\nclass Button extends React.Component\u003cIButtonProps, IButtonState\u003e {}\n```\n\n```js\nclass Button extends React.PureComponent\u003cIButtonProps, IButtonState\u003e {}\n```\n\n```js\nconst Button:React.StatelessComponent\u003cIButtonProps\u003e = (props) =\u003e {}\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdenisraslov%2Fsnappify","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdenisraslov%2Fsnappify","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdenisraslov%2Fsnappify/lists"}