{"id":15633965,"url":"https://github.com/tvler/prop-sets","last_synced_at":"2025-04-07T11:10:36.241Z","repository":{"id":34172746,"uuid":"171046051","full_name":"tvler/prop-sets","owner":"tvler","description":"Generate and test every possible instance of a component in React","archived":false,"fork":false,"pushed_at":"2023-01-04T21:40:12.000Z","size":625,"stargazers_count":146,"open_issues_count":11,"forks_count":0,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-31T09:08:04.945Z","etag":null,"topics":["javascript","react","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/tvler.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}},"created_at":"2019-02-16T20:01:20.000Z","updated_at":"2024-09-18T11:07:26.000Z","dependencies_parsed_at":"2023-01-15T05:04:23.978Z","dependency_job_id":null,"html_url":"https://github.com/tvler/prop-sets","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tvler%2Fprop-sets","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tvler%2Fprop-sets/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tvler%2Fprop-sets/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tvler%2Fprop-sets/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tvler","download_url":"https://codeload.github.com/tvler/prop-sets/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247640465,"owners_count":20971557,"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":["javascript","react","testing","typescript"],"created_at":"2024-10-03T10:50:46.529Z","updated_at":"2025-04-07T11:10:36.218Z","avatar_url":"https://github.com/tvler.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# `prop-sets`\n\n`prop-sets` is a test tool to help generate every possible instance of a component in JavaScript + TypeScript.\n\n\u003cimg src=\"https://user-images.githubusercontent.com/4934193/54797280-b61c3380-4c10-11e9-81ff-1b76be3cb8ea.png\" width=\"372\" /\u003e\n\nWith `prop-sets`, you don't need to outsmart your own code when writing tests. Instead of determining fragile points of failure from particular combinations of inputs, simply generate all possible combinations and assert everything.\n\nWorks with React, Vue, Jest, Mocha, etc. No dependencies.\n\n## Benefits\n\nLet's say you have a React component called Button with the props `disabled` and `color`, as well as a test that asserts the button is gray when `disabled` is true and `color` otherwise. Here's how to use `prop-sets` to assert the component renders the correct color:\n\n```jsx\nconst Button = props =\u003e (\n  \u003cbutton\n    disabled={props.disabled}\n    style={{\n      backgroundColor: props.disabled ? \"gray\" : props.color\n    }}\n  /\u003e\n);\n\nit(\"is gray when disabled, props.color otherwise\", () =\u003e {\n  propSets({\n    color: [\"red\", \"blue\"],\n    disabled: [true, false]\n  }).forEach(props =\u003e {\n    const component = \u003cButton {...props} /\u003e;\n    const color = getColor(component);\n\n    expect(color).toBe(props.disabled ? \"gray\" : props.color);\n  });\n});\n```\n\n`prop-sets` helps you easily write tests for assertions that are based on multiple input values (in this case, `disabled` and `color`) without greatly increasing the amount of code you have to write.\n\nWithout `prop-sets`, this test will need to be expanded to three assertions:\n\n```jsx\nit(\"is gray when disabled\", () =\u003e {\n  const component = \u003cButton disabled color=\"red\" /\u003e;\n  const color = getColor(component);\n\n  expect(color).toBe(\"gray\");\n});\n\nit(\"is red when props.color is red\", () =\u003e {\n  const component = \u003cButton color=\"red\" /\u003e;\n  const color = getColor(component);\n\n  expect(color).toBe(\"red\");\n});\n\nit(\"is blue when props.color is blue\", () =\u003e {\n  const component = \u003cButton color=\"blue\" /\u003e;\n  const color = getColor(component);\n\n  expect(color).toBe(\"blue\");\n});\n```\n\nBecause `backgroundColor`'s value is determined by both the `disabled` _and_ `color` prop, we need to have all three assertions to be sure the component behaves as expected. Here are some implementations of `Button` that will only pass certain tests but fail all others.\n\n```jsx\n// Passes 'is gray when disabled', fails all others\nconst Button = props =\u003e \u003cbutton style={{ backgroundColor: \"gray\" }} /\u003e;\n\n// Passes 'is red when color is red', fails all others\nconst Button = props =\u003e \u003cbutton style={{ backgroundColor: \"red\" }} /\u003e;\n\n// Passes 'is blue when color is blue', fails all others\nconst Button = props =\u003e \u003cbutton style={{ backgroundColor: \"blue\" }} /\u003e;\n\n// Passes 'is gray when disabled', 'is red when color is red', fails all others\nconst Button = props =\u003e (\n  \u003cbutton style={{ backgroundColor: props.disabled ? \"gray\" : \"red\" }} /\u003e\n);\n```\n\nThe amount of combinations `prop-sets` generates is the [Cartesian product](https://en.wikipedia.org/wiki/Cartesian_product) of all the values passed in (`a.length * b.length * c.length * ...`), so as the amount of props grows, `prop-sets` reduces your test's complexity at an exponential rate.\n\nFor example, if you have a component that only behaves a certain way if all 5 of its boolean props are true, the amount of tests you would need to write to formally assert that behavior is **32**. With `prop-sets`, just **one**!:\n\n```js\nit(\"does something if all props are true, false otherwise\", () =\u003e {\n  const tf = [true, false];\n  propSets({ a: tf, b: tf, c: tf, d: tf, e: tf }).forEach(props =\u003e {\n    expect(/* something */).toBe(\n      props.a \u0026\u0026 props.b \u0026\u0026 props.c \u0026\u0026 props.d \u0026\u0026 props.e\n    );\n  });\n});\n```\n\n## Use\n\n### Install\n\n`yarn add prop-sets` or `npm install prop-sets`\n\n### Import\n\n```js\nimport propSets from \"prop-sets\";\n```\n\n### API\n\n#### `propSets(object)`\n\n#### Arguments\n\n| Name     | Type                       | Description                                                |\n| -------- | -------------------------- | ---------------------------------------------------------- |\n| `object` | `{ [prop]: Array\u003cvalue\u003e }` | An object of arrays containing possible values of the prop |\n\n#### Return\n\n| Type                       | Description                                                        |\n| -------------------------- | ------------------------------------------------------------------ |\n| `Array\u003c{ [prop]: value }\u003e` | An array of props where every combination of prop values is unique |\n\n#### TypeScript\n\n`prop-sets` comes typed but works perfectly fine without TypeScript.\n\n```ts\ndeclare const propSets: \u003c\n  T extends Readonly\u003c{\n    [key: string]: ReadonlyArray\u003cany\u003e;\n  }\u003e\n\u003e(\n  obj: T\n) =\u003e {\n  [key in keyof T]: T[key] extends (infer ElementType)[] ? ElementType : any\n}[];\n```\n\n## Further reading\n\n[Why Don't People Use Formal Methods?](https://hillelwayne.com/post/why-dont-people-use-formal-methods/) by [Hillel Wayne](https://hillelwayne.com/)\n\n[Model checking](https://en.wikipedia.org/wiki/Model_checking)\n\n[Combinatorial explosion (state explosion problem)](https://en.wikipedia.org/wiki/Combinatorial_explosion)\n\n## License\n\n[MIT](./license)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftvler%2Fprop-sets","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftvler%2Fprop-sets","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftvler%2Fprop-sets/lists"}