blob: 50d03a268eb0c8b85bbba800c14a0c49d6dbc176 [file] [log] [blame]
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import '../../../test/common-test-setup-karma';
import './gr-repo';
import {GrRepo} from './gr-repo';
import {mockPromise} from '../../../test/test-utils';
import {
addListenerForTest,
queryAll,
queryAndAssert,
stubRestApi,
} from '../../../test/test-utils';
import {
createInheritedBoolean,
createServerInfo,
} from '../../../test/test-data-generators';
import {
ConfigInfo,
GitRef,
GroupId,
GroupName,
InheritedBooleanInfo,
MaxObjectSizeLimitInfo,
PluginParameterToConfigParameterInfoMap,
ProjectAccessGroups,
ProjectAccessInfoMap,
RepoName,
} from '../../../types/common';
import {
ConfigParameterInfoType,
InheritedBooleanInfoConfiguredValue,
ProjectState,
SubmitType,
} from '../../../constants/constants';
import {
createConfig,
createDownloadSchemes,
} from '../../../test/test-data-generators';
import {PageErrorEvent} from '../../../types/events.js';
import {GrButton} from '../../shared/gr-button/gr-button';
import {GrSelect} from '../../shared/gr-select/gr-select';
import {GrTextarea} from '../../shared/gr-textarea/gr-textarea';
import {IronInputElement} from '@polymer/iron-input/iron-input';
const basicFixture = fixtureFromElement('gr-repo');
suite('gr-repo tests', () => {
let element: GrRepo;
let loggedInStub: sinon.SinonStub;
let repoStub: sinon.SinonStub;
const repoConf: ConfigInfo = {
description: 'Access inherited by all other projects.',
use_contributor_agreements: {
value: false,
configured_value: InheritedBooleanInfoConfiguredValue.FALSE,
},
use_content_merge: {
value: false,
configured_value: InheritedBooleanInfoConfiguredValue.FALSE,
},
use_signed_off_by: {
value: false,
configured_value: InheritedBooleanInfoConfiguredValue.FALSE,
},
create_new_change_for_all_not_in_target: {
value: false,
configured_value: InheritedBooleanInfoConfiguredValue.FALSE,
},
require_change_id: {
value: false,
configured_value: InheritedBooleanInfoConfiguredValue.FALSE,
},
enable_signed_push: {
value: false,
configured_value: InheritedBooleanInfoConfiguredValue.FALSE,
},
require_signed_push: {
value: false,
configured_value: InheritedBooleanInfoConfiguredValue.FALSE,
},
reject_implicit_merges: {
value: false,
configured_value: InheritedBooleanInfoConfiguredValue.FALSE,
},
match_author_to_committer_date: {
value: false,
configured_value: InheritedBooleanInfoConfiguredValue.FALSE,
},
reject_empty_commit: {
value: false,
configured_value: InheritedBooleanInfoConfiguredValue.FALSE,
},
enable_reviewer_by_email: {
value: false,
configured_value: InheritedBooleanInfoConfiguredValue.FALSE,
},
private_by_default: {
value: false,
configured_value: InheritedBooleanInfoConfiguredValue.FALSE,
},
work_in_progress_by_default: {
value: false,
configured_value: InheritedBooleanInfoConfiguredValue.FALSE,
},
max_object_size_limit: {},
commentlinks: {},
submit_type: SubmitType.MERGE_IF_NECESSARY,
default_submit_type: {
value: SubmitType.MERGE_IF_NECESSARY,
configured_value: SubmitType.INHERIT,
inherited_value: SubmitType.MERGE_IF_NECESSARY,
},
};
const REPO = 'test-repo';
const SCHEMES = {
...createDownloadSchemes(),
http: {
url: 'test',
is_auth_required: false,
is_auth_supported: false,
commands: 'test',
clone_commands: {clone: 'test'},
},
repo: {
url: 'test',
is_auth_required: false,
is_auth_supported: false,
commands: 'test',
clone_commands: {clone: 'test'},
},
ssh: {
url: 'test',
is_auth_required: false,
is_auth_supported: false,
commands: 'test',
clone_commands: {clone: 'test'},
},
};
function getFormFields() {
const selects = Array.from(queryAll(element, 'select'));
const textareas = Array.from(queryAll(element, 'iron-autogrow-textarea'));
const inputs = Array.from(queryAll(element, 'input'));
return inputs.concat(textareas).concat(selects);
}
setup(async () => {
loggedInStub = stubRestApi('getLoggedIn').returns(Promise.resolve(false));
stubRestApi('getConfig').returns(Promise.resolve(createServerInfo()));
repoStub = stubRestApi('getProjectConfig').returns(
Promise.resolve(repoConf)
);
element = basicFixture.instantiate();
await element.updateComplete;
});
test('_computePluginData', async () => {
element.repoConfig = {
...createConfig(),
plugin_config: {},
};
await element.updateComplete;
assert.deepEqual(element.computePluginData(), []);
element.repoConfig.plugin_config = {
'test-plugin': {
test: {display_name: 'test plugin', type: 'STRING'},
} as PluginParameterToConfigParameterInfoMap,
};
await element.updateComplete;
assert.deepEqual(element.computePluginData(), [
{
name: 'test-plugin',
config: {
test: {
display_name: 'test plugin',
type: 'STRING' as ConfigParameterInfoType,
},
},
},
]);
});
test('handlePluginConfigChanged', async () => {
const requestUpdateStub = sinon.stub(element, 'requestUpdate');
element.repoConfig = {
...createConfig(),
plugin_config: {},
};
element.handlePluginConfigChanged({
detail: {
name: 'test',
config: {
test: {display_name: 'test plugin', type: 'STRING'},
} as PluginParameterToConfigParameterInfoMap,
},
});
await element.updateComplete;
assert.deepEqual(element.repoConfig.plugin_config!.test, {
test: {display_name: 'test plugin', type: 'STRING'},
} as PluginParameterToConfigParameterInfoMap);
assert.isTrue(requestUpdateStub.called);
});
test('loading displays before repo config is loaded', () => {
assert.isTrue(
queryAndAssert<HTMLDivElement>(element, '#loading').classList.contains(
'loading'
)
);
assert.isFalse(
getComputedStyle(queryAndAssert<HTMLDivElement>(element, '#loading'))
.display === 'none'
);
assert.isTrue(
queryAndAssert<HTMLDivElement>(
element,
'#loadedContent'
).classList.contains('loading')
);
assert.isTrue(
getComputedStyle(
queryAndAssert<HTMLDivElement>(element, '#loadedContent')
).display === 'none'
);
});
test('download commands visibility', async () => {
element.loading = false;
await element.updateComplete;
assert.isTrue(
queryAndAssert<HTMLDivElement>(
element,
'#downloadContent'
).classList.contains('hide')
);
assert.isTrue(
getComputedStyle(
queryAndAssert<HTMLDivElement>(element, '#downloadContent')
).display === 'none'
);
element.schemesObj = SCHEMES;
await element.updateComplete;
assert.isFalse(
queryAndAssert<HTMLDivElement>(
element,
'#downloadContent'
).classList.contains('hide')
);
assert.isFalse(
getComputedStyle(
queryAndAssert<HTMLDivElement>(element, '#downloadContent')
).display === 'none'
);
});
test('form defaults to read only', () => {
assert.isTrue(element.readOnly);
});
test('form defaults to read only when not logged in', async () => {
element.repo = REPO as RepoName;
await element.loadRepo();
assert.isTrue(element.readOnly);
});
test('form defaults to read only when logged in and not admin', async () => {
element.repo = REPO as RepoName;
stubRestApi('getRepoAccess').callsFake(() =>
Promise.resolve({
'test-repo': {
revision: 'xxxx',
local: {
'refs/*': {
permissions: {
owner: {rules: {xxx: {action: 'ALLOW', force: false}}},
},
},
},
owner_of: ['refs/*'] as GitRef[],
groups: {
xxxx: {
id: 'xxxx' as GroupId,
url: 'test',
name: 'test' as GroupName,
},
} as ProjectAccessGroups,
config_web_links: [{name: 'gitiles', url: 'test'}],
},
} as ProjectAccessInfoMap)
);
await element.loadRepo();
assert.isTrue(element.readOnly);
});
test('all form elements are disabled when not admin', async () => {
element.repo = REPO as RepoName;
await element.loadRepo();
await element.updateComplete;
const formFields = getFormFields();
for (const field of formFields) {
assert.isTrue(field.hasAttribute('disabled'));
}
});
test('formatBooleanSelect', () => {
let item: InheritedBooleanInfo = {
...createInheritedBoolean(true),
inherited_value: true,
};
assert.deepEqual(element.formatBooleanSelect(item), [
{
label: 'Inherit (true)',
value: 'INHERIT',
},
{
label: 'True',
value: 'TRUE',
},
{
label: 'False',
value: 'FALSE',
},
]);
item = {...createInheritedBoolean(false), inherited_value: false};
assert.deepEqual(element.formatBooleanSelect(item), [
{
label: 'Inherit (false)',
value: 'INHERIT',
},
{
label: 'True',
value: 'TRUE',
},
{
label: 'False',
value: 'FALSE',
},
]);
// For items without inherited values
item = createInheritedBoolean(false);
assert.deepEqual(element.formatBooleanSelect(item), [
{
label: 'Inherit',
value: 'INHERIT',
},
{
label: 'True',
value: 'TRUE',
},
{
label: 'False',
value: 'FALSE',
},
]);
});
test('fires page-error', async () => {
repoStub.restore();
element.repo = 'test' as RepoName;
const pageErrorFired = mockPromise();
const response = {...new Response(), status: 404};
stubRestApi('getProjectConfig').callsFake((_, errFn) => {
if (errFn !== undefined) {
errFn(response);
}
return Promise.resolve(undefined);
});
addListenerForTest(document, 'page-error', e => {
assert.deepEqual((e as PageErrorEvent).detail.response, response);
pageErrorFired.resolve();
});
element.loadRepo();
await pageErrorFired;
});
suite('admin', () => {
setup(() => {
element.repo = REPO as RepoName;
loggedInStub.returns(Promise.resolve(true));
stubRestApi('getRepoAccess').callsFake(() =>
Promise.resolve({
'test-repo': {
revision: 'xxxx',
local: {
'refs/*': {
permissions: {
owner: {rules: {xxx: {action: 'ALLOW', force: false}}},
},
},
},
is_owner: true,
owner_of: ['refs/*'] as GitRef[],
groups: {
xxxx: {
id: 'xxxx' as GroupId,
url: 'test',
name: 'test' as GroupName,
},
} as ProjectAccessGroups,
config_web_links: [{name: 'gitiles', url: 'test'}],
},
} as ProjectAccessInfoMap)
);
});
test('all form elements are enabled', async () => {
await element.loadRepo();
await element.updateComplete;
const formFields = getFormFields();
for (const field of formFields) {
assert.isFalse(field.hasAttribute('disabled'));
}
assert.isFalse(element.loading);
});
test('state gets set correctly', async () => {
await element.loadRepo();
assert.equal(element.repoConfig!.state, ProjectState.ACTIVE);
assert.equal(
queryAndAssert<GrSelect>(element, '#stateSelect').bindValue,
ProjectState.ACTIVE
);
});
test('inherited submit type value is calculated correctly', async () => {
await element.loadRepo();
const sel = queryAndAssert<GrSelect>(element, '#submitTypeSelect');
assert.equal(sel.bindValue, 'INHERIT');
assert.equal(
sel.nativeSelect.options[0].text,
'Inherit (Merge if necessary)'
);
});
test('fields update and save correctly', async () => {
const configInputObj = {
description: 'new description',
use_contributor_agreements: InheritedBooleanInfoConfiguredValue.TRUE,
use_content_merge: InheritedBooleanInfoConfiguredValue.TRUE,
use_signed_off_by: InheritedBooleanInfoConfiguredValue.TRUE,
create_new_change_for_all_not_in_target:
InheritedBooleanInfoConfiguredValue.TRUE,
require_change_id: InheritedBooleanInfoConfiguredValue.TRUE,
enable_signed_push: InheritedBooleanInfoConfiguredValue.TRUE,
require_signed_push: InheritedBooleanInfoConfiguredValue.TRUE,
reject_implicit_merges: InheritedBooleanInfoConfiguredValue.TRUE,
private_by_default: InheritedBooleanInfoConfiguredValue.TRUE,
work_in_progress_by_default: InheritedBooleanInfoConfiguredValue.TRUE,
match_author_to_committer_date:
InheritedBooleanInfoConfiguredValue.TRUE,
reject_empty_commit: InheritedBooleanInfoConfiguredValue.TRUE,
max_object_size_limit: '10' as MaxObjectSizeLimitInfo,
submit_type: SubmitType.FAST_FORWARD_ONLY,
state: ProjectState.READ_ONLY,
enable_reviewer_by_email: InheritedBooleanInfoConfiguredValue.TRUE,
};
const saveStub = stubRestApi('saveRepoConfig').callsFake(() =>
Promise.resolve(new Response())
);
const button = queryAll<GrButton>(element, 'gr-button')[2];
await element.loadRepo();
assert.isTrue(button.hasAttribute('disabled'));
assert.isFalse(
queryAndAssert<HTMLHeadingElement>(
element,
'#Title'
).classList.contains('edited')
);
queryAndAssert<GrTextarea>(element, '#descriptionInput').text =
configInputObj.description;
queryAndAssert<GrSelect>(element, '#stateSelect').bindValue =
configInputObj.state;
queryAndAssert<GrSelect>(element, '#submitTypeSelect').bindValue =
configInputObj.submit_type;
queryAndAssert<GrSelect>(element, '#contentMergeSelect').bindValue =
configInputObj.use_content_merge;
queryAndAssert<GrSelect>(element, '#newChangeSelect').bindValue =
configInputObj.create_new_change_for_all_not_in_target;
queryAndAssert<GrSelect>(element, '#requireChangeIdSelect').bindValue =
configInputObj.require_change_id;
queryAndAssert<GrSelect>(element, '#enableSignedPush').bindValue =
configInputObj.enable_signed_push;
queryAndAssert<GrSelect>(element, '#requireSignedPush').bindValue =
configInputObj.require_signed_push;
queryAndAssert<GrSelect>(
element,
'#rejectImplicitMergesSelect'
).bindValue = configInputObj.reject_implicit_merges;
queryAndAssert<GrSelect>(
element,
'#setAllnewChangesPrivateByDefaultSelect'
).bindValue = configInputObj.private_by_default;
queryAndAssert<GrSelect>(
element,
'#setAllNewChangesWorkInProgressByDefaultSelect'
).bindValue = configInputObj.work_in_progress_by_default;
queryAndAssert<GrSelect>(
element,
'#matchAuthoredDateWithCommitterDateSelect'
).bindValue = configInputObj.match_author_to_committer_date;
queryAndAssert<IronInputElement>(
element,
'#maxGitObjSizeIronInput'
).bindValue = String(configInputObj.max_object_size_limit);
queryAndAssert<GrSelect>(
element,
'#contributorAgreementSelect'
).bindValue = configInputObj.use_contributor_agreements;
queryAndAssert<GrSelect>(element, '#useSignedOffBySelect').bindValue =
configInputObj.use_signed_off_by;
queryAndAssert<GrSelect>(element, '#rejectEmptyCommitSelect').bindValue =
configInputObj.reject_empty_commit;
queryAndAssert<GrSelect>(element, '#unRegisteredCcSelect').bindValue =
configInputObj.enable_reviewer_by_email;
await element.updateComplete;
assert.isFalse(button.hasAttribute('disabled'));
assert.isTrue(
queryAndAssert<HTMLHeadingElement>(
element,
'#configurations'
).classList.contains('edited')
);
const formattedObj = element.formatRepoConfigForSave(element.repoConfig);
assert.deepEqual(formattedObj, configInputObj);
await element.handleSaveRepoConfig();
assert.isTrue(button.hasAttribute('disabled'));
assert.isFalse(
queryAndAssert<HTMLHeadingElement>(
element,
'#Title'
).classList.contains('edited')
);
assert.isTrue(
saveStub.lastCall.calledWithExactly(REPO as RepoName, configInputObj)
);
});
});
});