1 |
|
2 |
|
3 |
|
4 | import angular from 'angular';
|
5 | import 'angular-mocks';
|
6 |
|
7 | import Select from '../select/select';
|
8 | import styles from '../select/select.css';
|
9 |
|
10 | import SelectNg from './select-ng';
|
11 |
|
12 | describe('Select Ng', () => {
|
13 | let scope;
|
14 | let element;
|
15 | let ctrl;
|
16 | let $compile;
|
17 |
|
18 | const fakeItems = [
|
19 | {id: 1, name: '11'},
|
20 | {id: 2, name: '22'},
|
21 | {id: 3, name: '33'}
|
22 | ];
|
23 |
|
24 | beforeEach(window.module(SelectNg));
|
25 |
|
26 | function compileTemplate(template) {
|
27 | element = $compile(template)(scope);
|
28 | ctrl = element.controller('rgSelect');
|
29 | scope.$digest();
|
30 | }
|
31 |
|
32 | beforeEach(inject(($rootScope, _$compile_) => {
|
33 | scope = $rootScope.$new();
|
34 | $compile = _$compile_;
|
35 |
|
36 | scope.items = angular.copy(fakeItems);
|
37 | scope.selectedItem = scope.items[2];
|
38 | scope.selectedItems = scope.items.slice(1);
|
39 |
|
40 | compileTemplate('<rg-select options="item.name for item in items track by item.id" ng-model="selectedItem"></rg-select>');
|
41 | }));
|
42 |
|
43 | describe('DOM', () => {
|
44 | it('Should place container for select inside directive', () => {
|
45 | element[0].should.contain('span');
|
46 | });
|
47 |
|
48 | it('Should render select inside container', () => {
|
49 | element[0].should.contain('[data-test=ring-select]');
|
50 | });
|
51 |
|
52 | it('Should not render select if type=dropdown', () => {
|
53 | compileTemplate('<rg-select options="item.name for item in items track by item.id" ng-model="selectedItem" type="dropdown"></rg-select>');
|
54 |
|
55 | element[0].should.not.contain('[data-test=ring-select]');
|
56 | });
|
57 | });
|
58 |
|
59 | describe('Interface', () => {
|
60 | function selected(_ctrl) {
|
61 | return _ctrl.selectInstance.props.selected;
|
62 | }
|
63 |
|
64 | it('Should unmount react component on destroy', () => {
|
65 | initializeReactSelect(element[0]);
|
66 | ctrl.$onDestroy();
|
67 | should.not.exist(ctrl.selectInstance.node);
|
68 | });
|
69 |
|
70 | it('Should receive ngModel controller', () => {
|
71 | ctrl.ngModelCtrl.should.exist;
|
72 | });
|
73 |
|
74 | it('Should extend passed config', () => {
|
75 | scope.config = {someField: 'test'};
|
76 | compileTemplate('<rg-select options="item.name for item in items track by item.id" ng-model="selectedItem" config="config"></rg-select>');
|
77 |
|
78 | ctrl.config.someField.should.equal('test');
|
79 | });
|
80 |
|
81 | it('Should work without ng-model', () => {
|
82 | function initDirective() {
|
83 | compileTemplate('<rg-select options="item.name for item in items track by item.id"></rg-select>');
|
84 | }
|
85 |
|
86 | initDirective.should.not.throw;
|
87 | });
|
88 |
|
89 | it('Should update selected item on ngModel updates', () => {
|
90 | const newLabel = 'Some new label';
|
91 | scope.selectedItem.name = newLabel;
|
92 | scope.$digest();
|
93 | selected(ctrl).label.should.equal(newLabel);
|
94 | });
|
95 |
|
96 | it('Should clear selected item on ngModel clearing', () => {
|
97 | scope.selectedItem = null;
|
98 | scope.$digest();
|
99 | should.not.exist(selected(ctrl));
|
100 | });
|
101 |
|
102 | it('Should not get options on on initialization', () => {
|
103 | ctrl.selectInstance.props.data.length.should.equal(0);
|
104 | });
|
105 |
|
106 | it('Should get options on open', () => {
|
107 | ctrl.config.onBeforeOpen();
|
108 | scope.$digest();
|
109 | ctrl.selectInstance.props.data.length.should.equal(fakeItems.length);
|
110 | });
|
111 |
|
112 | it('Should convert ngModel to select supported object', () => {
|
113 | selected(ctrl).key.should.equal(scope.selectedItem.id);
|
114 | selected(ctrl).label.should.equal(scope.selectedItem.name);
|
115 | });
|
116 |
|
117 | it('Should convert options to select supported objects', () => {
|
118 | ctrl.loadOptionsToSelect();
|
119 | scope.$digest();
|
120 | ctrl.selectInstance.props.data[0].key.should.equal(fakeItems[0].id);
|
121 | ctrl.selectInstance.props.data[0].label.should.equal(fakeItems[0].name);
|
122 | });
|
123 |
|
124 | it('Should reject promise on loading error', inject($q => {
|
125 | const onError = sandbox.spy();
|
126 | sandbox.stub(ctrl, 'getOptions').returns($q.reject());
|
127 | ctrl.loadOptionsToSelect().catch(onError);
|
128 | scope.$digest();
|
129 | onError.should.be.called;
|
130 | }));
|
131 |
|
132 | it('Should use default type "Button" if type is not passed', () => {
|
133 | compileTemplate('<rg-select options="item.name for item in items track by item.id" ng-model="selectedItem"></rg-select>');
|
134 | ctrl.selectInstance.props.type.should.equal(Select.Type.MATERIAL);
|
135 | });
|
136 |
|
137 | it('Should support type "input"', () => {
|
138 | compileTemplate('<rg-select options="item.name for item in items track by item.id" ng-model="selectedItem" type="input"></rg-select>');
|
139 | ctrl.selectInstance.props.type.should.equal(Select.Type.INPUT);
|
140 | });
|
141 |
|
142 | it('Should support type "dropdown', () => {
|
143 | compileTemplate('<rg-select options="item.name for item in items track by item.id" ng-model="selectedItem" type="dropdown"></rg-select>');
|
144 | ctrl.selectInstance.props.type.should.equal(Select.Type.CUSTOM);
|
145 | });
|
146 |
|
147 | it('Should support selectedLabelField customization', () => {
|
148 | scope.selectedItem.testField = 'test';
|
149 | compileTemplate('<rg-select options="item.name select as item.testField for item in items track by item.id" ng-model="selectedItem"></rg-select>');
|
150 | selected(ctrl).selectedLabel.should.equal('test');
|
151 | });
|
152 |
|
153 | it('Should support selected formatter function', () => {
|
154 | scope.formatter = sandbox.stub().returns('Formatted label');
|
155 |
|
156 | compileTemplate('<rg-select options="item.name select as formatter(item) for item in items track by item.id" external-filter="true" ng-model="selectedItem"></rg-select>');
|
157 |
|
158 | selected(ctrl).selectedLabel.should.equal('Formatted label');
|
159 | });
|
160 |
|
161 | it('Should support description customization', () => {
|
162 | scope.selectedItem.testField = 'test';
|
163 | compileTemplate('<rg-select options="item.name describe as item.testField for item in items track by item.id" ng-model="selectedItem"></rg-select>');
|
164 |
|
165 | selected(ctrl).description.should.equal('test');
|
166 | });
|
167 |
|
168 | it('Should support description and selected label customization together', () => {
|
169 | scope.selectedItem.selectText = 'test';
|
170 | scope.selectedItem.descriptionText = 'description';
|
171 | compileTemplate('<rg-select options="item.name select as item.selectText describe as item.descriptionText for item in items track by item.id" ng-model="selectedItem"></rg-select>');
|
172 |
|
173 | selected(ctrl).selectedLabel.should.equal(scope.selectedItem.selectText);
|
174 | selected(ctrl).description.should.equal(scope.selectedItem.descriptionText);
|
175 | });
|
176 |
|
177 | it('Should not call get option by value for description customization', () => {
|
178 | scope.selectedItem.descriptionText = 'description';
|
179 |
|
180 | element = $compile('<rg-select options="item.name describe as item.descriptionText for item in items track by item.id" ng-model="selectedItem"></rg-select>')(scope);
|
181 | ctrl = element.controller('rgSelect');
|
182 | sandbox.spy(ctrl.optionsParser, 'getOptions');
|
183 | scope.$digest();
|
184 |
|
185 | ctrl.optionsParser.getOptions.should.not.called;
|
186 | });
|
187 |
|
188 | it('Should not call get option by value for select label customization', () => {
|
189 | scope.selectedItem.selectText = 'Test';
|
190 |
|
191 | element = $compile('<rg-select options="item.name select as item.descriptionText for item in items track by item.id" ng-model="selectedItem"></rg-select>')(scope);
|
192 | ctrl = element.controller('rgSelect');
|
193 | sandbox.spy(ctrl.optionsParser, 'getOptions');
|
194 | scope.$digest();
|
195 |
|
196 | ctrl.optionsParser.getOptions.should.not.called;
|
197 | });
|
198 |
|
199 | it('Should not call get option by value for description and selected label customization together', () => {
|
200 | scope.selectedItem.selectText = 'test';
|
201 | scope.selectedItem.descriptionText = 'description';
|
202 |
|
203 | element = $compile('<rg-select options="item.name select as item.selectText describe as item.descriptionText for item in items track by item.id" ng-model="selectedItem"></rg-select>')(scope);
|
204 | ctrl = element.controller('rgSelect');
|
205 | sandbox.spy(ctrl.optionsParser, 'getOptions');
|
206 | scope.$digest();
|
207 |
|
208 | ctrl.optionsParser.getOptions.should.not.called;
|
209 | });
|
210 |
|
211 | it('Should save original model in select items', () => {
|
212 | ctrl.loadOptionsToSelect();
|
213 | scope.$digest();
|
214 | ctrl.selectInstance.props.data[0].originalModel.should.deep.equal(fakeItems[0]);
|
215 | });
|
216 |
|
217 | it('Should update ng-model on selecting', () => {
|
218 | ctrl.config.onChange({originalModel: fakeItems[0]});
|
219 | scope.$digest();
|
220 | scope.selectedItem.should.equal(fakeItems[0]);
|
221 | });
|
222 |
|
223 | it('Should clear ng-model on clearing select', () => {
|
224 | ctrl.config.onChange(null);
|
225 | scope.$digest();
|
226 | should.not.exist(scope.selectedItem);
|
227 | });
|
228 |
|
229 | it('Should call datasource on opening', () => {
|
230 | scope.dataSource = sandbox.stub().returns(fakeItems);
|
231 |
|
232 | compileTemplate('<rg-select options="item.name for item in dataSource(query) track by item.id" external-filter="true" ng-model="selectedItem"></rg-select>');
|
233 |
|
234 | ctrl.config.onBeforeOpen();
|
235 | scope.$digest();
|
236 | scope.dataSource.should.have.been.called;
|
237 | });
|
238 |
|
239 | it('Should call datasource on filtering if external filter enabled', () => {
|
240 | scope.dataSource = sandbox.stub().returns(fakeItems);
|
241 |
|
242 | compileTemplate('<rg-select options="item.name for item in dataSource(query) track by item.id" external-filter="true" ng-model="selectedItem"></rg-select>');
|
243 |
|
244 | ctrl.config.onFilter('test');
|
245 | scope.$digest();
|
246 | scope.dataSource.should.have.been.calledWith('test');
|
247 | });
|
248 |
|
249 | it('Should reload options with a controller query', () => {
|
250 | const queryMock = 'query';
|
251 | ctrl.query = queryMock;
|
252 | sandbox.spy(ctrl, 'loadOptionsToSelect');
|
253 |
|
254 | ctrl.config.reloadOptions();
|
255 | scope.$digest();
|
256 |
|
257 | ctrl.loadOptionsToSelect.should.have.been.calledWith(queryMock);
|
258 | });
|
259 |
|
260 | it('Should reload options with a provided query parameter', () => {
|
261 | const queryMock = 'query';
|
262 | ctrl.query = 'ctrlQuery';
|
263 | sandbox.spy(ctrl, 'loadOptionsToSelect');
|
264 |
|
265 | ctrl.config.reloadOptions(queryMock);
|
266 | scope.$digest();
|
267 |
|
268 | ctrl.loadOptionsToSelect.should.have.been.calledWith(queryMock);
|
269 | });
|
270 |
|
271 | it('If externalFilter enabled should provide custom filter.fn which should always return true', () => {
|
272 | compileTemplate('<rg-select options="item.name for item in items track by item.id" external-filter="true" ng-model="selectedItem"></rg-select>');
|
273 |
|
274 | ctrl.filter.fn().should.be.true;
|
275 | });
|
276 |
|
277 | it('Should be disabled if disabled', () => {
|
278 | compileTemplate('<rg-select options="item.name for item in items track by item.id" ng-model="selectedItem" ng-disabled="true"></rg-select>');
|
279 |
|
280 | element[0].should.contain(`.${styles.disabled}`);
|
281 | });
|
282 |
|
283 | it('Should hide on route changes ($locationChangeSuccess)', () => {
|
284 | sandbox.stub(ctrl.selectInstance._popup, 'isVisible').returns(true);
|
285 | ctrl.selectInstance._hidePopup = sandbox.stub();
|
286 |
|
287 | scope.$broadcast('$locationChangeSuccess');
|
288 | ctrl.selectInstance._hidePopup.should.have.been.called;
|
289 | });
|
290 |
|
291 | it('Should not try to hide on route changes if not showed ($locationChangeSuccess)', () => {
|
292 | sandbox.stub(ctrl.selectInstance._popup, 'isVisible').returns(false);
|
293 | ctrl.selectInstance._hidePopup = sandbox.stub();
|
294 |
|
295 | scope.$broadcast('$locationChangeSuccess');
|
296 | ctrl.selectInstance._hidePopup.should.not.have.been.called;
|
297 | });
|
298 |
|
299 | it('Should extend select model with properties from ng model', () => {
|
300 | const selectModel = ctrl.convertNgModelToSelect({ext: 'test'});
|
301 | selectModel.ext.should.equal('test');
|
302 | });
|
303 |
|
304 | it('Should not try to extend select model with string', () => {
|
305 | sandbox.spy(angular, 'extend');
|
306 | const stringValue = 'str-value';
|
307 | ctrl.convertNgModelToSelect(stringValue);
|
308 | angular.extend.should.been.calledWith(sandbox.match({}), null);
|
309 | });
|
310 |
|
311 | it('Should use select-type if defined', () => {
|
312 | compileTemplate('<button rg-select="" options="itemvar in items track by itemvar.id" select-type="dropdown" type="submit"></button>');
|
313 |
|
314 | ctrl.selectInstance.props.type.should.equal(Select.Type.CUSTOM);
|
315 | });
|
316 |
|
317 | it('Should use "multiple" attribute and provide it to select', () => {
|
318 | compileTemplate('<rg-select options="item.name for item in items track by item.id" multiple="true" ng-model="selectedItems"></rg-select>');
|
319 |
|
320 | ctrl.selectInstance.props.multiple.should.be.true;
|
321 | });
|
322 |
|
323 | it('Should watch "multiple" and update select after change', () => {
|
324 | scope.selectMultiple = false;
|
325 | compileTemplate('<rg-select options="item.name for item in items track by item.id" multiple="selectMultiple" ng-model="selectedItems"></rg-select>');
|
326 |
|
327 | scope.selectMultiple = true;
|
328 | scope.$digest();
|
329 | ctrl.selectInstance.props.multiple.should.be.true;
|
330 | });
|
331 |
|
332 | it('Should return deselected item', () => {
|
333 | scope.selectedItem = scope.items[1];
|
334 | ctrl.config.onDeselect({originalModel: fakeItems[1]});
|
335 | scope.$digest();
|
336 |
|
337 | ctrl.selectInstance.props.selected.label.should.equal(fakeItems[1].name);
|
338 | });
|
339 |
|
340 | it('Should rerender with new config if config changed and autosync enabled', () => {
|
341 | scope.config = {};
|
342 | compileTemplate('<rg-select options="item.name for item in items track by item.id" ng-model="selectedItem" config="config" config-auto-update="true"></rg-select>');
|
343 |
|
344 | sandbox.spy(ctrl.selectInstance, 'rerender');
|
345 | scope.config.add = {label: 'fooo'};
|
346 | scope.$digest();
|
347 |
|
348 | ctrl.selectInstance.rerender.should.have.been.calledWith(sinon.match({add: {label: 'fooo'}}));
|
349 | });
|
350 |
|
351 |
|
352 | it('Should correctly reinitialize select with config', () => {
|
353 | const template = '<rg-select type="dropdown" options="item.name for item in items track by item.id" ng-model="selectedItem" config="config" config-auto-update="true"></rg-select>';
|
354 | scope.config = {};
|
355 |
|
356 | compileTemplate(template);
|
357 | initializeReactSelect(element[0]);
|
358 | scope.$digest();
|
359 | ctrl.$onDestroy();
|
360 |
|
361 | compileTemplate(template);
|
362 | initializeReactSelect(element[0]);
|
363 | scope.$digest();
|
364 | });
|
365 |
|
366 |
|
367 | it('Should update config and do not loose new selected items', () => {
|
368 | scope.config = {someField: 'AAA'};
|
369 | scope.selectedItem = [scope.items[1]];
|
370 | compileTemplate('<rg-select multiple=true options="item.name for item in items track by item.id" ng-model="selectedItem" config="config" config-auto-update="true"></rg-select>');
|
371 |
|
372 | selected(ctrl).length.should.equal(1);
|
373 |
|
374 | const newItems = [scope.items[0], scope.items[1]];
|
375 | scope.selectedItem = newItems;
|
376 | scope.$digest();
|
377 | selected(ctrl).length.should.equal(newItems.length);
|
378 |
|
379 | scope.config.someField = 'BBB';
|
380 | scope.$digest();
|
381 |
|
382 | selected(ctrl).length.should.equal(newItems.length);
|
383 | });
|
384 | });
|
385 |
|
386 | describe('Options parser', () => {
|
387 | it('Should support syntax "item in items"', () => {
|
388 | scope.items = [{key: 1, label: 'test1'}];
|
389 | scope.selectedItem = scope.items[0];
|
390 |
|
391 | compileTemplate('<rg-select options="item in items" ng-model="selectedItem"></rg-select>');
|
392 | ctrl.config.onBeforeOpen();
|
393 | scope.$digest();
|
394 | ctrl.selectInstance.props.data.length.should.equal(1);
|
395 | });
|
396 |
|
397 | it('Should support "item for item in items"', () => {
|
398 | scope.items = [{key: 1, label: 'test1'}];
|
399 | scope.selectedItem = scope.items[0];
|
400 | compileTemplate('<rg-select options="item as item.label for item in items" ng-model="selectedItem"></rg-select>');
|
401 | ctrl.config.onBeforeOpen();
|
402 | scope.$digest();
|
403 | ctrl.selectInstance.props.data[0].key.should.equal(scope.items[0].key);
|
404 | });
|
405 |
|
406 | it('Should support labeling item', () => {
|
407 | compileTemplate('<rg-select options="item.name for item in items track by item.id" ng-model="selectedItem"></rg-select>');
|
408 | ctrl.selectInstance.props.selected.label.should.equal(fakeItems[2].name);
|
409 | });
|
410 |
|
411 | it('Should support labeling item simple syntax', () => {
|
412 | scope.items = [{key: 1, name: 'test1'}];
|
413 | scope.selectedItem = scope.items[0];
|
414 | compileTemplate('<rg-select options="item.name for item in items" ng-model="selectedItem"></rg-select>');
|
415 | ctrl.selectInstance.props.selected.label.should.equal('test1');
|
416 | });
|
417 |
|
418 | it('Should support function as label', () => {
|
419 | scope.getLabel = sandbox.stub().returns('test label');
|
420 |
|
421 | compileTemplate('<rg-select options="getLabel(item) for item in items track by item.id" ng-model="selectedItem"></rg-select>');
|
422 |
|
423 | ctrl.optionsParser.getLabel(fakeItems[0]).should.equal('test label');
|
424 | scope.getLabel.should.been.calledWith(fakeItems[0]);
|
425 | });
|
426 |
|
427 | it('Should support custom key field with "track by" expression', () => {
|
428 | scope.items = [{id: 1, label: 'test1'}];
|
429 | scope.selectedItem = scope.items[0];
|
430 | compileTemplate('<rg-select options="item in items track by item.id" ng-model="selectedItem"></rg-select>');
|
431 |
|
432 | ctrl.optionsParser.getKey(scope.selectedItem).should.equal(scope.selectedItem.id);
|
433 | });
|
434 |
|
435 | it('Should support custom label field', () => {
|
436 | scope.options = [{key: 1, name: 'testname'}];
|
437 |
|
438 | compileTemplate('<rg-select options="item.name for item in options"></rg-select>');
|
439 |
|
440 | ctrl.optionsParser.getLabel(scope.options[0]).should.equal(scope.options[0].name);
|
441 | });
|
442 |
|
443 | it('Should support description', () => {
|
444 | scope.options = [{key: 1, fullText: 'testname'}];
|
445 |
|
446 | compileTemplate('<rg-select options="item.name select as item.fullText for item in options"></rg-select>');
|
447 |
|
448 | ctrl.optionsParser.getSelectedLabel(scope.options[0]).should.equal(scope.options[0].fullText);
|
449 | });
|
450 |
|
451 | it('Should support selected label customization', () => {
|
452 | scope.options = [{key: 1, fullText: 'testname'}];
|
453 |
|
454 | compileTemplate('<rg-select options="item.name select as item.fullText for item in options"></rg-select>');
|
455 |
|
456 | ctrl.optionsParser.getSelectedLabel(scope.options[0]).should.equal(scope.options[0].fullText);
|
457 | });
|
458 |
|
459 | it('Should pass selected to callback', () => {
|
460 | scope.options = [{key: 1, label: 'test'}];
|
461 | const selectedModel = {originalModel: scope.options[0]};
|
462 | scope.callback = sandbox.spy();
|
463 |
|
464 | compileTemplate('<rg-select options="item in options" on-select="callback(selected)"></rg-select>');
|
465 | ctrl.config.onSelect(selectedModel);
|
466 | scope.$digest();
|
467 |
|
468 | scope.callback.should.have.been.calledWith(selectedModel);
|
469 | });
|
470 |
|
471 | it('Should pass an event to a callback as a second parameter', () => {
|
472 | scope.event = {};
|
473 | scope.onSelect = sandbox.spy();
|
474 | scope.onDeselect = sandbox.spy();
|
475 | scope.onChange = sandbox.spy();
|
476 | scope.options = [{}];
|
477 | const model = {originalModel: scope.options[0]};
|
478 |
|
479 | compileTemplate('<rg-select options="item in options" on-change="onChange(selected,event)" on-select="onSelect(selected,event)" on-deselect="onDeselect(deselected,event)"></rg-select>');
|
480 | ctrl.config.onSelect(model, scope.event);
|
481 | ctrl.config.onChange(model, scope.event);
|
482 | ctrl.config.onDeselect(model, scope.event);
|
483 | scope.$digest();
|
484 |
|
485 | scope.onSelect.should.have.been.calledWith(model, scope.event);
|
486 | scope.onDeselect.should.have.been.calledWith(model, scope.event);
|
487 | scope.onChange.should.have.been.calledWith(model, scope.event);
|
488 | });
|
489 |
|
490 | it('Should take just plain option as label if option is string', () => {
|
491 | ctrl.optionsParser.getLabel('test').should.equal('test');
|
492 | });
|
493 |
|
494 | it('Should return no label if option is object and no valid label mapping provided', () => {
|
495 | should.not.exist(ctrl.optionsParser.getLabel({foo: 'bar'}));
|
496 | });
|
497 |
|
498 | it('Should support custom property for ng-model', () => {
|
499 | const optionMock = {value: 1, label: 'label'};
|
500 | scope.options = [optionMock];
|
501 | scope.selectedOption = null;
|
502 |
|
503 | compileTemplate('<rg-select ng-model="selectedOption" options="item.value as item.label for item in options"></rg-select>');
|
504 | ctrl.config.onChange({originalModel: optionMock});
|
505 |
|
506 | scope.selectedOption.should.equal(optionMock.value);
|
507 | });
|
508 |
|
509 | it('Should update select if we pass custom ng-model', () => {
|
510 | const optionMock = {value: 1, label: 'label'};
|
511 | scope.options = [optionMock];
|
512 | scope.selectedOption = optionMock.value;
|
513 |
|
514 | compileTemplate('<rg-select ng-model="selectedOption" options="item.value as item.label for item in options" lazy="false"></rg-select>');
|
515 |
|
516 | ctrl.selectInstance.props.selected.label.should.equal(optionMock.label);
|
517 | });
|
518 |
|
519 | it('Should call only once data source function for primitive ng-model', () => {
|
520 | function createOptionMock(value) {
|
521 | return {
|
522 | value,
|
523 | label: `label ${value}`
|
524 | };
|
525 | }
|
526 |
|
527 | scope.options = [
|
528 | createOptionMock(1),
|
529 | createOptionMock(2),
|
530 | createOptionMock(3),
|
531 | createOptionMock(4)
|
532 | ];
|
533 |
|
534 | scope.selectedOption = scope.options[0];
|
535 | scope.getOptions = sandbox.stub().returns(scope.options);
|
536 |
|
537 | compileTemplate('<rg-select ng-model="selectedOption" options="item.value as item.label for item in getOptions()"></rg-select>');
|
538 | ctrl.loadOptionsToSelect('');
|
539 | scope.$digest();
|
540 |
|
541 | scope.getOptions.should.been.calledOnce;
|
542 | });
|
543 |
|
544 | it('Should correct update select if options have "track by" with "for" expressions without "as"', () => {
|
545 | compileTemplate('<rg-select ng-model="selectedItem" options="item.name for item in items track by item.id"></rg-select>');
|
546 | ctrl.config.onChange({originalModel: fakeItems[0]});
|
547 | scope.$digest();
|
548 |
|
549 | scope.selectedItem.should.equal(fakeItems[0]);
|
550 | });
|
551 |
|
552 | it('Should update select if list of options load after ng-model', () => {
|
553 |
|
554 | |
555 |
|
556 |
|
557 |
|
558 | scope.items = null;
|
559 | scope.selectedItem = fakeItems[0].id;
|
560 | compileTemplate('<rg-select ng-model="selectedItem" lazy="false" options="item.id as item.name for item in items track by item.id"></rg-select>');
|
561 | scope.$digest();
|
562 |
|
563 | scope.items = angular.copy(fakeItems);
|
564 | scope.$digest();
|
565 |
|
566 | ctrl.selectInstance.props.selected.label.should.equal(fakeItems[0].name);
|
567 | });
|
568 |
|
569 | it('Should update select if list of options load after ng-model and update existing array not changing reference', () => {
|
570 | scope.items = [];
|
571 | scope.selectedItem = fakeItems[0].id;
|
572 | compileTemplate('<rg-select ng-model="selectedItem" lazy="false" options="item.id as item.name for item in items track by item.id"></rg-select>');
|
573 | scope.$digest();
|
574 |
|
575 | scope.items = angular.extend(scope.items, fakeItems);
|
576 | scope.$digest();
|
577 |
|
578 | ctrl.selectInstance.props.selected.label.should.equal(fakeItems[0].name);
|
579 | });
|
580 |
|
581 | it('Should throw exception if we have two options with same ng-model value', () => {
|
582 | const optionMock = {value: 1, label: 'label'};
|
583 | scope.options = [optionMock, optionMock];
|
584 | scope.selectedOption = optionMock.value;
|
585 |
|
586 | function compile() {
|
587 | compileTemplate('<rg-select ng-model="selectedOption" options="item.value as item.label for item in options" lazy="false"></rg-select>');
|
588 | }
|
589 |
|
590 | compile.should.throw(Error);
|
591 | });
|
592 |
|
593 | it('Should parse option variable name', () => {
|
594 | compileTemplate('<rg-select options="itemvar in items track by itemvar.id"></rg-select>');
|
595 |
|
596 | ctrl.optionsParser.optionVariableName.should.be.equal('itemvar');
|
597 | });
|
598 |
|
599 | it('should clear last query on close', () => {
|
600 | ctrl.query = 'query';
|
601 | ctrl.config.onClose();
|
602 | scope.$digest();
|
603 |
|
604 | should.not.exist(ctrl.query);
|
605 | });
|
606 | });
|
607 |
|
608 | function initializeReactSelect(node) {
|
609 | simulateClick(findContainerNode(node));
|
610 | }
|
611 |
|
612 | function simulateClick(node) {
|
613 | const clickEvent = new CustomEvent('click');
|
614 | node.dispatchEvent(clickEvent);
|
615 | }
|
616 |
|
617 | function findContainerNode(node) {
|
618 | return node.querySelector('span');
|
619 | }
|
620 | });
|