rails-assets-enzyme 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/lib/rails/assets/enzyme.rb +9 -0
- data/lib/rails/assets/enzyme/version.rb +7 -0
- data/vendor/assets/javascripts/Debug.js +133 -0
- data/vendor/assets/javascripts/MountedTraversal.js +305 -0
- data/vendor/assets/javascripts/ReactWrapper.js +777 -0
- data/vendor/assets/javascripts/ReactWrapperComponent.jsx +91 -0
- data/vendor/assets/javascripts/ShallowTraversal.js +173 -0
- data/vendor/assets/javascripts/ShallowWrapper.js +744 -0
- data/vendor/assets/javascripts/Utils.js +266 -0
- data/vendor/assets/javascripts/index.js +14 -0
- data/vendor/assets/javascripts/mount.js +11 -0
- data/vendor/assets/javascripts/react-compat.js +166 -0
- data/vendor/assets/javascripts/render.js +19 -0
- data/vendor/assets/javascripts/shallow.js +11 -0
- data/vendor/assets/javascripts/version.js +5 -0
- metadata +89 -0
@@ -0,0 +1,777 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import cheerio from 'cheerio';
|
3
|
+
import flatten from 'lodash/flatten';
|
4
|
+
import unique from 'lodash/uniq';
|
5
|
+
import compact from 'lodash/compact';
|
6
|
+
import createWrapperComponent from './ReactWrapperComponent';
|
7
|
+
import {
|
8
|
+
instHasClassName,
|
9
|
+
childrenOfInst,
|
10
|
+
parentsOfInst,
|
11
|
+
buildInstPredicate,
|
12
|
+
instEqual,
|
13
|
+
treeFilter,
|
14
|
+
getNode,
|
15
|
+
} from './MountedTraversal';
|
16
|
+
import {
|
17
|
+
renderWithOptions,
|
18
|
+
Simulate,
|
19
|
+
findDOMNode,
|
20
|
+
unmountComponentAtNode,
|
21
|
+
} from './react-compat';
|
22
|
+
import {
|
23
|
+
mapNativeEventNames,
|
24
|
+
containsChildrenSubArray,
|
25
|
+
propsOfNode,
|
26
|
+
typeOfNode,
|
27
|
+
} from './Utils';
|
28
|
+
import {
|
29
|
+
debugInsts,
|
30
|
+
} from './Debug';
|
31
|
+
|
32
|
+
/**
|
33
|
+
* Finds all nodes in the current wrapper nodes' render trees that match the provided predicate
|
34
|
+
* function.
|
35
|
+
*
|
36
|
+
* @param {ReactWrapper} wrapper
|
37
|
+
* @param {Function} predicate
|
38
|
+
* @returns {ReactWrapper}
|
39
|
+
*/
|
40
|
+
function findWhereUnwrapped(wrapper, predicate) {
|
41
|
+
return wrapper.flatMap(n => treeFilter(n.node, predicate));
|
42
|
+
}
|
43
|
+
|
44
|
+
/**
|
45
|
+
* Returns a new wrapper instance with only the nodes of the current wrapper instance that match
|
46
|
+
* the provided predicate function.
|
47
|
+
*
|
48
|
+
* @param {ReactWrapper} wrapper
|
49
|
+
* @param {Function} predicate
|
50
|
+
* @returns {ReactWrapper}
|
51
|
+
*/
|
52
|
+
function filterWhereUnwrapped(wrapper, predicate) {
|
53
|
+
return wrapper.wrap(compact(wrapper.nodes.filter(predicate)));
|
54
|
+
}
|
55
|
+
|
56
|
+
/**
|
57
|
+
* @class ReactWrapper
|
58
|
+
*/
|
59
|
+
export default class ReactWrapper {
|
60
|
+
|
61
|
+
constructor(nodes, root, options = {}) {
|
62
|
+
if (!global.window && !global.document) {
|
63
|
+
throw new Error(
|
64
|
+
'It looks like you called `mount()` without a global document being loaded.'
|
65
|
+
);
|
66
|
+
}
|
67
|
+
|
68
|
+
if (!root) {
|
69
|
+
const ReactWrapperComponent = createWrapperComponent(nodes, options);
|
70
|
+
this.component = renderWithOptions(
|
71
|
+
<ReactWrapperComponent
|
72
|
+
Component={nodes.type}
|
73
|
+
props={nodes.props}
|
74
|
+
context={options.context}
|
75
|
+
/>,
|
76
|
+
options);
|
77
|
+
this.root = this;
|
78
|
+
this.node = this.component.getWrappedComponent();
|
79
|
+
this.nodes = [this.node];
|
80
|
+
this.length = 1;
|
81
|
+
} else {
|
82
|
+
this.component = null;
|
83
|
+
this.root = root;
|
84
|
+
if (!Array.isArray(nodes)) {
|
85
|
+
this.node = nodes;
|
86
|
+
this.nodes = [nodes];
|
87
|
+
} else {
|
88
|
+
this.node = nodes[0];
|
89
|
+
this.nodes = nodes;
|
90
|
+
}
|
91
|
+
this.length = this.nodes.length;
|
92
|
+
}
|
93
|
+
this.options = options;
|
94
|
+
}
|
95
|
+
|
96
|
+
/**
|
97
|
+
* If the root component contained a ref, you can access it here
|
98
|
+
* and get a wrapper around it.
|
99
|
+
*
|
100
|
+
* NOTE: can only be called on a wrapper instance that is also the root instance.
|
101
|
+
*
|
102
|
+
* @param {String} refname
|
103
|
+
* @returns {ReactWrapper}
|
104
|
+
*/
|
105
|
+
ref(refname) {
|
106
|
+
if (this.root !== this) {
|
107
|
+
throw new Error('ReactWrapper::ref(refname) can only be called on the root');
|
108
|
+
}
|
109
|
+
return this.wrap(this.instance().refs[refname]);
|
110
|
+
}
|
111
|
+
|
112
|
+
/**
|
113
|
+
* Gets the instance of the component being rendered as the root node passed into `mount()`.
|
114
|
+
*
|
115
|
+
* NOTE: can only be called on a wrapper instance that is also the root instance.
|
116
|
+
*
|
117
|
+
* Example:
|
118
|
+
* ```
|
119
|
+
* const wrapper = mount(<MyComponent />);
|
120
|
+
* const inst = wrapper.instance();
|
121
|
+
* expect(inst).to.be.instanceOf(MyComponent);
|
122
|
+
* ```
|
123
|
+
* @returns {ReactComponent}
|
124
|
+
*/
|
125
|
+
instance() {
|
126
|
+
if (this.root !== this) {
|
127
|
+
throw new Error('ReactWrapper::instance() can only be called on the root');
|
128
|
+
}
|
129
|
+
return this.component.getInstance();
|
130
|
+
}
|
131
|
+
|
132
|
+
/**
|
133
|
+
* Forces a re-render. Useful to run before checking the render output if something external
|
134
|
+
* may be updating the state of the component somewhere.
|
135
|
+
*
|
136
|
+
* NOTE: can only be called on a wrapper instance that is also the root instance.
|
137
|
+
*
|
138
|
+
* @returns {ReactWrapper}
|
139
|
+
*/
|
140
|
+
update() {
|
141
|
+
if (this.root !== this) {
|
142
|
+
// TODO(lmr): this requirement may not be necessary for the ReactWrapper
|
143
|
+
throw new Error('ReactWrapper::update() can only be called on the root');
|
144
|
+
}
|
145
|
+
this.single(() => {
|
146
|
+
this.component.forceUpdate();
|
147
|
+
});
|
148
|
+
return this;
|
149
|
+
}
|
150
|
+
|
151
|
+
/**
|
152
|
+
* A method that unmounts the component. This can be used to simulate a component going through
|
153
|
+
* and unmount/mount lifecycle.
|
154
|
+
*
|
155
|
+
* @returns {ReactWrapper}
|
156
|
+
*/
|
157
|
+
unmount() {
|
158
|
+
if (this.root !== this) {
|
159
|
+
throw new Error('ReactWrapper::unmount() can only be called on the root');
|
160
|
+
}
|
161
|
+
this.single(() => {
|
162
|
+
this.component.setState({ mount: false });
|
163
|
+
});
|
164
|
+
return this;
|
165
|
+
}
|
166
|
+
|
167
|
+
/**
|
168
|
+
* A method that re-mounts the component. This can be used to simulate a component going through
|
169
|
+
* an unmount/mount lifecycle.
|
170
|
+
*
|
171
|
+
* @returns {ReactWrapper}
|
172
|
+
*/
|
173
|
+
mount() {
|
174
|
+
if (this.root !== this) {
|
175
|
+
throw new Error('ReactWrapper::mount() can only be called on the root');
|
176
|
+
}
|
177
|
+
this.single(() => {
|
178
|
+
this.component.setState({ mount: true });
|
179
|
+
});
|
180
|
+
return this;
|
181
|
+
}
|
182
|
+
|
183
|
+
/**
|
184
|
+
* A method that sets the props of the root component, and re-renders. Useful for when you are
|
185
|
+
* wanting to test how the component behaves over time with changing props. Calling this, for
|
186
|
+
* instance, will call the `componentWillReceiveProps` lifecycle method.
|
187
|
+
*
|
188
|
+
* Similar to `setState`, this method accepts a props object and will merge it in with the already
|
189
|
+
* existing props.
|
190
|
+
*
|
191
|
+
* NOTE: can only be called on a wrapper instance that is also the root instance.
|
192
|
+
*
|
193
|
+
* @param {Object} props object
|
194
|
+
* @returns {ReactWrapper}
|
195
|
+
*/
|
196
|
+
setProps(props) {
|
197
|
+
if (this.root !== this) {
|
198
|
+
throw new Error('ReactWrapper::setProps() can only be called on the root');
|
199
|
+
}
|
200
|
+
this.component.setChildProps(props);
|
201
|
+
return this;
|
202
|
+
}
|
203
|
+
|
204
|
+
/**
|
205
|
+
* A method to invoke `setState` on the root component instance similar to how you might in the
|
206
|
+
* definition of the component, and re-renders. This method is useful for testing your component
|
207
|
+
* in hard to achieve states, however should be used sparingly. If possible, you should utilize
|
208
|
+
* your component's external API in order to get it into whatever state you want to test, in order
|
209
|
+
* to be as accurate of a test as possible. This is not always practical, however.
|
210
|
+
*
|
211
|
+
* NOTE: can only be called on a wrapper instance that is also the root instance.
|
212
|
+
*
|
213
|
+
* @param {Object} state to merge
|
214
|
+
* @returns {ReactWrapper}
|
215
|
+
*/
|
216
|
+
setState(state) {
|
217
|
+
if (this.root !== this) {
|
218
|
+
throw new Error('ReactWrapper::setState() can only be called on the root');
|
219
|
+
}
|
220
|
+
this.instance().setState(state);
|
221
|
+
return this;
|
222
|
+
}
|
223
|
+
|
224
|
+
/**
|
225
|
+
* A method that sets the context of the root component, and re-renders. Useful for when you are
|
226
|
+
* wanting to test how the component behaves over time with changing contexts.
|
227
|
+
*
|
228
|
+
* NOTE: can only be called on a wrapper instance that is also the root instance.
|
229
|
+
*
|
230
|
+
* @param {Object} context object
|
231
|
+
* @returns {ReactWrapper}
|
232
|
+
*/
|
233
|
+
setContext(context) {
|
234
|
+
if (this.root !== this) {
|
235
|
+
throw new Error('ReactWrapper::setContext() can only be called on the root');
|
236
|
+
}
|
237
|
+
if (!this.options.context) {
|
238
|
+
throw new Error(
|
239
|
+
'ShallowWrapper::setContext() can only be called on a wrapper that was originally passed ' +
|
240
|
+
'a context option'
|
241
|
+
);
|
242
|
+
}
|
243
|
+
this.component.setChildContext(context);
|
244
|
+
return this;
|
245
|
+
}
|
246
|
+
|
247
|
+
/**
|
248
|
+
* Whether or not a given react element exists in the mount render tree.
|
249
|
+
*
|
250
|
+
* Example:
|
251
|
+
* ```
|
252
|
+
* const wrapper = mount(<MyComponent />);
|
253
|
+
* expect(wrapper.contains(<div className="foo bar" />)).to.equal(true);
|
254
|
+
* ```
|
255
|
+
*
|
256
|
+
* @param {ReactElement|Array<ReactElement>} nodeOrNodes
|
257
|
+
* @returns {Boolean}
|
258
|
+
*/
|
259
|
+
contains(nodeOrNodes) {
|
260
|
+
const predicate = Array.isArray(nodeOrNodes)
|
261
|
+
? other => containsChildrenSubArray(instEqual, other, nodeOrNodes)
|
262
|
+
: other => instEqual(nodeOrNodes, other);
|
263
|
+
return findWhereUnwrapped(this, predicate).length > 0;
|
264
|
+
}
|
265
|
+
|
266
|
+
/**
|
267
|
+
* Finds every node in the render tree of the current wrapper that matches the provided selector.
|
268
|
+
*
|
269
|
+
* @param {String|Function} selector
|
270
|
+
* @returns {ReactWrapper}
|
271
|
+
*/
|
272
|
+
find(selector) {
|
273
|
+
const predicate = buildInstPredicate(selector);
|
274
|
+
return findWhereUnwrapped(this, predicate);
|
275
|
+
}
|
276
|
+
|
277
|
+
/**
|
278
|
+
* Returns whether or not current node matches a provided selector.
|
279
|
+
*
|
280
|
+
* NOTE: can only be called on a wrapper of a single node.
|
281
|
+
*
|
282
|
+
* @param {String|Function} selector
|
283
|
+
* @returns {boolean}
|
284
|
+
*/
|
285
|
+
is(selector) {
|
286
|
+
const predicate = buildInstPredicate(selector);
|
287
|
+
return this.single(n => predicate(n));
|
288
|
+
}
|
289
|
+
|
290
|
+
/**
|
291
|
+
* Returns a new wrapper instance with only the nodes of the current wrapper instance that match
|
292
|
+
* the provided predicate function.
|
293
|
+
*
|
294
|
+
* @param {Function} predicate
|
295
|
+
* @returns {ReactWrapper}
|
296
|
+
*/
|
297
|
+
filterWhere(predicate) {
|
298
|
+
return filterWhereUnwrapped(this, n => predicate(this.wrap(n)));
|
299
|
+
}
|
300
|
+
|
301
|
+
/**
|
302
|
+
* Returns a new wrapper instance with only the nodes of the current wrapper instance that match
|
303
|
+
* the provided selector.
|
304
|
+
*
|
305
|
+
* @param {String|Function} selector
|
306
|
+
* @returns {ReactWrapper}
|
307
|
+
*/
|
308
|
+
filter(selector) {
|
309
|
+
const predicate = buildInstPredicate(selector);
|
310
|
+
return filterWhereUnwrapped(this, predicate);
|
311
|
+
}
|
312
|
+
|
313
|
+
/**
|
314
|
+
* Returns a new wrapper instance with only the nodes of the current wrapper that did not match
|
315
|
+
* the provided selector. Essentially the inverse of `filter`.
|
316
|
+
*
|
317
|
+
* @param {String|Function} selector
|
318
|
+
* @returns {ReactWrapper}
|
319
|
+
*/
|
320
|
+
not(selector) {
|
321
|
+
const predicate = buildInstPredicate(selector);
|
322
|
+
return filterWhereUnwrapped(this, n => !predicate(n));
|
323
|
+
}
|
324
|
+
|
325
|
+
/**
|
326
|
+
* Returns a string of the rendered text of the current render tree. This function should be
|
327
|
+
* looked at with skepticism if being used to test what the actual HTML output of the component
|
328
|
+
* will be. If that is what you would like to test, use enzyme's `render` function instead.
|
329
|
+
*
|
330
|
+
* NOTE: can only be called on a wrapper of a single node.
|
331
|
+
*
|
332
|
+
* @returns {String}
|
333
|
+
*/
|
334
|
+
text() {
|
335
|
+
return this.single(n => findDOMNode(n).textContent);
|
336
|
+
}
|
337
|
+
|
338
|
+
/**
|
339
|
+
* Returns the HTML of the node.
|
340
|
+
*
|
341
|
+
* NOTE: can only be called on a wrapper of a single node.
|
342
|
+
*
|
343
|
+
* @returns {String}
|
344
|
+
*/
|
345
|
+
html() {
|
346
|
+
return this.single(n => {
|
347
|
+
const node = findDOMNode(n);
|
348
|
+
return node === null ? null :
|
349
|
+
node.outerHTML.replace(/\sdata-(reactid|reactroot)+="([^"]*)+"/g, '');
|
350
|
+
});
|
351
|
+
}
|
352
|
+
|
353
|
+
/**
|
354
|
+
* Returns the current node rendered to HTML and wrapped in a CheerioWrapper.
|
355
|
+
*
|
356
|
+
* NOTE: can only be called on a wrapper of a single node.
|
357
|
+
*
|
358
|
+
* @returns {CheerioWrapper}
|
359
|
+
*/
|
360
|
+
render() {
|
361
|
+
const html = this.html();
|
362
|
+
return html === null ? cheerio() : cheerio.load(html).root();
|
363
|
+
}
|
364
|
+
|
365
|
+
/**
|
366
|
+
* Used to simulate events. Pass an eventname and (optionally) event arguments. This method of
|
367
|
+
* testing events should be met with some skepticism.
|
368
|
+
*
|
369
|
+
* @param {String} event
|
370
|
+
* @param {Array} args
|
371
|
+
* @returns {ReactWrapper}
|
372
|
+
*/
|
373
|
+
simulate(event, ...args) {
|
374
|
+
this.single(n => {
|
375
|
+
const mappedEvent = mapNativeEventNames(event);
|
376
|
+
const eventFn = Simulate[mappedEvent];
|
377
|
+
if (!eventFn) {
|
378
|
+
throw new TypeError(`ReactWrapper::simulate() event '${event}' does not exist`);
|
379
|
+
}
|
380
|
+
|
381
|
+
eventFn(findDOMNode(n), ...args);
|
382
|
+
});
|
383
|
+
return this;
|
384
|
+
}
|
385
|
+
|
386
|
+
/**
|
387
|
+
* Returns the props hash for the root node of the wrapper.
|
388
|
+
*
|
389
|
+
* NOTE: can only be called on a wrapper of a single node.
|
390
|
+
*
|
391
|
+
* @returns {Object}
|
392
|
+
*/
|
393
|
+
props() {
|
394
|
+
return this.single(propsOfNode);
|
395
|
+
}
|
396
|
+
|
397
|
+
/**
|
398
|
+
* Returns the state hash for the root node of the wrapper. Optionally pass in a prop name and it
|
399
|
+
* will return just that value.
|
400
|
+
*
|
401
|
+
* NOTE: can only be called on a wrapper of a single node.
|
402
|
+
*
|
403
|
+
* @param {String} name (optional)
|
404
|
+
* @returns {*}
|
405
|
+
*/
|
406
|
+
state(name) {
|
407
|
+
if (this.root !== this) {
|
408
|
+
throw new Error('ReactWrapper::state() can only be called on the root');
|
409
|
+
}
|
410
|
+
const _state = this.single(() => this.instance().state);
|
411
|
+
if (name !== undefined) {
|
412
|
+
return _state[name];
|
413
|
+
}
|
414
|
+
return _state;
|
415
|
+
}
|
416
|
+
|
417
|
+
/**
|
418
|
+
* Returns the context hash for the root node of the wrapper.
|
419
|
+
* Optionally pass in a prop name and it will return just that value.
|
420
|
+
*
|
421
|
+
* NOTE: can only be called on a wrapper of a single node.
|
422
|
+
*
|
423
|
+
* @param {String} name (optional)
|
424
|
+
* @returns {*}
|
425
|
+
*/
|
426
|
+
context(name) {
|
427
|
+
if (this.root !== this) {
|
428
|
+
throw new Error('ReactWrapper::context() can only be called on the root');
|
429
|
+
}
|
430
|
+
const _context = this.single(() => this.instance().context);
|
431
|
+
if (name !== undefined) {
|
432
|
+
return _context[name];
|
433
|
+
}
|
434
|
+
return _context;
|
435
|
+
}
|
436
|
+
|
437
|
+
/**
|
438
|
+
* Returns a new wrapper with all of the children of the current wrapper.
|
439
|
+
*
|
440
|
+
* @param {String|Function} [selector]
|
441
|
+
* @returns {ReactWrapper}
|
442
|
+
*/
|
443
|
+
children(selector) {
|
444
|
+
const allChildren = this.flatMap(n => childrenOfInst(n.node));
|
445
|
+
return selector ? allChildren.filter(selector) : allChildren;
|
446
|
+
}
|
447
|
+
|
448
|
+
/**
|
449
|
+
* Returns a new wrapper with a specific child
|
450
|
+
*
|
451
|
+
* @param {Number} [index]
|
452
|
+
* @returns {ReactWrapper}
|
453
|
+
*/
|
454
|
+
childAt(index) {
|
455
|
+
return this.single(() => this.children().at(index));
|
456
|
+
}
|
457
|
+
|
458
|
+
/**
|
459
|
+
* Returns a wrapper around all of the parents/ancestors of the wrapper. Does not include the node
|
460
|
+
* in the current wrapper.
|
461
|
+
*
|
462
|
+
* NOTE: can only be called on a wrapper of a single node.
|
463
|
+
*
|
464
|
+
* @param {String|Function} [selector]
|
465
|
+
* @returns {ReactWrapper}
|
466
|
+
*/
|
467
|
+
parents(selector) {
|
468
|
+
const allParents = this.wrap(this.single(n => parentsOfInst(n, this.root.node)));
|
469
|
+
return selector ? allParents.filter(selector) : allParents;
|
470
|
+
}
|
471
|
+
|
472
|
+
/**
|
473
|
+
* Returns a wrapper around the immediate parent of the current node.
|
474
|
+
*
|
475
|
+
* @returns {ReactWrapper}
|
476
|
+
*/
|
477
|
+
parent() {
|
478
|
+
return this.flatMap(n => [n.parents().get(0)]);
|
479
|
+
}
|
480
|
+
|
481
|
+
/**
|
482
|
+
*
|
483
|
+
* @param {String|Function} selector
|
484
|
+
* @returns {ReactWrapper}
|
485
|
+
*/
|
486
|
+
closest(selector) {
|
487
|
+
return this.is(selector) ? this : this.parents().filter(selector).first();
|
488
|
+
}
|
489
|
+
|
490
|
+
/**
|
491
|
+
* Returns the value of prop with the given name of the root node.
|
492
|
+
*
|
493
|
+
* @param {String} propName
|
494
|
+
* @returns {*}
|
495
|
+
*/
|
496
|
+
prop(propName) {
|
497
|
+
return this.props()[propName];
|
498
|
+
}
|
499
|
+
|
500
|
+
/**
|
501
|
+
* Returns the key assigned to the current node.
|
502
|
+
*
|
503
|
+
* @returns {String}
|
504
|
+
*/
|
505
|
+
key() {
|
506
|
+
return this.single((n) => getNode(n).key);
|
507
|
+
}
|
508
|
+
|
509
|
+
/**
|
510
|
+
* Returns the type of the root node of this wrapper. If it's a composite component, this will be
|
511
|
+
* the component constructor. If it's native DOM node, it will be a string.
|
512
|
+
*
|
513
|
+
* @returns {String|Function}
|
514
|
+
*/
|
515
|
+
type() {
|
516
|
+
return this.single(n => typeOfNode(getNode(n)));
|
517
|
+
}
|
518
|
+
|
519
|
+
/**
|
520
|
+
* Returns whether or not the current root node has the given class name or not.
|
521
|
+
*
|
522
|
+
* NOTE: can only be called on a wrapper of a single node.
|
523
|
+
*
|
524
|
+
* @param {String} className
|
525
|
+
* @returns {Boolean}
|
526
|
+
*/
|
527
|
+
hasClass(className) {
|
528
|
+
if (className && className.indexOf('.') !== -1) {
|
529
|
+
console.log(
|
530
|
+
'It looks like you\'re calling `ReactWrapper::hasClass()` with a CSS selector. ' +
|
531
|
+
'hasClass() expects a class name, not a CSS selector.'
|
532
|
+
);
|
533
|
+
}
|
534
|
+
return this.single(n => instHasClassName(n, className));
|
535
|
+
}
|
536
|
+
|
537
|
+
/**
|
538
|
+
* Iterates through each node of the current wrapper and executes the provided function with a
|
539
|
+
* wrapper around the corresponding node passed in as the first argument.
|
540
|
+
*
|
541
|
+
* @param {Function} fn
|
542
|
+
* @returns {ReactWrapper}
|
543
|
+
*/
|
544
|
+
forEach(fn) {
|
545
|
+
this.nodes.forEach((n, i) => fn.call(this, this.wrap(n), i));
|
546
|
+
return this;
|
547
|
+
}
|
548
|
+
|
549
|
+
/**
|
550
|
+
* Maps the current array of nodes to another array. Each node is passed in as a `ReactWrapper`
|
551
|
+
* to the map function.
|
552
|
+
*
|
553
|
+
* @param {Function} fn
|
554
|
+
* @returns {Array}
|
555
|
+
*/
|
556
|
+
map(fn) {
|
557
|
+
return this.nodes.map((n, i) => fn.call(this, this.wrap(n), i));
|
558
|
+
}
|
559
|
+
|
560
|
+
/**
|
561
|
+
* Reduces the current array of nodes to another array.
|
562
|
+
* Each node is passed in as a `ShallowWrapper` to the reducer function.
|
563
|
+
*
|
564
|
+
* @param {Function} fn - the reducer function
|
565
|
+
* @param {*} initialValue - the initial value
|
566
|
+
* @returns {*}
|
567
|
+
*/
|
568
|
+
reduce(fn, initialValue) {
|
569
|
+
return this.nodes.reduce(
|
570
|
+
(accum, n, i) => fn.call(this, accum, this.wrap(n), i),
|
571
|
+
initialValue
|
572
|
+
);
|
573
|
+
}
|
574
|
+
|
575
|
+
/**
|
576
|
+
* Reduces the current array of nodes to another array, from right to left. Each node is passed
|
577
|
+
* in as a `ShallowWrapper` to the reducer function.
|
578
|
+
*
|
579
|
+
* @param {Function} fn - the reducer function
|
580
|
+
* @param {*} initialValue - the initial value
|
581
|
+
* @returns {*}
|
582
|
+
*/
|
583
|
+
reduceRight(fn, initialValue) {
|
584
|
+
return this.nodes.reduceRight(
|
585
|
+
(accum, n, i) => fn.call(this, accum, this.wrap(n), i),
|
586
|
+
initialValue
|
587
|
+
);
|
588
|
+
}
|
589
|
+
|
590
|
+
/**
|
591
|
+
* Returns whether or not any of the nodes in the wrapper match the provided selector.
|
592
|
+
*
|
593
|
+
* @param {Function|String} selector
|
594
|
+
* @returns {Boolean}
|
595
|
+
*/
|
596
|
+
some(selector) {
|
597
|
+
const predicate = buildInstPredicate(selector);
|
598
|
+
return this.nodes.some(predicate);
|
599
|
+
}
|
600
|
+
|
601
|
+
/**
|
602
|
+
* Returns whether or not any of the nodes in the wrapper pass the provided predicate function.
|
603
|
+
*
|
604
|
+
* @param {Function} predicate
|
605
|
+
* @returns {Boolean}
|
606
|
+
*/
|
607
|
+
someWhere(predicate) {
|
608
|
+
return this.nodes.some((n, i) => predicate.call(this, this.wrap(n), i));
|
609
|
+
}
|
610
|
+
|
611
|
+
/**
|
612
|
+
* Returns whether or not all of the nodes in the wrapper match the provided selector.
|
613
|
+
*
|
614
|
+
* @param {Function|String} selector
|
615
|
+
* @returns {Boolean}
|
616
|
+
*/
|
617
|
+
every(selector) {
|
618
|
+
const predicate = buildInstPredicate(selector);
|
619
|
+
return this.nodes.every(predicate);
|
620
|
+
}
|
621
|
+
|
622
|
+
/**
|
623
|
+
* Returns whether or not any of the nodes in the wrapper pass the provided predicate function.
|
624
|
+
*
|
625
|
+
* @param {Function} predicate
|
626
|
+
* @returns {Boolean}
|
627
|
+
*/
|
628
|
+
everyWhere(predicate) {
|
629
|
+
return this.nodes.every((n, i) => predicate.call(this, this.wrap(n), i));
|
630
|
+
}
|
631
|
+
|
632
|
+
/**
|
633
|
+
* Utility method used to create new wrappers with a mapping function that returns an array of
|
634
|
+
* nodes in response to a single node wrapper. The returned wrapper is a single wrapper around
|
635
|
+
* all of the mapped nodes flattened (and de-duplicated).
|
636
|
+
*
|
637
|
+
* @param {Function} fn
|
638
|
+
* @returns {ReactWrapper}
|
639
|
+
*/
|
640
|
+
flatMap(fn) {
|
641
|
+
const nodes = this.nodes.map((n, i) => fn.call(this, this.wrap(n), i));
|
642
|
+
const flattened = flatten(nodes, true);
|
643
|
+
const uniques = unique(flattened);
|
644
|
+
return this.wrap(uniques);
|
645
|
+
}
|
646
|
+
|
647
|
+
/**
|
648
|
+
* Finds all nodes in the current wrapper nodes' render trees that match the provided predicate
|
649
|
+
* function.
|
650
|
+
*
|
651
|
+
* @param {Function} predicate
|
652
|
+
* @returns {ReactWrapper}
|
653
|
+
*/
|
654
|
+
findWhere(predicate) {
|
655
|
+
return findWhereUnwrapped(this, n => predicate(this.wrap(n)));
|
656
|
+
}
|
657
|
+
|
658
|
+
/**
|
659
|
+
* Returns the node at a given index of the current wrapper.
|
660
|
+
*
|
661
|
+
* @param {Number} index
|
662
|
+
* @returns {ReactElement}
|
663
|
+
*/
|
664
|
+
get(index) {
|
665
|
+
return this.nodes[index];
|
666
|
+
}
|
667
|
+
|
668
|
+
/**
|
669
|
+
* Returns a wrapper around the node at a given index of the current wrapper.
|
670
|
+
*
|
671
|
+
* @param {Number} index
|
672
|
+
* @returns {ReactWrapper}
|
673
|
+
*/
|
674
|
+
at(index) {
|
675
|
+
return this.wrap(this.nodes[index]);
|
676
|
+
}
|
677
|
+
|
678
|
+
/**
|
679
|
+
* Returns a wrapper around the first node of the current wrapper.
|
680
|
+
*
|
681
|
+
* @returns {ReactWrapper}
|
682
|
+
*/
|
683
|
+
first() {
|
684
|
+
return this.at(0);
|
685
|
+
}
|
686
|
+
|
687
|
+
/**
|
688
|
+
* Returns a wrapper around the last node of the current wrapper.
|
689
|
+
*
|
690
|
+
* @returns {ReactWrapper}
|
691
|
+
*/
|
692
|
+
last() {
|
693
|
+
return this.at(this.length - 1);
|
694
|
+
}
|
695
|
+
|
696
|
+
/**
|
697
|
+
* Returns true if the current wrapper has no nodes. False otherwise.
|
698
|
+
*
|
699
|
+
* @returns {boolean}
|
700
|
+
*/
|
701
|
+
isEmpty() {
|
702
|
+
return this.length === 0;
|
703
|
+
}
|
704
|
+
|
705
|
+
/**
|
706
|
+
* Utility method that throws an error if the current instance has a length other than one.
|
707
|
+
* This is primarily used to enforce that certain methods are only run on a wrapper when it is
|
708
|
+
* wrapping a single node.
|
709
|
+
*
|
710
|
+
* @param {Function} fn
|
711
|
+
* @returns {*}
|
712
|
+
*/
|
713
|
+
single(fn) {
|
714
|
+
if (this.length !== 1) {
|
715
|
+
throw new Error(
|
716
|
+
`This method is only meant to be run on single node. ${this.length} found instead.`
|
717
|
+
);
|
718
|
+
}
|
719
|
+
return fn.call(this, this.node);
|
720
|
+
}
|
721
|
+
|
722
|
+
/**
|
723
|
+
* Helpful utility method to create a new wrapper with the same root as the current wrapper, with
|
724
|
+
* any nodes passed in as the first parameter automatically wrapped.
|
725
|
+
*
|
726
|
+
* @param {ReactWrapper|ReactElement|Array<ReactElement>} node
|
727
|
+
* @returns {ReactWrapper}
|
728
|
+
*/
|
729
|
+
wrap(node) {
|
730
|
+
if (node instanceof ReactWrapper) {
|
731
|
+
return node;
|
732
|
+
}
|
733
|
+
return new ReactWrapper(node, this.root);
|
734
|
+
}
|
735
|
+
|
736
|
+
/**
|
737
|
+
* Returns an HTML-like string of the shallow render for debugging purposes.
|
738
|
+
*
|
739
|
+
* @returns {String}
|
740
|
+
*/
|
741
|
+
debug() {
|
742
|
+
return debugInsts(this.nodes);
|
743
|
+
}
|
744
|
+
|
745
|
+
/**
|
746
|
+
* Invokes intercepter and returns itself. intercepter is called with itself.
|
747
|
+
* This is helpful when debugging nodes in method chains.
|
748
|
+
* @param fn
|
749
|
+
* @returns {ReactWrapper}
|
750
|
+
*/
|
751
|
+
tap(intercepter) {
|
752
|
+
intercepter(this);
|
753
|
+
return this;
|
754
|
+
}
|
755
|
+
|
756
|
+
/**
|
757
|
+
* Detaches the react tree from the DOM. Runs `ReactDOM.unmountComponentAtNode()` under the hood.
|
758
|
+
*
|
759
|
+
* This method will most commonly be used as a "cleanup" method if you decide to use the
|
760
|
+
* `attachTo` option in `mount(node, options)`.
|
761
|
+
*
|
762
|
+
* The method is intentionally not "fluent" (in that it doesn't return `this`) because you should
|
763
|
+
* not be doing anything with this wrapper after this method is called.
|
764
|
+
*/
|
765
|
+
detach() {
|
766
|
+
if (this.root !== this) {
|
767
|
+
throw new Error('ReactWrapper::detach() can only be called on the root');
|
768
|
+
}
|
769
|
+
if (!this.options.attachTo) {
|
770
|
+
throw new Error(
|
771
|
+
'ReactWrapper::detach() can only be called on when the `attachTo` option was passed into ' +
|
772
|
+
'`mount()`.'
|
773
|
+
);
|
774
|
+
}
|
775
|
+
unmountComponentAtNode(this.options.attachTo);
|
776
|
+
}
|
777
|
+
}
|