UNPKG

@polymer/polymer

Version:

The Polymer library makes it easy to create your own web components. Give your element some markup and properties, and then use it on a site. Polymer provides features like dynamic templates and data binding to reduce the amount of boilerplate you need to

594 lines (553 loc) 23.8 kB
<!doctype html> <!-- @license Copyright (c) 2017 The Polymer Project Authors. All rights reserved. This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as part of the polymer project is also subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt --> <html> <head> <meta charset="utf-8"> <script src="../../../webcomponentsjs/webcomponents-lite.js"></script> <script src="../../../web-component-tester/browser.js"></script> <link rel="import" href="../../polymer.html"> <link rel="import" href="array-selector-elements.html"> <body> <test-fixture id="singleConfigured"> <template> <array-selector items='[{"name": "one"},{"name": "two"},{"name": "three"}]'> </array-selector> </template> </test-fixture> <test-fixture id="multiConfigured"> <template> <array-selector multi items='[{"name": "one"},{"name": "two"},{"name": "three"}]'> </array-selector> </template> </test-fixture> <test-fixture id="bind"> <template> <dom-bind> <template> <observe-el id="observer" single-selected="{{singleSelected}}" multi-selected="{{multiSelected}}"></observe-el> <array-selector id="singleBound" items="{{items}}" selected="{{singleSelected}}"></array-selector> <array-selector id="multiBound" items="{{items}}" selected="{{multiSelected}}" multi></array-selector> </template> </dom-bind> </template> </test-fixture> <script> suite('single selection', function() { test('single selection', function() { var el = fixture('singleConfigured'); // Nothing selected assert.strictEqual(el.selected, null); assert.strictEqual(el.selectedItem, null); assert.isFalse(el.isSelected(el.items[0])); assert.isFalse(el.isSelected(el.items[1])); assert.isFalse(el.isSelected(el.items[2])); // Select 0 el.select(el.items[0]); assert.strictEqual(el.selected, el.items[0]); assert.strictEqual(el.selectedItem, el.items[0]); assert.isTrue(el.isSelected(el.items[0])); assert.isFalse(el.isSelected(el.items[1])); assert.isFalse(el.isSelected(el.items[2])); // Re-select 0 el.select(el.items[0]); assert.strictEqual(el.selected, el.items[0]); assert.strictEqual(el.selectedItem, el.items[0]); assert.isTrue(el.isSelected(el.items[0])); assert.isFalse(el.isSelected(el.items[1])); assert.isFalse(el.isSelected(el.items[2])); // Select 2 (using index-based API) el.selectIndex(2); assert.strictEqual(el.selected, el.items[2]); assert.strictEqual(el.selectedItem, el.items[2]); assert.isFalse(el.isIndexSelected(0)); assert.isFalse(el.isIndexSelected(1)); assert.isTrue(el.isIndexSelected(2)); // Toggle 2 el.toggle = true; el.select(el.items[2]); assert.strictEqual(el.selected, null); assert.strictEqual(el.selectedItem, null); assert.isFalse(el.isSelected(el.items[0])); assert.isFalse(el.isSelected(el.items[1])); assert.isFalse(el.isSelected(el.items[2])); // Toggle 2 el.toggle = true; el.select(el.items[2]); assert.strictEqual(el.selected, el.items[2]); assert.strictEqual(el.selectedItem, el.items[2]); assert.isFalse(el.isSelected(el.items[0])); assert.isFalse(el.isSelected(el.items[1])); assert.isTrue(el.isSelected(el.items[2])); // clearSelection el.clearSelection(); assert.equal(el.selectedItem, null); }); test('bound defaults', function() { let bind = fixture('bind'); assert.equal(bind.$.observer.singleSelected, null); assert.sameMembers(bind.$.observer.multiSelected, []); bind.items = [ {name: 'one'}, {name: 'two'}, {name: 'three'} ]; assert.equal(bind.$.observer.singleSelected, null); assert.sameMembers(bind.$.observer.multiSelected, []); }); test('single selection notification', function() { let bind = fixture('bind'); bind.items = [ {name: 'one'}, {name: 'two'}, {name: 'three'} ]; bind.$.observer.singleChanged = sinon.spy(); bind.$.singleBound.select(bind.items[2]); assert.isTrue(bind.$.observer.singleChanged.calledOnce); assert.equal(bind.$.observer.singleChanged.firstCall.args[0].path, 'singleSelected'); assert.equal(bind.$.observer.singleChanged.firstCall.args[0].value, bind.items[2]); assert.equal(bind.$.observer.singleSelected, bind.items[2]); // clear selection bind.$.observer.singleChanged = sinon.spy(); bind.$.singleBound.clearSelection(); assert.equal(bind.$.observer.singleSelected, null); assert.isTrue(bind.$.observer.singleChanged.calledOnce); assert.equal(bind.$.observer.singleChanged.firstCall.args[0].path, 'singleSelected'); assert.equal(bind.$.observer.singleChanged.firstCall.args[0].value, null); }); test('single selection sub-property change', function() { let bind = fixture('bind'); bind.items = [ {name: 'one'}, {name: 'two'}, {name: 'three'} ]; bind.$.singleBound.select(bind.items[2]); bind.$.observer.singleChanged = sinon.spy(); bind.set(['items', 2, 'name'], 'test'); assert.isTrue(bind.$.observer.singleChanged.calledOnce); assert.equal(bind.$.observer.singleChanged.firstCall.args[0].path, 'singleSelected.name'); assert.equal(bind.$.observer.singleChanged.firstCall.args[0].value, 'test'); assert.equal(bind.$.observer.singleSelected.name, 'test'); bind.$.singleBound.select(bind.items[1]); bind.$.observer.singleChanged = sinon.spy(); bind.set(['items', 1, 'name'], 'test2'); assert.isTrue(bind.$.observer.singleChanged.calledOnce); assert.equal(bind.$.observer.singleChanged.firstCall.args[0].path, 'singleSelected.name'); assert.equal(bind.$.observer.singleChanged.firstCall.args[0].value, 'test2'); assert.equal(bind.$.observer.singleSelected.name, 'test2'); }); test('single selection sub-property change after unshift', function() { let bind = fixture('bind'); bind.items = [ {name: 'one'}, {name: 'two'}, {name: 'three'} ]; bind.$.singleBound.select(bind.items[2]); bind.unshift('items', {name: 'zero'}); bind.$.observer.singleChanged = sinon.spy(); bind.set(['items', 3, 'name'], 'test2'); assert.isTrue(bind.$.observer.singleChanged.calledOnce); assert.equal(bind.$.observer.singleChanged.firstCall.args[0].path, 'singleSelected.name'); assert.equal(bind.$.observer.singleChanged.firstCall.args[0].value, 'test2'); assert.equal(bind.$.observer.singleSelected.name, 'test2'); }); test('single selection removal via splice', function() { let bind = fixture('bind'); bind.items = [ {name: 'one'}, {name: 'two'}, {name: 'three'} ]; bind.$.singleBound.select(bind.items[1]); bind.$.observer.singleChanged = sinon.spy(); bind.splice('items', 1, 2); assert.isTrue(bind.$.observer.singleChanged.calledOnce); assert.equal(bind.$.observer.singleChanged.firstCall.args[0].path, 'singleSelected'); assert.equal(bind.$.observer.singleChanged.firstCall.args[0].value, null); assert.equal(bind.$.observer.singleSelected, null); }); test('copy array, selection should remain', function() { let bind = fixture('bind'); bind.items = [ {name: 'one'}, {name: 'two'}, {name: 'three'} ]; bind.$.singleBound.select(bind.items[2]); assert.equal(bind.$.singleBound.selected, bind.items[2]); // set items to copy; all should still be selected bind.items = bind.items.slice(); assert.equal(bind.$.singleBound.selected, bind.items[2]); }); test('change array, selection should go away', function() { let bind = fixture('bind'); bind.items = [ {name: 'one'}, {name: 'two'}, {name: 'three'} ]; bind.$.singleBound.select(bind.items[2]); assert.equal(bind.$.singleBound.selected, bind.items[2]); // set items to new objects; all should be removed (selection based on identity) bind.items = [ {name: 'one'}, {name: 'two'}, {name: 'three'} ]; assert.equal(bind.$.singleBound.selected, null); }); test('null array, selection should go away', function() { let bind = fixture('bind'); bind.items = [ {name: 'one'}, {name: 'two'}, {name: 'three'} ]; bind.$.singleBound.select(bind.items[2]); assert.equal(bind.$.singleBound.selected, bind.items[2]); // set items to new objects; all should be removed (selection based on identity) bind.items = null; assert.equal(bind.$.singleBound.selected, null); }); }); suite('multi selection', function() { test('multi selection', function() { var el = fixture('multiConfigured'); // Nothing selected assert.sameMembers(el.selected, []); assert.isFalse(el.isSelected(el.items[0])); assert.isFalse(el.isSelected(el.items[1])); assert.isFalse(el.isSelected(el.items[2])); // Select 0 el.select(el.items[0]); assert.sameMembers(el.selected, [el.items[0]]); assert.isTrue(el.isSelected(el.items[0])); assert.isFalse(el.isSelected(el.items[1])); assert.isFalse(el.isSelected(el.items[2])); // Re-select 0 el.select(el.items[0]); assert.sameMembers(el.selected, [el.items[0]]); assert.isTrue(el.isSelected(el.items[0])); assert.isFalse(el.isSelected(el.items[1])); assert.isFalse(el.isSelected(el.items[2])); // Select 2 (using index-based API) el.selectIndex(2); assert.sameMembers(el.selected, [el.items[0], el.items[2]]); assert.isTrue(el.isIndexSelected(0)); assert.isFalse(el.isIndexSelected(1)); assert.isTrue(el.isIndexSelected(2)); // Toggle 2 el.toggle = true; el.select(el.items[2]); assert.sameMembers(el.selected, [el.items[0]]); assert.isTrue(el.isSelected(el.items[0])); assert.isFalse(el.isSelected(el.items[1])); assert.isFalse(el.isSelected(el.items[2])); // Toggle 2 el.toggle = true; el.select(el.items[2]); assert.sameMembers(el.selected, [el.items[0], el.items[2]]); assert.isTrue(el.isSelected(el.items[0])); assert.isFalse(el.isSelected(el.items[1])); assert.isTrue(el.isSelected(el.items[2])); // clear selection el.clearSelection(); assert.sameMembers(el.selected, []); }); test('multi selection notification', function() { let bind = fixture('bind'); bind.items = [ {name: 'one'}, {name: 'two'}, {name: 'three'} ]; // select first bind.$.observer.multiChanged = sinon.spy(); bind.$.multiBound.select(bind.items[2]); assert.isTrue(bind.$.observer.multiChanged.calledTwice); assert.equal(bind.$.observer.multiChanged.firstCall.args[0].path, 'multiSelected.splices'); assert.equal(bind.$.observer.multiChanged.firstCall.args[0].value.indexSplices.length, 1); assert.equal(bind.$.observer.multiChanged.firstCall.args[0].value.indexSplices[0].addedCount, 1); assert.equal(bind.$.observer.multiChanged.firstCall.args[0].value.indexSplices[0].removed.length, 0); assert.sameMembers(bind.$.observer.multiSelected, [bind.items[2]]); assert.equal(bind.$.observer.multiChanged.secondCall.args[0].path, 'multiSelected.length'); assert.equal(bind.$.observer.multiChanged.secondCall.args[0].value, 1); // select second bind.$.observer.multiChanged = sinon.spy(); bind.$.multiBound.select(bind.items[0]); assert.isTrue(bind.$.observer.multiChanged.calledTwice); assert.equal(bind.$.observer.multiChanged.firstCall.args[0].path, 'multiSelected.splices'); assert.equal(bind.$.observer.multiChanged.firstCall.args[0].value.indexSplices.length, 1); assert.equal(bind.$.observer.multiChanged.firstCall.args[0].value.indexSplices[0].addedCount, 1); assert.equal(bind.$.observer.multiChanged.firstCall.args[0].value.indexSplices[0].removed.length, 0); assert.sameMembers(bind.$.observer.multiSelected, [bind.items[2], bind.items[0]]); assert.equal(bind.$.observer.multiChanged.secondCall.args[0].path, 'multiSelected.length'); assert.equal(bind.$.observer.multiChanged.secondCall.args[0].value, 2); // clear selection bind.$.observer.multiChanged = sinon.spy(); bind.$.multiBound.clearSelection(); assert.sameMembers(bind.$.observer.multiSelected, []); assert.isTrue(bind.$.observer.multiChanged.calledOnce); assert.equal(bind.$.observer.multiChanged.firstCall.args[0].path, 'multiSelected'); assert.sameMembers(bind.$.observer.multiChanged.firstCall.args[0].value, []); }); test('multi selection sub-property change', function() { let bind = fixture('bind'); bind.items = [ {name: 'one'}, {name: 'two'}, {name: 'three'} ]; bind.$.multiBound.select(bind.items[2]); bind.$.multiBound.select(bind.items[0]); bind.$.observer.multiChanged = sinon.spy(); bind.set(['items', 2, 'name'], 'test'); assert.isTrue(bind.$.observer.multiChanged.calledOnce); assert.equal(bind.$.observer.multiChanged.firstCall.args[0].path, 'multiSelected.0.name'); assert.equal(bind.$.observer.multiChanged.firstCall.args[0].value, 'test'); assert.equal(bind.$.observer.multiSelected[0].name, 'test'); bind.$.observer.multiChanged = sinon.spy(); bind.set(['items', 0, 'name'], 'test2'); assert.isTrue(bind.$.observer.multiChanged.calledOnce); assert.equal(bind.$.observer.multiChanged.firstCall.args[0].path, 'multiSelected.1.name'); assert.equal(bind.$.observer.multiChanged.firstCall.args[0].value, 'test2'); assert.equal(bind.$.observer.multiSelected[1].name, 'test2'); }); test('multi selection sub-property change after unshift', function() { let bind = fixture('bind'); bind.items = [ {name: 'one'}, {name: 'two'}, {name: 'three'} ]; bind.$.multiBound.select(bind.items[2]); bind.$.multiBound.select(bind.items[0]); bind.unshift('items', {name: 'zero'}); bind.$.observer.multiChanged = sinon.spy(); bind.set(['items', 1, 'name'], 'test'); assert.isTrue(bind.$.observer.multiChanged.calledOnce); assert.equal(bind.$.observer.multiChanged.firstCall.args[0].path, 'multiSelected.1.name'); assert.equal(bind.$.observer.multiChanged.firstCall.args[0].value, 'test'); assert.equal(bind.$.observer.multiSelected[1].name, 'test'); }); test('multi selection sub-property change after splice (removal)', function() { let bind = fixture('bind'); bind.items = [ {name: 'one'}, {name: 'two'}, {name: 'three'} ]; bind.$.multiBound.select(bind.items[0]); bind.$.multiBound.select(bind.items[2]); bind.$.observer.multiChanged = sinon.spy(); bind.splice('items', 0, 1); // assert.equal(bind.$.observer.multiChanged.firstCall.args[0].path, 'multiSelected'); // assert.sameMembers(bind.$.observer.multiChanged.firstCall.args[0].value, [bind.items[1]]); assert.equal(bind.$.observer.multiChanged.firstCall.args[0].path, 'multiSelected.splices'); assert.equal(bind.$.observer.multiChanged.firstCall.args[0].value.indexSplices.length, 1); assert.equal(bind.$.observer.multiChanged.firstCall.args[0].value.indexSplices[0].index, 0); assert.equal(bind.$.observer.multiChanged.firstCall.args[0].value.indexSplices[0].addedCount, 0); assert.equal(bind.$.observer.multiChanged.firstCall.args[0].value.indexSplices[0].removed.length, 1); bind.$.observer.multiChanged = sinon.spy(); bind.set(['items', 1, 'name'], 'test'); assert.isTrue(bind.$.observer.multiChanged.calledOnce); assert.equal(bind.$.observer.multiChanged.firstCall.args[0].path, 'multiSelected.0.name'); assert.equal(bind.$.observer.multiChanged.firstCall.args[0].value, 'test'); assert.equal(bind.$.observer.multiSelected[0].name, 'test'); }); test('multi selection sub-property change after deselect', function() { let bind = fixture('bind'); bind.items = [ {name: 'one'}, {name: 'two'}, {name: 'three'} ]; bind.$.multiBound.select(bind.items[2]); bind.$.multiBound.select(bind.items[0]); bind.$.observer.multiChanged = sinon.spy(); bind.set(['items', 0, 'name'], 'test'); assert.isTrue(bind.$.observer.multiChanged.calledOnce); assert.equal(bind.$.observer.multiChanged.firstCall.args[0].path, 'multiSelected.1.name'); assert.equal(bind.$.observer.multiChanged.firstCall.args[0].value, 'test'); assert.equal(bind.$.observer.multiSelected[1].name, 'test'); bind.$.multiBound.deselect(bind.items[2]); bind.$.observer.multiChanged = sinon.spy(); bind.set(['items', 0, 'name'], 'test4'); assert.isTrue(bind.$.observer.multiChanged.calledOnce); assert.equal(bind.$.observer.multiChanged.firstCall.args[0].path, 'multiSelected.0.name'); assert.equal(bind.$.observer.multiChanged.firstCall.args[0].value, 'test4'); assert.equal(bind.$.observer.multiSelected[0].name, 'test4'); }); test('copy array, selection should remain', function() { let bind = fixture('bind'); bind.items = [ {name: 'one'}, {name: 'two'}, {name: 'three'} ]; bind.$.multiBound.select(bind.items[2]); bind.$.multiBound.select(bind.items[0]); assert.sameMembers(bind.$.multiBound.selected, [bind.items[2], bind.items[0]]); // set items to copy; all should still be selected bind.items = bind.items.slice(); assert.sameMembers(bind.$.multiBound.selected, [bind.items[2], bind.items[0]]); }); test('change array, selection should go away', function() { let bind = fixture('bind'); bind.items = [ {name: 'one'}, {name: 'two'}, {name: 'three'} ]; bind.$.multiBound.select(bind.items[2]); bind.$.multiBound.select(bind.items[0]); assert.sameMembers(bind.$.multiBound.selected, [bind.items[2], bind.items[0]]); // set items to new objects; all should be removed (selection based on identity) bind.items = [ {name: 'one'}, {name: 'two'}, {name: 'three'} ]; assert.sameMembers(bind.$.multiBound.selected, []); }); test('null array, selection should go away', function() { let bind = fixture('bind'); bind.items = [ {name: 'one'}, {name: 'two'}, {name: 'three'} ]; bind.$.multiBound.select(bind.items[2]); bind.$.multiBound.select(bind.items[0]); assert.sameMembers(bind.$.multiBound.selected, [bind.items[2], bind.items[0]]); // set items to new objects; all should be removed (selection based on identity) bind.items = null; assert.sameMembers(bind.$.multiBound.selected, []); }); test('reset item in array, selection should go away', function() { let bind = fixture('bind'); bind.items = [ {name: 'one'}, {name: 'two'}, {name: 'three'} ]; bind.$.multiBound.select(bind.items[2]); bind.$.multiBound.select(bind.items[0]); assert.sameMembers(bind.$.multiBound.selected, [bind.items[2], bind.items[0]]); // set items to new objects; all should be removed (selection based on identity) bind.set('items.0', {name: 'new'}); assert.sameMembers(bind.$.multiBound.selected, [bind.items[2]]); }); }); suite('corner cases', function() { test('switch from single to multi', function() { var el = fixture('singleConfigured'); // Nothing selected assert.strictEqual(el.selected, null); assert.strictEqual(el.selectedItem, null); assert.isFalse(el.isSelected(el.items[0])); assert.isFalse(el.isSelected(el.items[1])); assert.isFalse(el.isSelected(el.items[2])); // Select 0 el.select(el.items[0]); assert.strictEqual(el.selected, el.items[0]); assert.strictEqual(el.selectedItem, el.items[0]); assert.isTrue(el.isSelected(el.items[0])); assert.isFalse(el.isSelected(el.items[1])); assert.isFalse(el.isSelected(el.items[2])); // switch to multi el.multi = true; assert.sameMembers(el.selected, []); assert.equal(el.selectedItem, null); }); test('switch from multi to single', function() { var el = fixture('multiConfigured'); // Nothing selected assert.sameMembers(el.selected, []); assert.isFalse(el.isSelected(el.items[0])); assert.isFalse(el.isSelected(el.items[1])); assert.isFalse(el.isSelected(el.items[2])); // Select 0 el.select(el.items[0]); assert.sameMembers(el.selected, [el.items[0]]); assert.isTrue(el.isSelected(el.items[0])); assert.isFalse(el.isSelected(el.items[1])); assert.isFalse(el.isSelected(el.items[2])); // switch to single el.multi = false; assert.equal(el.selected, null); assert.equal(el.selectedItem, null); }); test('reset mutated array with gaps resulting in multiple splices', function() { var bind = fixture('bind'); let i = bind.items = [ {name: '0'}, {name: '1'}, {name: '2'}, {name: '3'}, {name: '4'}, {name: '5'}, {name: '6'}, {name: '7'} ]; bind.$.multiBound.selectIndex(2); bind.$.multiBound.selectIndex(6); bind.$.multiBound.selectIndex(1); bind.$.multiBound.selectIndex(5); bind.$.multiBound.selectIndex(0); bind.$.multiBound.selectIndex(4); assert.sameMembers(bind.$.multiBound.selected, [i[2], i[6], i[1], i[5], i[0], i[4]]); bind.$.observer.multiChanged = sinon.spy(); bind.set('items.4.name', 'changed1'); assert.isTrue(bind.$.observer.multiChanged.calledOnce); assert.equal(bind.$.observer.multiChanged.firstCall.args[0].path, 'multiSelected.5.name'); assert.equal(bind.$.observer.multiChanged.firstCall.args[0].value, 'changed1'); bind.items = [ i[0], i[3], i[4], i[7] ]; assert.sameMembers(bind.$.multiBound.selected, [i[0], i[4]]); bind.$.observer.multiChanged = sinon.spy(); bind.set('items.2.name', 'changed2'); assert.isTrue(bind.$.observer.multiChanged.calledOnce); assert.equal(bind.$.observer.multiChanged.firstCall.args[0].path, 'multiSelected.1.name'); assert.equal(bind.$.observer.multiChanged.firstCall.args[0].value, 'changed2'); }); // Current algorithm does not handle reordering array while maintaining selection state test('reset mutated array reordered resulting in multiple splices', function() { var bind = fixture('bind'); let i = bind.items = [ {name: '0'}, {name: '1'}, {name: '2'}, {name: '3'}, {name: '4'}, {name: '5'}, {name: '6'}, {name: '7'} ]; bind.$.multiBound.selectIndex(2); bind.$.multiBound.selectIndex(6); bind.$.multiBound.selectIndex(1); bind.$.multiBound.selectIndex(5); bind.$.multiBound.selectIndex(0); bind.$.multiBound.selectIndex(4); assert.sameMembers(bind.$.multiBound.selected, [i[2], i[6], i[1], i[5], i[0], i[4]]); bind.$.observer.multiChanged = sinon.spy(); bind.set('items.4.name', 'changed1'); assert.isTrue(bind.$.observer.multiChanged.calledOnce); assert.equal(bind.$.observer.multiChanged.firstCall.args[0].path, 'multiSelected.5.name'); assert.equal(bind.$.observer.multiChanged.firstCall.args[0].value, 'changed1'); bind.items = [ i[4], i[5], i[6], i[7], i[0], i[1], i[2], i[3] ]; assert.sameMembers(bind.$.multiBound.selected, [i[2], i[6], i[1], i[5], i[0], i[4]]); bind.$.observer.multiChanged = sinon.spy(); bind.set('items.0.name', 'changed2'); assert.isTrue(bind.$.observer.multiChanged.calledOnce); assert.equal(bind.$.observer.multiChanged.firstCall.args[0].path, 'multiSelected.5.name'); assert.equal(bind.$.observer.multiChanged.firstCall.args[0].value, 'changed2'); }); }); </script> </body> </html>