blob: 1afd1230d5f89403c0a2df1ad469a379139c441e [file] [log] [blame]
/**
* @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';
import './gr-rule-editor';
import {GrRuleEditor} from './gr-rule-editor';
import {AccessPermissionId} from '../../../utils/access-util';
import {query, queryAll, queryAndAssert} from '../../../test/test-utils';
import {GrButton} from '../../shared/gr-button/gr-button';
import {GrSelect} from '../../shared/gr-select/gr-select';
import * as MockInteractions from '@polymer/iron-test-helpers/mock-interactions';
const basicFixture = fixtureFromElement('gr-rule-editor');
suite('gr-rule-editor tests', () => {
let element: GrRuleEditor;
setup(() => {
element = basicFixture.instantiate();
});
suite('unit tests', () => {
test('_computeForce, _computeForceClass, and _computeForceOptions', () => {
const ForcePushOptions = {
ALLOW: [
{name: 'Allow pushing (but not force pushing)', value: false},
{name: 'Allow pushing with or without force', value: true},
],
BLOCK: [
{name: 'Block pushing with or without force', value: false},
{name: 'Block force pushing', value: true},
],
};
const FORCE_EDIT_OPTIONS = [
{
name: 'No Force Edit',
value: false,
},
{
name: 'Force Edit',
value: true,
},
];
let permission = 'push' as AccessPermissionId;
let action = 'ALLOW';
assert.isTrue(element._computeForce(permission, action));
assert.equal(element._computeForceClass(permission, action), 'force');
assert.deepEqual(
element._computeForceOptions(permission, action),
ForcePushOptions.ALLOW
);
action = 'BLOCK';
assert.isTrue(element._computeForce(permission, action));
assert.equal(element._computeForceClass(permission, action), 'force');
assert.deepEqual(
element._computeForceOptions(permission, action),
ForcePushOptions.BLOCK
);
action = 'DENY';
assert.isFalse(element._computeForce(permission, action));
assert.equal(element._computeForceClass(permission, action), '');
assert.equal(element._computeForceOptions(permission, action).length, 0);
permission = 'editTopicName' as AccessPermissionId;
assert.isTrue(element._computeForce(permission));
assert.equal(element._computeForceClass(permission), 'force');
assert.deepEqual(
element._computeForceOptions(permission),
FORCE_EDIT_OPTIONS
);
permission = 'submit' as AccessPermissionId;
assert.isFalse(element._computeForce(permission));
assert.equal(element._computeForceClass(permission), '');
assert.deepEqual(element._computeForceOptions(permission), []);
});
test('_computeSectionClass', () => {
let deleted = true;
let editing = false;
assert.equal(element._computeSectionClass(editing, deleted), 'deleted');
deleted = false;
assert.equal(element._computeSectionClass(editing, deleted), '');
editing = true;
assert.equal(element._computeSectionClass(editing, deleted), 'editing');
deleted = true;
assert.equal(
element._computeSectionClass(editing, deleted),
'editing deleted'
);
});
test('_getDefaultRuleValues', () => {
let permission = 'priority' as AccessPermissionId;
let label;
assert.deepEqual(element._getDefaultRuleValues(permission, label), {
action: 'BATCH',
});
permission = 'label-Code-Review' as AccessPermissionId;
label = {
values: [
{value: -2, text: 'This shall not be merged'},
{value: -1, text: 'I would prefer this is not merged as is'},
{value: -0, text: 'No score'},
{value: 1, text: 'Looks good to me, but someone else must approve'},
{value: 2, text: 'Looks good to me, approved'},
],
};
assert.deepEqual(element._getDefaultRuleValues(permission, label), {
action: 'ALLOW',
max: 2,
min: -2,
});
permission = 'push' as AccessPermissionId;
label = undefined;
assert.deepEqual(element._getDefaultRuleValues(permission, label), {
action: 'ALLOW',
force: false,
});
permission = 'submit' as AccessPermissionId;
assert.deepEqual(element._getDefaultRuleValues(permission, label), {
action: 'ALLOW',
});
});
test('_setDefaultRuleValues', async () => {
element.rule = {value: {}};
const defaultValue = {action: 'ALLOW'};
const getDefaultRuleValuesStub = sinon
.stub(element, '_getDefaultRuleValues')
.returns(defaultValue);
element._setDefaultRuleValues();
assert.isTrue(getDefaultRuleValuesStub.called);
assert.equal(element.rule!.value, defaultValue);
});
test('_computeOptions', () => {
const PRIORITY_OPTIONS = ['BATCH', 'INTERACTIVE'];
const DROPDOWN_OPTIONS = ['ALLOW', 'DENY', 'BLOCK'];
let permission = 'priority';
assert.deepEqual(element._computeOptions(permission), PRIORITY_OPTIONS);
permission = 'submit';
assert.deepEqual(element._computeOptions(permission), DROPDOWN_OPTIONS);
});
test('_handleValueChange', () => {
const modifiedHandler = sinon.stub();
element.rule = {value: {}};
element.addEventListener('access-modified', modifiedHandler);
element._handleValueChange();
assert.isNotOk(element.rule!.value!.modified);
element._originalRuleValues = {};
element._handleValueChange();
assert.isTrue(element.rule!.value!.modified);
assert.isTrue(modifiedHandler.called);
});
test('_handleAccessSaved', () => {
const originalValue = {action: 'DENY'};
const newValue = {action: 'ALLOW'};
element._originalRuleValues = originalValue;
element.rule = {value: newValue};
element._handleAccessSaved();
assert.deepEqual(element._originalRuleValues, newValue);
});
test('_setOriginalRuleValues', () => {
const value = {
action: 'ALLOW',
force: false,
};
element._setOriginalRuleValues(value);
assert.deepEqual(element._originalRuleValues, value);
});
});
suite('already existing generic rule', () => {
setup(async () => {
element.groupName = 'Group Name';
element.permission = 'submit' as AccessPermissionId;
element.rule = {
value: {
action: 'ALLOW',
force: false,
},
};
element.section = 'refs/*';
// Typically called on ready since elements will have properties defined
// by the parent element.
element._setupValues(element.rule);
await flush();
element.connectedCallback();
});
test('_ruleValues and _originalRuleValues are set correctly', () => {
assert.deepEqual(element._originalRuleValues, element.rule!.value);
});
test('values are set correctly', () => {
assert.equal(
queryAndAssert<GrSelect>(element, '#action').bindValue,
element.rule!.value!.action
);
assert.isNotOk(query<GrSelect>(element, '#labelMin'));
assert.isNotOk(query<GrSelect>(element, '#labelMax'));
assert.isFalse(
queryAndAssert<GrSelect>(element, '#force').classList.contains('force')
);
});
test('modify and cancel restores original values', () => {
element.editing = true;
assert.notEqual(
getComputedStyle(queryAndAssert<GrButton>(element, '#removeBtn'))
.display,
'none'
);
assert.isNotOk(element.rule!.value!.modified);
const actionBindValue = queryAndAssert<GrSelect>(element, '#action');
actionBindValue.bindValue = 'DENY';
assert.isTrue(element.rule!.value!.modified);
element.editing = false;
assert.equal(
getComputedStyle(queryAndAssert<GrButton>(element, '#removeBtn'))
.display,
'none'
);
assert.deepEqual(element._originalRuleValues, element.rule!.value);
assert.equal(
queryAndAssert<GrSelect>(element, '#action').bindValue,
'ALLOW'
);
assert.isNotOk(element.rule!.value!.modified);
});
test('modify value', () => {
assert.isNotOk(element.rule!.value!.modified);
const actionBindValue = queryAndAssert<GrSelect>(element, '#action');
actionBindValue.bindValue = 'DENY';
flush();
assert.isTrue(element.rule!.value!.modified);
// The original value should now differ from the rule values.
assert.notDeepEqual(element._originalRuleValues, element.rule!.value);
});
test('all selects are disabled when not in edit mode', () => {
const selects = queryAll<HTMLSelectElement>(element, 'select');
for (const select of selects) {
assert.isTrue(select.disabled);
}
element.editing = true;
for (const select of selects) {
assert.isFalse(select.disabled);
}
});
test('remove rule and undo remove', () => {
element.editing = true;
element.rule = {value: {action: 'ALLOW'}};
assert.isFalse(
queryAndAssert<HTMLDivElement>(
element,
'#deletedContainer'
).classList.contains('deleted')
);
MockInteractions.tap(queryAndAssert<GrButton>(element, '#removeBtn'));
assert.isTrue(
queryAndAssert<HTMLDivElement>(
element,
'#deletedContainer'
).classList.contains('deleted')
);
assert.isTrue(element._deleted);
assert.isTrue(element.rule!.value!.deleted);
MockInteractions.tap(queryAndAssert<GrButton>(element, '#undoRemoveBtn'));
assert.isFalse(element._deleted);
assert.isNotOk(element.rule!.value!.deleted);
});
test('remove rule and cancel', () => {
element.editing = true;
assert.notEqual(
getComputedStyle(queryAndAssert<GrButton>(element, '#removeBtn'))
.display,
'none'
);
assert.equal(
getComputedStyle(
queryAndAssert<HTMLDivElement>(element, '#deletedContainer')
).display,
'none'
);
element.rule = {value: {action: 'ALLOW'}};
MockInteractions.tap(queryAndAssert<GrButton>(element, '#removeBtn'));
assert.notEqual(
getComputedStyle(queryAndAssert<GrButton>(element, '#removeBtn'))
.display,
'none'
);
assert.notEqual(
getComputedStyle(
queryAndAssert<HTMLDivElement>(element, '#deletedContainer')
).display,
'none'
);
assert.isTrue(element._deleted);
assert.isTrue(element.rule!.value!.deleted);
element.editing = false;
assert.isFalse(element._deleted);
assert.isNotOk(element.rule!.value!.deleted);
assert.isNotOk(element.rule!.value!.modified);
assert.deepEqual(element._originalRuleValues, element.rule!.value);
assert.equal(
getComputedStyle(queryAndAssert<GrButton>(element, '#removeBtn'))
.display,
'none'
);
assert.equal(
getComputedStyle(
queryAndAssert<HTMLDivElement>(element, '#deletedContainer')
).display,
'none'
);
});
test('_computeGroupPath', () => {
const group = '123';
assert.equal(element._computeGroupPath(group), '/admin/groups/123');
});
});
suite('new edit rule', () => {
setup(async () => {
element.groupName = 'Group Name';
element.permission = 'editTopicName' as AccessPermissionId;
element.rule = {};
element.section = 'refs/*';
element._setupValues(element.rule!);
await flush();
element.rule!.value!.added = true;
await flush();
element.connectedCallback();
});
test('_ruleValues and _originalRuleValues are set correctly', () => {
// Since the element does not already have default values, they should
// be set. The original values should be set to those too.
assert.isNotOk(element.rule!.value!.modified);
const expectedRuleValue = {
action: 'ALLOW',
force: false,
added: true,
};
assert.deepEqual(element.rule!.value, expectedRuleValue);
test('values are set correctly', () => {
assert.equal(
queryAndAssert<GrSelect>(element, '#action').bindValue,
expectedRuleValue.action
);
assert.equal(
queryAndAssert<GrSelect>(element, '#force').bindValue,
expectedRuleValue.action
);
});
});
test('modify value', () => {
assert.isNotOk(element.rule!.value!.modified);
const forceBindValue = queryAndAssert<GrSelect>(element, '#force');
forceBindValue.bindValue = true;
flush();
assert.isTrue(element.rule!.value!.modified);
// The original value should now differ from the rule values.
assert.notDeepEqual(element._originalRuleValues, element.rule!.value);
});
test('remove value', () => {
element.editing = true;
const removeStub = sinon.stub();
element.addEventListener('added-rule-removed', removeStub);
MockInteractions.tap(queryAndAssert<GrButton>(element, '#removeBtn'));
flush();
assert.isTrue(removeStub.called);
});
});
suite('already existing rule with labels', () => {
setup(async () => {
element.label = {
values: [
{value: -2, text: 'This shall not be merged'},
{value: -1, text: 'I would prefer this is not merged as is'},
{value: -0, text: 'No score'},
{value: 1, text: 'Looks good to me, but someone else must approve'},
{value: 2, text: 'Looks good to me, approved'},
],
};
element.groupName = 'Group Name';
element.permission = 'label-Code-Review' as AccessPermissionId;
element.rule = {
value: {
action: 'ALLOW',
force: false,
max: 2,
min: -2,
},
};
element.section = 'refs/*';
element._setupValues(element.rule);
await flush();
element.connectedCallback();
});
test('_ruleValues and _originalRuleValues are set correctly', () => {
assert.deepEqual(element._originalRuleValues, element.rule!.value);
});
test('values are set correctly', () => {
assert.equal(
queryAndAssert<GrSelect>(element, '#action').bindValue,
element.rule!.value!.action
);
assert.equal(
queryAndAssert<GrSelect>(element, '#labelMin').bindValue,
element.rule!.value!.min
);
assert.equal(
queryAndAssert<GrSelect>(element, '#labelMax').bindValue,
element.rule!.value!.max
);
assert.isFalse(
queryAndAssert<GrSelect>(element, '#force').classList.contains('force')
);
});
test('modify value', () => {
const removeStub = sinon.stub();
element.addEventListener('added-rule-removed', removeStub);
assert.isNotOk(element.rule!.value!.modified);
const labelMinBindValue = queryAndAssert<GrSelect>(element, '#labelMin');
labelMinBindValue.bindValue = 1;
flush();
assert.isTrue(element.rule!.value!.modified);
assert.isFalse(removeStub.called);
// The original value should now differ from the rule values.
assert.notDeepEqual(element._originalRuleValues, element.rule!.value);
});
});
suite('new rule with labels', () => {
let setDefaultRuleValuesSpy: sinon.SinonSpy;
setup(async () => {
setDefaultRuleValuesSpy = sinon.spy(element, '_setDefaultRuleValues');
element.label = {
values: [
{value: -2, text: 'This shall not be merged'},
{value: -1, text: 'I would prefer this is not merged as is'},
{value: -0, text: 'No score'},
{value: 1, text: 'Looks good to me, but someone else must approve'},
{value: 2, text: 'Looks good to me, approved'},
],
};
element.groupName = 'Group Name';
element.permission = 'label-Code-Review' as AccessPermissionId;
element.rule = {};
element.section = 'refs/*';
element._setupValues(element.rule!);
await flush();
element.rule!.value!.added = true;
await flush();
element.connectedCallback();
});
test('_ruleValues and _originalRuleValues are set correctly', () => {
// Since the element does not already have default values, they should
// be set. The original values should be set to those too.
assert.isNotOk(element.rule!.value!.modified);
assert.isTrue(setDefaultRuleValuesSpy.called);
const expectedRuleValue = {
max: element.label!.values![element.label!.values.length - 1].value,
min: element.label!.values![0].value,
action: 'ALLOW',
added: true,
};
assert.deepEqual(element.rule!.value, expectedRuleValue);
test('values are set correctly', () => {
assert.equal(
queryAndAssert<GrSelect>(element, '#action').bindValue,
expectedRuleValue.action
);
assert.equal(
queryAndAssert<GrSelect>(element, '#labelMin').bindValue,
expectedRuleValue.min
);
assert.equal(
queryAndAssert<GrSelect>(element, '#labelMax').bindValue,
expectedRuleValue.max
);
});
});
test('modify value', () => {
assert.isNotOk(element.rule!.value!.modified);
const labelMinBindValue = queryAndAssert<GrSelect>(element, '#labelMin');
labelMinBindValue.bindValue = 1;
flush();
assert.isTrue(element.rule!.value!.modified);
// The original value should now differ from the rule values.
assert.notDeepEqual(element._originalRuleValues, element.rule!.value);
});
});
suite('already existing push rule', () => {
setup(async () => {
element.groupName = 'Group Name';
element.permission = 'push' as AccessPermissionId;
element.rule = {
value: {
action: 'ALLOW',
force: true,
},
};
element.section = 'refs/*';
element._setupValues(element.rule!);
await flush();
element.connectedCallback();
});
test('_ruleValues and _originalRuleValues are set correctly', () => {
assert.deepEqual(element._originalRuleValues, element.rule!.value);
});
test('values are set correctly', () => {
assert.isTrue(
queryAndAssert<GrSelect>(element, '#force').classList.contains('force')
);
assert.equal(
queryAndAssert<GrSelect>(element, '#action').bindValue,
element.rule!.value!.action
);
assert.equal(
queryAndAssert<GrSelect>(element, '#force').bindValue,
element.rule!.value!.force
);
assert.isNotOk(query<GrSelect>(element, '#labelMin'));
assert.isNotOk(query<GrSelect>(element, '#labelMax'));
});
test('modify value', () => {
assert.isNotOk(element.rule!.value!.modified);
const actionBindValue = queryAndAssert<GrSelect>(element, '#action');
actionBindValue.bindValue = false;
flush();
assert.isTrue(element.rule!.value!.modified);
// The original value should now differ from the rule values.
assert.notDeepEqual(element._originalRuleValues, element.rule!.value);
});
});
suite('new push rule', () => {
setup(async () => {
element.groupName = 'Group Name';
element.permission = 'push' as AccessPermissionId;
element.rule = {};
element.section = 'refs/*';
element._setupValues(element.rule!);
await flush();
element.rule!.value!.added = true;
await flush();
element.connectedCallback();
});
test('_ruleValues and _originalRuleValues are set correctly', () => {
// Since the element does not already have default values, they should
// be set. The original values should be set to those too.
assert.isNotOk(element.rule!.value!.modified);
const expectedRuleValue = {
action: 'ALLOW',
force: false,
added: true,
};
assert.deepEqual(element.rule!.value, expectedRuleValue);
test('values are set correctly', () => {
assert.equal(
queryAndAssert<GrSelect>(element, '#action').bindValue,
expectedRuleValue.action
);
assert.equal(
queryAndAssert<GrSelect>(element, '#force').bindValue,
expectedRuleValue.action
);
});
});
test('modify value', () => {
assert.isNotOk(element.rule!.value!.modified);
const forceBindValue = queryAndAssert<GrSelect>(element, '#force');
forceBindValue.bindValue = true;
flush();
assert.isTrue(element.rule!.value!.modified);
// The original value should now differ from the rule values.
assert.notDeepEqual(element._originalRuleValues, element.rule!.value);
});
});
suite('already existing edit rule', () => {
setup(async () => {
element.groupName = 'Group Name';
element.permission = 'editTopicName' as AccessPermissionId;
element.rule = {
value: {
action: 'ALLOW',
force: true,
},
};
element.section = 'refs/*';
element._setupValues(element.rule);
await flush();
element.connectedCallback();
});
test('_ruleValues and _originalRuleValues are set correctly', () => {
assert.deepEqual(element._originalRuleValues, element.rule!.value);
});
test('values are set correctly', () => {
assert.isTrue(
queryAndAssert<GrSelect>(element, '#force').classList.contains('force')
);
assert.equal(
queryAndAssert<GrSelect>(element, '#action').bindValue,
element.rule!.value!.action
);
assert.equal(
queryAndAssert<GrSelect>(element, '#force').bindValue,
element.rule!.value!.force
);
assert.isNotOk(query<GrSelect>(element, '#labelMin'));
assert.isNotOk(query<GrSelect>(element, '#labelMax'));
});
test('modify value', async () => {
assert.isNotOk(element.rule!.value!.modified);
const actionBindValue = queryAndAssert<GrSelect>(element, '#action');
actionBindValue.bindValue = false;
await flush();
assert.isTrue(element.rule!.value!.modified);
// The original value should now differ from the rule values.
assert.notDeepEqual(element._originalRuleValues, element.rule!.value);
});
});
});