| /** |
| * @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. |
| */ |
| |
| import '../../../test/common-test-setup-karma.js'; |
| import './gr-access-section.js'; |
| import {AccessPermissions, toSortedPermissionsArray} from '../../../utils/access-util.js'; |
| |
| const fixture = fixtureFromElement('gr-access-section'); |
| |
| suite('gr-access-section tests', () => { |
| let element; |
| |
| setup(() => { |
| element = fixture.instantiate(); |
| }); |
| |
| 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); |
| flush(); |
| }); |
| |
| 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', () => { |
| const capabilities = { |
| push: { |
| rules: {}, |
| }, |
| read: { |
| 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, capabilities, |
| element.labels), expectedPermissions); |
| |
| // For everything else, include possible label values before filtering. |
| name = 'refs/for/*'; |
| assert.deepEqual( |
| element._computePermissions(name, capabilities, element.labels), |
| labelOptions |
| .concat(toSortedPermissionsArray(AccessPermissions)) |
| .filter(permission => permission.id !== 'read')); |
| }); |
| |
| test('_computePermissionName', () => { |
| let name = 'GLOBAL_CAPABILITIES'; |
| let permission = { |
| id: 'administrateServer', |
| value: {}, |
| }; |
| assert.equal(element._computePermissionName(name, permission, |
| element.capabilities), |
| element.capabilities[permission.id].name); |
| |
| permission = { |
| id: 'non-existent', |
| value: {}, |
| }; |
| assert.isUndefined(element._computePermissionName(name, permission, |
| element.capabilities)); |
| |
| name = 'refs/for/*'; |
| permission = { |
| id: 'abandon', |
| value: {}, |
| }; |
| |
| assert.equal(element._computePermissionName( |
| name, permission, element.capabilities), |
| AccessPermissions[permission.id].name); |
| |
| name = 'refs/for/*'; |
| permission = { |
| id: 'label-Code-Review', |
| value: { |
| label: 'Code-Review', |
| }, |
| }; |
| |
| assert.equal(element._computePermissionName(name, permission, |
| element.capabilities), |
| 'Label Code-Review'); |
| |
| permission = { |
| id: 'labelAs-Code-Review', |
| value: { |
| label: 'Code-Review', |
| }, |
| }; |
| |
| assert.equal(element._computePermissionName(name, permission, |
| 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 default 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); |
| flush(); |
| }); |
| |
| 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); |
| flush(); |
| }); |
| |
| 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 = []; |
| flush(); |
| 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); |
| flush(); |
| |
| // 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); |
| flush(); |
| |
| 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', async () => { |
| 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'; |
| await flush(); |
| 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 existing section. |
| const modifiedHandler = sinon.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); |
| flush(); |
| 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); |
| flush(); |
| 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.shadowRoot |
| .querySelector('gr-permission').dispatchEvent( |
| new CustomEvent('added-permission-removed', { |
| composed: true, bubbles: true, |
| })); |
| flush(); |
| assert.equal(element._permissions.length, 0); |
| }); |
| |
| test('remove an added section', () => { |
| const removeStub = sinon.stub(); |
| element.addEventListener('added-section-removed', removeStub); |
| element.editing = true; |
| element.section.value.added = true; |
| MockInteractions.tap(element.$.deleteBtn); |
| assert.isTrue(removeStub.called); |
| }); |
| }); |
| }); |
| }); |