{"id":23967937,"url":"https://github.com/devexpress/testcafe-react-selectors","last_synced_at":"2025-05-15T04:07:26.161Z","repository":{"id":14541485,"uuid":"66445767","full_name":"DevExpress/testcafe-react-selectors","owner":"DevExpress","description":"TestCafe selector extensions for React apps.","archived":false,"fork":false,"pushed_at":"2025-02-07T08:42:39.000Z","size":2589,"stargazers_count":203,"open_issues_count":3,"forks_count":42,"subscribers_count":20,"default_branch":"master","last_synced_at":"2025-04-02T09:47:40.578Z","etag":null,"topics":["e2e","plugin","react","reactjs","testcafe","testing"],"latest_commit_sha":null,"homepage":"https://testcafe.io","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/DevExpress.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}},"created_at":"2016-08-24T08:26:27.000Z","updated_at":"2025-03-13T03:22:55.000Z","dependencies_parsed_at":"2024-01-12T12:41:51.995Z","dependency_job_id":"3d70a1da-ca37-4e9e-a8a8-fca9b5f42137","html_url":"https://github.com/DevExpress/testcafe-react-selectors","commit_stats":{"total_commits":183,"total_committers":20,"mean_commits":9.15,"dds":0.3715846994535519,"last_synced_commit":"3a2a6a631e3cc61edcdce3c6df90227bc1b2f480"},"previous_names":[],"tags_count":41,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DevExpress%2Ftestcafe-react-selectors","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DevExpress%2Ftestcafe-react-selectors/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DevExpress%2Ftestcafe-react-selectors/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DevExpress%2Ftestcafe-react-selectors/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/DevExpress","download_url":"https://codeload.github.com/DevExpress/testcafe-react-selectors/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248027406,"owners_count":21035594,"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":["e2e","plugin","react","reactjs","testcafe","testing"],"created_at":"2025-01-06T23:57:12.297Z","updated_at":"2025-04-09T11:05:07.364Z","avatar_url":"https://github.com/DevExpress.png","language":"JavaScript","readme":"# testcafe-react-selectors\n\nThis plugin provides selector extensions that make it easier to test ReactJS components with [TestCafe](https://github.com/DevExpress/testcafe). These extensions allow you to select page elements in a way that is native to React.\n\n## Install\n\n`$ npm install testcafe-react-selectors`\n\n## Usage\n\n* [Wait for application to be ready to run tests](#wait-for-application-to-be-ready-to-run-tests)\n* [Creating selectors for ReactJS components](#creating-selectors-for-reactjs-components)\n  * [Selecting elements by the component name](#selecting-elements-by-the-component-name)\n  * [Selecting nested components](#selecting-nested-components)\n  * [Selecting components by the component key](#selecting-components-by-the-component-key)\n  * [Selecting components by display name](#selecting-components-by-display-name)\n  * [Selecting components by property values](#selecting-components-by-property-values)\n    * [Properties whose values are objects](#properties-whose-values-are-objects)\n  * [Searching for nested components](#searching-for-nested-components)\n  * [Combining with regular TestCafe selectors](#combining-with-regular-testcafe-selectors)\n* [Obtaining component's props and state](#obtaining-components-props-and-state)\n* [TypeScript Generic Selector](#typescript-generic-selector)\n  * [Composite Types in Props and State](#composite-types-in-props-and-state)\n* [Limitations](#limitations)\n\n### Wait for application to be ready to run tests\n\nTo wait until the React's component tree is loaded, add the `waitForReact` method to fixture's `beforeEach` hook.\n\n```js\nimport { waitForReact } from 'testcafe-react-selectors';\n\nfixture `App tests`\n    .page('http://react-app-url')\n    .beforeEach(async () =\u003e {\n        await waitForReact();\n    });\n```\n\nThe default timeout for `waitForReact` is `10000` ms. You can specify a custom timeout value:\n\n```js\nawait waitForReact(5000);\n```\n\nIf you need to call a selector from a Node.js callback, pass the current test controller as the second argument in the `waitForReact` function:\n\n```js\nimport { waitForReact } from 'testcafe-react-selectors';\n\nfixture `App tests`\n    .page('http://react-app-url')\n    .beforeEach(async t =\u003e {\n        await waitForReact(5000, t);\n    });\n``` \n\nThe test controller will be assigned to the [boundTestRun](https://devexpress.github.io/testcafe/documentation/test-api/obtaining-data-from-the-client/#optionsboundtestrun) function's option. Otherwise, TestCafe would throw the following error: `ClientFunction cannot implicitly resolve the test run in context of which it should be executed`. See the [TestCafe documentation](https://devexpress.github.io/testcafe/documentation/test-api/obtaining-data-from-the-client/#calling-client-functions-from-nodejs-callbacks) for further details.\n\n### Creating selectors for ReactJS components\n\n`ReactSelector` allows you to select page elements by the name of the component class or the nested component element.\n\nSuppose you have the following JSX.\n\n```xml\n\u003cTodoApp className=\"todo-app\"\u003e\n    \u003cTodoInput /\u003e\n    \u003cTodoList\u003e\n        \u003cTodoItem priority=\"High\" key=\"HighPriority\"\u003eItem 1\u003c/TodoItem\u003e\n        \u003cTodoItem priority=\"Low\" key=\"LowPriority\"\u003eItem 2\u003c/TodoItem\u003e\n    \u003c/TodoList\u003e\n\n    \u003cdiv className=\"items-count\"\u003eItems count: \u003cspan\u003e{this.state.itemCount}\u003c/span\u003e\u003c/div\u003e\n\u003c/TodoApp\u003e\n```\n\n#### Selecting elements by the component name\n\nTo get a root DOM element for a component, pass the component name to the `ReactSelector` constructor.\n\n```js\nimport { ReactSelector } from 'testcafe-react-selectors';\n\nconst todoInput = ReactSelector('TodoInput');\n```\n\n#### Selecting nested components\n\nTo obtain a nested component or DOM element, you can use a combined selector or add DOM element's tag name.\n\n```js\nimport { ReactSelector } from 'testcafe-react-selectors';\n\nconst TodoList         = ReactSelector('TodoApp TodoList');\nconst itemsCountStatus = ReactSelector('TodoApp div');\nconst itemsCount       = ReactSelector('TodoApp div span');\n```\n\nWarning: if you specify a DOM element's tag name, React selectors search for the element among the component's children without looking into nested components. For instance, for the JSX above the `ReactSelector('TodoApp div')` selector will be equal to `Selector('.todo-app \u003e div')`.\n\n#### Selecting components by the component key\n\nTo obtain a component by its key, use the `withKey` method. \n\n```js\nimport { ReactSelector } from 'testcafe-react-selectors';\n\nconst item = ReactSelector('TodoItem').withKey('HighPriority');\n```\n\n#### Selecting components by display name\n\nYou can select elements by the component's [displayName](https://reactjs.org/docs/react-component.html#displayname).\n\nFor instance, consider the `TodoList` component whose `displayName` class property is specified as follows:\n\n```js\nclass TodoList extends React.Component {\n  // ...\n}\n\nTodoList.displayName = 'TodoList';\n```\n\nIn this instance, you can use `todo-list-display-name` to identify `TodoList`.\n\n```js\nimport { ReactSelector } from 'testcafe-react-selectors';\n\nconst list = ReactSelector('todo-list-display-name');\n```\n\n#### Selecting components by property values\n\nReact selectors allow you to select elements that have a specific property value. To do this, use the `withProps` method. You can pass the property and its value as two parameters or an object.\n\n```js\nimport { ReactSelector } from 'testcafe-react-selectors';\n\nconst item1 = ReactSelector('TodoApp').withProps('priority', 'High');\nconst item2 = ReactSelector('TodoApp').withProps({ priority: 'Low' });\n```\n\nYou can also search for elements by multiple properties.\n\n```js\nimport { ReactSelector } from 'testcafe-react-selectors';\n\nconst element = ReactSelector('componentName').withProps({\n    propName: 'value',\n    anotherPropName: 'differentValue'\n});\n```\n\n##### Properties whose values are objects\n\nReact selectors allow you to filter components by properties whose values are objects.\n\nWhen the `withProps` function filters properties, it determines whether the objects (property values) are strictly or partially equal.\n\nThe following example illustrates strict and partial equality.\n\n```js\nobject1 = {\n    field1: 1\n}\nobject2 = {\n    field1: 1\n}\nobject3 = {\n    field1: 1\n    field2: 2\n}\nobject4 = {\n    field1: 3\n    field2: 2\n}\n```\n\n* `object1` strictly equals `object2`\n* `object2` partially equals `object3`\n* `object2` does not equal `object4`\n* `object3` does not equal `object4`\n\nPrior to version 3.0.0, `withProps` checked if objects are strictly equal when comparing them. Since 3.0.0, `withProps` checks for partial equality. To test objects for strict equality, specify the `exactObjectMatch` option.\n\nThe following example returns the `componentName` component because the `objProp` property values are strictly equal and `exactObjectMatch` is set to true.\n\n```js\n// props = {\n//   simpleProp: 'value',\n//   objProp: {\n//       field1: 'value',\n//       field2: 'value'\n//   }\n// }\n\nconst element = ReactSelector('componentName').withProps({\n    simpleProp: 'value',\n    objProp: {\n        field1: 'value',\n        field2: 'value'\n    }\n}, { exactObjectMatch: true })\n```\n\nNote that the partial equality check works for objects of any depth.\n\n```js\n// props = {\n//     simpleProp: 'value',\n//     objProp: {\n//         field1: 'value',\n//         field2: 'value',\n//         nested1: {\n//             someField: 'someValue',\n//             nested2: {\n//                 someField: 'someValue',\n//                 nested3: {\n//                     field: 'value',\n//                     someField: 'someValue'\n//                 }\n//             }\n//         }\n//     }\n// }\n\n\nconst element = ReactSelector('componentName').withProps({\n    simpleProp: 'value',\n    objProp: {\n        field1: 'value',\n        nested1: {\n            nested2: {\n                nested3: {\n                    field: 'value'\n                }\n            }\n        }\n    }\n}, { exactObjectMatch: false })\n```\n\n#### Searching for nested components\n\nYou can search for a desired subcomponent or DOM element among the component's children using the `.findReact(element)` method. The method takes the subcomponent name or tag name as a parameter.\n\nSuppose you have the following JSX.\n\n```xml\n\u003cTodoApp className=\"todo-app\"\u003e\n    \u003cdiv\u003e\n        \u003cTodoList\u003e\n            \u003cTodoItem priority=\"High\"\u003eItem 1\u003c/TodoItem\u003e\n            \u003cTodoItem priority=\"Low\"\u003eItem 2\u003c/TodoItem\u003e\n        \u003c/TodoList\u003e\n    \u003c/div\u003e\n\u003c/TodoApp\u003e\n```\n\nThe following sample demonstrates how to obtain the `TodoItem` subcomponent.\n\n```js\nimport { ReactSelector } from 'testcafe-react-selectors';\n\nconst component    = ReactSelector('TodoApp');\nconst div          = component.findReact('div');\nconst subComponent = div.findReact('TodoItem');\n```\n\nYou can call the `.findReact` method in a chain, for example:\n\n```js\nimport { ReactSelector } from 'testcafe-react-selectors';\n\nconst subComponent = ReactSelector('TodoApp').findReact('div').findReact('TodoItem');\n```\n\nYou can also combine `.findReact` with regular selectors and [other](http://devexpress.github.io/testcafe/documentation/test-api/selecting-page-elements/selectors.html#functional-style-selectors)) methods like [.find](http://devexpress.github.io/testcafe/documentation/test-api/selecting-page-elements/selectors.html#find) or [.withText](http://devexpress.github.io/testcafe/documentation/test-api/selecting-page-elements/selectors.html#withtext), for example:\n\n```js\nimport { ReactSelector } from 'testcafe-react-selectors';\n\nconst subComponent = ReactSelector('TodoApp').find('div').findReact('TodoItem');\n```\n\n#### Combining with regular TestCafe selectors\n\nSelectors returned by the `ReactSelector` constructor are recognized as TestCafe selectors. You can combine them with regular selectors and filter with [.withText](http://devexpress.github.io/testcafe/documentation/test-api/selecting-page-elements/selectors.html#withtext), [.nth](http://devexpress.github.io/testcafe/documentation/test-api/selecting-page-elements/selectors.html#nth), [.find](http://devexpress.github.io/testcafe/documentation/test-api/selecting-page-elements/selectors.html#find) and [other](http://devexpress.github.io/testcafe/documentation/test-api/selecting-page-elements/selectors.html#functional-style-selectors) functions. To search for elements within a component, you can use the following combined approach.\n\n```js\nimport { ReactSelector } from 'testcafe-react-selectors';\n\nvar itemsCount = ReactSelector('TodoApp').find('.items-count span');\n```\n\n**Example**\n\nLet's use the API described above to add a task to a Todo list and check that the number of items changed.\n\n```js\nimport { ReactSelector } from 'testcafe-react-selectors';\n\nfixture `TODO list test`\n\t.page('http://localhost:1337');\n\ntest('Add new task', async t =\u003e {\n    const todoTextInput = ReactSelector('TodoInput');\n    const todoItem      = ReactSelector('TodoList TodoItem');\n\n    await t\n        .typeText(todoTextInput, 'My Item')\n        .pressKey('enter')\n        .expect(todoItem.count).eql(3);\n});\n```\n\n### Obtaining component's props and state\n\nAs an alternative to [testcafe snapshot properties](http://devexpress.github.io/testcafe/documentation/test-api/selecting-page-elements/dom-node-state.html), you can obtain `state`, `props` or `key` of a ReactJS component.\n\nTo obtain component's properties, state and key, use the React selector's `.getReact()` method.\n\nThe `.getReact()` method returns a [client function](https://devexpress.github.io/testcafe/documentation/test-api/obtaining-data-from-the-client.html). This function resolves to an object that contains component's properties (excluding properties of its `children`), state and key.\n\n```js\nconst reactComponent      = ReactSelector('MyComponent');\nconst reactComponentState = await reactComponent.getReact();\n\n// \u003e\u003e reactComponentState\n//\n// {\n//     props:    \u003ccomponent_props\u003e,\n//     state:    \u003ccomponent_state\u003e,\n//     key:      \u003ccomponent_key\u003e\n// }\n```\n\nThe returned client function can be passed to assertions activating the [Smart Assertion Query mechanism](https://devexpress.github.io/testcafe/documentation/test-api/assertions/#smart-assertion-query-mechanism).\n\n**Example**\n\n```js\nimport { ReactSelector } from 'testcafe-react-selectors';\n\nfixture `TODO list test`\n\t.page('http://localhost:1337');\n\ntest('Check list item', async t =\u003e {\n    const el         = ReactSelector('TodoList');\n    const component  = await el.getReact();\n\n    await t.expect(component.props.priority).eql('High');\n    await t.expect(component.state.isActive).eql(false);\n    await t.expect(component.key).eql('componentID');\n});\n```\n\nAs an alternative, the `.getReact()` method can take a function that returns the required property, state or key. This function acts as a filter. Its argument is an object returned by `.getReact()`, i.e. `{ props: ..., state: ..., key: ...}`.\n\n```js\nReactSelector('Component').getReact(({ props, state, key }) =\u003e {...})\n```\n\n**Example**\n\n```js\nimport { ReactSelector } from 'testcafe-react-selectors';\n\nfixture `TODO list test`\n    .page('http://localhost:1337');\n\ntest('Check list item', async t =\u003e {\n    const el = ReactSelector('TodoList');\n\n    await t\n        .expect(el.getReact(({ props }) =\u003e props.priority)).eql('High')\n        .expect(el.getReact(({ state }) =\u003e state.isActive)).eql(false)\n        .expect(el.getReact(({ key }) =\u003e key)).eql('componentID');\n});\n```\n\nThe `.getReact()` method can be called for the `ReactSelector` or the snapshot this selector returns.\n\n### TypeScript Generic Selector\n\nUse the generic `ReactComponent` type to create scalable selectors in TypeScript.\n\nPass the `props` object as the type argument to `ReactComponent` to introduce a type for a specific component.\n\n```ts\ntype TodoItem = ReactComponent\u003c{ id: string }\u003e;\n```\n\nYou can then pass the created `TodoItem` type to the `withProps` and `getReact` generic methods.\n\n```ts\nconst component  = ReactSelector('TodoItem');\ntype TodoItem    = ReactComponent\u003c{ id: string }\u003e;\n\nconst item1  = component.withProps\u003cTodoItem\u003e('id', 'tdi-1');\nconst itemId = component.getReact\u003cTodoItem\u003e(({ props }) =\u003e props.id);\n```\n\n**Example**\n\n``` ts\nimport { ReactSelector, ReactComponent } from 'testcafe-react-selectors';\n\nfixture`typescript support`\n    .page('http://react-page-example.com')\n\ntest('ReactComponent', async t =\u003e {\n    const todoList         = ReactSelector('TodoList');\n    type TodoListComponent = ReactComponent\u003c{ id: string }\u003e;\n\n    const todoListId = todoList.getReact\u003cTodoListComponent\u003e(({ props }) =\u003e props.id);\n\n    await t.expect(todoListId).eql('ul-item');\n});\n```\n\n#### Composite Types in Props and State\n\nIf a component's props and state include other composite types, you can create your own type definitions for them. Then pass these definitions to `ReactComponent` as type arguments.\n\nThe following example shows custom `Props` and `State` type definitions. The `State` type uses another composite type - `Option`.\n\n``` ts\nimport { ReactComponent } from 'testcafe-react-selectors';\n\ninterface Props {\n    id: string;\n    text: string;\n}\n\ninterface Option {\n    id: number;\n    title: string;\n    description: string;\n}\n\ninterface State {\n    optionsCount: number;\n    options: Option[];\n}\n\nexport type OptionReactComponent = ReactComponent\u003cProps, State\u003e;\n```\n\n### Limitations\n\n* `testcafe-react-selectors` support ReactJS starting with version 16. To check if a component can be found, use the [react-dev-tools](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi) extension.\n* Search for a component starts from the root React component, so selectors like `ReactSelector('body MyComponent')` will return `null`.\n* ReactSelectors need class names to select components on the page. Code minification usually does not keep the original class names. So you should either use non-minified code or configure the minificator to keep class names.\n\n  For `babel-minify`, add the following options to the configuration:\n\n  ```js\n  { keepClassName: true, keepFnName: true }\n  ```\n\n  In UglifyJS, use the following configuration:\n\n   ```js\n   {\n       compress: {\n           keep_fnames: true\n       },\n\n       mangle: {\n           keep_fnames: true\n       }\n   }\n   ```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevexpress%2Ftestcafe-react-selectors","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdevexpress%2Ftestcafe-react-selectors","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevexpress%2Ftestcafe-react-selectors/lists"}