| <!DOCTYPE html> |
| <!-- |
| @license |
| Copyright (C) 2017 The Android Open Source Project |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| --> |
| |
| <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes"> |
| <title>gr-access-section</title> |
| |
| <script src="../../../bower_components/page/page.js"></script> |
| <script src="../../../bower_components/webcomponentsjs/webcomponents-lite.min.js"></script> |
| <script src="../../../bower_components/web-component-tester/browser.js"></script> |
| <link rel="import" href="../../../test/common-test-setup.html"/> |
| <link rel="import" href="gr-access-section.html"> |
| |
| <script>void(0);</script> |
| |
| <test-fixture id="basic"> |
| <template> |
| <gr-access-section></gr-access-section> |
| </template> |
| </test-fixture> |
| |
| <script> |
| suite('gr-access-section tests', () => { |
| let element; |
| let sandbox; |
| |
| setup(() => { |
| sandbox = sinon.sandbox.create(); |
| element = fixture('basic'); |
| }); |
| |
| teardown(() => { |
| sandbox.restore(); |
| }); |
| |
| suite('unit tests', () => { |
| setup(() => { |
| element.section = { |
| id: 'refs/*', |
| value: { |
| permissions: { |
| read: { |
| rules: {}, |
| }, |
| }, |
| }, |
| }; |
| element.capabilities = { |
| accessDatabase: { |
| id: 'accessDatabase', |
| name: 'Access Database', |
| }, |
| administrateServer: { |
| id: 'administrateServer', |
| name: 'Administrate Server', |
| }, |
| batchChangesLimit: { |
| id: 'batchChangesLimit', |
| name: 'Batch Changes Limit', |
| }, |
| createAccount: { |
| id: 'createAccount', |
| name: 'Create Account', |
| }, |
| }; |
| element.labels = { |
| 'Code-Review': { |
| values: { |
| ' 0': 'No score', |
| '-1': 'I would prefer this is not merged as is', |
| '-2': 'This shall not be merged', |
| '+1': 'Looks good to me, but someone else must approve', |
| '+2': 'Looks good to me, approved', |
| }, |
| default_value: 0, |
| }, |
| }; |
| element._updateSection(element.section); |
| flushAsynchronousOperations(); |
| }); |
| |
| test('_updateSection', () => { |
| // _updateSection was called in setup, so just make assertions. |
| const expectedPermissions = [ |
| { |
| id: 'read', |
| value: { |
| rules: {}, |
| }, |
| }, |
| ]; |
| assert.deepEqual(element._permissions, expectedPermissions); |
| assert.equal(element._originalId, element.section.id); |
| }); |
| |
| test('_computeLabelOptions', () => { |
| const expectedLabelOptions = [ |
| { |
| id: 'label-Code-Review', |
| value: { |
| name: 'Label Code-Review', |
| id: 'label-Code-Review', |
| }, |
| }, |
| { |
| id: 'labelAs-Code-Review', |
| value: { |
| name: 'Label Code-Review (On Behalf Of)', |
| id: 'labelAs-Code-Review', |
| }, |
| }, |
| ]; |
| |
| assert.deepEqual(element._computeLabelOptions(element.labels), |
| expectedLabelOptions); |
| }); |
| |
| test('_handleAccessSaved', () => { |
| assert.equal(element._originalId, 'refs/*'); |
| element.section.id = 'refs/for/bar'; |
| element._handleAccessSaved(); |
| assert.equal(element._originalId, 'refs/for/bar'); |
| }); |
| |
| test('_computePermissions', () => { |
| sandbox.stub(element, 'toSortedArray').returns( |
| [{ |
| id: 'push', |
| value: { |
| rules: {}, |
| }, |
| }, |
| { |
| id: 'read', |
| value: { |
| rules: {}, |
| }, |
| }, |
| ]); |
| |
| const expectedPermissions = [{ |
| id: 'push', |
| value: { |
| rules: {}, |
| }, |
| }, |
| ]; |
| const labelOptions = [ |
| { |
| id: 'label-Code-Review', |
| value: { |
| name: 'Label Code-Review', |
| id: 'label-Code-Review', |
| }, |
| }, |
| { |
| id: 'labelAs-Code-Review', |
| value: { |
| name: 'Label Code-Review (On Behalf Of)', |
| id: 'labelAs-Code-Review', |
| }, |
| }, |
| ]; |
| |
| // For global capabilities, just return the sorted array filtered by |
| // existing permissions. |
| let name = 'GLOBAL_CAPABILITIES'; |
| assert.deepEqual(element._computePermissions(name, element.capabilities, |
| element.labels), expectedPermissions); |
| |
| // Uses the capabilities array to come up with possible values. |
| assert.isTrue(element.toSortedArray.lastCall. |
| calledWithExactly(element.capabilities)); |
| |
| |
| // For everything else, include possible label values before filtering. |
| name = 'refs/for/*'; |
| assert.deepEqual(element._computePermissions(name, element.capabilities, |
| element.labels), labelOptions.concat(expectedPermissions)); |
| |
| // Uses permissionValues (defined in gr-access-behavior) to come up with |
| // possible values. |
| assert.isTrue(element.toSortedArray.lastCall. |
| calledWithExactly(element.permissionValues)); |
| }); |
| |
| test('_computePermissionName', () => { |
| let name = 'GLOBAL_CAPABILITIES'; |
| let permission = { |
| id: 'administrateServer', |
| value: {}, |
| }; |
| assert.equal(element._computePermissionName(name, permission, |
| element.permissionValues, element.capabilities), |
| element.capabilities[permission.id].name); |
| |
| name = 'refs/for/*'; |
| permission = { |
| id: 'abandon', |
| value: {}, |
| }; |
| |
| assert.equal(element._computePermissionName( |
| name, permission, element.permissionValues, element.capabilities), |
| element.permissionValues[permission.id].name); |
| |
| name = 'refs/for/*'; |
| permission = { |
| id: 'label-Code-Review', |
| value: { |
| label: 'Code-Review', |
| }, |
| }; |
| |
| assert.equal(element._computePermissionName(name, permission, |
| element.permissionValues, element.capabilities), |
| 'Label Code-Review'); |
| |
| permission = { |
| id: 'labelAs-Code-Review', |
| value: { |
| label: 'Code-Review', |
| }, |
| }; |
| |
| assert.equal(element._computePermissionName(name, permission, |
| element.permissionValues, element.capabilities), |
| 'Label Code-Review(On Behalf Of)'); |
| }); |
| |
| test('_computeSectionName', () => { |
| let name; |
| // When computing the section name for an undefined name, it means a |
| // new section is being added. In this case, it should defualt to |
| // 'refs/heads/*'. |
| element._editingRef = false; |
| assert.equal(element._computeSectionName(name), |
| 'Reference: refs/heads/*'); |
| assert.isTrue(element._editingRef); |
| assert.equal(element.section.id, 'refs/heads/*'); |
| |
| // Reset editing to false. |
| element._editingRef = false; |
| name = 'GLOBAL_CAPABILITIES'; |
| assert.equal(element._computeSectionName(name), 'Global Capabilities'); |
| assert.isFalse(element._editingRef); |
| |
| name = 'refs/for/*'; |
| assert.equal(element._computeSectionName(name), |
| 'Reference: refs/for/*'); |
| assert.isFalse(element._editingRef); |
| }); |
| |
| test('editReference', () => { |
| element.editReference(); |
| assert.isTrue(element._editingRef); |
| }); |
| |
| test('_computeSectionClass', () => { |
| let editingRef = false; |
| let canUpload = false; |
| let ownerOf = []; |
| let editing = false; |
| let deleted = false; |
| assert.equal(element._computeSectionClass(editing, canUpload, ownerOf, |
| editingRef, deleted), ''); |
| |
| editing = true; |
| assert.equal(element._computeSectionClass(editing, canUpload, ownerOf, |
| editingRef, deleted), ''); |
| |
| ownerOf = ['refs/*']; |
| assert.equal(element._computeSectionClass(editing, canUpload, ownerOf, |
| editingRef, deleted), 'editing'); |
| |
| ownerOf = []; |
| canUpload = true; |
| assert.equal(element._computeSectionClass(editing, canUpload, ownerOf, |
| editingRef, deleted), 'editing'); |
| |
| editingRef = true; |
| assert.equal(element._computeSectionClass(editing, canUpload, ownerOf, |
| editingRef, deleted), 'editing editingRef'); |
| |
| deleted = true; |
| assert.equal(element._computeSectionClass(editing, canUpload, ownerOf, |
| editingRef, deleted), 'editing editingRef deleted'); |
| |
| editingRef = false; |
| assert.equal(element._computeSectionClass(editing, canUpload, ownerOf, |
| editingRef, deleted), 'editing deleted'); |
| }); |
| |
| test('_computeEditBtnClass', () => { |
| let name = 'GLOBAL_CAPABILITIES'; |
| assert.equal(element._computeEditBtnClass(name), 'global'); |
| name = 'refs/for/*'; |
| assert.equal(element._computeEditBtnClass(name), ''); |
| }); |
| }); |
| |
| suite('interactive tests', () => { |
| setup(() => { |
| element.labels = { |
| 'Code-Review': { |
| values: { |
| ' 0': 'No score', |
| '-1': 'I would prefer this is not merged as is', |
| '-2': 'This shall not be merged', |
| '+1': 'Looks good to me, but someone else must approve', |
| '+2': 'Looks good to me, approved', |
| }, |
| default_value: 0, |
| }, |
| }; |
| }); |
| suite('Global section', () => { |
| setup(() => { |
| element.section = { |
| id: 'GLOBAL_CAPABILITIES', |
| value: { |
| permissions: { |
| accessDatabase: { |
| rules: {}, |
| }, |
| }, |
| }, |
| }; |
| element.capabilities = { |
| accessDatabase: { |
| id: 'accessDatabase', |
| name: 'Access Database', |
| }, |
| administrateServer: { |
| id: 'administrateServer', |
| name: 'Administrate Server', |
| }, |
| batchChangesLimit: { |
| id: 'batchChangesLimit', |
| name: 'Batch Changes Limit', |
| }, |
| createAccount: { |
| id: 'createAccount', |
| name: 'Create Account', |
| }, |
| }; |
| element._updateSection(element.section); |
| flushAsynchronousOperations(); |
| }); |
| |
| test('classes are assigned correctly', () => { |
| assert.isFalse(element.$.section.classList.contains('editing')); |
| assert.isFalse(element.$.section.classList.contains('deleted')); |
| assert.isTrue(element.$.editBtn.classList.contains('global')); |
| element.editing = true; |
| element.canUpload = true; |
| element.ownerOf = []; |
| assert.equal(getComputedStyle(element.$.editBtn).display, 'none'); |
| }); |
| }); |
| |
| suite('Non-global section', () => { |
| setup(() => { |
| element.section = { |
| id: 'refs/*', |
| value: { |
| permissions: { |
| read: { |
| rules: {}, |
| }, |
| }, |
| }, |
| }; |
| element.capabilities = {}; |
| element._updateSection(element.section); |
| flushAsynchronousOperations(); |
| }); |
| |
| test('classes are assigned correctly', () => { |
| assert.isFalse(element.$.section.classList.contains('editing')); |
| assert.isFalse(element.$.section.classList.contains('deleted')); |
| assert.isFalse(element.$.editBtn.classList.contains('global')); |
| element.editing = true; |
| element.canUpload = true; |
| element.ownerOf = []; |
| flushAsynchronousOperations(); |
| assert.notEqual(getComputedStyle(element.$.editBtn).display, 'none'); |
| }); |
| |
| test('add permission', () => { |
| element.editing = true; |
| element.$.permissionSelect.value = 'label-Code-Review'; |
| assert.equal(element._permissions.length, 1); |
| assert.equal(Object.keys(element.section.value.permissions).length, |
| 1); |
| MockInteractions.tap(element.$.addBtn); |
| flushAsynchronousOperations(); |
| |
| // The permission is added to both the permissions array and also |
| // the section's permission object. |
| assert.equal(element._permissions.length, 2); |
| let permission = { |
| id: 'label-Code-Review', |
| value: { |
| added: true, |
| label: 'Code-Review', |
| rules: {}, |
| }, |
| }; |
| assert.equal(element._permissions.length, 2); |
| assert.deepEqual(element._permissions[1], permission); |
| assert.equal(Object.keys(element.section.value.permissions).length, |
| 2); |
| assert.deepEqual( |
| element.section.value.permissions['label-Code-Review'], |
| permission.value); |
| |
| element.$.permissionSelect.value = 'abandon'; |
| MockInteractions.tap(element.$.addBtn); |
| flushAsynchronousOperations(); |
| |
| permission = { |
| id: 'abandon', |
| value: { |
| added: true, |
| rules: {}, |
| }, |
| }; |
| |
| assert.equal(element._permissions.length, 3); |
| assert.deepEqual(element._permissions[2], permission); |
| assert.equal(Object.keys(element.section.value.permissions).length, |
| 3); |
| assert.deepEqual(element.section.value.permissions['abandon'], |
| permission.value); |
| |
| // Unsaved changes are discarded when editing is cancelled. |
| element.editing = false; |
| assert.equal(element._permissions.length, 1); |
| assert.equal(Object.keys(element.section.value.permissions).length, |
| 1); |
| }); |
| |
| test('edit section reference', () => { |
| element.canUpload = true; |
| element.ownerOf = []; |
| element.section = {id: 'refs/for/bar', value: {permissions: {}}}; |
| assert.isFalse(element.$.section.classList.contains('editing')); |
| element.editing = true; |
| assert.isTrue(element.$.section.classList.contains('editing')); |
| assert.isFalse(element._editingRef); |
| MockInteractions.tap(element.$.editBtn); |
| element.$.editRefInput.bindValue='new/ref'; |
| flushAsynchronousOperations(); |
| assert.equal(element.section.id, 'new/ref'); |
| assert.isTrue(element._editingRef); |
| assert.isTrue(element.$.section.classList.contains('editingRef')); |
| element.editing = false; |
| assert.isFalse(element._editingRef); |
| assert.equal(element.section.id, 'refs/for/bar'); |
| }); |
| |
| test('_handleValueChange', () => { |
| // For an exising section. |
| const modifiedHandler = sandbox.stub(); |
| element.section = {id: 'refs/for/bar', value: {permissions: {}}}; |
| assert.notOk(element.section.value.updatedId); |
| element.section.id = 'refs/for/baz'; |
| element.addEventListener('access-modified', modifiedHandler); |
| assert.isNotOk(element.section.value.modified); |
| element._handleValueChange(); |
| assert.equal(element.section.value.updatedId, 'refs/for/baz'); |
| assert.isTrue(element.section.value.modified); |
| assert.equal(modifiedHandler.callCount, 1); |
| element.section.id = 'refs/for/bar'; |
| element._handleValueChange(); |
| assert.isFalse(element.section.value.modified); |
| assert.equal(modifiedHandler.callCount, 2); |
| |
| // For a new section. |
| element.section.value.added = true; |
| element._handleValueChange(); |
| assert.isFalse(element.section.value.modified); |
| assert.equal(modifiedHandler.callCount, 2); |
| element.section.id = 'refs/for/bar'; |
| element._handleValueChange(); |
| assert.isFalse(element.section.value.modified); |
| assert.equal(modifiedHandler.callCount, 2); |
| }); |
| |
| test('remove section', () => { |
| element.editing = true; |
| element.canUpload = true; |
| element.ownerOf = []; |
| assert.isFalse(element._deleted); |
| assert.isNotOk(element.section.value.deleted); |
| MockInteractions.tap(element.$.deleteBtn); |
| flushAsynchronousOperations(); |
| assert.isTrue(element._deleted); |
| assert.isTrue(element.section.value.deleted); |
| assert.isTrue(element.$.section.classList.contains('deleted')); |
| assert.isTrue(element.section.value.deleted); |
| |
| MockInteractions.tap(element.$.undoRemoveBtn); |
| flushAsynchronousOperations(); |
| assert.isFalse(element._deleted); |
| assert.isNotOk(element.section.value.deleted); |
| |
| MockInteractions.tap(element.$.deleteBtn); |
| assert.isTrue(element._deleted); |
| assert.isTrue(element.section.value.deleted); |
| element.editing = false; |
| assert.isFalse(element._deleted); |
| assert.isNotOk(element.section.value.deleted); |
| }); |
| |
| test('removing an added permission', () => { |
| element.editing = true; |
| assert.equal(element._permissions.length, 1); |
| element.$$('gr-permission').fire('added-permission-removed'); |
| flushAsynchronousOperations(); |
| assert.equal(element._permissions.length, 0); |
| }); |
| |
| test('remove an added section', () => { |
| const removeStub = sandbox.stub(); |
| element.addEventListener('added-section-removed', removeStub); |
| element.editing = true; |
| element.section.value.added = true; |
| MockInteractions.tap(element.$.deleteBtn); |
| assert.isTrue(removeStub.called); |
| }); |
| }); |
| }); |
| }); |
| </script> |