UNPKG

12.5 kBJavaScriptView Raw
1import React from 'react';
2import {shallow, mount} from 'enzyme';
3import VirtualizedList from 'react-virtualized/dist/commonjs/List';
4
5import getUID from '../global/get-uid';
6import Icon, {CheckmarkIcon} from '../icon';
7
8import List from './list';
9import ListItem from './list__item';
10import ListCustom from './list__custom';
11import ListLink from './list__link';
12import ListTitle from './list__title';
13import ListSeparator from './list__separator';
14import styles from './list.css';
15
16describe('List', () => {
17 const Type = List.ListProps.Type;
18
19
20 const shallowList = props => shallow(<List {...props}/>);
21 const mountList = props => mount(<List {...props}/>);
22
23 describe('virtualized', () => {
24 function createItemMock(itemType) {
25 return {
26 rgItemType: itemType,
27 label: getUID('list-test-')
28 };
29 }
30
31 it('should pad the list with top/bottom margins', () => {
32 const data = [
33 createItemMock(List.ListProps.Type.ITEM),
34 createItemMock(List.ListProps.Type.ITEM)
35 ];
36
37 const instance = shallowList({data}).instance();
38
39 shallow(
40 instance.renderItem({index: 0}),
41 {disableLifecycleMethods: true}
42 ).should.have.tagName('div');
43 shallow(
44 instance.renderItem({index: 3}),
45 {disableLifecycleMethods: true}
46 ).should.have.tagName('div');
47 });
48
49 it('should apply styles from virtualized', () => {
50 const data = [
51 createItemMock(List.ListProps.Type.ITEM),
52 createItemMock(List.ListProps.Type.ITEM)
53 ];
54
55 const instance = shallowList({data}).instance();
56 const style = {
57 top: -1000
58 };
59 const parent = {};
60
61 shallow(
62 instance.renderItem({index: 0, style, parent}),
63 {disableLifecycleMethods: true}
64 ).should.have.style('top', '-1000px');
65 shallow(
66 instance.renderItem({index: 1, style, parent}),
67 {disableLifecycleMethods: true}
68 ).should.have.style('top', '-1000px');
69 shallow(
70 instance.renderItem({index: 2, style, parent}),
71 {disableLifecycleMethods: true}
72 ).should.have.style('top', '-1000px');
73 shallow(
74 instance.renderItem({index: 3, style, parent}),
75 {disableLifecycleMethods: true}
76 ).should.have.style('top', '-1000px');
77 });
78
79 it('should scroll to the active item', () => {
80 const data = [
81 createItemMock(List.ListProps.Type.ITEM),
82 createItemMock(List.ListProps.Type.ITEM),
83 createItemMock(List.ListProps.Type.ITEM),
84 createItemMock(List.ListProps.Type.ITEM),
85 createItemMock(List.ListProps.Type.ITEM),
86 createItemMock(List.ListProps.Type.ITEM)
87 ];
88
89 const activeIndex = 1;
90
91 const wrapper = mountList({data});
92 wrapper.setState({
93 activeIndex,
94 needScrollToActive: true
95 });
96
97 wrapper.find(VirtualizedList).should.have.prop('scrollToIndex', 2);
98 });
99
100 it('should\'n scroll to the active item when needScrollToActive is false', () => {
101 const data = [
102 createItemMock(List.ListProps.Type.ITEM),
103 createItemMock(List.ListProps.Type.ITEM),
104 createItemMock(List.ListProps.Type.ITEM),
105 createItemMock(List.ListProps.Type.ITEM),
106 createItemMock(List.ListProps.Type.ITEM),
107 createItemMock(List.ListProps.Type.ITEM)
108 ];
109
110 const activeIndex = 1;
111
112 const wrapper = mountList({data});
113 wrapper.setState({
114 activeIndex,
115 needScrollToActive: false
116 });
117
118 wrapper.find(VirtualizedList).should.not.have.prop('scrollToIndex', 2);
119 });
120 });
121
122 it('should check type of item', () => {
123 const itemMock = {
124 rgItemType: Type.SEPARATOR
125 };
126
127 List.isItemType(Type.SEPARATOR, itemMock).should.been.equal(true);
128 });
129
130 it('by default item has type equal ITEM', () => {
131 const itemMock = {};
132
133 List.isItemType(Type.ITEM, itemMock).should.been.equal(true);
134 List.isItemType(Type.SEPARATOR, itemMock).should.been.equal(false);
135 });
136
137 it('should deselect item', () => {
138 const instance = shallowList({
139 data: [
140 {}
141 ],
142 activeIndex: 0
143 }).instance();
144
145 instance.clearSelected();
146
147 should.not.exist(instance.getSelected());
148 });
149
150 describe('should track activeIndex', () => {
151 let wrapper;
152 let instance;
153 beforeEach(() => {
154 sandbox.stub(window, 'requestAnimationFrame').callsFake(cb => cb());
155 wrapper = mountList({
156 data: [{key: 0}, {key: 1}, {key: 2}],
157 activeIndex: 0,
158 restoreActiveIndex: true
159 });
160 instance = wrapper.instance();
161 });
162
163 it('should set activeIndex from props', () => {
164 wrapper.should.have.state('activeIndex', 0);
165 wrapper.state('activeItem').key.should.equal(0);
166 });
167
168 it('should activate item', () => {
169 instance.hoverHandler(1)();
170 wrapper.should.have.state('activeIndex', 1);
171 wrapper.state('activeItem').key.should.equal(1);
172 });
173
174 it('should reset activeIndex when it\'s changed in props', () => {
175 instance.hoverHandler(1)();
176 const activeIndex = 2;
177 wrapper.setProps({
178 activeIndex
179 });
180 wrapper.should.have.state('activeIndex', activeIndex);
181 wrapper.state('activeItem').key.should.equal(activeIndex);
182 });
183
184 it('shouldn\'t reset activeIndex when it isn\'t changed in props', () => {
185 instance.hoverHandler(1)();
186 wrapper.setProps({
187 activeIndex: 0
188 });
189 wrapper.should.have.state('activeIndex', 1);
190 wrapper.state('activeItem').key.should.equal(1);
191 });
192 });
193
194 describe('should render items', () => {
195 const mountFirstItem = instance =>
196 mount(instance.renderItem({index: 1}));
197
198 it('should render for empty element', () => {
199 const instance = shallowList({
200 data: [
201 {}
202 ]
203 }).instance();
204 const firstItemWrapper = mountFirstItem(instance).find(ListItem);
205 firstItemWrapper.should.have.className(styles.action);
206 firstItemWrapper.should.have.text('');
207 });
208
209 it('should render instance item if type is not defined', () => {
210 const instance = shallowList({
211 data: [
212 {label: 'Hello!'}
213 ]
214 }).instance();
215
216 mount(instance.renderItem({index: 1})).
217 should.have.descendants('[data-test~="ring-list-item"]');
218 });
219
220 it('should render a if href defined', () => {
221 const instance = shallowList({
222 data: [
223 {label: 'Hello!', href: 'http://www.jetbrains.com'}
224 ]
225 }).instance();
226
227 const firstItemWrapper = mountFirstItem(instance).find(ListLink);
228 firstItemWrapper.should.exist;
229 firstItemWrapper.should.have.data('test', 'ring-link ring-list-link ring-list-item');
230 firstItemWrapper.should.have.text('Hello!');
231 firstItemWrapper.should.have.tagName('a');
232 firstItemWrapper.should.have.attr('href', 'http://www.jetbrains.com');
233 });
234
235 it('should render a if url defined', () => {
236 const instance = shallowList({
237 data: [
238 {label: 'Hello!', url: 'http://www.jetbrains.com'}
239 ]
240 }).instance();
241
242 const firstItemWrapper = mountFirstItem(instance).find(ListLink);
243 firstItemWrapper.should.exist;
244 firstItemWrapper.should.have.data('test', 'ring-link ring-list-link ring-list-item');
245 firstItemWrapper.should.have.text('Hello!');
246 firstItemWrapper.should.have.tagName('a');
247 firstItemWrapper.should.have.attr('href', 'http://www.jetbrains.com');
248 });
249
250 it('should render separator', () => {
251 const instance = shallowList({
252 data: [
253 {rgItemType: List.ListProps.Type.SEPARATOR}
254 ]
255 }).instance();
256
257 const firstItemWrapper = mountFirstItem(instance).find(ListSeparator);
258 firstItemWrapper.should.exist;
259 firstItemWrapper.should.have.className(styles.separator);
260 });
261
262 it('should render title', () => {
263 const instance = shallowList({
264 data: [
265 {rgItemType: List.ListProps.Type.TITLE, label: 'Foo', description: 'Bar'}
266 ]
267 }).instance();
268
269 const firstItemWrapper = mountFirstItem(instance).find(ListTitle);
270 firstItemWrapper.should.exist;
271 firstItemWrapper.should.have.text('FooBar');
272 });
273
274 it('should render pseudo link if link without href', () => {
275 const instance = shallowList({
276 data: [
277 {label: 'Hello!', rgItemType: List.ListProps.Type.LINK}
278 ]
279 }).instance();
280
281 const firstItemWrapper = mountFirstItem(instance).find(ListLink);
282 firstItemWrapper.should.exist;
283 firstItemWrapper.should.have.data('test', 'ring-link ring-list-link ring-list-item');
284 firstItemWrapper.should.have.text('Hello!');
285 firstItemWrapper.should.have.tagName('button');
286 });
287
288 it('should not render icon if not provided', () => {
289 const instance = shallowList({
290 data: [
291 {label: 'Hello!', type: List.ListProps.Type.ITEM}
292 ]
293 }).instance();
294
295 const firstItemWrapper = mountFirstItem(instance).find(ListItem);
296 firstItemWrapper.should.not.have.descendants(`.${styles.icon}`);
297 });
298
299 it('should render icon if provided', () => {
300 const instance = shallowList({
301 data: [
302 {label: 'Hello!', icon: 'http://some.url/', type: List.ListProps.Type.ITEM}
303 ]
304 }).instance();
305
306 const icon = mountFirstItem(instance).find(`.${styles.icon}`);
307 icon.prop('style').backgroundImage.should.contain('http://some.url');
308 });
309
310 it('should not render glyph if not provided', () => {
311 const instance = shallowList({
312 data: [
313 {label: 'Hello!', type: List.ListProps.Type.ITEM}
314 ]
315 }).instance();
316
317 mountFirstItem(instance).find('use').should.be.empty;
318 });
319
320 it('should render glyph if provided', () => {
321 const instance = shallowList({
322 data: [
323 {label: 'Hello!', glyph: CheckmarkIcon, type: List.ListProps.Type.ITEM}
324 ]
325 }).instance();
326
327 mountFirstItem(instance).find(Icon).should.have.prop('glyph', CheckmarkIcon);
328 });
329
330 it('should throw error on unknown type', () => {
331 (() => {
332 const instance = shallowList({
333 data: [
334 {label: 'Hello!', rgItemType: 'none'}
335 ]
336 }).instance();
337
338 mountFirstItem(instance);
339 }).should.throw(Error, 'Unknown menu element type: none');
340 });
341
342 it('should handle click', () => {
343 const clicked = sandbox.stub();
344
345 const instance = mountList({
346 data: [
347 {label: 'Hello!', onClick: clicked}
348 ]
349 }).instance();
350
351 const firstItemWrapper = mountFirstItem(instance).find(ListItem);
352 firstItemWrapper.simulate('click');
353 clicked.should.have.been.called;
354 });
355
356 it('should handle select', () => {
357 const onSelect = sandbox.stub();
358
359 const instance = mountList({
360 onSelect,
361 data: [{label: 'Hello!'}]
362 }).instance();
363
364 const firstItemWrapper = mountFirstItem(instance).find(ListItem);
365 firstItemWrapper.simulate('click');
366 onSelect.should.have.been.called;
367 });
368
369 it('Should support custom elements', () => {
370 const instance = shallowList({
371 data: [
372 {
373 template: React.createElement('span', {}, 'custom item'),
374 rgItemType: List.ListProps.Type.CUSTOM
375 }
376 ]
377 }).instance();
378
379 const firstItemWrapper = mountFirstItem(instance).find(ListCustom);
380 firstItemWrapper.should.have.text('custom item');
381 });
382
383 it('Should support click on custom elements', () => {
384 const onClick = sandbox.stub();
385 const instance = mountList({
386 data: [
387 {
388 template: React.createElement('span', {}, 'custom item'),
389 rgItemType: List.ListProps.Type.CUSTOM,
390 onClick
391 }
392 ]
393 }).instance();
394
395 const firstItemWrapper = mountFirstItem(instance).find(ListCustom);
396 firstItemWrapper.simulate('click');
397 onClick.should.have.been.called;
398 });
399
400 it('Should support disable property for custom elements', () => {
401 const instance = shallowList({
402 data: [
403 {
404 template: React.createElement('span', {}, 'custom item'),
405 rgItemType: List.ListProps.Type.CUSTOM,
406 disabled: true
407 }
408 ]
409 }).instance();
410
411 const firstItemWrapper = mountFirstItem(instance).find(ListCustom);
412 firstItemWrapper.should.not.have.className(styles.action);
413 });
414 });
415});