blob: 47c3bea42f7fd786d8978794e7af6f5496a99ded [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(async () => {
element = basicFixture.instantiate() as GrRuleEditor;
await element.updateComplete;
});
suite('unit tests', () => {
test('computeForce 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,
},
];
element.permission = 'push' as AccessPermissionId;
let action = 'ALLOW';
assert.isTrue(element.computeForce(action));
assert.deepEqual(
element.computeForceOptions(action),
ForcePushOptions.ALLOW
);
action = 'BLOCK';
assert.isTrue(element.computeForce(action));
assert.deepEqual(
element.computeForceOptions(action),
ForcePushOptions.BLOCK
);
action = 'DENY';
assert.isFalse(element.computeForce(action));
assert.equal(element.computeForceOptions(action).length, 0);
element.permission = 'editTopicName' as AccessPermissionId;
assert.isTrue(element.computeForce());
assert.deepEqual(element.computeForceOptions(), FORCE_EDIT_OPTIONS);
element.permission = 'submit' as AccessPermissionId;
assert.isFalse(element.computeForce());
assert.deepEqual(element.computeForceOptions(), []);
});
test('computeSectionClass', () => {
element.deleted = true;
element.editing = false;
assert.equal(element.computeSectionClass(), 'deleted');
element.deleted = false;
assert.equal(element.computeSectionClass(), '');
element.editing = true;
assert.equal(element.computeSectionClass(), 'editing');
element.deleted = true;
assert.equal(element.computeSectionClass(), 'editing deleted');
});
test('getDefaultRuleValues', () => {
element.permission = 'priority' as AccessPermissionId;
assert.deepEqual(element.getDefaultRuleValues(), {
action: 'BATCH',
});
element.permission = 'label-Code-Review' as AccessPermissionId;
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'},
],
};
assert.deepEqual(element.getDefaultRuleValues(), {
action: 'ALLOW',
max: 2,
min: -2,
});
element.permission = 'push' as AccessPermissionId;
element.label = undefined;
assert.deepEqual(element.getDefaultRuleValues(), {
action: 'ALLOW',
force: false,
});
element.permission = 'submit' as AccessPermissionId;
assert.deepEqual(element.getDefaultRuleValues(), {
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'];
element.permission = 'priority' as AccessPermissionId;
assert.deepEqual(element.computeOptions(), PRIORITY_OPTIONS);
element.permission = 'submit' as AccessPermissionId;
assert.deepEqual(element.computeOptions(), 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', () => {
element.rule = {
value: {
action: 'ALLOW',
force: false,
},
};
element.setOriginalRuleValues();
assert.deepEqual(element.originalRuleValues, element.rule.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/*';
element.setupValues();
element.setOriginalRuleValues();
await element.updateComplete;
});
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', async () => {
element.rule = {value: {}};
element.editing = true;
await element.updateComplete;
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;
await element.updateComplete;
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', async () => {
assert.isNotOk(element.rule!.value!.modified);
const actionBindValue = queryAndAssert<GrSelect>(element, '#action');
actionBindValue.bindValue = 'DENY';
await element.updateComplete;
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', async () => {
const selects = queryAll<HTMLSelectElement>(element, 'select');
for (const select of selects) {
assert.isTrue(select.disabled);
}
element.editing = true;
await element.updateComplete;
for (const select of selects) {
assert.isFalse(select.disabled);
}
});
test('remove rule and undo remove', async () => {
element.editing = true;
element.rule = {value: {action: 'ALLOW'}};
await element.updateComplete;
assert.isFalse(
queryAndAssert<HTMLDivElement>(
element,
'#deletedContainer'
).classList.contains('deleted')
);
MockInteractions.tap(queryAndAssert<GrButton>(element, '#removeBtn'));
await element.updateComplete;
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'));
await element.updateComplete;
assert.isFalse(element.deleted);
assert.isNotOk(element.rule!.value!.deleted);
});
test('remove rule and cancel', async () => {
element.editing = true;
await element.updateComplete;
assert.notEqual(
getComputedStyle(queryAndAssert<GrButton>(element, '#removeBtn'))
.display,
'none'
);
assert.equal(
getComputedStyle(
queryAndAssert<HTMLDivElement>(element, '#deletedContainer')
).display,
'none'
);
element.rule = {value: {action: 'ALLOW'}};
await element.updateComplete;
MockInteractions.tap(queryAndAssert<GrButton>(element, '#removeBtn'));
await element.updateComplete;
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;
await element.updateComplete;
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();
await element.updateComplete;
element.rule!.value!.added = true;
await element.updateComplete;
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', async () => {
assert.isNotOk(element.rule!.value!.modified);
const forceBindValue = queryAndAssert<GrSelect>(element, '#force');
forceBindValue.bindValue = 'true';
await element.updateComplete;
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', async () => {
element.editing = true;
const removeStub = sinon.stub();
element.addEventListener('added-rule-removed', removeStub);
MockInteractions.tap(queryAndAssert<GrButton>(element, '#removeBtn'));
await element.updateComplete;
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();
await element.updateComplete;
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', async () => {
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;
await element.updateComplete;
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();
await element.updateComplete;
element.rule!.value!.added = true;
await element.updateComplete;
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', async () => {
assert.isNotOk(element.rule!.value!.modified);
const labelMinBindValue = queryAndAssert<GrSelect>(element, '#labelMin');
labelMinBindValue.bindValue = 1;
await element.updateComplete;
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();
await element.updateComplete;
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 element.updateComplete;
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', async () => {
setup(async () => {
element.groupName = 'Group Name';
element.permission = 'push' as AccessPermissionId;
element.rule = {};
element.section = 'refs/*';
element.setupValues();
await element.updateComplete;
element.rule!.value!.added = true;
await element.updateComplete;
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', async () => {
assert.isNotOk(element.rule!.value!.modified);
const forceBindValue = queryAndAssert<GrSelect>(element, '#force');
forceBindValue.bindValue = true;
await element.updateComplete;
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();
await element.updateComplete;
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 element.updateComplete;
assert.isTrue(element.rule!.value!.modified);
// The original value should now differ from the rule values.
assert.notDeepEqual(element.originalRuleValues, element.rule!.value);
});
});
});