
This is a partial roll-forward of c/106190 This replaces all loads of iron-test-helpers with a load of a file that wraps it, and adds that file to test files that do not currently load iron-test-helpers. A future CL will also install polymer-resin via common-test-helpers.html. I tested by running $ WCT_ARGS="-l chrome" ./polygerrit-ui/app/run_test.sh Change-Id: Ifb3cd2c8db13d724f57e56e7e78045470d103a43
764 lines
24 KiB
HTML
764 lines
24 KiB
HTML
<!DOCTYPE html>
|
|
<!--
|
|
Copyright (C) 2015 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-reply-dialog</title>
|
|
|
|
<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-reply-dialog.html">
|
|
|
|
<script>void(0);</script>
|
|
|
|
<test-fixture id="basic">
|
|
<template>
|
|
<gr-reply-dialog></gr-reply-dialog>
|
|
</template>
|
|
</test-fixture>
|
|
|
|
<script>
|
|
suite('gr-reply-dialog tests', () => {
|
|
let element;
|
|
let changeNum;
|
|
let patchNum;
|
|
|
|
let sandbox;
|
|
let getDraftCommentStub;
|
|
let setDraftCommentStub;
|
|
let eraseDraftCommentStub;
|
|
|
|
let lastId = 0;
|
|
const makeAccount = function() { return {_account_id: lastId++}; };
|
|
const makeGroup = function() { return {id: lastId++}; };
|
|
|
|
setup(() => {
|
|
sandbox = sinon.sandbox.create();
|
|
|
|
changeNum = 42;
|
|
patchNum = 1;
|
|
|
|
stub('gr-rest-api-interface', {
|
|
getConfig() { return Promise.resolve({}); },
|
|
getAccount() { return Promise.resolve({}); },
|
|
});
|
|
|
|
element = fixture('basic');
|
|
element.change = {
|
|
_number: changeNum,
|
|
labels: {
|
|
'Verified': {
|
|
values: {
|
|
'-1': 'Fails',
|
|
' 0': 'No score',
|
|
'+1': 'Verified',
|
|
},
|
|
default_value: 0,
|
|
},
|
|
'Code-Review': {
|
|
values: {
|
|
'-2': 'Do not submit',
|
|
'-1': 'I would prefer that you didn\'t submit this',
|
|
' 0': 'No score',
|
|
'+1': 'Looks good to me, but someone else must approve',
|
|
'+2': 'Looks good to me, approved',
|
|
},
|
|
default_value: 0,
|
|
},
|
|
},
|
|
};
|
|
element.patchNum = patchNum;
|
|
element.permittedLabels = {
|
|
'Code-Review': [
|
|
'-1',
|
|
' 0',
|
|
'+1',
|
|
],
|
|
'Verified': [
|
|
'-1',
|
|
' 0',
|
|
'+1',
|
|
],
|
|
};
|
|
element.serverConfig = {};
|
|
|
|
getDraftCommentStub = sandbox.stub(element.$.storage, 'getDraftComment');
|
|
setDraftCommentStub = sandbox.stub(element.$.storage, 'setDraftComment');
|
|
eraseDraftCommentStub = sandbox.stub(element.$.storage,
|
|
'eraseDraftComment');
|
|
|
|
sandbox.stub(element, 'fetchIsLatestKnown',
|
|
() => { return Promise.resolve(true); });
|
|
|
|
// Allow the elements created by dom-repeat to be stamped.
|
|
flushAsynchronousOperations();
|
|
});
|
|
|
|
teardown(() => {
|
|
sandbox.restore();
|
|
});
|
|
|
|
test('default to publishing drafts with reply', done => {
|
|
// Async tick is needed because iron-selector content is distributed and
|
|
// distributed content requires an observer to be set up.
|
|
// Note: Double flush seems to be needed in Safari. {@see Issue 4963}.
|
|
flush(() => {
|
|
flush(() => {
|
|
element.draft = 'I wholeheartedly disapprove';
|
|
|
|
sandbox.stub(element, '_saveReview', review => {
|
|
assert.deepEqual(review, {
|
|
drafts: 'PUBLISH_ALL_REVISIONS',
|
|
labels: {},
|
|
message: 'I wholeheartedly disapprove',
|
|
reviewers: [],
|
|
});
|
|
assert.isFalse(element.$.commentList.hidden);
|
|
done();
|
|
return Promise.resolve({ok: true});
|
|
});
|
|
|
|
// This is needed on non-Blink engines most likely due to the ways in
|
|
// which the dom-repeat elements are stamped.
|
|
flush(() => {
|
|
MockInteractions.tap(element.$$('.send'));
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
test('keep drafts with reply', done => {
|
|
MockInteractions.tap(element.$$('#includeComments'));
|
|
assert.equal(element._includeComments, false);
|
|
|
|
// Async tick is needed because iron-selector content is distributed and
|
|
// distributed content requires an observer to be set up.
|
|
// Note: Double flush seems to be needed in Safari. {@see Issue 4963}.
|
|
flush(() => {
|
|
flush(() => {
|
|
element.draft = 'I wholeheartedly disapprove';
|
|
|
|
sandbox.stub(element, '_saveReview', review => {
|
|
assert.deepEqual(review, {
|
|
drafts: 'KEEP',
|
|
labels: {},
|
|
message: 'I wholeheartedly disapprove',
|
|
reviewers: [],
|
|
});
|
|
assert.isTrue(element.$.commentList.hidden);
|
|
done();
|
|
return Promise.resolve({ok: true});
|
|
});
|
|
|
|
// This is needed on non-Blink engines most likely due to the ways in
|
|
// which the dom-repeat elements are stamped.
|
|
flush(() => {
|
|
MockInteractions.tap(element.$$('.send'));
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
test('label picker', done => {
|
|
element.draft = 'I wholeheartedly disapprove';
|
|
sandbox.stub(element, '_saveReview', review => {
|
|
assert.deepEqual(review, {
|
|
drafts: 'PUBLISH_ALL_REVISIONS',
|
|
labels: {
|
|
'Code-Review': -1,
|
|
'Verified': -1,
|
|
},
|
|
message: 'I wholeheartedly disapprove',
|
|
reviewers: [],
|
|
});
|
|
return Promise.resolve({ok: true});
|
|
});
|
|
|
|
sandbox.stub(element.$.labelScores, 'getLabelValues', () => {
|
|
return {
|
|
'Code-Review': -1,
|
|
'Verified': -1,
|
|
};
|
|
});
|
|
|
|
element.addEventListener('send', () => {
|
|
assert.isFalse(element.disabled,
|
|
'Element should be enabled when done sending reply.');
|
|
assert.equal(element.draft.length, 0);
|
|
done();
|
|
});
|
|
|
|
// This is needed on non-Blink engines most likely due to the ways in
|
|
// which the dom-repeat elements are stamped.
|
|
flush(() => {
|
|
MockInteractions.tap(element.$$('.send'));
|
|
assert.isTrue(element.disabled);
|
|
});
|
|
});
|
|
|
|
test('getlabelValue returns value', done => {
|
|
flush(() => {
|
|
element.$$('gr-label-scores').$$(`gr-label-score-row[name="Verified"]`)
|
|
.setSelectedValue(-1);
|
|
assert.equal('-1', element.getLabelValue('Verified'));
|
|
done();
|
|
});
|
|
});
|
|
|
|
test('getlabelValue when no score is selected', done => {
|
|
flush(() => {
|
|
element.$$('gr-label-scores').$$(`gr-label-score-row[name="Code-Review"]`)
|
|
.setSelectedValue(-1);
|
|
assert.isNull(element.getLabelValue('Verified'));
|
|
done();
|
|
});
|
|
});
|
|
|
|
test('setlabelValue', () => {
|
|
element._account = {_account_id: 1};
|
|
flushAsynchronousOperations();
|
|
const label = 'Verified';
|
|
const value = '+1';
|
|
element.setLabelValue(label, value);
|
|
flushAsynchronousOperations();
|
|
const labels = element.$.labelScores.getLabelValues();
|
|
assert.deepEqual(labels, {Verified: 1});
|
|
});
|
|
|
|
function getActiveElement() {
|
|
return Polymer.IronOverlayManager.deepActiveElement;
|
|
}
|
|
|
|
function isVisible(el) {
|
|
assert.ok(el);
|
|
return getComputedStyle(el).getPropertyValue('display') != 'none';
|
|
}
|
|
|
|
function overlayObserver(mode) {
|
|
return new Promise(resolve => {
|
|
function listener() {
|
|
element.removeEventListener('iron-overlay-' + mode, listener);
|
|
resolve();
|
|
}
|
|
element.addEventListener('iron-overlay-' + mode, listener);
|
|
});
|
|
}
|
|
|
|
function testConfirmationDialog(done, cc) {
|
|
const yesButton =
|
|
element.$$('.reviewerConfirmationButtons gr-button:first-child');
|
|
const noButton =
|
|
element.$$('.reviewerConfirmationButtons gr-button:last-child');
|
|
|
|
element.serverConfig = {note_db_enabled: true};
|
|
element._ccPendingConfirmation = null;
|
|
element._reviewerPendingConfirmation = null;
|
|
flushAsynchronousOperations();
|
|
assert.isFalse(isVisible(element.$.reviewerConfirmationOverlay));
|
|
|
|
// Cause the confirmation dialog to display.
|
|
let observer = overlayObserver('opened');
|
|
const group = {
|
|
id: 'id',
|
|
name: 'name',
|
|
};
|
|
if (cc) {
|
|
element._ccPendingConfirmation = {
|
|
group,
|
|
count: 10,
|
|
};
|
|
} else {
|
|
element._reviewerPendingConfirmation = {
|
|
group,
|
|
count: 10,
|
|
};
|
|
}
|
|
flushAsynchronousOperations();
|
|
|
|
if (cc) {
|
|
assert.deepEqual(
|
|
element._ccPendingConfirmation,
|
|
element._pendingConfirmationDetails);
|
|
} else {
|
|
assert.deepEqual(
|
|
element._reviewerPendingConfirmation,
|
|
element._pendingConfirmationDetails);
|
|
}
|
|
|
|
observer.then(() => {
|
|
assert.isTrue(isVisible(element.$.reviewerConfirmationOverlay));
|
|
observer = overlayObserver('closed');
|
|
const expected = 'Group name has 10 members';
|
|
assert.notEqual(
|
|
element.$.reviewerConfirmationOverlay.innerText.indexOf(expected),
|
|
-1);
|
|
MockInteractions.tap(noButton); // close the overlay
|
|
return observer;
|
|
}).then(() => {
|
|
assert.isFalse(isVisible(element.$.reviewerConfirmationOverlay));
|
|
|
|
// We should be focused on account entry input.
|
|
assert.equal(getActiveElement().id, 'input');
|
|
|
|
// No reviewer/CC should have been added.
|
|
assert.equal(element.$$('#ccs').additions().length, 0);
|
|
assert.equal(element.$.reviewers.additions().length, 0);
|
|
|
|
// Reopen confirmation dialog.
|
|
observer = overlayObserver('opened');
|
|
if (cc) {
|
|
element._ccPendingConfirmation = {
|
|
group,
|
|
count: 10,
|
|
};
|
|
} else {
|
|
element._reviewerPendingConfirmation = {
|
|
group,
|
|
count: 10,
|
|
};
|
|
}
|
|
return observer;
|
|
}).then(() => {
|
|
assert.isTrue(isVisible(element.$.reviewerConfirmationOverlay));
|
|
observer = overlayObserver('closed');
|
|
MockInteractions.tap(yesButton); // Confirm the group.
|
|
return observer;
|
|
}).then(() => {
|
|
assert.isFalse(isVisible(element.$.reviewerConfirmationOverlay));
|
|
const additions = cc ?
|
|
element.$$('#ccs').additions() :
|
|
element.$.reviewers.additions();
|
|
assert.deepEqual(
|
|
additions,
|
|
[
|
|
{
|
|
group: {
|
|
id: 'id',
|
|
name: 'name',
|
|
confirmed: true,
|
|
_group: true,
|
|
_pendingAdd: true,
|
|
},
|
|
},
|
|
]);
|
|
|
|
// We should be focused on account entry input.
|
|
assert.equal(getActiveElement().id, 'input');
|
|
}).then(done);
|
|
}
|
|
|
|
test('cc confirmation', done => {
|
|
testConfirmationDialog(done, true);
|
|
});
|
|
|
|
test('reviewer confirmation', done => {
|
|
testConfirmationDialog(done, false);
|
|
});
|
|
|
|
test('_getStorageLocation', () => {
|
|
const actual = element._getStorageLocation();
|
|
assert.equal(actual.changeNum, changeNum);
|
|
assert.equal(actual.patchNum, '@change');
|
|
assert.equal(actual.path, '@change');
|
|
});
|
|
|
|
test('gets draft from storage on open', () => {
|
|
const storedDraft = 'hello world';
|
|
getDraftCommentStub.returns({message: storedDraft});
|
|
element.open();
|
|
assert.isTrue(getDraftCommentStub.called);
|
|
assert.equal(element.draft, storedDraft);
|
|
});
|
|
|
|
test('blank if no stored draft', () => {
|
|
getDraftCommentStub.returns(null);
|
|
element.open();
|
|
assert.isTrue(getDraftCommentStub.called);
|
|
assert.equal(element.draft, '');
|
|
});
|
|
|
|
test('updates stored draft on edits', () => {
|
|
const firstEdit = 'hello';
|
|
const location = element._getStorageLocation();
|
|
|
|
element.draft = firstEdit;
|
|
element.flushDebouncer('store');
|
|
|
|
assert.isTrue(setDraftCommentStub.calledWith(location, firstEdit));
|
|
|
|
element.draft = '';
|
|
element.flushDebouncer('store');
|
|
|
|
assert.isTrue(eraseDraftCommentStub.calledWith(location));
|
|
});
|
|
|
|
test('400 converts to human-readable server-error', done => {
|
|
sandbox.stub(window, 'fetch', () => {
|
|
const text = '....{"reviewers":{"id1":{"error":"first error"}},' +
|
|
'"ccs":{"id2":{"error":"second error"}}}';
|
|
return Promise.resolve({
|
|
ok: false,
|
|
status: 400,
|
|
text() { return Promise.resolve(text); },
|
|
});
|
|
});
|
|
|
|
element.addEventListener('server-error', event => {
|
|
if (event.target !== element) {
|
|
return;
|
|
}
|
|
event.detail.response.text().then(body => {
|
|
assert.equal(body, 'first error, second error');
|
|
done();
|
|
});
|
|
});
|
|
|
|
// Async tick is needed because iron-selector content is distributed and
|
|
// distributed content requires an observer to be set up.
|
|
flush(() => { element.send(); });
|
|
});
|
|
|
|
test('ccs are displayed if NoteDb is enabled', () => {
|
|
function hasCc() {
|
|
flushAsynchronousOperations();
|
|
return !!element.$$('#ccs');
|
|
}
|
|
|
|
element.serverConfig = {};
|
|
assert.isFalse(hasCc());
|
|
|
|
element.serverConfig = {note_db_enabled: true};
|
|
assert.isTrue(hasCc());
|
|
});
|
|
|
|
test('filterReviewerSuggestion', () => {
|
|
const owner = makeAccount();
|
|
const reviewer1 = makeAccount();
|
|
const reviewer2 = makeGroup();
|
|
const cc1 = makeAccount();
|
|
const cc2 = makeGroup();
|
|
let filter = element._filterReviewerSuggestionGenerator(false);
|
|
|
|
element._owner = owner;
|
|
element._reviewers = [reviewer1, reviewer2];
|
|
element._ccs = [cc1, cc2];
|
|
|
|
assert.isTrue(filter({account: makeAccount()}));
|
|
assert.isTrue(filter({group: makeGroup()}));
|
|
|
|
// Owner should be excluded.
|
|
assert.isFalse(filter({account: owner}));
|
|
|
|
// Existing and pending reviewers should be excluded when isCC = false.
|
|
assert.isFalse(filter({account: reviewer1}));
|
|
assert.isFalse(filter({group: reviewer2}));
|
|
|
|
filter = element._filterReviewerSuggestionGenerator(true);
|
|
|
|
// Existing and pending CCs should be excluded when isCC = true;.
|
|
assert.isFalse(filter({account: cc1}));
|
|
assert.isFalse(filter({group: cc2}));
|
|
});
|
|
|
|
test('_chooseFocusTarget', () => {
|
|
element._account = null;
|
|
assert.strictEqual(
|
|
element._chooseFocusTarget(), element.FocusTarget.BODY);
|
|
|
|
element._account = {_account_id: 1};
|
|
assert.strictEqual(
|
|
element._chooseFocusTarget(), element.FocusTarget.BODY);
|
|
|
|
element.change.owner = {_account_id: 2};
|
|
assert.strictEqual(
|
|
element._chooseFocusTarget(), element.FocusTarget.BODY);
|
|
|
|
element.change.owner._account_id = 1;
|
|
element.change._reviewers = null;
|
|
assert.strictEqual(
|
|
element._chooseFocusTarget(), element.FocusTarget.REVIEWERS);
|
|
|
|
element._reviewers = [];
|
|
assert.strictEqual(
|
|
element._chooseFocusTarget(), element.FocusTarget.REVIEWERS);
|
|
|
|
element._reviewers.push({});
|
|
assert.strictEqual(
|
|
element._chooseFocusTarget(), element.FocusTarget.BODY);
|
|
});
|
|
|
|
test('only send labels that have changed', done => {
|
|
flush(() => {
|
|
sandbox.stub(element, '_saveReview', review => {
|
|
assert.deepEqual(review.labels, {Verified: -1});
|
|
return Promise.resolve({ok: true});
|
|
});
|
|
|
|
element.addEventListener('send', () => {
|
|
done();
|
|
});
|
|
// Without wrapping this test in flush(), the below two calls to
|
|
// MockInteractions.tap() cause a race in some situations in shadow DOM.
|
|
// The send button can be tapped before the others, causing the test to
|
|
// fail.
|
|
|
|
element.$$('gr-label-scores').$$(
|
|
'gr-label-score-row[name="Verified"]').setSelectedValue(-1);
|
|
MockInteractions.tap(element.$$('.send'));
|
|
});
|
|
});
|
|
|
|
test('_processReviewerChange', () => {
|
|
const mockIndexSplices = function(toRemove) {
|
|
return [{
|
|
removed: [toRemove],
|
|
}];
|
|
};
|
|
|
|
element._processReviewerChange(
|
|
mockIndexSplices(makeAccount()), 'REVIEWER');
|
|
assert.equal(element._reviewersPendingRemove.REVIEWER.length, 1);
|
|
});
|
|
|
|
test('_purgeReviewersPendingRemove', () => {
|
|
const removeStub = sandbox.stub(element, '_removeAccount');
|
|
const mock = function() {
|
|
element._reviewersPendingRemove = {
|
|
test: [makeAccount()],
|
|
test2: [makeAccount(), makeAccount()],
|
|
};
|
|
};
|
|
const checkObjEmpty = function(obj) {
|
|
for (const prop in obj) {
|
|
if (obj.hasOwnProperty(prop) && obj[prop].length) { return false; }
|
|
}
|
|
return true;
|
|
};
|
|
mock();
|
|
element._purgeReviewersPendingRemove(true); // Cancel
|
|
assert.isFalse(removeStub.called);
|
|
assert.isTrue(checkObjEmpty(element._reviewersPendingRemove));
|
|
|
|
mock();
|
|
element._purgeReviewersPendingRemove(false); // Submit
|
|
assert.isTrue(removeStub.called);
|
|
assert.isTrue(checkObjEmpty(element._reviewersPendingRemove));
|
|
});
|
|
|
|
test('_removeAccount', done => {
|
|
sandbox.stub(element.$.restAPI, 'removeChangeReviewer')
|
|
.returns(Promise.resolve({ok: true}));
|
|
const arr = [makeAccount(), makeAccount()];
|
|
element.change.reviewers = {
|
|
REVIEWER: arr.slice(),
|
|
};
|
|
|
|
element._removeAccount(arr[1], 'REVIEWER').then(() => {
|
|
assert.equal(element.change.reviewers.REVIEWER.length, 1);
|
|
assert.deepEqual(element.change.reviewers.REVIEWER, arr.slice(0, 1));
|
|
done();
|
|
});
|
|
});
|
|
|
|
test('moving from cc to reviewer', () => {
|
|
element.serverConfig = {note_db_enabled: true};
|
|
element._reviewersPendingRemove = {
|
|
CC: [],
|
|
REVIEWER: [],
|
|
};
|
|
flushAsynchronousOperations();
|
|
|
|
const reviewer1 = makeAccount();
|
|
const reviewer2 = makeAccount();
|
|
const reviewer3 = makeAccount();
|
|
const cc1 = makeAccount();
|
|
const cc2 = makeAccount();
|
|
const cc3 = makeAccount();
|
|
const cc4 = makeAccount();
|
|
element._reviewers = [reviewer1, reviewer2, reviewer3];
|
|
element._ccs = [cc1, cc2, cc3, cc4];
|
|
element.push('_reviewers', cc1);
|
|
flushAsynchronousOperations();
|
|
|
|
assert.deepEqual(element._reviewers,
|
|
[reviewer1, reviewer2, reviewer3, cc1]);
|
|
assert.deepEqual(element._ccs, [cc2, cc3, cc4]);
|
|
assert.deepEqual(element._reviewersPendingRemove.CC, [cc1]);
|
|
|
|
element.push('_reviewers', cc4, cc3);
|
|
flushAsynchronousOperations();
|
|
|
|
assert.deepEqual(element._reviewers,
|
|
[reviewer1, reviewer2, reviewer3, cc1, cc4, cc3]);
|
|
assert.deepEqual(element._ccs, [cc2]);
|
|
assert.deepEqual(element._reviewersPendingRemove.CC, [cc1, cc4, cc3]);
|
|
});
|
|
|
|
test('migrate reviewers between states', done => {
|
|
element.serverConfig = {note_db_enabled: true};
|
|
element._reviewersPendingRemove = {
|
|
CC: [],
|
|
REVIEWER: [],
|
|
};
|
|
flushAsynchronousOperations();
|
|
const reviewers = element.$.reviewers;
|
|
const ccs = element.$$('#ccs');
|
|
const reviewer1 = makeAccount();
|
|
const reviewer2 = makeAccount();
|
|
const cc1 = makeAccount();
|
|
const cc2 = makeAccount();
|
|
const cc3 = makeAccount();
|
|
element._reviewers = [reviewer1, reviewer2];
|
|
element._ccs = [cc1, cc2, cc3];
|
|
|
|
const mutations = [];
|
|
|
|
sandbox.stub(element, '_saveReview', review => {
|
|
mutations.push(...review.reviewers);
|
|
return Promise.resolve({ok: true});
|
|
});
|
|
|
|
sandbox.stub(element, '_removeAccount', (account, type) => {
|
|
mutations.push({state: 'REMOVED', account});
|
|
return Promise.resolve();
|
|
});
|
|
|
|
// Remove and add to other field.
|
|
reviewers.fire('remove', {account: reviewer1});
|
|
ccs.$.entry.fire('add', {value: {account: reviewer1}});
|
|
ccs.fire('remove', {account: cc1});
|
|
ccs.fire('remove', {account: cc3});
|
|
reviewers.$.entry.fire('add', {value: {account: cc1}});
|
|
|
|
// Add to other field without removing from former field.
|
|
// (Currently not possible in UI, but this is a good consistency check).
|
|
reviewers.$.entry.fire('add', {value: {account: cc2}});
|
|
ccs.$.entry.fire('add', {value: {account: reviewer2}});
|
|
const mapReviewer = function(reviewer, opt_state) {
|
|
const result = {reviewer: reviewer._account_id, confirmed: undefined};
|
|
if (opt_state) {
|
|
result.state = opt_state;
|
|
}
|
|
return result;
|
|
};
|
|
|
|
// Send and purge and verify moves, delete cc3.
|
|
element.send()
|
|
.then(keepReviewers =>
|
|
element._purgeReviewersPendingRemove(false, keepReviewers))
|
|
.then(() => {
|
|
assert.deepEqual(
|
|
mutations, [
|
|
mapReviewer(cc1),
|
|
mapReviewer(cc2),
|
|
mapReviewer(reviewer1, 'CC'),
|
|
mapReviewer(reviewer2, 'CC'),
|
|
{account: cc3, state: 'REMOVED'},
|
|
]);
|
|
done();
|
|
});
|
|
});
|
|
|
|
test('emits cancel on esc key', () => {
|
|
const cancelHandler = sandbox.spy();
|
|
element.addEventListener('cancel', cancelHandler);
|
|
MockInteractions.pressAndReleaseKeyOn(element, 27, null, 'esc');
|
|
flushAsynchronousOperations();
|
|
|
|
assert.isTrue(cancelHandler.called);
|
|
});
|
|
|
|
test('_computeMessagePlaceholder', () => {
|
|
assert.equal(
|
|
element._computeMessagePlaceholder(false),
|
|
'Say something nice...');
|
|
assert.equal(
|
|
element._computeMessagePlaceholder(true),
|
|
'Add a note for your reviewers...');
|
|
});
|
|
|
|
test('_computeSendButtonLabel', () => {
|
|
assert.equal(
|
|
element._computeSendButtonLabel(false),
|
|
'Send');
|
|
assert.equal(
|
|
element._computeSendButtonLabel(true),
|
|
'Start review');
|
|
});
|
|
|
|
test('_handle400Error reviewrs and CCs', done => {
|
|
const error1 = 'error 1';
|
|
const error2 = 'error 2';
|
|
const error3 = 'error 3';
|
|
const response = {
|
|
status: 400,
|
|
text() {
|
|
return Promise.resolve(')]}\'' + JSON.stringify({
|
|
reviewers: {
|
|
username1: {
|
|
input: 'user 1',
|
|
error: error1,
|
|
},
|
|
username2: {
|
|
input: 'user 2',
|
|
error: error2,
|
|
},
|
|
},
|
|
ccs: {
|
|
username3: {
|
|
input: 'user 3',
|
|
error: error3,
|
|
},
|
|
},
|
|
}));
|
|
},
|
|
};
|
|
element.addEventListener('server-error', e => {
|
|
e.detail.response.text().then(text => {
|
|
assert.equal(text, [error1, error2, error3].join(', '));
|
|
done();
|
|
});
|
|
});
|
|
element._handle400Error(response);
|
|
});
|
|
|
|
test('_handle400Error CCs only', done => {
|
|
const error1 = 'error 1';
|
|
const response = {
|
|
status: 400,
|
|
text() {
|
|
return Promise.resolve(')]}\'' + JSON.stringify({
|
|
ccs: {
|
|
username1: {
|
|
input: 'user 1',
|
|
error: error1,
|
|
},
|
|
},
|
|
}));
|
|
},
|
|
};
|
|
element.addEventListener('server-error', e => {
|
|
e.detail.response.text().then(text => {
|
|
assert.equal(text, error1);
|
|
done();
|
|
});
|
|
});
|
|
element._handle400Error(response);
|
|
});
|
|
});
|
|
</script>
|