text: /**
   * @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('_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();
      });
    });
  });
  
  