1 | # reselector
|
2 |
|
3 | [![Travis branch](https://img.shields.io/travis/lttb/reselector/master.svg?style=flat)](https://travis-ci.org/lttb/reselector)
|
4 | [![Coverage Status branch](https://img.shields.io/coveralls/lttb/reselector/master.svg?style=flat)](https://img.shields.io/coveralls/lttb/reselector/master.svg?branch=master)
|
5 | [![npm version](https://img.shields.io/npm/v/reselector.svg?style=flat)](https://www.npmjs.com/package/reselector)
|
6 | [![npm license](https://img.shields.io/npm/l/reselector.svg?style=flat)](https://www.npmjs.com/package/reselector)
|
7 |
|
8 | ## Installation
|
9 |
|
10 | ```sh
|
11 | npm install --save-dev reselector
|
12 | ```
|
13 |
|
14 | ## Usage
|
15 |
|
16 | You can use it as a babel-plugin or as the runtime function, or both.
|
17 |
|
18 | ### babel-plugin
|
19 |
|
20 | Add `reselector` to the plugin list in `.babelrc` for your client code. For example:
|
21 |
|
22 | ```js
|
23 | {
|
24 | presets: ['react'],
|
25 | env: {
|
26 | test: {
|
27 | plugins: [
|
28 | 'reselector/babel',
|
29 | ],
|
30 | },
|
31 | },
|
32 | }
|
33 | ```
|
34 |
|
35 | ### Find Components in the DOM
|
36 |
|
37 | Use `select` function to build any css selector by React Components.
|
38 |
|
39 | Just a simple example with [jest](https://facebook.github.io/jest/)
|
40 |
|
41 | ```jsx
|
42 | import React from 'react'
|
43 | import {render} from 'react-dom'
|
44 | import {select} from 'reselector'
|
45 |
|
46 | const Text = ({children}) => <p>{children}</p>
|
47 |
|
48 | const Button = ({children}) => (
|
49 | <button>
|
50 | <Text>{children}</Text>
|
51 | </button>
|
52 | )
|
53 |
|
54 | describe('Button', () => {
|
55 | beforeEach(() => document.body.innerHTML = '<div id="app" />')
|
56 |
|
57 | it('should render a text', () => {
|
58 | const text = 'hello world!'
|
59 | render(<Button>{text}</Button>, window.app)
|
60 |
|
61 | const node = document.querySelector(select`${Button} > ${Text}`)
|
62 | expect(node.textContent).toBe(text)
|
63 | })
|
64 | })
|
65 | ```
|
66 |
|
67 | ### enzyme
|
68 |
|
69 | It also works with libraries like [enzyme](https://github.com/airbnb/enzyme) out of the box.
|
70 |
|
71 | ```jsx
|
72 | import {render} from 'enzyme'
|
73 |
|
74 | import Button from './Button'
|
75 | import Text from './Text'
|
76 |
|
77 | describe('Button', () => {
|
78 | it('should render a text', () => {
|
79 | const text = 'hello world!'
|
80 | const wrapper = render(<Button>{text}</Button>)
|
81 |
|
82 | expect(wrapper.find(select`${Button} > ${Text}`).text()).toBe(text)
|
83 | })
|
84 | })
|
85 | ```
|
86 |
|
87 | #### Babel
|
88 |
|
89 | If you have a chanсe to transpile components with this plugin for your unit tests/autotests, you can import React Component as is.
|
90 |
|
91 | ```jsx
|
92 | import {select} from 'reselector'
|
93 |
|
94 | import MyComponent from './MyComponent'
|
95 | import MyButton from './MyButton'
|
96 |
|
97 | /**
|
98 | * [data-dadad] [data-czczx]
|
99 | */
|
100 | console.log(select`${MyComponent} ${MyButton}`)
|
101 |
|
102 | /**
|
103 | * .myClassName > [data-czczx]
|
104 | */
|
105 | console.log(select`.myClassName > ${MyButton}`)
|
106 | ```
|
107 |
|
108 | #### Runtime (just node.js, without babel)
|
109 |
|
110 | It may be useful for autotests (for example, with PageObjects) when you don't need to transpile code. Just use `resolve` or `resolveBy` functions to get Components' selector.
|
111 |
|
112 | ```jsx
|
113 | const {resolve, select} = require('reselector')
|
114 |
|
115 | const {MyComponent} = resolve(require.resolve('./MyComponent'))
|
116 | const {MyButton} = resolve(require.resolve('./MyButton'))
|
117 |
|
118 | /**
|
119 | * [data-dadad] [data-czczx]
|
120 | */
|
121 | console.log(select`${MyComponent} ${MyButton}`)
|
122 |
|
123 | /**
|
124 | * .myClassName > [data-czczx]
|
125 | */
|
126 | console.log(select`.myClassName > ${MyButton}`)
|
127 | ```
|
128 |
|
129 | ```jsx
|
130 | const {resolveBy, select} = require('reselector')
|
131 |
|
132 | const resolve = resolveBy(require.resolve)
|
133 |
|
134 | const {MyComponent} = resolve('./MyComponent')
|
135 | const {MyButton} = resolve('./MyButton')
|
136 |
|
137 | /**
|
138 | * [data-dadad] [data-czczx]
|
139 | */
|
140 | console.log(select`${MyComponent} ${MyButton}`)
|
141 |
|
142 | /**
|
143 | * .myClassName > [data-czczx]
|
144 | */
|
145 | console.log(select`.myClassName > ${MyButton}`)
|
146 | ```
|
147 |
|
148 | ## How it works
|
149 |
|
150 | This plugin tries to find all React Component declarations and to add `data-{hash}` attribute with the uniq hash-id to the Component's root node. It also saves this hash as the static property for the Component, so `get` function uses this property to build a selector.
|
151 |
|
152 |
|
153 | ## Configuration
|
154 |
|
155 | You can provide some options via `reselector.config.js`, rc-files or in `package.json`.
|
156 |
|
157 | ### prefix
|
158 |
|
159 | {**string**} By default, it's `data-`. So this plugin generates attributes like `data-c7b7156f`.
|
160 |
|
161 | But you can define your own prefix, for example
|
162 |
|
163 | ```js
|
164 | module.exports = {prefix: ''}
|
165 | ```
|
166 |
|
167 | With that, you'll get just a `{hash}` attribute on nodes like `<button c7b7156f />`.
|
168 |
|
169 | ### env
|
170 |
|
171 | {**boolean**} Be default, `false`. Just set it on `true` to control attributes appending by `process.env.RESELECTOR`. So it will no append hashes at runtime when `process.env.RESELECTOR !== 'true'`.
|
172 |
|
173 | For example:
|
174 |
|
175 | ```js
|
176 | module.exports = {env: true}
|
177 | ```
|
178 |
|
179 | ### syntaxes
|
180 |
|
181 | {**string[]**} By default, this plugin works with these syntax list:
|
182 |
|
183 | ```
|
184 | @babel/plugin-syntax-async-generators
|
185 | @babel/plugin-syntax-class-properties
|
186 | @babel/plugin-syntax-decorators
|
187 | @babel/plugin-syntax-dynamic-import
|
188 | @babel/plugin-syntax-export-default-from
|
189 | @babel/plugin-syntax-export-namespace-from
|
190 | @babel/plugin-syntax-flow
|
191 | @babel/plugin-syntax-function-bind
|
192 | @babel/plugin-syntax-import-meta
|
193 | @babel/plugin-syntax-jsx
|
194 | @babel/plugin-syntax-nullish-coalescing-operator
|
195 | @babel/plugin-syntax-numeric-separator
|
196 | @babel/plugin-syntax-object-rest-spread
|
197 | @babel/plugin-syntax-optional-catch-binding
|
198 | @babel/plugin-syntax-optional-chaining
|
199 | @babel/plugin-syntax-pipeline-operator
|
200 | @babel/plugin-syntax-throw-expressions
|
201 | ```
|
202 |
|
203 | But you can declare your own syntax list, for example:
|
204 |
|
205 | ```js
|
206 | // .reselectorrc.js
|
207 |
|
208 | module.exports = {
|
209 | syntaxes: [
|
210 | '@babel/plugin-syntax-async-generators',
|
211 | '@babel/plugin-syntax-class-properties',
|
212 | '@babel/plugin-syntax-decorators',
|
213 | '@babel/plugin-syntax-dynamic-import',
|
214 | '@babel/plugin-syntax-export-default-from',
|
215 | '@babel/plugin-syntax-export-namespace-from',
|
216 | '@babel/plugin-syntax-flow',
|
217 | '@babel/plugin-syntax-function-bind',
|
218 | '@babel/plugin-syntax-import-meta',
|
219 | '@babel/plugin-syntax-jsx',
|
220 | '@babel/plugin-syntax-nullish-coalescing-operator',
|
221 | '@babel/plugin-syntax-numeric-separator',
|
222 | '@babel/plugin-syntax-object-rest-spread',
|
223 | '@babel/plugin-syntax-optional-catch-binding',
|
224 | '@babel/plugin-syntax-optional-chaining',
|
225 | '@babel/plugin-syntax-pipeline-operator',
|
226 | '@babel/plugin-syntax-throw-expressions',
|
227 | ],
|
228 | }
|
229 | ```
|