/** * @license * Copyright (C) 2016 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-related-changes-list.js'; import {GerritNav} from '../../core/gr-navigation/gr-navigation.js'; import {getPluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader.js'; import {_testOnly_initGerritPluginApi} from '../../shared/gr-js-api-interface/gr-gerrit.js'; import {resetPlugins} from '../../../test/test-utils.js'; const pluginApi = _testOnly_initGerritPluginApi(); const basicFixture = fixtureFromElement('gr-related-changes-list'); suite('gr-related-changes-list tests', () => { let element; setup(() => { element = basicFixture.instantiate(); }); test('connected revisions', () => { const change = { revisions: { 'e3c6d60783bfdec9ebae7dcfec4662360433449e': { _number: 1, }, '26e5e4c9c7ae31cbd876271cca281ce22b413997': { _number: 2, }, 'bf7884d695296ca0c91702ba3e2bc8df0f69a907': { _number: 7, }, 'b5fc49f2e67d1889d5275cac04ad3648f2ec7fe3': { _number: 5, }, 'd6bcee67570859ccb684873a85cf50b1f0e96fda': { _number: 6, }, 'cc960918a7f90388f4a9e05753d0f7b90ad44546': { _number: 3, }, '9e593f6dcc2c0785a2ad2c895a34ad2aa9a0d8b6': { _number: 4, }, }, }; let patchNum = 7; let relatedChanges = [ { commit: { commit: '2cebeedfb1e80f4b872d0a13ade529e70652c0c8', parents: [ { commit: '87ed20b241576b620bbaa3dfd47715ce6782b7dd', }, ], }, }, { commit: { commit: '87ed20b241576b620bbaa3dfd47715ce6782b7dd', parents: [ { commit: '6c71f9e86ba955a7e01e2088bce0050a90eb9fbb', }, ], }, }, { commit: { commit: '6c71f9e86ba955a7e01e2088bce0050a90eb9fbb', parents: [ { commit: 'b0ccb183494a8e340b8725a2dc553967d61e6dae', }, ], }, }, { commit: { commit: 'b0ccb183494a8e340b8725a2dc553967d61e6dae', parents: [ { commit: 'bf7884d695296ca0c91702ba3e2bc8df0f69a907', }, ], }, }, { commit: { commit: 'bf7884d695296ca0c91702ba3e2bc8df0f69a907', parents: [ { commit: '613bc4f81741a559c6667ac08d71dcc3348f73ce', }, ], }, }, { commit: { commit: '613bc4f81741a559c6667ac08d71dcc3348f73ce', parents: [ { commit: '455ed9cd27a16bf6991f04dcc57ef575dc4d5e75', }, ], }, }, ]; let connectedChanges = element._computeConnectedRevisions(change, patchNum, relatedChanges); assert.deepEqual(connectedChanges, [ '613bc4f81741a559c6667ac08d71dcc3348f73ce', 'bf7884d695296ca0c91702ba3e2bc8df0f69a907', 'bf7884d695296ca0c91702ba3e2bc8df0f69a907', 'b0ccb183494a8e340b8725a2dc553967d61e6dae', '6c71f9e86ba955a7e01e2088bce0050a90eb9fbb', '87ed20b241576b620bbaa3dfd47715ce6782b7dd', '2cebeedfb1e80f4b872d0a13ade529e70652c0c8', ]); patchNum = 4; relatedChanges = [ { commit: { commit: '2cebeedfb1e80f4b872d0a13ade529e70652c0c8', parents: [ { commit: '87ed20b241576b620bbaa3dfd47715ce6782b7dd', }, ], }, }, { commit: { commit: '87ed20b241576b620bbaa3dfd47715ce6782b7dd', parents: [ { commit: '6c71f9e86ba955a7e01e2088bce0050a90eb9fbb', }, ], }, }, { commit: { commit: '6c71f9e86ba955a7e01e2088bce0050a90eb9fbb', parents: [ { commit: 'b0ccb183494a8e340b8725a2dc553967d61e6dae', }, ], }, }, { commit: { commit: 'a3e5d9d4902b915a39e2efba5577211b9b3ebe7b', parents: [ { commit: '9e593f6dcc2c0785a2ad2c895a34ad2aa9a0d8b6', }, ], }, }, { commit: { commit: '9e593f6dcc2c0785a2ad2c895a34ad2aa9a0d8b6', parents: [ { commit: 'af815dac54318826b7f1fa468acc76349ffc588e', }, ], }, }, { commit: { commit: 'af815dac54318826b7f1fa468acc76349ffc588e', parents: [ { commit: '58f76e406e24cb8b0f5d64c7f5ac1e8616d0a22c', }, ], }, }, ]; connectedChanges = element._computeConnectedRevisions(change, patchNum, relatedChanges); assert.deepEqual(connectedChanges, [ 'af815dac54318826b7f1fa468acc76349ffc588e', '9e593f6dcc2c0785a2ad2c895a34ad2aa9a0d8b6', '9e593f6dcc2c0785a2ad2c895a34ad2aa9a0d8b6', 'a3e5d9d4902b915a39e2efba5577211b9b3ebe7b', ]); }); test('_computeChangeContainerClass', () => { const change1 = {change_id: 123, _number: 0}; const change2 = {change_id: 456, _change_number: 1}; const change3 = {change_id: 123, _number: 2}; assert.notEqual(element._computeChangeContainerClass( change1, change1).indexOf('thisChange'), -1); assert.equal(element._computeChangeContainerClass( change1, change2).indexOf('thisChange'), -1); assert.equal(element._computeChangeContainerClass( change1, change3).indexOf('thisChange'), -1); }); test('_changesEqual', () => { const change1 = {change_id: 123, _number: 0}; const change2 = {change_id: 456, _number: 1}; const change3 = {change_id: 123, _number: 2}; const change4 = {change_id: 123, _change_number: 1}; assert.isTrue(element._changesEqual(change1, change1)); assert.isFalse(element._changesEqual(change1, change2)); assert.isFalse(element._changesEqual(change1, change3)); assert.isTrue(element._changesEqual(change2, change4)); }); test('_getChangeNumber', () => { const change1 = {change_id: 123, _number: 0}; const change2 = {change_id: 456, _change_number: 1}; assert.equal(element._getChangeNumber(change1), 0); assert.equal(element._getChangeNumber(change2), 1); }); test('event for section loaded fires for each section ', () => { const loadedStub = sinon.stub(); element.patchNum = 7; element.change = { change_id: 123, status: 'NEW', }; element.mergeable = true; element.addEventListener('new-section-loaded', loadedStub); sinon.stub(element, '_getRelatedChanges') .returns(Promise.resolve({changes: []})); sinon.stub(element, '_getSubmittedTogether') .returns(Promise.resolve()); sinon.stub(element, '_getCherryPicks') .returns(Promise.resolve()); sinon.stub(element, '_getConflicts') .returns(Promise.resolve()); return element.reload().then(() => { assert.equal(loadedStub.callCount, 4); }); }); suite('_getConflicts resolves undefined', () => { let element; setup(() => { element = basicFixture.instantiate(); sinon.stub(element, '_getRelatedChanges') .returns(Promise.resolve({changes: []})); sinon.stub(element, '_getSubmittedTogether') .returns(Promise.resolve()); sinon.stub(element, '_getCherryPicks') .returns(Promise.resolve()); sinon.stub(element, '_getConflicts') .returns(Promise.resolve()); }); test('_conflicts are an empty array', () => { element.patchNum = 7; element.change = { change_id: 123, status: 'NEW', }; element.mergeable = true; element.reload(); assert.equal(element._conflicts.length, 0); }); }); suite('get conflicts tests', () => { let element; let conflictsStub; setup(() => { element = basicFixture.instantiate(); sinon.stub(element, '_getRelatedChanges') .returns(Promise.resolve({changes: []})); sinon.stub(element, '_getSubmittedTogether') .returns(Promise.resolve()); sinon.stub(element, '_getCherryPicks') .returns(Promise.resolve()); conflictsStub = sinon.stub(element, '_getConflicts') .returns(Promise.resolve()); }); test('request conflicts if open and mergeable', () => { element.patchNum = 7; element.change = { change_id: 123, status: 'NEW', }; element.mergeable = true; element.reload(); assert.isTrue(conflictsStub.called); }); test('does not request conflicts if closed and mergeable', () => { element.patchNum = 7; element.change = { change_id: 123, status: 'MERGED', }; element.reload(); assert.isFalse(conflictsStub.called); }); test('does not request conflicts if open and not mergeable', () => { element.patchNum = 7; element.change = { change_id: 123, status: 'NEW', }; element.mergeable = false; element.reload(); assert.isFalse(conflictsStub.called); }); test('doesnt request conflicts if closed and not mergeable', () => { element.patchNum = 7; element.change = { change_id: 123, status: 'MERGED', }; element.mergeable = false; element.reload(); assert.isFalse(conflictsStub.called); }); }); test('_calculateHasParent', () => { const changeId = 123; const relatedChanges = []; assert.equal(element._calculateHasParent(changeId, relatedChanges), false); relatedChanges.push({change_id: 123}); assert.equal(element._calculateHasParent(changeId, relatedChanges), false); relatedChanges.push({change_id: 234}); assert.equal(element._calculateHasParent(changeId, relatedChanges), true); }); suite('hidden attribute and update event', () => { const changes = [{ project: 'foo/bar', change_id: 'Ideadbeef', commit: { commit: 'deadbeef', parents: [{commit: 'abc123'}], author: {}, subject: 'do that thing', }, _change_number: 12345, _revision_number: 1, _current_revision_number: 1, status: 'NEW', }]; test('clear and empties', () => { element._relatedResponse = {changes}; element._submittedTogether = {changes}; element._conflicts = changes; element._cherryPicks = changes; element._sameTopic = changes; element.hidden = false; element.clear(); assert.isTrue(element.hidden); assert.equal(element._relatedResponse.changes.length, 0); assert.equal(element._submittedTogether.changes.length, 0); assert.equal(element._conflicts.length, 0); assert.equal(element._cherryPicks.length, 0); assert.equal(element._sameTopic.length, 0); }); test('update fires', () => { const updateHandler = sinon.stub(); element.addEventListener('update', updateHandler); element._resultsChanged({}, {}, [], [], []); assert.isTrue(element.hidden); assert.isFalse(updateHandler.called); element._resultsChanged({}, {}, [], [], ['test']); assert.isFalse(element.hidden); assert.isTrue(updateHandler.called); updateHandler.reset(); element._resultsChanged( {}, {changes: [], non_visible_changes: 0}, [], [], []); assert.isTrue(element.hidden); assert.isFalse(updateHandler.called); element._resultsChanged( {}, {changes: ['test'], non_visible_changes: 0}, [], [], []); assert.isFalse(element.hidden); assert.isTrue(updateHandler.called); updateHandler.reset(); element._resultsChanged( {}, {changes: [], non_visible_changes: 1}, [], [], []); assert.isFalse(element.hidden); assert.isTrue(updateHandler.called); }); suite('hiding and unhiding', () => { test('related response', () => { assert.isTrue(element.hidden); element._resultsChanged({changes}, {}, [], [], []); assert.isFalse(element.hidden); }); test('submitted together', () => { assert.isTrue(element.hidden); element._resultsChanged({}, {changes}, [], [], []); assert.isFalse(element.hidden); }); test('conflicts', () => { assert.isTrue(element.hidden); element._resultsChanged({}, {}, changes, [], []); assert.isFalse(element.hidden); }); test('cherrypicks', () => { assert.isTrue(element.hidden); element._resultsChanged({}, {}, [], changes, []); assert.isFalse(element.hidden); }); test('same topic', () => { assert.isTrue(element.hidden); element._resultsChanged({}, {}, [], [], changes); assert.isFalse(element.hidden); }); }); }); test('_computeChangeURL uses GerritNav', () => { const getUrlStub = sinon.stub(GerritNav, 'getUrlForChangeById'); element._computeChangeURL(123, 'abc/def', 12); assert.isTrue(getUrlStub.called); }); suite('submitted together changes', () => { const change = { project: 'foo/bar', change_id: 'Ideadbeef', commit: { commit: 'deadbeef', parents: [{commit: 'abc123'}], author: {}, subject: 'do that thing', }, _change_number: 12345, _revision_number: 1, _current_revision_number: 1, status: 'NEW', }; test('_computeSubmittedTogetherClass', () => { assert.strictEqual( element._computeSubmittedTogetherClass(undefined), 'hidden'); assert.strictEqual( element._computeSubmittedTogetherClass({changes: []}), 'hidden'); assert.strictEqual( element._computeSubmittedTogetherClass({changes: [{}]}), ''); assert.strictEqual( element._computeSubmittedTogetherClass({ changes: [], non_visible_changes: 0, }), 'hidden'); assert.strictEqual( element._computeSubmittedTogetherClass({ changes: [], non_visible_changes: 1, }), ''); assert.strictEqual( element._computeSubmittedTogetherClass({ changes: [{}], non_visible_changes: 1, }), ''); }); test('no submitted together changes', () => { flushAsynchronousOperations(); assert.include(element.$.submittedTogether.className, 'hidden'); }); test('no non-visible submitted together changes', () => { element._submittedTogether = {changes: [change]}; flushAsynchronousOperations(); assert.notInclude(element.$.submittedTogether.className, 'hidden'); assert.isNull(element.shadowRoot .querySelector('.note')); }); test('no visible submitted together changes', () => { // Technically this should never happen, but worth asserting the logic. element._submittedTogether = {changes: [], non_visible_changes: 1}; flushAsynchronousOperations(); assert.notInclude(element.$.submittedTogether.className, 'hidden'); assert.isNotNull(element.shadowRoot .querySelector('.note')); assert.strictEqual( element.shadowRoot .querySelector('.note').innerText.trim(), '(+ 1 non-visible change)'); }); test('visible and non-visible submitted together changes', () => { element._submittedTogether = {changes: [change], non_visible_changes: 2}; flushAsynchronousOperations(); assert.notInclude(element.$.submittedTogether.className, 'hidden'); assert.isNotNull(element.shadowRoot .querySelector('.note')); assert.strictEqual( element.shadowRoot .querySelector('.note').innerText.trim(), '(+ 2 non-visible changes)'); }); }); }); suite('gr-related-changes-list plugin tests', () => { let element; setup(() => { resetPlugins(); element = basicFixture.instantiate(); }); teardown(() => { resetPlugins(); }); test('endpoint params', done => { element.change = {labels: {}}; let hookEl; let plugin; pluginApi.install( p => { plugin = p; plugin.hook('related-changes-section').getLastAttached() .then(el => hookEl = el); }, '0.1', 'http://some/plugins/url1.html'); getPluginLoader().loadPlugins([]); flush(() => { assert.strictEqual(hookEl.plugin, plugin); assert.strictEqual(hookEl.change, element.change); done(); }); }); test('hiding and unhiding', done => { element.change = {labels: {}}; let hookEl; let plugin; // No changes, and no plugin. The element is still hidden. element._resultsChanged({}, {}, [], [], []); assert.isTrue(element.hidden); pluginApi.install( p => { plugin = p; plugin.hook('related-changes-section').getLastAttached() .then(el => hookEl = el); }, '0.1', 'http://some/plugins/url2.html'); getPluginLoader().loadPlugins([]); flush(() => { // No changes, and plugin without hidden attribute. So it's visible. element._resultsChanged({}, {}, [], [], []); assert.isFalse(element.hidden); // No changes, but plugin with true hidden attribute. So it's invisible. hookEl.hidden = true; element._resultsChanged({}, {}, [], [], []); assert.isTrue(element.hidden); // No changes, and plugin with false hidden attribute. So it's visible. hookEl.hidden = false; element._resultsChanged({}, {}, [], [], []); assert.isFalse(element.hidden); // Hiding triggered by plugin itself hookEl.hidden = true; hookEl.dispatchEvent(new CustomEvent('new-section-loaded', { composed: true, bubbles: true, })); assert.isTrue(element.hidden); // Unhiding triggered by plugin itself hookEl.hidden = false; hookEl.dispatchEvent(new CustomEvent('new-section-loaded', { composed: true, bubbles: true, })); assert.isFalse(element.hidden); // Hiding plugin keeps list visible, if there are changes hookEl.hidden = false; element._sameTopic = ['test']; element._resultsChanged({}, {}, [], [], ['test']); assert.isFalse(element.hidden); hookEl.hidden = true; hookEl.dispatchEvent(new CustomEvent('new-section-loaded', { composed: true, bubbles: true, })); assert.isFalse(element.hidden); done(); }); }); });