Convert polygerrit to es6-modules
This change replace all HTML imports with es6-modules. The only exceptions are:
* gr-app.html file, which can be deleted only after updating the
gerrit/httpd/raw/PolyGerritIndexHtml.soy file.
* dark-theme.html which is loaded via importHref. Must be updated manually
later in a separate change.
This change was produced automatically by ./es6-modules-converter.sh script.
No manual changes were made.
Change-Id: I0c447dd8c05757741e2c940720652d01d9fb7d67
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.html b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.html
index 26bcbf2..4dc0e9b3 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.html
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.html
@@ -19,18 +19,24 @@
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
<title>gr-change-view</title>
-<script src="/bower_components/webcomponentsjs/custom-elements-es5-adapter.js"></script>
+<script src="/node_modules/@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js"></script>
-<script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
-<script src="/bower_components/web-component-tester/browser.js"></script>
-<script src="../../../test/test-pre-setup.js"></script>
-<link rel="import" href="../../../test/common-test-setup.html"/>
-<script src="/bower_components/page/page.js"></script>
+<script src="/node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js"></script>
+<script src="/components/wct-browser-legacy/browser.js"></script>
+<script type="module" src="../../../test/test-pre-setup.js"></script>
+<script type="module" src="../../../test/common-test-setup.js"></script>
+<script src="/node_modules/page/page.js"></script>
-<link rel="import" href="../../edit/gr-edit-constants.html">
-<link rel="import" href="gr-change-view.html">
+<script type="module" src="../../edit/gr-edit-constants.js"></script>
+<script type="module" src="./gr-change-view.js"></script>
-<script>void(0);</script>
+<script type="module">
+import '../../../test/test-pre-setup.js';
+import '../../../test/common-test-setup.js';
+import '../../edit/gr-edit-constants.js';
+import './gr-change-view.js';
+void(0);
+</script>
<test-fixture id="basic">
<template>
@@ -44,887 +50,667 @@
</template>
</test-fixture>
-<script>
- suite('gr-change-view tests', async () => {
- await readyToTest();
- const kb = window.Gerrit.KeyboardShortcutBinder;
- kb.bindShortcut(kb.Shortcut.SEND_REPLY, 'ctrl+enter');
- kb.bindShortcut(kb.Shortcut.REFRESH_CHANGE, 'shift+r');
- kb.bindShortcut(kb.Shortcut.OPEN_REPLY_DIALOG, 'a');
- kb.bindShortcut(kb.Shortcut.OPEN_DOWNLOAD_DIALOG, 'd');
- kb.bindShortcut(kb.Shortcut.TOGGLE_DIFF_MODE, 'm');
- kb.bindShortcut(kb.Shortcut.TOGGLE_CHANGE_STAR, 's');
- kb.bindShortcut(kb.Shortcut.UP_TO_DASHBOARD, 'u');
- kb.bindShortcut(kb.Shortcut.EXPAND_ALL_MESSAGES, 'x');
- kb.bindShortcut(kb.Shortcut.COLLAPSE_ALL_MESSAGES, 'z');
- kb.bindShortcut(kb.Shortcut.OPEN_DIFF_PREFS, ',');
- kb.bindShortcut(kb.Shortcut.EDIT_TOPIC, 't');
+<script type="module">
+import '../../../test/test-pre-setup.js';
+import '../../../test/common-test-setup.js';
+import '../../edit/gr-edit-constants.js';
+import './gr-change-view.js';
+import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
+suite('gr-change-view tests', () => {
+ const kb = window.Gerrit.KeyboardShortcutBinder;
+ kb.bindShortcut(kb.Shortcut.SEND_REPLY, 'ctrl+enter');
+ kb.bindShortcut(kb.Shortcut.REFRESH_CHANGE, 'shift+r');
+ kb.bindShortcut(kb.Shortcut.OPEN_REPLY_DIALOG, 'a');
+ kb.bindShortcut(kb.Shortcut.OPEN_DOWNLOAD_DIALOG, 'd');
+ kb.bindShortcut(kb.Shortcut.TOGGLE_DIFF_MODE, 'm');
+ kb.bindShortcut(kb.Shortcut.TOGGLE_CHANGE_STAR, 's');
+ kb.bindShortcut(kb.Shortcut.UP_TO_DASHBOARD, 'u');
+ kb.bindShortcut(kb.Shortcut.EXPAND_ALL_MESSAGES, 'x');
+ kb.bindShortcut(kb.Shortcut.COLLAPSE_ALL_MESSAGES, 'z');
+ kb.bindShortcut(kb.Shortcut.OPEN_DIFF_PREFS, ',');
+ kb.bindShortcut(kb.Shortcut.EDIT_TOPIC, 't');
- let element;
- let sandbox;
- let navigateToChangeStub;
- const TEST_SCROLL_TOP_PX = 100;
+ let element;
+ let sandbox;
+ let navigateToChangeStub;
+ const TEST_SCROLL_TOP_PX = 100;
- const CommentTabs = {
- CHANGE_LOG: 0,
- COMMENT_THREADS: 1,
+ const CommentTabs = {
+ CHANGE_LOG: 0,
+ COMMENT_THREADS: 1,
+ };
+ const ROBOT_COMMENTS_LIMIT = 10;
+
+ const THREADS = [
+ {
+ comments: [
+ {
+ __path: '/COMMIT_MSG',
+ author: {
+ _account_id: 1000000,
+ name: 'user',
+ username: 'user',
+ },
+ patch_set: 2,
+ robot_id: 'rb1',
+ id: 'ecf9fa_fe1a5f62',
+ line: 5,
+ updated: '2018-02-08 18:49:18.000000000',
+ message: 'test',
+ unresolved: true,
+ },
+ {
+ __path: '/COMMIT_MSG',
+ author: {
+ _account_id: 1000000,
+ name: 'user',
+ username: 'user',
+ },
+ patch_set: 4,
+ id: 'ecf0b9fa_fe1a5f62',
+ line: 5,
+ updated: '2018-02-08 18:49:18.000000000',
+ message: 'test',
+ unresolved: true,
+ },
+ {
+ id: '503008e2_0ab203ee',
+ path: '/COMMIT_MSG',
+ line: 5,
+ in_reply_to: 'ecf0b9fa_fe1a5f62',
+ updated: '2018-02-13 22:48:48.018000000',
+ message: 'draft',
+ unresolved: false,
+ __draft: true,
+ __draftID: '0.m683trwff68',
+ __editing: false,
+ patch_set: '2',
+ },
+ ],
+ patchNum: 4,
+ path: '/COMMIT_MSG',
+ line: 5,
+ rootId: 'ecf0b9fa_fe1a5f62',
+ start_datetime: '2018-02-08 18:49:18.000000000',
+ },
+ {
+ comments: [
+ {
+ __path: '/COMMIT_MSG',
+ author: {
+ _account_id: 1000000,
+ name: 'user',
+ username: 'user',
+ },
+ patch_set: 3,
+ id: 'ecf0b9fa_fe5f62',
+ robot_id: 'rb2',
+ line: 5,
+ updated: '2018-02-08 18:49:18.000000000',
+ message: 'test',
+ unresolved: true,
+ },
+ {
+ __path: 'test.txt',
+ author: {
+ _account_id: 1000000,
+ name: 'user',
+ username: 'user',
+ },
+ patch_set: 3,
+ id: '09a9fb0a_1484e6cf',
+ side: 'PARENT',
+ updated: '2018-02-13 22:47:19.000000000',
+ message: 'Some comment on another patchset.',
+ unresolved: false,
+ },
+ ],
+ patchNum: 3,
+ path: 'test.txt',
+ rootId: '09a9fb0a_1484e6cf',
+ start_datetime: '2018-02-13 22:47:19.000000000',
+ commentSide: 'PARENT',
+ },
+ {
+ comments: [
+ {
+ __path: '/COMMIT_MSG',
+ author: {
+ _account_id: 1000000,
+ name: 'user',
+ username: 'user',
+ },
+ patch_set: 2,
+ id: '8caddf38_44770ec1',
+ line: 4,
+ updated: '2018-02-13 22:48:40.000000000',
+ message: 'Another unresolved comment',
+ unresolved: true,
+ },
+ ],
+ patchNum: 2,
+ path: '/COMMIT_MSG',
+ line: 4,
+ rootId: '8caddf38_44770ec1',
+ start_datetime: '2018-02-13 22:48:40.000000000',
+ },
+ {
+ comments: [
+ {
+ __path: '/COMMIT_MSG',
+ author: {
+ _account_id: 1000000,
+ name: 'user',
+ username: 'user',
+ },
+ patch_set: 2,
+ id: 'scaddf38_44770ec1',
+ line: 4,
+ updated: '2018-02-14 22:48:40.000000000',
+ message: 'Yet another unresolved comment',
+ unresolved: true,
+ },
+ ],
+ patchNum: 2,
+ path: '/COMMIT_MSG',
+ line: 4,
+ rootId: 'scaddf38_44770ec1',
+ start_datetime: '2018-02-14 22:48:40.000000000',
+ },
+ {
+ comments: [
+ {
+ id: 'zcf0b9fa_fe1a5f62',
+ path: '/COMMIT_MSG',
+ line: 6,
+ updated: '2018-02-15 22:48:48.018000000',
+ message: 'resolved draft',
+ unresolved: false,
+ __draft: true,
+ __draftID: '0.m683trwff68',
+ __editing: false,
+ patch_set: '2',
+ },
+ ],
+ patchNum: 4,
+ path: '/COMMIT_MSG',
+ line: 6,
+ rootId: 'zcf0b9fa_fe1a5f62',
+ start_datetime: '2018-02-09 18:49:18.000000000',
+ },
+ {
+ comments: [
+ {
+ __path: '/COMMIT_MSG',
+ author: {
+ _account_id: 1000000,
+ name: 'user',
+ username: 'user',
+ },
+ patch_set: 4,
+ id: 'rc1',
+ line: 5,
+ updated: '2019-02-08 18:49:18.000000000',
+ message: 'test',
+ unresolved: true,
+ robot_id: 'rc1',
+ },
+ ],
+ patchNum: 4,
+ path: '/COMMIT_MSG',
+ line: 5,
+ rootId: 'rc1',
+ start_datetime: '2019-02-08 18:49:18.000000000',
+ },
+ {
+ comments: [
+ {
+ __path: '/COMMIT_MSG',
+ author: {
+ _account_id: 1000000,
+ name: 'user',
+ username: 'user',
+ },
+ patch_set: 4,
+ id: 'rc2',
+ line: 5,
+ updated: '2019-03-08 18:49:18.000000000',
+ message: 'test',
+ unresolved: true,
+ robot_id: 'rc2',
+ },
+ {
+ __path: '/COMMIT_MSG',
+ author: {
+ _account_id: 1000000,
+ name: 'user',
+ username: 'user',
+ },
+ patch_set: 4,
+ id: 'c2_1',
+ line: 5,
+ updated: '2019-03-08 18:49:18.000000000',
+ message: 'test',
+ unresolved: true,
+ },
+ ],
+ patchNum: 4,
+ path: '/COMMIT_MSG',
+ line: 5,
+ rootId: 'rc2',
+ start_datetime: '2019-03-08 18:49:18.000000000',
+ },
+ ];
+
+ setup(() => {
+ sandbox = sinon.sandbox.create();
+ stub('gr-endpoint-decorator', {
+ _import: sandbox.stub().returns(Promise.resolve()),
+ });
+ // Since _endpoints are global, must reset state.
+ Gerrit._endpoints = new GrPluginEndpoints();
+ navigateToChangeStub = sandbox.stub(Gerrit.Nav, 'navigateToChange');
+ stub('gr-rest-api-interface', {
+ getConfig() { return Promise.resolve({test: 'config'}); },
+ getAccount() { return Promise.resolve(null); },
+ getDiffComments() { return Promise.resolve({}); },
+ getDiffRobotComments() { return Promise.resolve({}); },
+ getDiffDrafts() { return Promise.resolve({}); },
+ _fetchSharedCacheURL() { return Promise.resolve({}); },
+ });
+ element = fixture('basic');
+ sandbox.stub(element.$.actions, 'reload').returns(Promise.resolve());
+ Gerrit._loadPlugins([]);
+ Gerrit.install(
+ plugin => {
+ plugin.registerDynamicCustomComponent(
+ 'change-view-tab-header',
+ 'gr-checks-change-view-tab-header-view'
+ );
+ plugin.registerDynamicCustomComponent(
+ 'change-view-tab-content',
+ 'gr-checks-view'
+ );
+ },
+ '0.1',
+ 'http://some/plugins/url.html'
+ );
+ });
+
+ teardown(done => {
+ flush(() => {
+ sandbox.restore();
+ done();
+ });
+ });
+
+ const getCustomCssValue =
+ cssParam => util.getComputedStyleValue(cssParam, element);
+
+ test('_handleMessageAnchorTap', () => {
+ element._changeNum = '1';
+ element._patchRange = {
+ basePatchNum: 'PARENT',
+ patchNum: 1,
};
- const ROBOT_COMMENTS_LIMIT = 10;
+ const getUrlStub = sandbox.stub(Gerrit.Nav, 'getUrlForChange');
+ const replaceStateStub = sandbox.stub(history, 'replaceState');
+ element._handleMessageAnchorTap({detail: {id: 'a12345'}});
- const THREADS = [
- {
- comments: [
- {
- __path: '/COMMIT_MSG',
- author: {
- _account_id: 1000000,
- name: 'user',
- username: 'user',
- },
- patch_set: 2,
- robot_id: 'rb1',
- id: 'ecf9fa_fe1a5f62',
- line: 5,
- updated: '2018-02-08 18:49:18.000000000',
- message: 'test',
- unresolved: true,
- },
- {
- __path: '/COMMIT_MSG',
- author: {
- _account_id: 1000000,
- name: 'user',
- username: 'user',
- },
- patch_set: 4,
- id: 'ecf0b9fa_fe1a5f62',
- line: 5,
- updated: '2018-02-08 18:49:18.000000000',
- message: 'test',
- unresolved: true,
- },
- {
- id: '503008e2_0ab203ee',
- path: '/COMMIT_MSG',
- line: 5,
- in_reply_to: 'ecf0b9fa_fe1a5f62',
- updated: '2018-02-13 22:48:48.018000000',
- message: 'draft',
- unresolved: false,
- __draft: true,
- __draftID: '0.m683trwff68',
- __editing: false,
- patch_set: '2',
- },
- ],
- patchNum: 4,
- path: '/COMMIT_MSG',
- line: 5,
- rootId: 'ecf0b9fa_fe1a5f62',
- start_datetime: '2018-02-08 18:49:18.000000000',
- },
- {
- comments: [
- {
- __path: '/COMMIT_MSG',
- author: {
- _account_id: 1000000,
- name: 'user',
- username: 'user',
- },
- patch_set: 3,
- id: 'ecf0b9fa_fe5f62',
- robot_id: 'rb2',
- line: 5,
- updated: '2018-02-08 18:49:18.000000000',
- message: 'test',
- unresolved: true,
- },
- {
- __path: 'test.txt',
- author: {
- _account_id: 1000000,
- name: 'user',
- username: 'user',
- },
- patch_set: 3,
- id: '09a9fb0a_1484e6cf',
- side: 'PARENT',
- updated: '2018-02-13 22:47:19.000000000',
- message: 'Some comment on another patchset.',
- unresolved: false,
- },
- ],
- patchNum: 3,
- path: 'test.txt',
- rootId: '09a9fb0a_1484e6cf',
- start_datetime: '2018-02-13 22:47:19.000000000',
- commentSide: 'PARENT',
- },
- {
- comments: [
- {
- __path: '/COMMIT_MSG',
- author: {
- _account_id: 1000000,
- name: 'user',
- username: 'user',
- },
- patch_set: 2,
- id: '8caddf38_44770ec1',
- line: 4,
- updated: '2018-02-13 22:48:40.000000000',
- message: 'Another unresolved comment',
- unresolved: true,
- },
- ],
- patchNum: 2,
- path: '/COMMIT_MSG',
- line: 4,
- rootId: '8caddf38_44770ec1',
- start_datetime: '2018-02-13 22:48:40.000000000',
- },
- {
- comments: [
- {
- __path: '/COMMIT_MSG',
- author: {
- _account_id: 1000000,
- name: 'user',
- username: 'user',
- },
- patch_set: 2,
- id: 'scaddf38_44770ec1',
- line: 4,
- updated: '2018-02-14 22:48:40.000000000',
- message: 'Yet another unresolved comment',
- unresolved: true,
- },
- ],
- patchNum: 2,
- path: '/COMMIT_MSG',
- line: 4,
- rootId: 'scaddf38_44770ec1',
- start_datetime: '2018-02-14 22:48:40.000000000',
- },
- {
- comments: [
- {
- id: 'zcf0b9fa_fe1a5f62',
- path: '/COMMIT_MSG',
- line: 6,
- updated: '2018-02-15 22:48:48.018000000',
- message: 'resolved draft',
- unresolved: false,
- __draft: true,
- __draftID: '0.m683trwff68',
- __editing: false,
- patch_set: '2',
- },
- ],
- patchNum: 4,
- path: '/COMMIT_MSG',
- line: 6,
- rootId: 'zcf0b9fa_fe1a5f62',
- start_datetime: '2018-02-09 18:49:18.000000000',
- },
- {
- comments: [
- {
- __path: '/COMMIT_MSG',
- author: {
- _account_id: 1000000,
- name: 'user',
- username: 'user',
- },
- patch_set: 4,
- id: 'rc1',
- line: 5,
- updated: '2019-02-08 18:49:18.000000000',
- message: 'test',
- unresolved: true,
- robot_id: 'rc1',
- },
- ],
- patchNum: 4,
- path: '/COMMIT_MSG',
- line: 5,
- rootId: 'rc1',
- start_datetime: '2019-02-08 18:49:18.000000000',
- },
- {
- comments: [
- {
- __path: '/COMMIT_MSG',
- author: {
- _account_id: 1000000,
- name: 'user',
- username: 'user',
- },
- patch_set: 4,
- id: 'rc2',
- line: 5,
- updated: '2019-03-08 18:49:18.000000000',
- message: 'test',
- unresolved: true,
- robot_id: 'rc2',
- },
- {
- __path: '/COMMIT_MSG',
- author: {
- _account_id: 1000000,
- name: 'user',
- username: 'user',
- },
- patch_set: 4,
- id: 'c2_1',
- line: 5,
- updated: '2019-03-08 18:49:18.000000000',
- message: 'test',
- unresolved: true,
- },
- ],
- patchNum: 4,
- path: '/COMMIT_MSG',
- line: 5,
- rootId: 'rc2',
- start_datetime: '2019-03-08 18:49:18.000000000',
- },
- ];
+ assert.equal(getUrlStub.lastCall.args[4], '#message-a12345');
+ assert.isTrue(replaceStateStub.called);
+ });
- setup(() => {
- sandbox = sinon.sandbox.create();
- stub('gr-endpoint-decorator', {
- _import: sandbox.stub().returns(Promise.resolve()),
- });
- // Since _endpoints are global, must reset state.
- Gerrit._endpoints = new GrPluginEndpoints();
- navigateToChangeStub = sandbox.stub(Gerrit.Nav, 'navigateToChange');
- stub('gr-rest-api-interface', {
- getConfig() { return Promise.resolve({test: 'config'}); },
- getAccount() { return Promise.resolve(null); },
- getDiffComments() { return Promise.resolve({}); },
- getDiffRobotComments() { return Promise.resolve({}); },
- getDiffDrafts() { return Promise.resolve({}); },
- _fetchSharedCacheURL() { return Promise.resolve({}); },
- });
- element = fixture('basic');
- sandbox.stub(element.$.actions, 'reload').returns(Promise.resolve());
- Gerrit._loadPlugins([]);
- Gerrit.install(
- plugin => {
- plugin.registerDynamicCustomComponent(
- 'change-view-tab-header',
- 'gr-checks-change-view-tab-header-view'
- );
- plugin.registerDynamicCustomComponent(
- 'change-view-tab-content',
- 'gr-checks-view'
- );
- },
- '0.1',
- 'http://some/plugins/url.html'
- );
+ suite('plugins adding to file tab', () => {
+ setup(done => {
+ // Resolving it here instead of during setup() as other tests depend
+ // on flush() not being called during setup.
+ flush(() => done());
});
- teardown(done => {
+ test('plugin added tab shows up as a dynamic endpoint', () => {
+ assert(element._dynamicTabHeaderEndpoints.includes(
+ 'change-view-tab-header-url'));
+ const paperTabs = element.shadowRoot.querySelector('#primaryTabs');
+ // 3 Tabs are : Files, Plugin, Findings
+ assert.equal(paperTabs.querySelectorAll('paper-tab').length, 3);
+ assert.equal(paperTabs.querySelectorAll('paper-tab')[1].dataset.name,
+ 'change-view-tab-header-url');
+ });
+
+ test('handleShowTab switched tab correctly', done => {
+ const paperTabs = element.shadowRoot.querySelector('#primaryTabs');
+ assert.equal(paperTabs.selected, 0);
+ element._handleShowTab({detail:
+ {tab: 'change-view-tab-header-url'}});
flush(() => {
- sandbox.restore();
+ assert.equal(paperTabs.selected, 1);
done();
});
});
- const getCustomCssValue =
- cssParam => util.getComputedStyleValue(cssParam, element);
+ test('switching tab sets _selectedTabPluginEndpoint', done => {
+ const paperTabs = element.shadowRoot.querySelector('#primaryTabs');
+ MockInteractions.tap(paperTabs.querySelectorAll('paper-tab')[1]);
+ flush(() => {
+ assert.equal(element._selectedTabPluginEndpoint,
+ 'change-view-tab-content-url');
+ done();
+ });
+ });
+ });
- test('_handleMessageAnchorTap', () => {
+ suite('keyboard shortcuts', () => {
+ test('t to add topic', () => {
+ const editStub = sandbox.stub(element.$.metadata, 'editTopic');
+ MockInteractions.pressAndReleaseKeyOn(element, 83, null, 't');
+ assert(editStub.called);
+ });
+
+ test('S should toggle the CL star', () => {
+ const starStub = sandbox.stub(element.$.changeStar, 'toggleStar');
+ MockInteractions.pressAndReleaseKeyOn(element, 83, null, 's');
+ assert(starStub.called);
+ });
+
+ test('U should navigate to root if no backPage set', () => {
+ const relativeNavStub = sandbox.stub(Gerrit.Nav,
+ 'navigateToRelativeUrl');
+ MockInteractions.pressAndReleaseKeyOn(element, 85, null, 'u');
+ assert.isTrue(relativeNavStub.called);
+ assert.isTrue(relativeNavStub.lastCall.calledWithExactly(
+ Gerrit.Nav.getUrlForRoot()));
+ });
+
+ test('U should navigate to backPage if set', () => {
+ const relativeNavStub = sandbox.stub(Gerrit.Nav,
+ 'navigateToRelativeUrl');
+ element.backPage = '/dashboard/self';
+ MockInteractions.pressAndReleaseKeyOn(element, 85, null, 'u');
+ assert.isTrue(relativeNavStub.called);
+ assert.isTrue(relativeNavStub.lastCall.calledWithExactly(
+ '/dashboard/self'));
+ });
+
+ test('A fires an error event when not logged in', done => {
+ sandbox.stub(element, '_getLoggedIn').returns(Promise.resolve(false));
+ const loggedInErrorSpy = sandbox.spy();
+ element.addEventListener('show-auth-required', loggedInErrorSpy);
+ MockInteractions.pressAndReleaseKeyOn(element, 65, null, 'a');
+ flush(() => {
+ assert.isFalse(element.$.replyOverlay.opened);
+ assert.isTrue(loggedInErrorSpy.called);
+ done();
+ });
+ });
+
+ test('shift A does not open reply overlay', done => {
+ sandbox.stub(element, '_getLoggedIn').returns(Promise.resolve(true));
+ MockInteractions.pressAndReleaseKeyOn(element, 65, 'shift', 'a');
+ flush(() => {
+ assert.isFalse(element.$.replyOverlay.opened);
+ done();
+ });
+ });
+
+ test('A toggles overlay when logged in', done => {
+ sandbox.stub(element, '_getLoggedIn').returns(Promise.resolve(true));
+ sandbox.stub(element.$.replyDialog, 'fetchChangeUpdates')
+ .returns(Promise.resolve({isLatest: true}));
+ element._change = {labels: {}};
+ const openSpy = sandbox.spy(element, '_openReplyDialog');
+
+ MockInteractions.pressAndReleaseKeyOn(element, 65, null, 'a');
+ flush(() => {
+ assert.isTrue(element.$.replyOverlay.opened);
+ element.$.replyOverlay.close();
+ assert.isFalse(element.$.replyOverlay.opened);
+ assert(openSpy.lastCall.calledWithExactly(
+ element.$.replyDialog.FocusTarget.ANY),
+ '_openReplyDialog should have been passed ANY');
+ assert.equal(openSpy.callCount, 1);
+ done();
+ });
+ });
+
+ test('fullscreen-overlay-opened hides content', () => {
+ element._loggedIn = true;
+ element._loading = false;
+ element._change = {
+ owner: {_account_id: 1},
+ labels: {},
+ actions: {
+ abandon: {
+ enabled: true,
+ label: 'Abandon',
+ method: 'POST',
+ title: 'Abandon',
+ },
+ },
+ };
+ sandbox.spy(element, '_handleHideBackgroundContent');
+ element.$.replyDialog.fire('fullscreen-overlay-opened');
+ assert.isTrue(element._handleHideBackgroundContent.called);
+ assert.isTrue(element.$.mainContent.classList.contains('overlayOpen'));
+ assert.equal(getComputedStyle(element.$.actions).display, 'flex');
+ });
+
+ test('fullscreen-overlay-closed shows content', () => {
+ element._loggedIn = true;
+ element._loading = false;
+ element._change = {
+ owner: {_account_id: 1},
+ labels: {},
+ actions: {
+ abandon: {
+ enabled: true,
+ label: 'Abandon',
+ method: 'POST',
+ title: 'Abandon',
+ },
+ },
+ };
+ sandbox.spy(element, '_handleShowBackgroundContent');
+ element.$.replyDialog.fire('fullscreen-overlay-closed');
+ assert.isTrue(element._handleShowBackgroundContent.called);
+ assert.isFalse(element.$.mainContent.classList.contains('overlayOpen'));
+ });
+
+ test('expand all messages when expand-diffs fired', () => {
+ const handleExpand =
+ sandbox.stub(element.$.fileList, 'expandAllDiffs');
+ element.$.fileListHeader.fire('expand-diffs');
+ assert.isTrue(handleExpand.called);
+ });
+
+ test('collapse all messages when collapse-diffs fired', () => {
+ const handleCollapse =
+ sandbox.stub(element.$.fileList, 'collapseAllDiffs');
+ element.$.fileListHeader.fire('collapse-diffs');
+ assert.isTrue(handleCollapse.called);
+ });
+
+ test('X should expand all messages', done => {
+ flush(() => {
+ const handleExpand = sandbox.stub(element.messagesList,
+ 'handleExpandCollapse');
+ MockInteractions.pressAndReleaseKeyOn(element, 88, null, 'x');
+ assert(handleExpand.calledWith(true));
+ done();
+ });
+ });
+
+ test('Z should collapse all messages', done => {
+ flush(() => {
+ const handleExpand = sandbox.stub(element.messagesList,
+ 'handleExpandCollapse');
+ MockInteractions.pressAndReleaseKeyOn(element, 90, null, 'z');
+ assert(handleExpand.calledWith(false));
+ done();
+ });
+ });
+
+ test('shift + R should fetch and navigate to the latest patch set',
+ done => {
+ element._changeNum = '42';
+ element._patchRange = {
+ basePatchNum: 'PARENT',
+ patchNum: 1,
+ };
+ element._change = {
+ change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
+ _number: 42,
+ revisions: {
+ rev1: {_number: 1, commit: {parents: []}},
+ },
+ current_revision: 'rev1',
+ status: 'NEW',
+ labels: {},
+ actions: {},
+ };
+
+ navigateToChangeStub.restore();
+ navigateToChangeStub = sandbox.stub(Gerrit.Nav, 'navigateToChange',
+ (change, patchNum, basePatchNum) => {
+ assert.equal(change, element._change);
+ assert.isUndefined(patchNum);
+ assert.isUndefined(basePatchNum);
+ done();
+ });
+
+ MockInteractions.pressAndReleaseKeyOn(element, 82, 'shift', 'r');
+ });
+
+ test('d should open download overlay', () => {
+ const stub = sandbox.stub(element.$.downloadOverlay, 'open');
+ MockInteractions.pressAndReleaseKeyOn(element, 68, null, 'd');
+ assert.isTrue(stub.called);
+ });
+
+ test(', should open diff preferences', () => {
+ const stub = sandbox.stub(
+ element.$.fileList.$.diffPreferencesDialog, 'open');
+ element._loggedIn = false;
+ element.disableDiffPrefs = true;
+ MockInteractions.pressAndReleaseKeyOn(element, 188, null, ',');
+ assert.isFalse(stub.called);
+
+ element._loggedIn = true;
+ MockInteractions.pressAndReleaseKeyOn(element, 188, null, ',');
+ assert.isFalse(stub.called);
+
+ element.disableDiffPrefs = false;
+ MockInteractions.pressAndReleaseKeyOn(element, 188, null, ',');
+ assert.isTrue(stub.called);
+ });
+
+ test('m should toggle diff mode', () => {
+ sandbox.stub(element, 'shouldSuppressKeyboardShortcut').returns(false);
+ const setModeStub = sandbox.stub(element.$.fileListHeader,
+ 'setDiffViewMode');
+ const e = {preventDefault: () => {}};
+ flushAsynchronousOperations();
+
+ element.viewState.diffMode = 'SIDE_BY_SIDE';
+ element._handleToggleDiffMode(e);
+ assert.isTrue(setModeStub.calledWith('UNIFIED_DIFF'));
+
+ element.viewState.diffMode = 'UNIFIED_DIFF';
+ element._handleToggleDiffMode(e);
+ assert.isTrue(setModeStub.calledWith('SIDE_BY_SIDE'));
+ });
+ });
+
+ suite('reloading drafts', () => {
+ let reloadStub;
+ const drafts = {
+ 'testfile.txt': [
+ {
+ patch_set: 5,
+ id: 'dd2982f5_c01c9e6a',
+ line: 1,
+ updated: '2017-11-08 18:47:45.000000000',
+ message: 'test',
+ unresolved: true,
+ },
+ ],
+ };
+ setup(() => {
+ // Fake computeDraftCount as its required for ChangeComments,
+ // see gr-comment-api#reloadDrafts.
+ reloadStub = sandbox.stub(element.$.commentAPI, 'reloadDrafts')
+ .returns(Promise.resolve({
+ drafts,
+ getAllThreadsForChange: () => ([]),
+ computeDraftCount: () => 1,
+ }));
+ });
+
+ test('drafts are reloaded when reload-drafts fired', done => {
+ element.$.fileList.fire('reload-drafts', {
+ resolve: () => {
+ assert.isTrue(reloadStub.called);
+ assert.deepEqual(element._diffDrafts, drafts);
+ done();
+ },
+ });
+ });
+
+ test('drafts are reloaded when comment-refresh fired', () => {
+ element.fire('comment-refresh');
+ assert.isTrue(reloadStub.called);
+ });
+ });
+
+ test('diff comments modified', () => {
+ sandbox.spy(element, '_handleReloadCommentThreads');
+ return element._reloadComments().then(() => {
+ element.fire('diff-comments-modified');
+ assert.isTrue(element._handleReloadCommentThreads.called);
+ });
+ });
+
+ test('thread list modified', () => {
+ sandbox.spy(element, '_handleReloadDiffComments');
+ element._currentView = CommentTabs.COMMENT_THREADS;
+ flushAsynchronousOperations();
+
+ return element._reloadComments().then(() => {
+ element.threadList.fire('thread-list-modified');
+ assert.isTrue(element._handleReloadDiffComments.called);
+
+ let draftStub = sinon.stub(element._changeComments, 'computeDraftCount')
+ .returns(1);
+ assert.equal(element._computeTotalCommentCounts(5,
+ element._changeComments), '5 unresolved, 1 draft');
+ assert.equal(element._computeTotalCommentCounts(0,
+ element._changeComments), '1 draft');
+ draftStub.restore();
+ draftStub = sinon.stub(element._changeComments, 'computeDraftCount')
+ .returns(0);
+ assert.equal(element._computeTotalCommentCounts(0,
+ element._changeComments), '');
+ assert.equal(element._computeTotalCommentCounts(1,
+ element._changeComments), '1 unresolved');
+ draftStub.restore();
+ draftStub = sinon.stub(element._changeComments, 'computeDraftCount')
+ .returns(2);
+ assert.equal(element._computeTotalCommentCounts(1,
+ element._changeComments), '1 unresolved, 2 drafts');
+ draftStub.restore();
+ });
+ });
+
+ suite('thread list and change log tabs', () => {
+ setup(() => {
element._changeNum = '1';
element._patchRange = {
basePatchNum: 'PARENT',
patchNum: 1,
};
- const getUrlStub = sandbox.stub(Gerrit.Nav, 'getUrlForChange');
- const replaceStateStub = sandbox.stub(history, 'replaceState');
- element._handleMessageAnchorTap({detail: {id: 'a12345'}});
-
- assert.equal(getUrlStub.lastCall.args[4], '#message-a12345');
- assert.isTrue(replaceStateStub.called);
- });
-
- suite('plugins adding to file tab', () => {
- setup(done => {
- // Resolving it here instead of during setup() as other tests depend
- // on flush() not being called during setup.
- flush(() => done());
- });
-
- test('plugin added tab shows up as a dynamic endpoint', () => {
- assert(element._dynamicTabHeaderEndpoints.includes(
- 'change-view-tab-header-url'));
- const paperTabs = element.shadowRoot.querySelector('#primaryTabs');
- // 3 Tabs are : Files, Plugin, Findings
- assert.equal(paperTabs.querySelectorAll('paper-tab').length, 3);
- assert.equal(paperTabs.querySelectorAll('paper-tab')[1].dataset.name,
- 'change-view-tab-header-url');
- });
-
- test('handleShowTab switched tab correctly', done => {
- const paperTabs = element.shadowRoot.querySelector('#primaryTabs');
- assert.equal(paperTabs.selected, 0);
- element._handleShowTab({detail:
- {tab: 'change-view-tab-header-url'}});
- flush(() => {
- assert.equal(paperTabs.selected, 1);
- done();
- });
- });
-
- test('switching tab sets _selectedTabPluginEndpoint', done => {
- const paperTabs = element.shadowRoot.querySelector('#primaryTabs');
- MockInteractions.tap(paperTabs.querySelectorAll('paper-tab')[1]);
- flush(() => {
- assert.equal(element._selectedTabPluginEndpoint,
- 'change-view-tab-content-url');
- done();
- });
- });
- });
-
- suite('keyboard shortcuts', () => {
- test('t to add topic', () => {
- const editStub = sandbox.stub(element.$.metadata, 'editTopic');
- MockInteractions.pressAndReleaseKeyOn(element, 83, null, 't');
- assert(editStub.called);
- });
-
- test('S should toggle the CL star', () => {
- const starStub = sandbox.stub(element.$.changeStar, 'toggleStar');
- MockInteractions.pressAndReleaseKeyOn(element, 83, null, 's');
- assert(starStub.called);
- });
-
- test('U should navigate to root if no backPage set', () => {
- const relativeNavStub = sandbox.stub(Gerrit.Nav,
- 'navigateToRelativeUrl');
- MockInteractions.pressAndReleaseKeyOn(element, 85, null, 'u');
- assert.isTrue(relativeNavStub.called);
- assert.isTrue(relativeNavStub.lastCall.calledWithExactly(
- Gerrit.Nav.getUrlForRoot()));
- });
-
- test('U should navigate to backPage if set', () => {
- const relativeNavStub = sandbox.stub(Gerrit.Nav,
- 'navigateToRelativeUrl');
- element.backPage = '/dashboard/self';
- MockInteractions.pressAndReleaseKeyOn(element, 85, null, 'u');
- assert.isTrue(relativeNavStub.called);
- assert.isTrue(relativeNavStub.lastCall.calledWithExactly(
- '/dashboard/self'));
- });
-
- test('A fires an error event when not logged in', done => {
- sandbox.stub(element, '_getLoggedIn').returns(Promise.resolve(false));
- const loggedInErrorSpy = sandbox.spy();
- element.addEventListener('show-auth-required', loggedInErrorSpy);
- MockInteractions.pressAndReleaseKeyOn(element, 65, null, 'a');
- flush(() => {
- assert.isFalse(element.$.replyOverlay.opened);
- assert.isTrue(loggedInErrorSpy.called);
- done();
- });
- });
-
- test('shift A does not open reply overlay', done => {
- sandbox.stub(element, '_getLoggedIn').returns(Promise.resolve(true));
- MockInteractions.pressAndReleaseKeyOn(element, 65, 'shift', 'a');
- flush(() => {
- assert.isFalse(element.$.replyOverlay.opened);
- done();
- });
- });
-
- test('A toggles overlay when logged in', done => {
- sandbox.stub(element, '_getLoggedIn').returns(Promise.resolve(true));
- sandbox.stub(element.$.replyDialog, 'fetchChangeUpdates')
- .returns(Promise.resolve({isLatest: true}));
- element._change = {labels: {}};
- const openSpy = sandbox.spy(element, '_openReplyDialog');
-
- MockInteractions.pressAndReleaseKeyOn(element, 65, null, 'a');
- flush(() => {
- assert.isTrue(element.$.replyOverlay.opened);
- element.$.replyOverlay.close();
- assert.isFalse(element.$.replyOverlay.opened);
- assert(openSpy.lastCall.calledWithExactly(
- element.$.replyDialog.FocusTarget.ANY),
- '_openReplyDialog should have been passed ANY');
- assert.equal(openSpy.callCount, 1);
- done();
- });
- });
-
- test('fullscreen-overlay-opened hides content', () => {
- element._loggedIn = true;
- element._loading = false;
- element._change = {
- owner: {_account_id: 1},
- labels: {},
- actions: {
- abandon: {
- enabled: true,
- label: 'Abandon',
- method: 'POST',
- title: 'Abandon',
- },
- },
- };
- sandbox.spy(element, '_handleHideBackgroundContent');
- element.$.replyDialog.fire('fullscreen-overlay-opened');
- assert.isTrue(element._handleHideBackgroundContent.called);
- assert.isTrue(element.$.mainContent.classList.contains('overlayOpen'));
- assert.equal(getComputedStyle(element.$.actions).display, 'flex');
- });
-
- test('fullscreen-overlay-closed shows content', () => {
- element._loggedIn = true;
- element._loading = false;
- element._change = {
- owner: {_account_id: 1},
- labels: {},
- actions: {
- abandon: {
- enabled: true,
- label: 'Abandon',
- method: 'POST',
- title: 'Abandon',
- },
- },
- };
- sandbox.spy(element, '_handleShowBackgroundContent');
- element.$.replyDialog.fire('fullscreen-overlay-closed');
- assert.isTrue(element._handleShowBackgroundContent.called);
- assert.isFalse(element.$.mainContent.classList.contains('overlayOpen'));
- });
-
- test('expand all messages when expand-diffs fired', () => {
- const handleExpand =
- sandbox.stub(element.$.fileList, 'expandAllDiffs');
- element.$.fileListHeader.fire('expand-diffs');
- assert.isTrue(handleExpand.called);
- });
-
- test('collapse all messages when collapse-diffs fired', () => {
- const handleCollapse =
- sandbox.stub(element.$.fileList, 'collapseAllDiffs');
- element.$.fileListHeader.fire('collapse-diffs');
- assert.isTrue(handleCollapse.called);
- });
-
- test('X should expand all messages', done => {
- flush(() => {
- const handleExpand = sandbox.stub(element.messagesList,
- 'handleExpandCollapse');
- MockInteractions.pressAndReleaseKeyOn(element, 88, null, 'x');
- assert(handleExpand.calledWith(true));
- done();
- });
- });
-
- test('Z should collapse all messages', done => {
- flush(() => {
- const handleExpand = sandbox.stub(element.messagesList,
- 'handleExpandCollapse');
- MockInteractions.pressAndReleaseKeyOn(element, 90, null, 'z');
- assert(handleExpand.calledWith(false));
- done();
- });
- });
-
- test('shift + R should fetch and navigate to the latest patch set',
- done => {
- element._changeNum = '42';
- element._patchRange = {
- basePatchNum: 'PARENT',
- patchNum: 1,
- };
- element._change = {
- change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
- _number: 42,
- revisions: {
- rev1: {_number: 1, commit: {parents: []}},
- },
- current_revision: 'rev1',
- status: 'NEW',
- labels: {},
- actions: {},
- };
-
- navigateToChangeStub.restore();
- navigateToChangeStub = sandbox.stub(Gerrit.Nav, 'navigateToChange',
- (change, patchNum, basePatchNum) => {
- assert.equal(change, element._change);
- assert.isUndefined(patchNum);
- assert.isUndefined(basePatchNum);
- done();
- });
-
- MockInteractions.pressAndReleaseKeyOn(element, 82, 'shift', 'r');
- });
-
- test('d should open download overlay', () => {
- const stub = sandbox.stub(element.$.downloadOverlay, 'open');
- MockInteractions.pressAndReleaseKeyOn(element, 68, null, 'd');
- assert.isTrue(stub.called);
- });
-
- test(', should open diff preferences', () => {
- const stub = sandbox.stub(
- element.$.fileList.$.diffPreferencesDialog, 'open');
- element._loggedIn = false;
- element.disableDiffPrefs = true;
- MockInteractions.pressAndReleaseKeyOn(element, 188, null, ',');
- assert.isFalse(stub.called);
-
- element._loggedIn = true;
- MockInteractions.pressAndReleaseKeyOn(element, 188, null, ',');
- assert.isFalse(stub.called);
-
- element.disableDiffPrefs = false;
- MockInteractions.pressAndReleaseKeyOn(element, 188, null, ',');
- assert.isTrue(stub.called);
- });
-
- test('m should toggle diff mode', () => {
- sandbox.stub(element, 'shouldSuppressKeyboardShortcut').returns(false);
- const setModeStub = sandbox.stub(element.$.fileListHeader,
- 'setDiffViewMode');
- const e = {preventDefault: () => {}};
- flushAsynchronousOperations();
-
- element.viewState.diffMode = 'SIDE_BY_SIDE';
- element._handleToggleDiffMode(e);
- assert.isTrue(setModeStub.calledWith('UNIFIED_DIFF'));
-
- element.viewState.diffMode = 'UNIFIED_DIFF';
- element._handleToggleDiffMode(e);
- assert.isTrue(setModeStub.calledWith('SIDE_BY_SIDE'));
- });
- });
-
- suite('reloading drafts', () => {
- let reloadStub;
- const drafts = {
- 'testfile.txt': [
- {
- patch_set: 5,
- id: 'dd2982f5_c01c9e6a',
- line: 1,
- updated: '2017-11-08 18:47:45.000000000',
- message: 'test',
- unresolved: true,
- },
- ],
- };
- setup(() => {
- // Fake computeDraftCount as its required for ChangeComments,
- // see gr-comment-api#reloadDrafts.
- reloadStub = sandbox.stub(element.$.commentAPI, 'reloadDrafts')
- .returns(Promise.resolve({
- drafts,
- getAllThreadsForChange: () => ([]),
- computeDraftCount: () => 1,
- }));
- });
-
- test('drafts are reloaded when reload-drafts fired', done => {
- element.$.fileList.fire('reload-drafts', {
- resolve: () => {
- assert.isTrue(reloadStub.called);
- assert.deepEqual(element._diffDrafts, drafts);
- done();
- },
- });
- });
-
- test('drafts are reloaded when comment-refresh fired', () => {
- element.fire('comment-refresh');
- assert.isTrue(reloadStub.called);
- });
- });
-
- test('diff comments modified', () => {
- sandbox.spy(element, '_handleReloadCommentThreads');
- return element._reloadComments().then(() => {
- element.fire('diff-comments-modified');
- assert.isTrue(element._handleReloadCommentThreads.called);
- });
- });
-
- test('thread list modified', () => {
- sandbox.spy(element, '_handleReloadDiffComments');
- element._currentView = CommentTabs.COMMENT_THREADS;
- flushAsynchronousOperations();
-
- return element._reloadComments().then(() => {
- element.threadList.fire('thread-list-modified');
- assert.isTrue(element._handleReloadDiffComments.called);
-
- let draftStub = sinon.stub(element._changeComments, 'computeDraftCount')
- .returns(1);
- assert.equal(element._computeTotalCommentCounts(5,
- element._changeComments), '5 unresolved, 1 draft');
- assert.equal(element._computeTotalCommentCounts(0,
- element._changeComments), '1 draft');
- draftStub.restore();
- draftStub = sinon.stub(element._changeComments, 'computeDraftCount')
- .returns(0);
- assert.equal(element._computeTotalCommentCounts(0,
- element._changeComments), '');
- assert.equal(element._computeTotalCommentCounts(1,
- element._changeComments), '1 unresolved');
- draftStub.restore();
- draftStub = sinon.stub(element._changeComments, 'computeDraftCount')
- .returns(2);
- assert.equal(element._computeTotalCommentCounts(1,
- element._changeComments), '1 unresolved, 2 drafts');
- draftStub.restore();
- });
- });
-
- suite('thread list and change log tabs', () => {
- setup(() => {
- element._changeNum = '1';
- element._patchRange = {
- basePatchNum: 'PARENT',
- patchNum: 1,
- };
- element._change = {
- change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
- revisions: {
- rev2: {_number: 2, commit: {parents: []}},
- rev1: {_number: 1, commit: {parents: []}},
- rev13: {_number: 13, commit: {parents: []}},
- rev3: {_number: 3, commit: {parents: []}},
- },
- current_revision: 'rev3',
- status: 'NEW',
- labels: {
- test: {
- all: [],
- default_value: 0,
- values: [],
- approved: {},
- },
- },
- };
- sandbox.stub(element.$.relatedChanges, 'reload');
- sandbox.stub(element, '_reload').returns(Promise.resolve());
- sandbox.spy(element, '_paramsChanged');
- element.params = {view: 'change', changeNum: '1'};
- });
-
- test('tab switch works correctly', done => {
- assert.isTrue(element._paramsChanged.called);
- assert.equal(element.$.commentTabs.selected, CommentTabs.CHANGE_LOG);
- assert.equal(element._currentView, CommentTabs.CHANGE_LOG);
-
- const commentTab = element.shadowRoot.querySelector(
- 'paper-tab.commentThreads'
- );
- // Switch to comment thread tab
- MockInteractions.tap(commentTab);
- const commentTabs = element.$.commentTabs;
- assert.equal(commentTabs.selected,
- CommentTabs.COMMENT_THREADS);
- assert.equal(element._currentView, CommentTabs.COMMENT_THREADS);
-
- // Switch back to 'Change Log' tab
- element._paramsChanged(element.params);
- flush(() => {
- assert.equal(commentTabs.selected,
- CommentTabs.CHANGE_LOG);
- assert.equal(element._currentView, CommentTabs.CHANGE_LOG);
- done();
- });
- });
- });
-
- suite('Findings comment tab', () => {
- setup(done => {
- element._change = {
- change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
- revisions: {
- rev2: {_number: 2, commit: {parents: []}},
- rev1: {_number: 1, commit: {parents: []}},
- rev13: {_number: 13, commit: {parents: []}},
- rev3: {_number: 3, commit: {parents: []}},
- rev4: {_number: 4, commit: {parents: []}},
- },
- current_revision: 'rev4',
- };
- element._commentThreads = THREADS;
- const paperTabs = element.shadowRoot.querySelector('#primaryTabs');
- MockInteractions.tap(paperTabs.querySelectorAll('paper-tab')[2]);
- flush(() => {
- done();
- });
- });
-
- test('robot comments count per patchset', () => {
- const count = element._robotCommentCountPerPatchSet(THREADS);
- const expectedCount = {
- 2: 1,
- 3: 1,
- 4: 2,
- };
- assert.deepEqual(count, expectedCount);
- assert.equal(element._computeText({_number: 2}, THREADS),
- 'Patchset 2 (1 finding)');
- assert.equal(element._computeText({_number: 4}, THREADS),
- 'Patchset 4 (2 findings)');
- assert.equal(element._computeText({_number: 5}, THREADS),
- 'Patchset 5');
- });
-
- test('only robot comments are rendered', () => {
- assert.equal(element._robotCommentThreads.length, 2);
- assert.equal(element._robotCommentThreads[0].comments[0].robot_id,
- 'rc1');
- assert.equal(element._robotCommentThreads[1].comments[0].robot_id,
- 'rc2');
- });
-
- test('changing patchsets resets robot comments', done => {
- element.set('_change.current_revision', 'rev3');
- flush(() => {
- assert.equal(element._robotCommentThreads.length, 1);
- done();
- });
- });
-
- test('Show more button is hidden', () => {
- assert.isNull(element.shadowRoot.querySelector('.show-robot-comments'));
- });
-
- suite('robot comments show more button', () => {
- setup(done => {
- const arr = [];
- for (let i = 0; i <= 30; i++) {
- arr.push(...THREADS);
- }
- element._commentThreads = arr;
- flush(() => {
- done();
- });
- });
-
- test('Show more button is rendered', () => {
- assert.isOk(element.shadowRoot.querySelector('.show-robot-comments'));
- assert.equal(element._robotCommentThreads.length,
- ROBOT_COMMENTS_LIMIT);
- });
-
- test('Clicking show more button renders all comments', done => {
- MockInteractions.tap(element.shadowRoot.querySelector(
- '.show-robot-comments'));
- flush(() => {
- assert.equal(element._robotCommentThreads.length, 62);
- done();
- });
- });
- });
- });
-
- test('reply button is not visible when logged out', () => {
- assert.equal(getComputedStyle(element.$.replyBtn).display, 'none');
- element._loggedIn = true;
- assert.notEqual(getComputedStyle(element.$.replyBtn).display, 'none');
- });
-
- test('download tap calls _handleOpenDownloadDialog', () => {
- sandbox.stub(element, '_handleOpenDownloadDialog');
- element.$.actions.fire('download-tap');
- assert.isTrue(element._handleOpenDownloadDialog.called);
- });
-
- test('fetches the server config on attached', done => {
- flush(() => {
- assert.equal(element._serverConfig.test, 'config');
- done();
- });
- });
-
- test('_changeStatuses', () => {
- sandbox.stub(element, 'changeStatuses').returns(
- ['Merged', 'WIP']);
- element._loading = false;
element._change = {
change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
revisions: {
- rev2: {_number: 2},
- rev1: {_number: 1},
- rev13: {_number: 13},
- rev3: {_number: 3},
- },
- current_revision: 'rev3',
- labels: {
- test: {
- all: [],
- default_value: 0,
- values: [],
- approved: {},
- },
- },
- };
- element._mergeable = true;
- const expectedStatuses = ['Merged', 'WIP'];
- assert.deepEqual(element._changeStatuses, expectedStatuses);
- assert.equal(element._changeStatus, expectedStatuses.join(', '));
- flushAsynchronousOperations();
- const statusChips = Polymer.dom(element.root)
- .querySelectorAll('gr-change-status');
- assert.equal(statusChips.length, 2);
- });
-
- test('diff preferences open when open-diff-prefs is fired', () => {
- const overlayOpenStub = sandbox.stub(element.$.fileList,
- 'openDiffPrefs');
- element.$.fileListHeader.fire('open-diff-prefs');
- assert.isTrue(overlayOpenStub.called);
- });
-
- test('_prepareCommitMsgForLinkify', () => {
- let commitMessage = 'R=test@google.com';
- let result = element._prepareCommitMsgForLinkify(commitMessage);
- assert.equal(result, 'R=\u200Btest@google.com');
-
- commitMessage = 'R=test@google.com\nR=test@google.com';
- result = element._prepareCommitMsgForLinkify(commitMessage);
- assert.equal(result, 'R=\u200Btest@google.com\nR=\u200Btest@google.com');
-
- commitMessage = 'CC=test@google.com';
- result = element._prepareCommitMsgForLinkify(commitMessage);
- assert.equal(result, 'CC=\u200Btest@google.com');
- }),
-
- test('_isSubmitEnabled', () => {
- assert.isFalse(element._isSubmitEnabled({}));
- assert.isFalse(element._isSubmitEnabled({submit: {}}));
- assert.isTrue(element._isSubmitEnabled(
- {submit: {enabled: true}}));
- });
-
- test('_reload is called when an approved label is removed', () => {
- const vote = {_account_id: 1, name: 'bojack', value: 1};
- element._changeNum = '42';
- element._patchRange = {
- basePatchNum: 'PARENT',
- patchNum: 1,
- };
- element._change = {
- change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
- owner: {email: 'abc@def'},
- revisions: {
rev2: {_number: 2, commit: {parents: []}},
rev1: {_number: 1, commit: {parents: []}},
rev13: {_number: 13, commit: {parents: []}},
@@ -934,1312 +720,1536 @@
status: 'NEW',
labels: {
test: {
- all: [vote],
+ all: [],
default_value: 0,
values: [],
approved: {},
},
},
};
- flushAsynchronousOperations();
- const reloadStub = sandbox.stub(element, '_reload');
- element.splice('_change.labels.test.all', 0, 1);
- assert.isFalse(reloadStub.called);
- element._change.labels.test.all.push(vote);
- element._change.labels.test.all.push(vote);
- element._change.labels.test.approved = vote;
- flushAsynchronousOperations();
- element.splice('_change.labels.test.all', 0, 2);
- assert.isTrue(reloadStub.called);
- assert.isTrue(reloadStub.calledOnce);
- });
-
- test('reply button has updated count when there are drafts', () => {
- const getLabel = element._computeReplyButtonLabel;
-
- assert.equal(getLabel(null, false), 'Reply');
- assert.equal(getLabel(null, true), 'Start review');
-
- const changeRecord = {base: null};
- assert.equal(getLabel(changeRecord, false), 'Reply');
-
- changeRecord.base = {};
- assert.equal(getLabel(changeRecord, false), 'Reply');
-
- changeRecord.base = {
- 'file1.txt': [{}],
- 'file2.txt': [{}, {}],
- };
- assert.equal(getLabel(changeRecord, false), 'Reply (3)');
- });
-
- test('start review button when owner of WIP change', () => {
- assert.equal(
- element._computeReplyButtonLabel(null, true),
- 'Start review');
- });
-
- test('comment events properly update diff drafts', () => {
- element._patchRange = {
- basePatchNum: 'PARENT',
- patchNum: 2,
- };
- const draft = {
- __draft: true,
- id: 'id1',
- path: '/foo/bar.txt',
- text: 'hello',
- };
- element._handleCommentSave({detail: {comment: draft}});
- draft.patch_set = 2;
- assert.deepEqual(element._diffDrafts, {'/foo/bar.txt': [draft]});
- draft.patch_set = null;
- draft.text = 'hello, there';
- element._handleCommentSave({detail: {comment: draft}});
- draft.patch_set = 2;
- assert.deepEqual(element._diffDrafts, {'/foo/bar.txt': [draft]});
- const draft2 = {
- __draft: true,
- id: 'id2',
- path: '/foo/bar.txt',
- text: 'hola',
- };
- element._handleCommentSave({detail: {comment: draft2}});
- draft2.patch_set = 2;
- assert.deepEqual(element._diffDrafts, {'/foo/bar.txt': [draft, draft2]});
- draft.patch_set = null;
- element._handleCommentDiscard({detail: {comment: draft}});
- draft.patch_set = 2;
- assert.deepEqual(element._diffDrafts, {'/foo/bar.txt': [draft2]});
- element._handleCommentDiscard({detail: {comment: draft2}});
- assert.deepEqual(element._diffDrafts, {});
- });
-
- test('change num change', () => {
- element._changeNum = null;
- element._patchRange = {
- basePatchNum: 'PARENT',
- patchNum: 2,
- };
- element._change = {
- change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
- labels: {},
- };
- element.viewState.changeNum = null;
- element.viewState.diffMode = 'UNIFIED';
- assert.equal(element.viewState.numFilesShown, 200);
- assert.equal(element._numFilesShown, 200);
- element._numFilesShown = 150;
- flushAsynchronousOperations();
- assert.equal(element.viewState.diffMode, 'UNIFIED');
- assert.equal(element.viewState.numFilesShown, 150);
-
- element._changeNum = '1';
- element.params = {changeNum: '1'};
- element._change.newProp = '1';
- flushAsynchronousOperations();
- assert.equal(element.viewState.diffMode, 'UNIFIED');
- assert.equal(element.viewState.changeNum, '1');
-
- element._changeNum = '2';
- element.params = {changeNum: '2'};
- element._change.newProp = '2';
- flushAsynchronousOperations();
- assert.equal(element.viewState.diffMode, 'UNIFIED');
- assert.equal(element.viewState.changeNum, '2');
- assert.equal(element.viewState.numFilesShown, 200);
- assert.equal(element._numFilesShown, 200);
- });
-
- test('_setDiffViewMode is called with reset when new change is loaded',
- () => {
- sandbox.stub(element, '_setDiffViewMode');
- element.viewState = {changeNum: 1};
- element._changeNum = 2;
- element._resetFileListViewState();
- assert.isTrue(
- element._setDiffViewMode.lastCall.calledWithExactly(true));
- });
-
- test('diffViewMode is propagated from file list header', () => {
- element.viewState = {diffMode: 'UNIFIED'};
- element.$.fileListHeader.diffViewMode = 'SIDE_BY_SIDE';
- assert.equal(element.viewState.diffMode, 'SIDE_BY_SIDE');
- });
-
- test('diffMode defaults to side by side without preferences', done => {
- sandbox.stub(element.$.restAPI, 'getPreferences').returns(
- Promise.resolve({}));
- // No user prefs or diff view mode set.
-
- element._setDiffViewMode().then(() => {
- assert.equal(element.viewState.diffMode, 'SIDE_BY_SIDE');
- done();
- });
- });
-
- test('diffMode defaults to preference when not already set', done => {
- sandbox.stub(element.$.restAPI, 'getPreferences').returns(
- Promise.resolve({default_diff_view: 'UNIFIED'}));
-
- element._setDiffViewMode().then(() => {
- assert.equal(element.viewState.diffMode, 'UNIFIED');
- done();
- });
- });
-
- test('existing diffMode overrides preference', done => {
- element.viewState.diffMode = 'SIDE_BY_SIDE';
- sandbox.stub(element.$.restAPI, 'getPreferences').returns(
- Promise.resolve({default_diff_view: 'UNIFIED'}));
- element._setDiffViewMode().then(() => {
- assert.equal(element.viewState.diffMode, 'SIDE_BY_SIDE');
- done();
- });
- });
-
- test('don’t reload entire page when patchRange changes', () => {
- const reloadStub = sandbox.stub(element, '_reload',
- () => Promise.resolve());
- const reloadPatchDependentStub = sandbox.stub(element,
- '_reloadPatchNumDependentResources',
- () => Promise.resolve());
- const relatedClearSpy = sandbox.spy(element.$.relatedChanges, 'clear');
- const collapseStub = sandbox.stub(element.$.fileList, 'collapseAllDiffs');
-
- const value = {
- view: Gerrit.Nav.View.CHANGE,
- patchNum: '1',
- };
- element._paramsChanged(value);
- assert.isTrue(reloadStub.calledOnce);
- assert.isTrue(relatedClearSpy.calledOnce);
-
- element._initialLoadComplete = true;
-
- value.basePatchNum = '1';
- value.patchNum = '2';
- element._paramsChanged(value);
- assert.isFalse(reloadStub.calledTwice);
- assert.isTrue(reloadPatchDependentStub.calledOnce);
- assert.isTrue(relatedClearSpy.calledOnce);
- assert.isTrue(collapseStub.calledTwice);
- });
-
- test('reload entire page when patchRange doesnt change', () => {
- const reloadStub = sandbox.stub(element, '_reload',
- () => Promise.resolve());
- const collapseStub = sandbox.stub(element.$.fileList, 'collapseAllDiffs');
- const value = {
- view: Gerrit.Nav.View.CHANGE,
- };
- element._paramsChanged(value);
- assert.isTrue(reloadStub.calledOnce);
- element._initialLoadComplete = true;
- element._paramsChanged(value);
- assert.isTrue(reloadStub.calledTwice);
- assert.isTrue(collapseStub.calledTwice);
- });
-
- test('related changes are updated and new patch selected after rebase',
- done => {
- element._changeNum = '42';
- sandbox.stub(element, 'computeLatestPatchNum', () => 1);
- sandbox.stub(element, '_reload',
- () => Promise.resolve());
- const e = {detail: {action: 'rebase'}};
- element._handleReloadChange(e).then(() => {
- assert.isTrue(navigateToChangeStub.lastCall.calledWithExactly(
- element._change));
- done();
- });
- });
-
- test('related changes are not updated after other action', done => {
- sandbox.stub(element, '_reload', () => Promise.resolve());
- sandbox.stub(element.$.relatedChanges, 'reload');
- const e = {detail: {action: 'abandon'}};
- element._handleReloadChange(e).then(() => {
- assert.isFalse(navigateToChangeStub.called);
- done();
- });
- });
-
- test('_computeMergedCommitInfo', () => {
- const dummyRevs = {
- 1: {commit: {commit: 1}},
- 2: {commit: {}},
- };
- assert.deepEqual(element._computeMergedCommitInfo(0, dummyRevs), {});
- assert.deepEqual(element._computeMergedCommitInfo(1, dummyRevs),
- dummyRevs[1].commit);
-
- // Regression test for issue 5337.
- const commit = element._computeMergedCommitInfo(2, dummyRevs);
- assert.notDeepEqual(commit, dummyRevs[2]);
- assert.deepEqual(commit, {commit: 2});
- });
-
- test('_computeCopyTextForTitle', () => {
- const change = {
- _number: 123,
- subject: 'test subject',
- revisions: {
- rev1: {_number: 1},
- rev3: {_number: 3},
- },
- current_revision: 'rev3',
- };
- sandbox.stub(Gerrit.Nav, 'getUrlForChange')
- .returns('/change/123');
- assert.equal(
- element._computeCopyTextForTitle(change),
- '123: test subject | https://localhost:8081/change/123'
- );
- });
-
- test('get latest revision', () => {
- let change = {
- revisions: {
- rev1: {_number: 1},
- rev3: {_number: 3},
- },
- current_revision: 'rev3',
- };
- assert.equal(element._getLatestRevisionSHA(change), 'rev3');
- change = {
- revisions: {
- rev1: {_number: 1},
- },
- };
- assert.equal(element._getLatestRevisionSHA(change), 'rev1');
- });
-
- test('show commit message edit button', () => {
- const _change = {
- status: element.ChangeStatus.MERGED,
- };
- assert.isTrue(element._computeHideEditCommitMessage(false, false, {}));
- assert.isTrue(element._computeHideEditCommitMessage(true, true, {}));
- assert.isTrue(element._computeHideEditCommitMessage(false, true, {}));
- assert.isFalse(element._computeHideEditCommitMessage(true, false, {}));
- assert.isTrue(element._computeHideEditCommitMessage(true, false,
- _change));
- assert.isTrue(element._computeHideEditCommitMessage(true, false, {},
- true));
- assert.isFalse(element._computeHideEditCommitMessage(true, false, {},
- false));
- });
-
- test('_handleCommitMessageSave trims trailing whitespace', () => {
- const putStub = sandbox.stub(element.$.restAPI, 'putChangeCommitMessage')
- .returns(Promise.resolve({}));
-
- const mockEvent = content => { return {detail: {content}}; };
-
- element._handleCommitMessageSave(mockEvent('test \n test '));
- assert.equal(putStub.lastCall.args[1], 'test\n test');
-
- element._handleCommitMessageSave(mockEvent(' test\ntest'));
- assert.equal(putStub.lastCall.args[1], ' test\ntest');
-
- element._handleCommitMessageSave(mockEvent('\n\n\n\n\n\n\n\n'));
- assert.equal(putStub.lastCall.args[1], '\n\n\n\n\n\n\n\n');
- });
-
- test('_computeChangeIdCommitMessageError', () => {
- let commitMessage =
- 'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282483';
- let change = {change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282483'};
- assert.equal(
- element._computeChangeIdCommitMessageError(commitMessage, change),
- null);
-
- change = {change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282484'};
- assert.equal(
- element._computeChangeIdCommitMessageError(commitMessage, change),
- 'mismatch');
-
- commitMessage = 'This is the greatest change.';
- assert.equal(
- element._computeChangeIdCommitMessageError(commitMessage, change),
- 'missing');
- });
-
- test('multiple change Ids in commit message picks last', () => {
- const commitMessage = [
- 'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282484',
- 'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282483',
- ].join('\n');
- let change = {change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282483'};
- assert.equal(
- element._computeChangeIdCommitMessageError(commitMessage, change),
- null);
- change = {change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282484'};
- assert.equal(
- element._computeChangeIdCommitMessageError(commitMessage, change),
- 'mismatch');
- });
-
- test('does not count change Id that starts mid line', () => {
- const commitMessage = [
- 'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282484',
- 'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282483',
- ].join(' and ');
- let change = {change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282484'};
- assert.equal(
- element._computeChangeIdCommitMessageError(commitMessage, change),
- null);
- change = {change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282483'};
- assert.equal(
- element._computeChangeIdCommitMessageError(commitMessage, change),
- 'mismatch');
- });
-
- test('_computeTitleAttributeWarning', () => {
- let changeIdCommitMessageError = 'missing';
- assert.equal(
- element._computeTitleAttributeWarning(changeIdCommitMessageError),
- 'No Change-Id in commit message');
-
- changeIdCommitMessageError = 'mismatch';
- assert.equal(
- element._computeTitleAttributeWarning(changeIdCommitMessageError),
- 'Change-Id mismatch');
- });
-
- test('_computeChangeIdClass', () => {
- let changeIdCommitMessageError = 'missing';
- assert.equal(
- element._computeChangeIdClass(changeIdCommitMessageError), '');
-
- changeIdCommitMessageError = 'mismatch';
- assert.equal(
- element._computeChangeIdClass(changeIdCommitMessageError), 'warning');
- });
-
- test('topic is coalesced to null', done => {
- sandbox.stub(element, '_changeChanged');
- sandbox.stub(element.$.restAPI, 'getChangeDetail', () => Promise.resolve({
- id: '123456789',
- labels: {},
- current_revision: 'foo',
- revisions: {foo: {commit: {}}},
- }));
-
- element._getChangeDetail().then(() => {
- assert.isNull(element._change.topic);
- done();
- });
- });
-
- test('commit sha is populated from getChangeDetail', done => {
- sandbox.stub(element, '_changeChanged');
- sandbox.stub(element.$.restAPI, 'getChangeDetail', () => Promise.resolve({
- id: '123456789',
- labels: {},
- current_revision: 'foo',
- revisions: {foo: {commit: {}}},
- }));
-
- element._getChangeDetail().then(() => {
- assert.equal('foo', element._commitInfo.commit);
- done();
- });
- });
-
- test('edit is added to change', () => {
- sandbox.stub(element, '_changeChanged');
- sandbox.stub(element.$.restAPI, 'getChangeDetail', () => Promise.resolve({
- id: '123456789',
- labels: {},
- current_revision: 'foo',
- revisions: {foo: {commit: {}}},
- }));
- sandbox.stub(element, '_getEdit', () => Promise.resolve({
- base_patch_set_number: 1,
- commit: {commit: 'bar'},
- }));
- element._patchRange = {};
-
- return element._getChangeDetail().then(() => {
- const revs = element._change.revisions;
- assert.equal(Object.keys(revs).length, 2);
- assert.deepEqual(revs['foo'], {commit: {commit: 'foo'}});
- assert.deepEqual(revs['bar'], {
- _number: element.EDIT_NAME,
- basePatchNum: 1,
- commit: {commit: 'bar'},
- fetch: undefined,
- });
- });
- });
-
- test('_getBasePatchNum', () => {
- const _change = {
- _number: 42,
- revisions: {
- '98da160735fb81604b4c40e93c368f380539dd0e': {
- _number: 1,
- commit: {
- parents: [],
- },
- },
- },
- };
- const _patchRange = {
- basePatchNum: 'PARENT',
- };
- assert.equal(element._getBasePatchNum(_change, _patchRange), 'PARENT');
-
- element._prefs = {
- default_base_for_merges: 'FIRST_PARENT',
- };
-
- const _change2 = {
- _number: 42,
- revisions: {
- '98da160735fb81604b4c40e93c368f380539dd0e': {
- _number: 1,
- commit: {
- parents: [
- {
- commit: '6e12bdf1176eb4ab24d8491ba3b6d0704409cde8',
- subject: 'test',
- },
- {
- commit: '22f7db4754b5d9816fc581f3d9a6c0ef8429c841',
- subject: 'test3',
- },
- ],
- },
- },
- },
- };
- assert.equal(element._getBasePatchNum(_change2, _patchRange), -1);
-
- _patchRange.patchNum = 1;
- assert.equal(element._getBasePatchNum(_change2, _patchRange), 'PARENT');
- });
-
- test('_openReplyDialog called with `ANY` when coming from tap event',
- () => {
- const openStub = sandbox.stub(element, '_openReplyDialog');
- element._serverConfig = {};
- MockInteractions.tap(element.$.replyBtn);
- assert(openStub.lastCall.calledWithExactly(
- element.$.replyDialog.FocusTarget.ANY),
- '_openReplyDialog should have been passed ANY');
- assert.equal(openStub.callCount, 1);
- });
-
- test('_openReplyDialog called with `BODY` when coming from message reply' +
- 'event', done => {
- flush(() => {
- const openStub = sandbox.stub(element, '_openReplyDialog');
- element.messagesList.fire('reply',
- {message: {message: 'text'}});
- assert(openStub.lastCall.calledWithExactly(
- element.$.replyDialog.FocusTarget.BODY),
- '_openReplyDialog should have been passed BODY');
- assert.equal(openStub.callCount, 1);
- done();
- });
- });
-
- test('reply dialog focus can be controlled', () => {
- const FocusTarget = element.$.replyDialog.FocusTarget;
- const openStub = sandbox.stub(element, '_openReplyDialog');
-
- const e = {detail: {}};
- element._handleShowReplyDialog(e);
- assert(openStub.lastCall.calledWithExactly(FocusTarget.REVIEWERS),
- '_openReplyDialog should have been passed REVIEWERS');
- assert.equal(openStub.callCount, 1);
-
- e.detail.value = {ccsOnly: true};
- element._handleShowReplyDialog(e);
- assert(openStub.lastCall.calledWithExactly(FocusTarget.CCS),
- '_openReplyDialog should have been passed CCS');
- assert.equal(openStub.callCount, 2);
- });
-
- test('getUrlParameter functionality', () => {
- const locationStub = sandbox.stub(element, '_getLocationSearch');
-
- locationStub.returns('?test');
- assert.equal(element._getUrlParameter('test'), 'test');
- locationStub.returns('?test2=12&test=3');
- assert.equal(element._getUrlParameter('test'), 'test');
- locationStub.returns('');
- assert.isNull(element._getUrlParameter('test'));
- locationStub.returns('?');
- assert.isNull(element._getUrlParameter('test'));
- locationStub.returns('?test2');
- assert.isNull(element._getUrlParameter('test'));
- });
-
- test('revert dialog opened with revert param', done => {
- sandbox.stub(element.$.restAPI, 'getLoggedIn', () => Promise.resolve(true));
- sandbox.stub(Gerrit, 'awaitPluginsLoaded', () => Promise.resolve());
-
- element._patchRange = {
- basePatchNum: 'PARENT',
- patchNum: 2,
- };
- element._change = {
- change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
- revisions: {
- rev1: {_number: 1, commit: {parents: []}},
- rev2: {_number: 2, commit: {parents: []}},
- },
- current_revision: 'rev1',
- status: element.ChangeStatus.MERGED,
- labels: {},
- actions: {},
- };
-
- sandbox.stub(element, '_getUrlParameter',
- param => {
- assert.equal(param, 'revert');
- return param;
- });
-
- sandbox.stub(element.$.actions, 'showRevertDialog',
- done);
-
- element._maybeShowRevertDialog();
- assert.isTrue(Gerrit.awaitPluginsLoaded.called);
- });
-
- suite('scroll related tests', () => {
- test('document scrolling calls function to set scroll height', done => {
- const originalHeight = document.body.scrollHeight;
- const scrollStub = sandbox.stub(element, '_handleScroll',
- () => {
- assert.isTrue(scrollStub.called);
- document.body.style.height = originalHeight + 'px';
- scrollStub.restore();
- done();
- });
- document.body.style.height = '10000px';
- element._handleScroll();
- });
-
- test('scrollTop is set correctly', () => {
- element.viewState = {scrollTop: TEST_SCROLL_TOP_PX};
-
- sandbox.stub(element, '_reload', () => {
- // When element is reloaded, ensure that the history
- // state has the scrollTop set earlier. This will then
- // be reset.
- assert.isTrue(element.viewState.scrollTop == TEST_SCROLL_TOP_PX);
- return Promise.resolve({});
- });
-
- // simulate reloading component, which is done when route
- // changes to match a regex of change view type.
- element._paramsChanged({view: Gerrit.Nav.View.CHANGE});
- });
-
- test('scrollTop is reset when new change is loaded', () => {
- element._resetFileListViewState();
- assert.equal(element.viewState.scrollTop, 0);
- });
- });
-
- suite('reply dialog tests', () => {
- setup(() => {
- sandbox.stub(element.$.replyDialog, '_draftChanged');
- sandbox.stub(element.$.replyDialog, 'fetchChangeUpdates',
- () => Promise.resolve({isLatest: true}));
- element._change = {labels: {}};
- });
-
- test('reply from comment adds quote text', () => {
- const e = {detail: {message: {message: 'quote text'}}};
- element._handleMessageReply(e);
- assert.equal(element.$.replyDialog.quote, '> quote text\n\n');
- });
-
- test('reply from comment replaces quote text', () => {
- element.$.replyDialog.draft = '> old quote text\n\n some draft text';
- element.$.replyDialog.quote = '> old quote text\n\n';
- const e = {detail: {message: {message: 'quote text'}}};
- element._handleMessageReply(e);
- assert.equal(element.$.replyDialog.quote, '> quote text\n\n');
- });
-
- test('reply from same comment preserves quote text', () => {
- element.$.replyDialog.draft = '> quote text\n\n some draft text';
- element.$.replyDialog.quote = '> quote text\n\n';
- const e = {detail: {message: {message: 'quote text'}}};
- element._handleMessageReply(e);
- assert.equal(element.$.replyDialog.draft,
- '> quote text\n\n some draft text');
- assert.equal(element.$.replyDialog.quote, '> quote text\n\n');
- });
-
- test('reply from top of page contains previous draft', () => {
- const div = document.createElement('div');
- element.$.replyDialog.draft = '> quote text\n\n some draft text';
- element.$.replyDialog.quote = '> quote text\n\n';
- const e = {target: div, preventDefault: sandbox.spy()};
- element._handleReplyTap(e);
- assert.equal(element.$.replyDialog.draft,
- '> quote text\n\n some draft text');
- assert.equal(element.$.replyDialog.quote, '> quote text\n\n');
- });
- });
-
- test('reply button is disabled until server config is loaded', () => {
- assert.isTrue(element._replyDisabled);
- element._serverConfig = {};
- assert.isFalse(element._replyDisabled);
- });
-
- suite('commit message expand/collapse', () => {
- setup(() => {
- sandbox.stub(element, 'fetchChangeUpdates',
- () => Promise.resolve({isLatest: false}));
- });
-
- test('commitCollapseToggle hidden for short commit message', () => {
- element._latestCommitMessage = '';
- assert.isTrue(element.$.commitCollapseToggle.hasAttribute('hidden'));
- });
-
- test('commitCollapseToggle shown for long commit message', () => {
- element._latestCommitMessage = _.times(31, String).join('\n');
- assert.isFalse(element.$.commitCollapseToggle.hasAttribute('hidden'));
- });
-
- test('commitCollapseToggle functions', () => {
- element._latestCommitMessage = _.times(35, String).join('\n');
- assert.isTrue(element._commitCollapsed);
- assert.isTrue(element._commitCollapsible);
- assert.isTrue(
- element.$.commitMessageEditor.hasAttribute('collapsed'));
- MockInteractions.tap(element.$.commitCollapseToggleButton);
- assert.isFalse(element._commitCollapsed);
- assert.isTrue(element._commitCollapsible);
- assert.isFalse(
- element.$.commitMessageEditor.hasAttribute('collapsed'));
- });
- });
-
- suite('related changes expand/collapse', () => {
- let updateHeightSpy;
- setup(() => {
- updateHeightSpy = sandbox.spy(element, '_updateRelatedChangeMaxHeight');
- });
-
- test('relatedChangesToggle shown height greater than changeInfo height',
- () => {
- assert.isFalse(element.$.relatedChangesToggle.classList
- .contains('showToggle'));
- sandbox.stub(element, '_getOffsetHeight', () => 50);
- sandbox.stub(element, '_getScrollHeight', () => 60);
- sandbox.stub(element, '_getLineHeight', () => 5);
- sandbox.stub(window, 'matchMedia', () => { return {matches: true}; });
- element.$.relatedChanges.dispatchEvent(
- new CustomEvent('new-section-loaded'));
- assert.isTrue(element.$.relatedChangesToggle.classList
- .contains('showToggle'));
- assert.equal(updateHeightSpy.callCount, 1);
- });
-
- test('relatedChangesToggle hidden height less than changeInfo height',
- () => {
- assert.isFalse(element.$.relatedChangesToggle.classList
- .contains('showToggle'));
- sandbox.stub(element, '_getOffsetHeight', () => 50);
- sandbox.stub(element, '_getScrollHeight', () => 40);
- sandbox.stub(element, '_getLineHeight', () => 5);
- sandbox.stub(window, 'matchMedia', () => { return {matches: true}; });
- element.$.relatedChanges.dispatchEvent(
- new CustomEvent('new-section-loaded'));
- assert.isFalse(element.$.relatedChangesToggle.classList
- .contains('showToggle'));
- assert.equal(updateHeightSpy.callCount, 1);
- });
-
- test('relatedChangesToggle functions', () => {
- sandbox.stub(element, '_getOffsetHeight', () => 50);
- sandbox.stub(window, 'matchMedia', () => { return {matches: false}; });
- element._relatedChangesLoading = false;
- assert.isTrue(element._relatedChangesCollapsed);
- assert.isTrue(
- element.$.relatedChanges.classList.contains('collapsed'));
- MockInteractions.tap(element.$.relatedChangesToggleButton);
- assert.isFalse(element._relatedChangesCollapsed);
- assert.isFalse(
- element.$.relatedChanges.classList.contains('collapsed'));
- });
-
- test('_updateRelatedChangeMaxHeight without commit toggle', () => {
- sandbox.stub(element, '_getOffsetHeight', () => 50);
- sandbox.stub(element, '_getLineHeight', () => 12);
- sandbox.stub(window, 'matchMedia', () => { return {matches: false}; });
-
- // 50 (existing height) - 30 (extra height) = 20 (adjusted height).
- // 20 (max existing height) % 12 (line height) = 6 (remainder).
- // 20 (adjusted height) - 8 (remainder) = 12 (max height to set).
-
- element._updateRelatedChangeMaxHeight();
- assert.equal(getCustomCssValue('--relation-chain-max-height'),
- '12px');
- assert.equal(getCustomCssValue('--related-change-btn-top-padding'),
- '');
- });
-
- test('_updateRelatedChangeMaxHeight with commit toggle', () => {
- element._latestCommitMessage = _.times(31, String).join('\n');
- sandbox.stub(element, '_getOffsetHeight', () => 50);
- sandbox.stub(element, '_getLineHeight', () => 12);
- sandbox.stub(window, 'matchMedia', () => { return {matches: false}; });
-
- // 50 (existing height) % 12 (line height) = 2 (remainder).
- // 50 (existing height) - 2 (remainder) = 48 (max height to set).
-
- element._updateRelatedChangeMaxHeight();
- assert.equal(getCustomCssValue('--relation-chain-max-height'),
- '48px');
- assert.equal(getCustomCssValue('--related-change-btn-top-padding'),
- '2px');
- });
-
- test('_updateRelatedChangeMaxHeight in small screen mode', () => {
- element._latestCommitMessage = _.times(31, String).join('\n');
- sandbox.stub(element, '_getOffsetHeight', () => 50);
- sandbox.stub(element, '_getLineHeight', () => 12);
- sandbox.stub(window, 'matchMedia', () => { return {matches: true}; });
-
- element._updateRelatedChangeMaxHeight();
-
- // 400 (new height) % 12 (line height) = 4 (remainder).
- // 400 (new height) - 4 (remainder) = 396.
-
- assert.equal(getCustomCssValue('--relation-chain-max-height'),
- '396px');
- });
-
- test('_updateRelatedChangeMaxHeight in medium screen mode', () => {
- element._latestCommitMessage = _.times(31, String).join('\n');
- sandbox.stub(element, '_getOffsetHeight', () => 50);
- sandbox.stub(element, '_getLineHeight', () => 12);
- sandbox.stub(window, 'matchMedia', () => {
- if (window.matchMedia.lastCall.args[0] === '(max-width: 75em)') {
- return {matches: true};
- } else {
- return {matches: false};
- }
- });
-
- // 100 (new height) % 12 (line height) = 4 (remainder).
- // 100 (new height) - 4 (remainder) = 96.
- element._updateRelatedChangeMaxHeight();
- assert.equal(getCustomCssValue('--relation-chain-max-height'),
- '96px');
- });
-
- suite('update checks', () => {
- setup(() => {
- sandbox.spy(element, '_startUpdateCheckTimer');
- sandbox.stub(element, 'async', f => {
- // Only fire the async callback one time.
- if (element.async.callCount > 1) { return; }
- f.call(element);
- });
- });
-
- test('_startUpdateCheckTimer negative delay', () => {
- sandbox.stub(element, 'fetchChangeUpdates');
-
- element._serverConfig = {change: {update_delay: -1}};
-
- assert.isTrue(element._startUpdateCheckTimer.called);
- assert.isFalse(element.fetchChangeUpdates.called);
- });
-
- test('_startUpdateCheckTimer up-to-date', () => {
- sandbox.stub(element, 'fetchChangeUpdates',
- () => Promise.resolve({isLatest: true}));
-
- element._serverConfig = {change: {update_delay: 12345}};
-
- assert.isTrue(element._startUpdateCheckTimer.called);
- assert.isTrue(element.fetchChangeUpdates.called);
- assert.equal(element.async.lastCall.args[1], 12345 * 1000);
- });
-
- test('_startUpdateCheckTimer out-of-date shows an alert', done => {
- sandbox.stub(element, 'fetchChangeUpdates',
- () => Promise.resolve({isLatest: false}));
- element.addEventListener('show-alert', e => {
- assert.equal(e.detail.message,
- 'A newer patch set has been uploaded');
- done();
- });
- element._serverConfig = {change: {update_delay: 12345}};
- });
-
- test('_startUpdateCheckTimer new status shows an alert', done => {
- sandbox.stub(element, 'fetchChangeUpdates')
- .returns(Promise.resolve({
- isLatest: true,
- newStatus: element.ChangeStatus.MERGED,
- }));
- element.addEventListener('show-alert', e => {
- assert.equal(e.detail.message, 'This change has been merged');
- done();
- });
- element._serverConfig = {change: {update_delay: 12345}};
- });
-
- test('_startUpdateCheckTimer new messages shows an alert', done => {
- sandbox.stub(element, 'fetchChangeUpdates')
- .returns(Promise.resolve({
- isLatest: true,
- newMessages: true,
- }));
- element.addEventListener('show-alert', e => {
- assert.equal(e.detail.message,
- 'There are new messages on this change');
- done();
- });
- element._serverConfig = {change: {update_delay: 12345}};
- });
- });
-
- test('canStartReview computation', () => {
- const change1 = {};
- const change2 = {
- actions: {
- ready: {
- enabled: true,
- },
- },
- };
- const change3 = {
- actions: {
- ready: {
- label: 'Ready for Review',
- },
- },
- };
- assert.isFalse(element._computeCanStartReview(change1));
- assert.isTrue(element._computeCanStartReview(change2));
- assert.isFalse(element._computeCanStartReview(change3));
- });
- });
-
- test('header class computation', () => {
- assert.equal(element._computeHeaderClass(), 'header');
- assert.equal(element._computeHeaderClass(true), 'header editMode');
- });
-
- test('_maybeScrollToMessage', done => {
- flush(() => {
- const scrollStub = sandbox.stub(element.messagesList,
- 'scrollToMessage');
-
- element._maybeScrollToMessage('');
- assert.isFalse(scrollStub.called);
- element._maybeScrollToMessage('message');
- assert.isFalse(scrollStub.called);
- element._maybeScrollToMessage('#message-TEST');
- assert.isTrue(scrollStub.called);
- assert.equal(scrollStub.lastCall.args[0], 'TEST');
- done();
- });
- });
-
- test('topic update reloads related changes', () => {
- sandbox.stub(element.$.relatedChanges, 'reload');
- element.dispatchEvent(new CustomEvent('topic-changed'));
- assert.isTrue(element.$.relatedChanges.reload.calledOnce);
- });
-
- test('_computeEditMode', () => {
- const callCompute = (range, params) =>
- element._computeEditMode({base: range}, {base: params});
- assert.isFalse(callCompute({}, {}));
- assert.isTrue(callCompute({}, {edit: true}));
- assert.isFalse(callCompute({basePatchNum: 'PARENT', patchNum: 1}, {}));
- assert.isFalse(callCompute({basePatchNum: 'edit', patchNum: 1}, {}));
- assert.isTrue(callCompute({basePatchNum: 1, patchNum: 'edit'}, {}));
- });
-
- test('_processEdit', () => {
- element._patchRange = {};
- const change = {
- current_revision: 'foo',
- revisions: {foo: {commit: {}, actions: {cherrypick: {enabled: true}}}},
- };
- let mockChange;
-
- // With no edit, mockChange should be unmodified.
- element._processEdit(mockChange = _.cloneDeep(change), null);
- assert.deepEqual(mockChange, change);
-
- // When edit is not based on the latest PS, current_revision should be
- // unmodified.
- const edit = {
- base_patch_set_number: 1,
- commit: {commit: 'bar'},
- fetch: true,
- };
- element._processEdit(mockChange = _.cloneDeep(change), edit);
- assert.notDeepEqual(mockChange, change);
- assert.equal(mockChange.revisions.bar._number, element.EDIT_NAME);
- assert.equal(mockChange.current_revision, change.current_revision);
- assert.deepEqual(mockChange.revisions.bar.commit, {commit: 'bar'});
- assert.notOk(mockChange.revisions.bar.actions);
-
- edit.base_revision = 'foo';
- element._processEdit(mockChange = _.cloneDeep(change), edit);
- assert.notDeepEqual(mockChange, change);
- assert.equal(mockChange.current_revision, 'bar');
- assert.deepEqual(mockChange.revisions.bar.actions,
- mockChange.revisions.foo.actions);
-
- // If _patchRange.patchNum is defined, do not load edit.
- element._patchRange.patchNum = 'baz';
- change.current_revision = 'baz';
- element._processEdit(mockChange = _.cloneDeep(change), edit);
- assert.equal(element._patchRange.patchNum, 'baz');
- assert.notOk(mockChange.revisions.bar.actions);
- });
-
- test('file-action-tap handling', () => {
- element._patchRange = {
- basePatchNum: 'PARENT',
- patchNum: 1,
- };
- const fileList = element.$.fileList;
- const Actions = GrEditConstants.Actions;
- const controls = element.$.fileListHeader.$.editControls;
- sandbox.stub(controls, 'openDeleteDialog');
- sandbox.stub(controls, 'openRenameDialog');
- sandbox.stub(controls, 'openRestoreDialog');
- sandbox.stub(Gerrit.Nav, 'getEditUrlForDiff');
- sandbox.stub(Gerrit.Nav, 'navigateToRelativeUrl');
-
- // Delete
- fileList.dispatchEvent(new CustomEvent('file-action-tap', {
- detail: {action: Actions.DELETE.id, path: 'foo'},
- bubbles: true,
- composed: true,
- }));
- flushAsynchronousOperations();
-
- assert.isTrue(controls.openDeleteDialog.called);
- assert.equal(controls.openDeleteDialog.lastCall.args[0], 'foo');
-
- // Restore
- fileList.dispatchEvent(new CustomEvent('file-action-tap', {
- detail: {action: Actions.RESTORE.id, path: 'foo'},
- bubbles: true,
- composed: true,
- }));
- flushAsynchronousOperations();
-
- assert.isTrue(controls.openRestoreDialog.called);
- assert.equal(controls.openRestoreDialog.lastCall.args[0], 'foo');
-
- // Rename
- fileList.dispatchEvent(new CustomEvent('file-action-tap', {
- detail: {action: Actions.RENAME.id, path: 'foo'},
- bubbles: true,
- composed: true,
- }));
- flushAsynchronousOperations();
-
- assert.isTrue(controls.openRenameDialog.called);
- assert.equal(controls.openRenameDialog.lastCall.args[0], 'foo');
-
- // Open
- fileList.dispatchEvent(new CustomEvent('file-action-tap', {
- detail: {action: Actions.OPEN.id, path: 'foo'},
- bubbles: true,
- composed: true,
- }));
- flushAsynchronousOperations();
-
- assert.isTrue(Gerrit.Nav.getEditUrlForDiff.called);
- assert.equal(Gerrit.Nav.getEditUrlForDiff.lastCall.args[1], 'foo');
- assert.equal(Gerrit.Nav.getEditUrlForDiff.lastCall.args[2], '1');
- assert.isTrue(Gerrit.Nav.navigateToRelativeUrl.called);
- });
-
- test('_selectedRevision updates when patchNum is changed', () => {
- const revision1 = {_number: 1, commit: {parents: []}};
- const revision2 = {_number: 2, commit: {parents: []}};
- sandbox.stub(element.$.restAPI, 'getChangeDetail').returns(
- Promise.resolve({
- revisions: {
- aaa: revision1,
- bbb: revision2,
- },
- labels: {},
- actions: {},
- current_revision: 'bbb',
- change_id: 'loremipsumdolorsitamet',
- }));
- sandbox.stub(element, '_getEdit').returns(Promise.resolve());
- sandbox.stub(element, '_getPreferences').returns(Promise.resolve({}));
- element._patchRange = {patchNum: '2'};
- return element._getChangeDetail().then(() => {
- assert.strictEqual(element._selectedRevision, revision2);
-
- element.set('_patchRange.patchNum', '1');
- assert.strictEqual(element._selectedRevision, revision1);
- });
- });
-
- test('_selectedRevision is assigned when patchNum is edit', () => {
- const revision1 = {_number: 1, commit: {parents: []}};
- const revision2 = {_number: 2, commit: {parents: []}};
- const revision3 = {_number: 'edit', commit: {parents: []}};
- sandbox.stub(element.$.restAPI, 'getChangeDetail').returns(
- Promise.resolve({
- revisions: {
- aaa: revision1,
- bbb: revision2,
- ccc: revision3,
- },
- labels: {},
- actions: {},
- current_revision: 'ccc',
- change_id: 'loremipsumdolorsitamet',
- }));
- sandbox.stub(element, '_getEdit').returns(Promise.resolve());
- sandbox.stub(element, '_getPreferences').returns(Promise.resolve({}));
- element._patchRange = {patchNum: 'edit'};
- return element._getChangeDetail().then(() => {
- assert.strictEqual(element._selectedRevision, revision3);
- });
- });
-
- test('_sendShowChangeEvent', () => {
- element._change = {labels: {}};
- element._patchRange = {patchNum: 4};
- element._mergeable = true;
- const showStub = sandbox.stub(element.$.jsAPI, 'handleEvent');
- element._sendShowChangeEvent();
- assert.isTrue(showStub.calledOnce);
- assert.equal(
- showStub.lastCall.args[0], element.$.jsAPI.EventType.SHOW_CHANGE);
- assert.deepEqual(showStub.lastCall.args[1], {
- change: {labels: {}},
- patchNum: 4,
- info: {mergeable: true},
- });
- });
-
- suite('_handleEditTap', () => {
- let fireEdit;
-
- setup(() => {
- fireEdit = () => {
- element.$.actions.dispatchEvent(new CustomEvent('edit-tap'));
- };
- navigateToChangeStub.restore();
-
- element._change = {revisions: {rev1: {_number: 1}}};
- });
-
- test('edit exists in revisions', done => {
- sandbox.stub(Gerrit.Nav, 'navigateToChange', (...args) => {
- assert.equal(args.length, 2);
- assert.equal(args[1], element.EDIT_NAME); // patchNum
- done();
- });
-
- element.set('_change.revisions.rev2', {_number: element.EDIT_NAME});
- flushAsynchronousOperations();
-
- fireEdit();
- });
-
- test('no edit exists in revisions, non-latest patchset', done => {
- sandbox.stub(Gerrit.Nav, 'navigateToChange', (...args) => {
- assert.equal(args.length, 4);
- assert.equal(args[1], 1); // patchNum
- assert.equal(args[3], true); // opt_isEdit
- done();
- });
-
- element.set('_change.revisions.rev2', {_number: 2});
- element._patchRange = {patchNum: 1};
- flushAsynchronousOperations();
-
- fireEdit();
- });
-
- test('no edit exists in revisions, latest patchset', done => {
- sandbox.stub(Gerrit.Nav, 'navigateToChange', (...args) => {
- assert.equal(args.length, 4);
- // No patch should be specified when patchNum == latest.
- assert.isNotOk(args[1]); // patchNum
- assert.equal(args[3], true); // opt_isEdit
- done();
- });
-
- element.set('_change.revisions.rev2', {_number: 2});
- element._patchRange = {patchNum: 2};
- flushAsynchronousOperations();
-
- fireEdit();
- });
- });
-
- test('_handleStopEditTap', done => {
- sandbox.stub(element.$.metadata, '_computeLabelNames');
- navigateToChangeStub.restore();
- sandbox.stub(element, 'computeLatestPatchNum').returns(1);
- sandbox.stub(Gerrit.Nav, 'navigateToChange', (...args) => {
- assert.equal(args.length, 2);
- assert.equal(args[1], 1); // patchNum
- done();
- });
-
- element._patchRange = {patchNum: 1};
- element.$.actions.dispatchEvent(new CustomEvent('stop-edit-tap',
- {bubbles: false}));
- });
-
- suite('plugin endpoints', () => {
- test('endpoint params', done => {
- element._change = {labels: {}};
- element._selectedRevision = {};
- let hookEl;
- let plugin;
- Gerrit.install(
- p => {
- plugin = p;
- plugin.hook('change-view-integration').getLastAttached()
- .then(
- el => hookEl = el);
- },
- '0.1',
- 'http://some/plugins/url.html');
- flush(() => {
- assert.strictEqual(hookEl.plugin, plugin);
- assert.strictEqual(hookEl.change, element._change);
- assert.strictEqual(hookEl.revision, element._selectedRevision);
- done();
- });
- });
- });
-
- suite('_getMergeability', () => {
- let getMergeableStub;
-
- setup(() => {
- element._change = {labels: {}};
- getMergeableStub = sandbox.stub(element.$.restAPI, 'getMergeable')
- .returns(Promise.resolve({mergeable: true}));
- });
-
- test('merged change', () => {
- element._mergeable = null;
- element._change.status = element.ChangeStatus.MERGED;
- return element._getMergeability().then(() => {
- assert.isFalse(element._mergeable);
- assert.isFalse(getMergeableStub.called);
- });
- });
-
- test('abandoned change', () => {
- element._mergeable = null;
- element._change.status = element.ChangeStatus.ABANDONED;
- return element._getMergeability().then(() => {
- assert.isFalse(element._mergeable);
- assert.isFalse(getMergeableStub.called);
- });
- });
-
- test('open change', () => {
- element._mergeable = null;
- return element._getMergeability().then(() => {
- assert.isTrue(element._mergeable);
- assert.isTrue(getMergeableStub.called);
- });
- });
- });
-
- test('_paramsChanged sets in projectLookup', () => {
sandbox.stub(element.$.relatedChanges, 'reload');
sandbox.stub(element, '_reload').returns(Promise.resolve());
- const setStub = sandbox.stub(element.$.restAPI, 'setInProjectLookup');
- element._paramsChanged({
- view: Gerrit.Nav.View.CHANGE,
- changeNum: 101,
- project: 'test-project',
- });
- assert.isTrue(setStub.calledOnce);
- assert.isTrue(setStub.calledWith(101, 'test-project'));
+ sandbox.spy(element, '_paramsChanged');
+ element.params = {view: 'change', changeNum: '1'};
});
- test('_handleToggleStar called when star is tapped', () => {
+ test('tab switch works correctly', done => {
+ assert.isTrue(element._paramsChanged.called);
+ assert.equal(element.$.commentTabs.selected, CommentTabs.CHANGE_LOG);
+ assert.equal(element._currentView, CommentTabs.CHANGE_LOG);
+
+ const commentTab = element.shadowRoot.querySelector(
+ 'paper-tab.commentThreads'
+ );
+ // Switch to comment thread tab
+ MockInteractions.tap(commentTab);
+ const commentTabs = element.$.commentTabs;
+ assert.equal(commentTabs.selected,
+ CommentTabs.COMMENT_THREADS);
+ assert.equal(element._currentView, CommentTabs.COMMENT_THREADS);
+
+ // Switch back to 'Change Log' tab
+ element._paramsChanged(element.params);
+ flush(() => {
+ assert.equal(commentTabs.selected,
+ CommentTabs.CHANGE_LOG);
+ assert.equal(element._currentView, CommentTabs.CHANGE_LOG);
+ done();
+ });
+ });
+ });
+
+ suite('Findings comment tab', () => {
+ setup(done => {
element._change = {
- owner: {_account_id: 1},
- starred: false,
+ change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
+ revisions: {
+ rev2: {_number: 2, commit: {parents: []}},
+ rev1: {_number: 1, commit: {parents: []}},
+ rev13: {_number: 13, commit: {parents: []}},
+ rev3: {_number: 3, commit: {parents: []}},
+ rev4: {_number: 4, commit: {parents: []}},
+ },
+ current_revision: 'rev4',
};
- element._loggedIn = true;
- const stub = sandbox.stub(element, '_handleToggleStar');
- flushAsynchronousOperations();
-
- MockInteractions.tap(element.$.changeStar.shadowRoot
- .querySelector('button'));
- assert.isTrue(stub.called);
+ element._commentThreads = THREADS;
+ const paperTabs = element.shadowRoot.querySelector('#primaryTabs');
+ MockInteractions.tap(paperTabs.querySelectorAll('paper-tab')[2]);
+ flush(() => {
+ done();
+ });
});
- suite('gr-reporting tests', () => {
- setup(() => {
- element._patchRange = {
- basePatchNum: 'PARENT',
- patchNum: 1,
- };
- sandbox.stub(element, '_getChangeDetail').returns(Promise.resolve());
- sandbox.stub(element, '_getProjectConfig').returns(Promise.resolve());
- sandbox.stub(element, '_reloadComments').returns(Promise.resolve());
- sandbox.stub(element, '_getMergeability').returns(Promise.resolve());
- sandbox.stub(element, '_getLatestCommitMessage')
- .returns(Promise.resolve());
- });
+ test('robot comments count per patchset', () => {
+ const count = element._robotCommentCountPerPatchSet(THREADS);
+ const expectedCount = {
+ 2: 1,
+ 3: 1,
+ 4: 2,
+ };
+ assert.deepEqual(count, expectedCount);
+ assert.equal(element._computeText({_number: 2}, THREADS),
+ 'Patchset 2 (1 finding)');
+ assert.equal(element._computeText({_number: 4}, THREADS),
+ 'Patchset 4 (2 findings)');
+ assert.equal(element._computeText({_number: 5}, THREADS),
+ 'Patchset 5');
+ });
- test('don\'t report changedDisplayed on reply', done => {
- const changeDisplayStub =
- sandbox.stub(element.$.reporting, 'changeDisplayed');
- const changeFullyLoadedStub =
- sandbox.stub(element.$.reporting, 'changeFullyLoaded');
- element._handleReplySent();
+ test('only robot comments are rendered', () => {
+ assert.equal(element._robotCommentThreads.length, 2);
+ assert.equal(element._robotCommentThreads[0].comments[0].robot_id,
+ 'rc1');
+ assert.equal(element._robotCommentThreads[1].comments[0].robot_id,
+ 'rc2');
+ });
+
+ test('changing patchsets resets robot comments', done => {
+ element.set('_change.current_revision', 'rev3');
+ flush(() => {
+ assert.equal(element._robotCommentThreads.length, 1);
+ done();
+ });
+ });
+
+ test('Show more button is hidden', () => {
+ assert.isNull(element.shadowRoot.querySelector('.show-robot-comments'));
+ });
+
+ suite('robot comments show more button', () => {
+ setup(done => {
+ const arr = [];
+ for (let i = 0; i <= 30; i++) {
+ arr.push(...THREADS);
+ }
+ element._commentThreads = arr;
flush(() => {
- assert.isFalse(changeDisplayStub.called);
- assert.isFalse(changeFullyLoadedStub.called);
done();
});
});
- test('report changedDisplayed on _paramsChanged', done => {
- const changeDisplayStub =
- sandbox.stub(element.$.reporting, 'changeDisplayed');
- const changeFullyLoadedStub =
- sandbox.stub(element.$.reporting, 'changeFullyLoaded');
- element._paramsChanged({
- view: Gerrit.Nav.View.CHANGE,
- changeNum: 101,
- project: 'test-project',
- });
+ test('Show more button is rendered', () => {
+ assert.isOk(element.shadowRoot.querySelector('.show-robot-comments'));
+ assert.equal(element._robotCommentThreads.length,
+ ROBOT_COMMENTS_LIMIT);
+ });
+
+ test('Clicking show more button renders all comments', done => {
+ MockInteractions.tap(element.shadowRoot.querySelector(
+ '.show-robot-comments'));
flush(() => {
- assert.isTrue(changeDisplayStub.called);
- assert.isTrue(changeFullyLoadedStub.called);
+ assert.equal(element._robotCommentThreads.length, 62);
done();
});
});
});
});
+
+ test('reply button is not visible when logged out', () => {
+ assert.equal(getComputedStyle(element.$.replyBtn).display, 'none');
+ element._loggedIn = true;
+ assert.notEqual(getComputedStyle(element.$.replyBtn).display, 'none');
+ });
+
+ test('download tap calls _handleOpenDownloadDialog', () => {
+ sandbox.stub(element, '_handleOpenDownloadDialog');
+ element.$.actions.fire('download-tap');
+ assert.isTrue(element._handleOpenDownloadDialog.called);
+ });
+
+ test('fetches the server config on attached', done => {
+ flush(() => {
+ assert.equal(element._serverConfig.test, 'config');
+ done();
+ });
+ });
+
+ test('_changeStatuses', () => {
+ sandbox.stub(element, 'changeStatuses').returns(
+ ['Merged', 'WIP']);
+ element._loading = false;
+ element._change = {
+ change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
+ revisions: {
+ rev2: {_number: 2},
+ rev1: {_number: 1},
+ rev13: {_number: 13},
+ rev3: {_number: 3},
+ },
+ current_revision: 'rev3',
+ labels: {
+ test: {
+ all: [],
+ default_value: 0,
+ values: [],
+ approved: {},
+ },
+ },
+ };
+ element._mergeable = true;
+ const expectedStatuses = ['Merged', 'WIP'];
+ assert.deepEqual(element._changeStatuses, expectedStatuses);
+ assert.equal(element._changeStatus, expectedStatuses.join(', '));
+ flushAsynchronousOperations();
+ const statusChips = dom(element.root)
+ .querySelectorAll('gr-change-status');
+ assert.equal(statusChips.length, 2);
+ });
+
+ test('diff preferences open when open-diff-prefs is fired', () => {
+ const overlayOpenStub = sandbox.stub(element.$.fileList,
+ 'openDiffPrefs');
+ element.$.fileListHeader.fire('open-diff-prefs');
+ assert.isTrue(overlayOpenStub.called);
+ });
+
+ test('_prepareCommitMsgForLinkify', () => {
+ let commitMessage = 'R=test@google.com';
+ let result = element._prepareCommitMsgForLinkify(commitMessage);
+ assert.equal(result, 'R=\u200Btest@google.com');
+
+ commitMessage = 'R=test@google.com\nR=test@google.com';
+ result = element._prepareCommitMsgForLinkify(commitMessage);
+ assert.equal(result, 'R=\u200Btest@google.com\nR=\u200Btest@google.com');
+
+ commitMessage = 'CC=test@google.com';
+ result = element._prepareCommitMsgForLinkify(commitMessage);
+ assert.equal(result, 'CC=\u200Btest@google.com');
+ }),
+
+ test('_isSubmitEnabled', () => {
+ assert.isFalse(element._isSubmitEnabled({}));
+ assert.isFalse(element._isSubmitEnabled({submit: {}}));
+ assert.isTrue(element._isSubmitEnabled(
+ {submit: {enabled: true}}));
+ });
+
+ test('_reload is called when an approved label is removed', () => {
+ const vote = {_account_id: 1, name: 'bojack', value: 1};
+ element._changeNum = '42';
+ element._patchRange = {
+ basePatchNum: 'PARENT',
+ patchNum: 1,
+ };
+ element._change = {
+ change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
+ owner: {email: 'abc@def'},
+ revisions: {
+ rev2: {_number: 2, commit: {parents: []}},
+ rev1: {_number: 1, commit: {parents: []}},
+ rev13: {_number: 13, commit: {parents: []}},
+ rev3: {_number: 3, commit: {parents: []}},
+ },
+ current_revision: 'rev3',
+ status: 'NEW',
+ labels: {
+ test: {
+ all: [vote],
+ default_value: 0,
+ values: [],
+ approved: {},
+ },
+ },
+ };
+ flushAsynchronousOperations();
+ const reloadStub = sandbox.stub(element, '_reload');
+ element.splice('_change.labels.test.all', 0, 1);
+ assert.isFalse(reloadStub.called);
+ element._change.labels.test.all.push(vote);
+ element._change.labels.test.all.push(vote);
+ element._change.labels.test.approved = vote;
+ flushAsynchronousOperations();
+ element.splice('_change.labels.test.all', 0, 2);
+ assert.isTrue(reloadStub.called);
+ assert.isTrue(reloadStub.calledOnce);
+ });
+
+ test('reply button has updated count when there are drafts', () => {
+ const getLabel = element._computeReplyButtonLabel;
+
+ assert.equal(getLabel(null, false), 'Reply');
+ assert.equal(getLabel(null, true), 'Start review');
+
+ const changeRecord = {base: null};
+ assert.equal(getLabel(changeRecord, false), 'Reply');
+
+ changeRecord.base = {};
+ assert.equal(getLabel(changeRecord, false), 'Reply');
+
+ changeRecord.base = {
+ 'file1.txt': [{}],
+ 'file2.txt': [{}, {}],
+ };
+ assert.equal(getLabel(changeRecord, false), 'Reply (3)');
+ });
+
+ test('start review button when owner of WIP change', () => {
+ assert.equal(
+ element._computeReplyButtonLabel(null, true),
+ 'Start review');
+ });
+
+ test('comment events properly update diff drafts', () => {
+ element._patchRange = {
+ basePatchNum: 'PARENT',
+ patchNum: 2,
+ };
+ const draft = {
+ __draft: true,
+ id: 'id1',
+ path: '/foo/bar.txt',
+ text: 'hello',
+ };
+ element._handleCommentSave({detail: {comment: draft}});
+ draft.patch_set = 2;
+ assert.deepEqual(element._diffDrafts, {'/foo/bar.txt': [draft]});
+ draft.patch_set = null;
+ draft.text = 'hello, there';
+ element._handleCommentSave({detail: {comment: draft}});
+ draft.patch_set = 2;
+ assert.deepEqual(element._diffDrafts, {'/foo/bar.txt': [draft]});
+ const draft2 = {
+ __draft: true,
+ id: 'id2',
+ path: '/foo/bar.txt',
+ text: 'hola',
+ };
+ element._handleCommentSave({detail: {comment: draft2}});
+ draft2.patch_set = 2;
+ assert.deepEqual(element._diffDrafts, {'/foo/bar.txt': [draft, draft2]});
+ draft.patch_set = null;
+ element._handleCommentDiscard({detail: {comment: draft}});
+ draft.patch_set = 2;
+ assert.deepEqual(element._diffDrafts, {'/foo/bar.txt': [draft2]});
+ element._handleCommentDiscard({detail: {comment: draft2}});
+ assert.deepEqual(element._diffDrafts, {});
+ });
+
+ test('change num change', () => {
+ element._changeNum = null;
+ element._patchRange = {
+ basePatchNum: 'PARENT',
+ patchNum: 2,
+ };
+ element._change = {
+ change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
+ labels: {},
+ };
+ element.viewState.changeNum = null;
+ element.viewState.diffMode = 'UNIFIED';
+ assert.equal(element.viewState.numFilesShown, 200);
+ assert.equal(element._numFilesShown, 200);
+ element._numFilesShown = 150;
+ flushAsynchronousOperations();
+ assert.equal(element.viewState.diffMode, 'UNIFIED');
+ assert.equal(element.viewState.numFilesShown, 150);
+
+ element._changeNum = '1';
+ element.params = {changeNum: '1'};
+ element._change.newProp = '1';
+ flushAsynchronousOperations();
+ assert.equal(element.viewState.diffMode, 'UNIFIED');
+ assert.equal(element.viewState.changeNum, '1');
+
+ element._changeNum = '2';
+ element.params = {changeNum: '2'};
+ element._change.newProp = '2';
+ flushAsynchronousOperations();
+ assert.equal(element.viewState.diffMode, 'UNIFIED');
+ assert.equal(element.viewState.changeNum, '2');
+ assert.equal(element.viewState.numFilesShown, 200);
+ assert.equal(element._numFilesShown, 200);
+ });
+
+ test('_setDiffViewMode is called with reset when new change is loaded',
+ () => {
+ sandbox.stub(element, '_setDiffViewMode');
+ element.viewState = {changeNum: 1};
+ element._changeNum = 2;
+ element._resetFileListViewState();
+ assert.isTrue(
+ element._setDiffViewMode.lastCall.calledWithExactly(true));
+ });
+
+ test('diffViewMode is propagated from file list header', () => {
+ element.viewState = {diffMode: 'UNIFIED'};
+ element.$.fileListHeader.diffViewMode = 'SIDE_BY_SIDE';
+ assert.equal(element.viewState.diffMode, 'SIDE_BY_SIDE');
+ });
+
+ test('diffMode defaults to side by side without preferences', done => {
+ sandbox.stub(element.$.restAPI, 'getPreferences').returns(
+ Promise.resolve({}));
+ // No user prefs or diff view mode set.
+
+ element._setDiffViewMode().then(() => {
+ assert.equal(element.viewState.diffMode, 'SIDE_BY_SIDE');
+ done();
+ });
+ });
+
+ test('diffMode defaults to preference when not already set', done => {
+ sandbox.stub(element.$.restAPI, 'getPreferences').returns(
+ Promise.resolve({default_diff_view: 'UNIFIED'}));
+
+ element._setDiffViewMode().then(() => {
+ assert.equal(element.viewState.diffMode, 'UNIFIED');
+ done();
+ });
+ });
+
+ test('existing diffMode overrides preference', done => {
+ element.viewState.diffMode = 'SIDE_BY_SIDE';
+ sandbox.stub(element.$.restAPI, 'getPreferences').returns(
+ Promise.resolve({default_diff_view: 'UNIFIED'}));
+ element._setDiffViewMode().then(() => {
+ assert.equal(element.viewState.diffMode, 'SIDE_BY_SIDE');
+ done();
+ });
+ });
+
+ test('don’t reload entire page when patchRange changes', () => {
+ const reloadStub = sandbox.stub(element, '_reload',
+ () => Promise.resolve());
+ const reloadPatchDependentStub = sandbox.stub(element,
+ '_reloadPatchNumDependentResources',
+ () => Promise.resolve());
+ const relatedClearSpy = sandbox.spy(element.$.relatedChanges, 'clear');
+ const collapseStub = sandbox.stub(element.$.fileList, 'collapseAllDiffs');
+
+ const value = {
+ view: Gerrit.Nav.View.CHANGE,
+ patchNum: '1',
+ };
+ element._paramsChanged(value);
+ assert.isTrue(reloadStub.calledOnce);
+ assert.isTrue(relatedClearSpy.calledOnce);
+
+ element._initialLoadComplete = true;
+
+ value.basePatchNum = '1';
+ value.patchNum = '2';
+ element._paramsChanged(value);
+ assert.isFalse(reloadStub.calledTwice);
+ assert.isTrue(reloadPatchDependentStub.calledOnce);
+ assert.isTrue(relatedClearSpy.calledOnce);
+ assert.isTrue(collapseStub.calledTwice);
+ });
+
+ test('reload entire page when patchRange doesnt change', () => {
+ const reloadStub = sandbox.stub(element, '_reload',
+ () => Promise.resolve());
+ const collapseStub = sandbox.stub(element.$.fileList, 'collapseAllDiffs');
+ const value = {
+ view: Gerrit.Nav.View.CHANGE,
+ };
+ element._paramsChanged(value);
+ assert.isTrue(reloadStub.calledOnce);
+ element._initialLoadComplete = true;
+ element._paramsChanged(value);
+ assert.isTrue(reloadStub.calledTwice);
+ assert.isTrue(collapseStub.calledTwice);
+ });
+
+ test('related changes are updated and new patch selected after rebase',
+ done => {
+ element._changeNum = '42';
+ sandbox.stub(element, 'computeLatestPatchNum', () => 1);
+ sandbox.stub(element, '_reload',
+ () => Promise.resolve());
+ const e = {detail: {action: 'rebase'}};
+ element._handleReloadChange(e).then(() => {
+ assert.isTrue(navigateToChangeStub.lastCall.calledWithExactly(
+ element._change));
+ done();
+ });
+ });
+
+ test('related changes are not updated after other action', done => {
+ sandbox.stub(element, '_reload', () => Promise.resolve());
+ sandbox.stub(element.$.relatedChanges, 'reload');
+ const e = {detail: {action: 'abandon'}};
+ element._handleReloadChange(e).then(() => {
+ assert.isFalse(navigateToChangeStub.called);
+ done();
+ });
+ });
+
+ test('_computeMergedCommitInfo', () => {
+ const dummyRevs = {
+ 1: {commit: {commit: 1}},
+ 2: {commit: {}},
+ };
+ assert.deepEqual(element._computeMergedCommitInfo(0, dummyRevs), {});
+ assert.deepEqual(element._computeMergedCommitInfo(1, dummyRevs),
+ dummyRevs[1].commit);
+
+ // Regression test for issue 5337.
+ const commit = element._computeMergedCommitInfo(2, dummyRevs);
+ assert.notDeepEqual(commit, dummyRevs[2]);
+ assert.deepEqual(commit, {commit: 2});
+ });
+
+ test('_computeCopyTextForTitle', () => {
+ const change = {
+ _number: 123,
+ subject: 'test subject',
+ revisions: {
+ rev1: {_number: 1},
+ rev3: {_number: 3},
+ },
+ current_revision: 'rev3',
+ };
+ sandbox.stub(Gerrit.Nav, 'getUrlForChange')
+ .returns('/change/123');
+ assert.equal(
+ element._computeCopyTextForTitle(change),
+ '123: test subject | https://localhost:8081/change/123'
+ );
+ });
+
+ test('get latest revision', () => {
+ let change = {
+ revisions: {
+ rev1: {_number: 1},
+ rev3: {_number: 3},
+ },
+ current_revision: 'rev3',
+ };
+ assert.equal(element._getLatestRevisionSHA(change), 'rev3');
+ change = {
+ revisions: {
+ rev1: {_number: 1},
+ },
+ };
+ assert.equal(element._getLatestRevisionSHA(change), 'rev1');
+ });
+
+ test('show commit message edit button', () => {
+ const _change = {
+ status: element.ChangeStatus.MERGED,
+ };
+ assert.isTrue(element._computeHideEditCommitMessage(false, false, {}));
+ assert.isTrue(element._computeHideEditCommitMessage(true, true, {}));
+ assert.isTrue(element._computeHideEditCommitMessage(false, true, {}));
+ assert.isFalse(element._computeHideEditCommitMessage(true, false, {}));
+ assert.isTrue(element._computeHideEditCommitMessage(true, false,
+ _change));
+ assert.isTrue(element._computeHideEditCommitMessage(true, false, {},
+ true));
+ assert.isFalse(element._computeHideEditCommitMessage(true, false, {},
+ false));
+ });
+
+ test('_handleCommitMessageSave trims trailing whitespace', () => {
+ const putStub = sandbox.stub(element.$.restAPI, 'putChangeCommitMessage')
+ .returns(Promise.resolve({}));
+
+ const mockEvent = content => { return {detail: {content}}; };
+
+ element._handleCommitMessageSave(mockEvent('test \n test '));
+ assert.equal(putStub.lastCall.args[1], 'test\n test');
+
+ element._handleCommitMessageSave(mockEvent(' test\ntest'));
+ assert.equal(putStub.lastCall.args[1], ' test\ntest');
+
+ element._handleCommitMessageSave(mockEvent('\n\n\n\n\n\n\n\n'));
+ assert.equal(putStub.lastCall.args[1], '\n\n\n\n\n\n\n\n');
+ });
+
+ test('_computeChangeIdCommitMessageError', () => {
+ let commitMessage =
+ 'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282483';
+ let change = {change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282483'};
+ assert.equal(
+ element._computeChangeIdCommitMessageError(commitMessage, change),
+ null);
+
+ change = {change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282484'};
+ assert.equal(
+ element._computeChangeIdCommitMessageError(commitMessage, change),
+ 'mismatch');
+
+ commitMessage = 'This is the greatest change.';
+ assert.equal(
+ element._computeChangeIdCommitMessageError(commitMessage, change),
+ 'missing');
+ });
+
+ test('multiple change Ids in commit message picks last', () => {
+ const commitMessage = [
+ 'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282484',
+ 'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282483',
+ ].join('\n');
+ let change = {change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282483'};
+ assert.equal(
+ element._computeChangeIdCommitMessageError(commitMessage, change),
+ null);
+ change = {change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282484'};
+ assert.equal(
+ element._computeChangeIdCommitMessageError(commitMessage, change),
+ 'mismatch');
+ });
+
+ test('does not count change Id that starts mid line', () => {
+ const commitMessage = [
+ 'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282484',
+ 'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282483',
+ ].join(' and ');
+ let change = {change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282484'};
+ assert.equal(
+ element._computeChangeIdCommitMessageError(commitMessage, change),
+ null);
+ change = {change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282483'};
+ assert.equal(
+ element._computeChangeIdCommitMessageError(commitMessage, change),
+ 'mismatch');
+ });
+
+ test('_computeTitleAttributeWarning', () => {
+ let changeIdCommitMessageError = 'missing';
+ assert.equal(
+ element._computeTitleAttributeWarning(changeIdCommitMessageError),
+ 'No Change-Id in commit message');
+
+ changeIdCommitMessageError = 'mismatch';
+ assert.equal(
+ element._computeTitleAttributeWarning(changeIdCommitMessageError),
+ 'Change-Id mismatch');
+ });
+
+ test('_computeChangeIdClass', () => {
+ let changeIdCommitMessageError = 'missing';
+ assert.equal(
+ element._computeChangeIdClass(changeIdCommitMessageError), '');
+
+ changeIdCommitMessageError = 'mismatch';
+ assert.equal(
+ element._computeChangeIdClass(changeIdCommitMessageError), 'warning');
+ });
+
+ test('topic is coalesced to null', done => {
+ sandbox.stub(element, '_changeChanged');
+ sandbox.stub(element.$.restAPI, 'getChangeDetail', () => Promise.resolve({
+ id: '123456789',
+ labels: {},
+ current_revision: 'foo',
+ revisions: {foo: {commit: {}}},
+ }));
+
+ element._getChangeDetail().then(() => {
+ assert.isNull(element._change.topic);
+ done();
+ });
+ });
+
+ test('commit sha is populated from getChangeDetail', done => {
+ sandbox.stub(element, '_changeChanged');
+ sandbox.stub(element.$.restAPI, 'getChangeDetail', () => Promise.resolve({
+ id: '123456789',
+ labels: {},
+ current_revision: 'foo',
+ revisions: {foo: {commit: {}}},
+ }));
+
+ element._getChangeDetail().then(() => {
+ assert.equal('foo', element._commitInfo.commit);
+ done();
+ });
+ });
+
+ test('edit is added to change', () => {
+ sandbox.stub(element, '_changeChanged');
+ sandbox.stub(element.$.restAPI, 'getChangeDetail', () => Promise.resolve({
+ id: '123456789',
+ labels: {},
+ current_revision: 'foo',
+ revisions: {foo: {commit: {}}},
+ }));
+ sandbox.stub(element, '_getEdit', () => Promise.resolve({
+ base_patch_set_number: 1,
+ commit: {commit: 'bar'},
+ }));
+ element._patchRange = {};
+
+ return element._getChangeDetail().then(() => {
+ const revs = element._change.revisions;
+ assert.equal(Object.keys(revs).length, 2);
+ assert.deepEqual(revs['foo'], {commit: {commit: 'foo'}});
+ assert.deepEqual(revs['bar'], {
+ _number: element.EDIT_NAME,
+ basePatchNum: 1,
+ commit: {commit: 'bar'},
+ fetch: undefined,
+ });
+ });
+ });
+
+ test('_getBasePatchNum', () => {
+ const _change = {
+ _number: 42,
+ revisions: {
+ '98da160735fb81604b4c40e93c368f380539dd0e': {
+ _number: 1,
+ commit: {
+ parents: [],
+ },
+ },
+ },
+ };
+ const _patchRange = {
+ basePatchNum: 'PARENT',
+ };
+ assert.equal(element._getBasePatchNum(_change, _patchRange), 'PARENT');
+
+ element._prefs = {
+ default_base_for_merges: 'FIRST_PARENT',
+ };
+
+ const _change2 = {
+ _number: 42,
+ revisions: {
+ '98da160735fb81604b4c40e93c368f380539dd0e': {
+ _number: 1,
+ commit: {
+ parents: [
+ {
+ commit: '6e12bdf1176eb4ab24d8491ba3b6d0704409cde8',
+ subject: 'test',
+ },
+ {
+ commit: '22f7db4754b5d9816fc581f3d9a6c0ef8429c841',
+ subject: 'test3',
+ },
+ ],
+ },
+ },
+ },
+ };
+ assert.equal(element._getBasePatchNum(_change2, _patchRange), -1);
+
+ _patchRange.patchNum = 1;
+ assert.equal(element._getBasePatchNum(_change2, _patchRange), 'PARENT');
+ });
+
+ test('_openReplyDialog called with `ANY` when coming from tap event',
+ () => {
+ const openStub = sandbox.stub(element, '_openReplyDialog');
+ element._serverConfig = {};
+ MockInteractions.tap(element.$.replyBtn);
+ assert(openStub.lastCall.calledWithExactly(
+ element.$.replyDialog.FocusTarget.ANY),
+ '_openReplyDialog should have been passed ANY');
+ assert.equal(openStub.callCount, 1);
+ });
+
+ test('_openReplyDialog called with `BODY` when coming from message reply' +
+ 'event', done => {
+ flush(() => {
+ const openStub = sandbox.stub(element, '_openReplyDialog');
+ element.messagesList.fire('reply',
+ {message: {message: 'text'}});
+ assert(openStub.lastCall.calledWithExactly(
+ element.$.replyDialog.FocusTarget.BODY),
+ '_openReplyDialog should have been passed BODY');
+ assert.equal(openStub.callCount, 1);
+ done();
+ });
+ });
+
+ test('reply dialog focus can be controlled', () => {
+ const FocusTarget = element.$.replyDialog.FocusTarget;
+ const openStub = sandbox.stub(element, '_openReplyDialog');
+
+ const e = {detail: {}};
+ element._handleShowReplyDialog(e);
+ assert(openStub.lastCall.calledWithExactly(FocusTarget.REVIEWERS),
+ '_openReplyDialog should have been passed REVIEWERS');
+ assert.equal(openStub.callCount, 1);
+
+ e.detail.value = {ccsOnly: true};
+ element._handleShowReplyDialog(e);
+ assert(openStub.lastCall.calledWithExactly(FocusTarget.CCS),
+ '_openReplyDialog should have been passed CCS');
+ assert.equal(openStub.callCount, 2);
+ });
+
+ test('getUrlParameter functionality', () => {
+ const locationStub = sandbox.stub(element, '_getLocationSearch');
+
+ locationStub.returns('?test');
+ assert.equal(element._getUrlParameter('test'), 'test');
+ locationStub.returns('?test2=12&test=3');
+ assert.equal(element._getUrlParameter('test'), 'test');
+ locationStub.returns('');
+ assert.isNull(element._getUrlParameter('test'));
+ locationStub.returns('?');
+ assert.isNull(element._getUrlParameter('test'));
+ locationStub.returns('?test2');
+ assert.isNull(element._getUrlParameter('test'));
+ });
+
+ test('revert dialog opened with revert param', done => {
+ sandbox.stub(element.$.restAPI, 'getLoggedIn', () => Promise.resolve(true));
+ sandbox.stub(Gerrit, 'awaitPluginsLoaded', () => Promise.resolve());
+
+ element._patchRange = {
+ basePatchNum: 'PARENT',
+ patchNum: 2,
+ };
+ element._change = {
+ change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
+ revisions: {
+ rev1: {_number: 1, commit: {parents: []}},
+ rev2: {_number: 2, commit: {parents: []}},
+ },
+ current_revision: 'rev1',
+ status: element.ChangeStatus.MERGED,
+ labels: {},
+ actions: {},
+ };
+
+ sandbox.stub(element, '_getUrlParameter',
+ param => {
+ assert.equal(param, 'revert');
+ return param;
+ });
+
+ sandbox.stub(element.$.actions, 'showRevertDialog',
+ done);
+
+ element._maybeShowRevertDialog();
+ assert.isTrue(Gerrit.awaitPluginsLoaded.called);
+ });
+
+ suite('scroll related tests', () => {
+ test('document scrolling calls function to set scroll height', done => {
+ const originalHeight = document.body.scrollHeight;
+ const scrollStub = sandbox.stub(element, '_handleScroll',
+ () => {
+ assert.isTrue(scrollStub.called);
+ document.body.style.height = originalHeight + 'px';
+ scrollStub.restore();
+ done();
+ });
+ document.body.style.height = '10000px';
+ element._handleScroll();
+ });
+
+ test('scrollTop is set correctly', () => {
+ element.viewState = {scrollTop: TEST_SCROLL_TOP_PX};
+
+ sandbox.stub(element, '_reload', () => {
+ // When element is reloaded, ensure that the history
+ // state has the scrollTop set earlier. This will then
+ // be reset.
+ assert.isTrue(element.viewState.scrollTop == TEST_SCROLL_TOP_PX);
+ return Promise.resolve({});
+ });
+
+ // simulate reloading component, which is done when route
+ // changes to match a regex of change view type.
+ element._paramsChanged({view: Gerrit.Nav.View.CHANGE});
+ });
+
+ test('scrollTop is reset when new change is loaded', () => {
+ element._resetFileListViewState();
+ assert.equal(element.viewState.scrollTop, 0);
+ });
+ });
+
+ suite('reply dialog tests', () => {
+ setup(() => {
+ sandbox.stub(element.$.replyDialog, '_draftChanged');
+ sandbox.stub(element.$.replyDialog, 'fetchChangeUpdates',
+ () => Promise.resolve({isLatest: true}));
+ element._change = {labels: {}};
+ });
+
+ test('reply from comment adds quote text', () => {
+ const e = {detail: {message: {message: 'quote text'}}};
+ element._handleMessageReply(e);
+ assert.equal(element.$.replyDialog.quote, '> quote text\n\n');
+ });
+
+ test('reply from comment replaces quote text', () => {
+ element.$.replyDialog.draft = '> old quote text\n\n some draft text';
+ element.$.replyDialog.quote = '> old quote text\n\n';
+ const e = {detail: {message: {message: 'quote text'}}};
+ element._handleMessageReply(e);
+ assert.equal(element.$.replyDialog.quote, '> quote text\n\n');
+ });
+
+ test('reply from same comment preserves quote text', () => {
+ element.$.replyDialog.draft = '> quote text\n\n some draft text';
+ element.$.replyDialog.quote = '> quote text\n\n';
+ const e = {detail: {message: {message: 'quote text'}}};
+ element._handleMessageReply(e);
+ assert.equal(element.$.replyDialog.draft,
+ '> quote text\n\n some draft text');
+ assert.equal(element.$.replyDialog.quote, '> quote text\n\n');
+ });
+
+ test('reply from top of page contains previous draft', () => {
+ const div = document.createElement('div');
+ element.$.replyDialog.draft = '> quote text\n\n some draft text';
+ element.$.replyDialog.quote = '> quote text\n\n';
+ const e = {target: div, preventDefault: sandbox.spy()};
+ element._handleReplyTap(e);
+ assert.equal(element.$.replyDialog.draft,
+ '> quote text\n\n some draft text');
+ assert.equal(element.$.replyDialog.quote, '> quote text\n\n');
+ });
+ });
+
+ test('reply button is disabled until server config is loaded', () => {
+ assert.isTrue(element._replyDisabled);
+ element._serverConfig = {};
+ assert.isFalse(element._replyDisabled);
+ });
+
+ suite('commit message expand/collapse', () => {
+ setup(() => {
+ sandbox.stub(element, 'fetchChangeUpdates',
+ () => Promise.resolve({isLatest: false}));
+ });
+
+ test('commitCollapseToggle hidden for short commit message', () => {
+ element._latestCommitMessage = '';
+ assert.isTrue(element.$.commitCollapseToggle.hasAttribute('hidden'));
+ });
+
+ test('commitCollapseToggle shown for long commit message', () => {
+ element._latestCommitMessage = _.times(31, String).join('\n');
+ assert.isFalse(element.$.commitCollapseToggle.hasAttribute('hidden'));
+ });
+
+ test('commitCollapseToggle functions', () => {
+ element._latestCommitMessage = _.times(35, String).join('\n');
+ assert.isTrue(element._commitCollapsed);
+ assert.isTrue(element._commitCollapsible);
+ assert.isTrue(
+ element.$.commitMessageEditor.hasAttribute('collapsed'));
+ MockInteractions.tap(element.$.commitCollapseToggleButton);
+ assert.isFalse(element._commitCollapsed);
+ assert.isTrue(element._commitCollapsible);
+ assert.isFalse(
+ element.$.commitMessageEditor.hasAttribute('collapsed'));
+ });
+ });
+
+ suite('related changes expand/collapse', () => {
+ let updateHeightSpy;
+ setup(() => {
+ updateHeightSpy = sandbox.spy(element, '_updateRelatedChangeMaxHeight');
+ });
+
+ test('relatedChangesToggle shown height greater than changeInfo height',
+ () => {
+ assert.isFalse(element.$.relatedChangesToggle.classList
+ .contains('showToggle'));
+ sandbox.stub(element, '_getOffsetHeight', () => 50);
+ sandbox.stub(element, '_getScrollHeight', () => 60);
+ sandbox.stub(element, '_getLineHeight', () => 5);
+ sandbox.stub(window, 'matchMedia', () => { return {matches: true}; });
+ element.$.relatedChanges.dispatchEvent(
+ new CustomEvent('new-section-loaded'));
+ assert.isTrue(element.$.relatedChangesToggle.classList
+ .contains('showToggle'));
+ assert.equal(updateHeightSpy.callCount, 1);
+ });
+
+ test('relatedChangesToggle hidden height less than changeInfo height',
+ () => {
+ assert.isFalse(element.$.relatedChangesToggle.classList
+ .contains('showToggle'));
+ sandbox.stub(element, '_getOffsetHeight', () => 50);
+ sandbox.stub(element, '_getScrollHeight', () => 40);
+ sandbox.stub(element, '_getLineHeight', () => 5);
+ sandbox.stub(window, 'matchMedia', () => { return {matches: true}; });
+ element.$.relatedChanges.dispatchEvent(
+ new CustomEvent('new-section-loaded'));
+ assert.isFalse(element.$.relatedChangesToggle.classList
+ .contains('showToggle'));
+ assert.equal(updateHeightSpy.callCount, 1);
+ });
+
+ test('relatedChangesToggle functions', () => {
+ sandbox.stub(element, '_getOffsetHeight', () => 50);
+ sandbox.stub(window, 'matchMedia', () => { return {matches: false}; });
+ element._relatedChangesLoading = false;
+ assert.isTrue(element._relatedChangesCollapsed);
+ assert.isTrue(
+ element.$.relatedChanges.classList.contains('collapsed'));
+ MockInteractions.tap(element.$.relatedChangesToggleButton);
+ assert.isFalse(element._relatedChangesCollapsed);
+ assert.isFalse(
+ element.$.relatedChanges.classList.contains('collapsed'));
+ });
+
+ test('_updateRelatedChangeMaxHeight without commit toggle', () => {
+ sandbox.stub(element, '_getOffsetHeight', () => 50);
+ sandbox.stub(element, '_getLineHeight', () => 12);
+ sandbox.stub(window, 'matchMedia', () => { return {matches: false}; });
+
+ // 50 (existing height) - 30 (extra height) = 20 (adjusted height).
+ // 20 (max existing height) % 12 (line height) = 6 (remainder).
+ // 20 (adjusted height) - 8 (remainder) = 12 (max height to set).
+
+ element._updateRelatedChangeMaxHeight();
+ assert.equal(getCustomCssValue('--relation-chain-max-height'),
+ '12px');
+ assert.equal(getCustomCssValue('--related-change-btn-top-padding'),
+ '');
+ });
+
+ test('_updateRelatedChangeMaxHeight with commit toggle', () => {
+ element._latestCommitMessage = _.times(31, String).join('\n');
+ sandbox.stub(element, '_getOffsetHeight', () => 50);
+ sandbox.stub(element, '_getLineHeight', () => 12);
+ sandbox.stub(window, 'matchMedia', () => { return {matches: false}; });
+
+ // 50 (existing height) % 12 (line height) = 2 (remainder).
+ // 50 (existing height) - 2 (remainder) = 48 (max height to set).
+
+ element._updateRelatedChangeMaxHeight();
+ assert.equal(getCustomCssValue('--relation-chain-max-height'),
+ '48px');
+ assert.equal(getCustomCssValue('--related-change-btn-top-padding'),
+ '2px');
+ });
+
+ test('_updateRelatedChangeMaxHeight in small screen mode', () => {
+ element._latestCommitMessage = _.times(31, String).join('\n');
+ sandbox.stub(element, '_getOffsetHeight', () => 50);
+ sandbox.stub(element, '_getLineHeight', () => 12);
+ sandbox.stub(window, 'matchMedia', () => { return {matches: true}; });
+
+ element._updateRelatedChangeMaxHeight();
+
+ // 400 (new height) % 12 (line height) = 4 (remainder).
+ // 400 (new height) - 4 (remainder) = 396.
+
+ assert.equal(getCustomCssValue('--relation-chain-max-height'),
+ '396px');
+ });
+
+ test('_updateRelatedChangeMaxHeight in medium screen mode', () => {
+ element._latestCommitMessage = _.times(31, String).join('\n');
+ sandbox.stub(element, '_getOffsetHeight', () => 50);
+ sandbox.stub(element, '_getLineHeight', () => 12);
+ sandbox.stub(window, 'matchMedia', () => {
+ if (window.matchMedia.lastCall.args[0] === '(max-width: 75em)') {
+ return {matches: true};
+ } else {
+ return {matches: false};
+ }
+ });
+
+ // 100 (new height) % 12 (line height) = 4 (remainder).
+ // 100 (new height) - 4 (remainder) = 96.
+ element._updateRelatedChangeMaxHeight();
+ assert.equal(getCustomCssValue('--relation-chain-max-height'),
+ '96px');
+ });
+
+ suite('update checks', () => {
+ setup(() => {
+ sandbox.spy(element, '_startUpdateCheckTimer');
+ sandbox.stub(element, 'async', f => {
+ // Only fire the async callback one time.
+ if (element.async.callCount > 1) { return; }
+ f.call(element);
+ });
+ });
+
+ test('_startUpdateCheckTimer negative delay', () => {
+ sandbox.stub(element, 'fetchChangeUpdates');
+
+ element._serverConfig = {change: {update_delay: -1}};
+
+ assert.isTrue(element._startUpdateCheckTimer.called);
+ assert.isFalse(element.fetchChangeUpdates.called);
+ });
+
+ test('_startUpdateCheckTimer up-to-date', () => {
+ sandbox.stub(element, 'fetchChangeUpdates',
+ () => Promise.resolve({isLatest: true}));
+
+ element._serverConfig = {change: {update_delay: 12345}};
+
+ assert.isTrue(element._startUpdateCheckTimer.called);
+ assert.isTrue(element.fetchChangeUpdates.called);
+ assert.equal(element.async.lastCall.args[1], 12345 * 1000);
+ });
+
+ test('_startUpdateCheckTimer out-of-date shows an alert', done => {
+ sandbox.stub(element, 'fetchChangeUpdates',
+ () => Promise.resolve({isLatest: false}));
+ element.addEventListener('show-alert', e => {
+ assert.equal(e.detail.message,
+ 'A newer patch set has been uploaded');
+ done();
+ });
+ element._serverConfig = {change: {update_delay: 12345}};
+ });
+
+ test('_startUpdateCheckTimer new status shows an alert', done => {
+ sandbox.stub(element, 'fetchChangeUpdates')
+ .returns(Promise.resolve({
+ isLatest: true,
+ newStatus: element.ChangeStatus.MERGED,
+ }));
+ element.addEventListener('show-alert', e => {
+ assert.equal(e.detail.message, 'This change has been merged');
+ done();
+ });
+ element._serverConfig = {change: {update_delay: 12345}};
+ });
+
+ test('_startUpdateCheckTimer new messages shows an alert', done => {
+ sandbox.stub(element, 'fetchChangeUpdates')
+ .returns(Promise.resolve({
+ isLatest: true,
+ newMessages: true,
+ }));
+ element.addEventListener('show-alert', e => {
+ assert.equal(e.detail.message,
+ 'There are new messages on this change');
+ done();
+ });
+ element._serverConfig = {change: {update_delay: 12345}};
+ });
+ });
+
+ test('canStartReview computation', () => {
+ const change1 = {};
+ const change2 = {
+ actions: {
+ ready: {
+ enabled: true,
+ },
+ },
+ };
+ const change3 = {
+ actions: {
+ ready: {
+ label: 'Ready for Review',
+ },
+ },
+ };
+ assert.isFalse(element._computeCanStartReview(change1));
+ assert.isTrue(element._computeCanStartReview(change2));
+ assert.isFalse(element._computeCanStartReview(change3));
+ });
+ });
+
+ test('header class computation', () => {
+ assert.equal(element._computeHeaderClass(), 'header');
+ assert.equal(element._computeHeaderClass(true), 'header editMode');
+ });
+
+ test('_maybeScrollToMessage', done => {
+ flush(() => {
+ const scrollStub = sandbox.stub(element.messagesList,
+ 'scrollToMessage');
+
+ element._maybeScrollToMessage('');
+ assert.isFalse(scrollStub.called);
+ element._maybeScrollToMessage('message');
+ assert.isFalse(scrollStub.called);
+ element._maybeScrollToMessage('#message-TEST');
+ assert.isTrue(scrollStub.called);
+ assert.equal(scrollStub.lastCall.args[0], 'TEST');
+ done();
+ });
+ });
+
+ test('topic update reloads related changes', () => {
+ sandbox.stub(element.$.relatedChanges, 'reload');
+ element.dispatchEvent(new CustomEvent('topic-changed'));
+ assert.isTrue(element.$.relatedChanges.reload.calledOnce);
+ });
+
+ test('_computeEditMode', () => {
+ const callCompute = (range, params) =>
+ element._computeEditMode({base: range}, {base: params});
+ assert.isFalse(callCompute({}, {}));
+ assert.isTrue(callCompute({}, {edit: true}));
+ assert.isFalse(callCompute({basePatchNum: 'PARENT', patchNum: 1}, {}));
+ assert.isFalse(callCompute({basePatchNum: 'edit', patchNum: 1}, {}));
+ assert.isTrue(callCompute({basePatchNum: 1, patchNum: 'edit'}, {}));
+ });
+
+ test('_processEdit', () => {
+ element._patchRange = {};
+ const change = {
+ current_revision: 'foo',
+ revisions: {foo: {commit: {}, actions: {cherrypick: {enabled: true}}}},
+ };
+ let mockChange;
+
+ // With no edit, mockChange should be unmodified.
+ element._processEdit(mockChange = _.cloneDeep(change), null);
+ assert.deepEqual(mockChange, change);
+
+ // When edit is not based on the latest PS, current_revision should be
+ // unmodified.
+ const edit = {
+ base_patch_set_number: 1,
+ commit: {commit: 'bar'},
+ fetch: true,
+ };
+ element._processEdit(mockChange = _.cloneDeep(change), edit);
+ assert.notDeepEqual(mockChange, change);
+ assert.equal(mockChange.revisions.bar._number, element.EDIT_NAME);
+ assert.equal(mockChange.current_revision, change.current_revision);
+ assert.deepEqual(mockChange.revisions.bar.commit, {commit: 'bar'});
+ assert.notOk(mockChange.revisions.bar.actions);
+
+ edit.base_revision = 'foo';
+ element._processEdit(mockChange = _.cloneDeep(change), edit);
+ assert.notDeepEqual(mockChange, change);
+ assert.equal(mockChange.current_revision, 'bar');
+ assert.deepEqual(mockChange.revisions.bar.actions,
+ mockChange.revisions.foo.actions);
+
+ // If _patchRange.patchNum is defined, do not load edit.
+ element._patchRange.patchNum = 'baz';
+ change.current_revision = 'baz';
+ element._processEdit(mockChange = _.cloneDeep(change), edit);
+ assert.equal(element._patchRange.patchNum, 'baz');
+ assert.notOk(mockChange.revisions.bar.actions);
+ });
+
+ test('file-action-tap handling', () => {
+ element._patchRange = {
+ basePatchNum: 'PARENT',
+ patchNum: 1,
+ };
+ const fileList = element.$.fileList;
+ const Actions = GrEditConstants.Actions;
+ const controls = element.$.fileListHeader.$.editControls;
+ sandbox.stub(controls, 'openDeleteDialog');
+ sandbox.stub(controls, 'openRenameDialog');
+ sandbox.stub(controls, 'openRestoreDialog');
+ sandbox.stub(Gerrit.Nav, 'getEditUrlForDiff');
+ sandbox.stub(Gerrit.Nav, 'navigateToRelativeUrl');
+
+ // Delete
+ fileList.dispatchEvent(new CustomEvent('file-action-tap', {
+ detail: {action: Actions.DELETE.id, path: 'foo'},
+ bubbles: true,
+ composed: true,
+ }));
+ flushAsynchronousOperations();
+
+ assert.isTrue(controls.openDeleteDialog.called);
+ assert.equal(controls.openDeleteDialog.lastCall.args[0], 'foo');
+
+ // Restore
+ fileList.dispatchEvent(new CustomEvent('file-action-tap', {
+ detail: {action: Actions.RESTORE.id, path: 'foo'},
+ bubbles: true,
+ composed: true,
+ }));
+ flushAsynchronousOperations();
+
+ assert.isTrue(controls.openRestoreDialog.called);
+ assert.equal(controls.openRestoreDialog.lastCall.args[0], 'foo');
+
+ // Rename
+ fileList.dispatchEvent(new CustomEvent('file-action-tap', {
+ detail: {action: Actions.RENAME.id, path: 'foo'},
+ bubbles: true,
+ composed: true,
+ }));
+ flushAsynchronousOperations();
+
+ assert.isTrue(controls.openRenameDialog.called);
+ assert.equal(controls.openRenameDialog.lastCall.args[0], 'foo');
+
+ // Open
+ fileList.dispatchEvent(new CustomEvent('file-action-tap', {
+ detail: {action: Actions.OPEN.id, path: 'foo'},
+ bubbles: true,
+ composed: true,
+ }));
+ flushAsynchronousOperations();
+
+ assert.isTrue(Gerrit.Nav.getEditUrlForDiff.called);
+ assert.equal(Gerrit.Nav.getEditUrlForDiff.lastCall.args[1], 'foo');
+ assert.equal(Gerrit.Nav.getEditUrlForDiff.lastCall.args[2], '1');
+ assert.isTrue(Gerrit.Nav.navigateToRelativeUrl.called);
+ });
+
+ test('_selectedRevision updates when patchNum is changed', () => {
+ const revision1 = {_number: 1, commit: {parents: []}};
+ const revision2 = {_number: 2, commit: {parents: []}};
+ sandbox.stub(element.$.restAPI, 'getChangeDetail').returns(
+ Promise.resolve({
+ revisions: {
+ aaa: revision1,
+ bbb: revision2,
+ },
+ labels: {},
+ actions: {},
+ current_revision: 'bbb',
+ change_id: 'loremipsumdolorsitamet',
+ }));
+ sandbox.stub(element, '_getEdit').returns(Promise.resolve());
+ sandbox.stub(element, '_getPreferences').returns(Promise.resolve({}));
+ element._patchRange = {patchNum: '2'};
+ return element._getChangeDetail().then(() => {
+ assert.strictEqual(element._selectedRevision, revision2);
+
+ element.set('_patchRange.patchNum', '1');
+ assert.strictEqual(element._selectedRevision, revision1);
+ });
+ });
+
+ test('_selectedRevision is assigned when patchNum is edit', () => {
+ const revision1 = {_number: 1, commit: {parents: []}};
+ const revision2 = {_number: 2, commit: {parents: []}};
+ const revision3 = {_number: 'edit', commit: {parents: []}};
+ sandbox.stub(element.$.restAPI, 'getChangeDetail').returns(
+ Promise.resolve({
+ revisions: {
+ aaa: revision1,
+ bbb: revision2,
+ ccc: revision3,
+ },
+ labels: {},
+ actions: {},
+ current_revision: 'ccc',
+ change_id: 'loremipsumdolorsitamet',
+ }));
+ sandbox.stub(element, '_getEdit').returns(Promise.resolve());
+ sandbox.stub(element, '_getPreferences').returns(Promise.resolve({}));
+ element._patchRange = {patchNum: 'edit'};
+ return element._getChangeDetail().then(() => {
+ assert.strictEqual(element._selectedRevision, revision3);
+ });
+ });
+
+ test('_sendShowChangeEvent', () => {
+ element._change = {labels: {}};
+ element._patchRange = {patchNum: 4};
+ element._mergeable = true;
+ const showStub = sandbox.stub(element.$.jsAPI, 'handleEvent');
+ element._sendShowChangeEvent();
+ assert.isTrue(showStub.calledOnce);
+ assert.equal(
+ showStub.lastCall.args[0], element.$.jsAPI.EventType.SHOW_CHANGE);
+ assert.deepEqual(showStub.lastCall.args[1], {
+ change: {labels: {}},
+ patchNum: 4,
+ info: {mergeable: true},
+ });
+ });
+
+ suite('_handleEditTap', () => {
+ let fireEdit;
+
+ setup(() => {
+ fireEdit = () => {
+ element.$.actions.dispatchEvent(new CustomEvent('edit-tap'));
+ };
+ navigateToChangeStub.restore();
+
+ element._change = {revisions: {rev1: {_number: 1}}};
+ });
+
+ test('edit exists in revisions', done => {
+ sandbox.stub(Gerrit.Nav, 'navigateToChange', (...args) => {
+ assert.equal(args.length, 2);
+ assert.equal(args[1], element.EDIT_NAME); // patchNum
+ done();
+ });
+
+ element.set('_change.revisions.rev2', {_number: element.EDIT_NAME});
+ flushAsynchronousOperations();
+
+ fireEdit();
+ });
+
+ test('no edit exists in revisions, non-latest patchset', done => {
+ sandbox.stub(Gerrit.Nav, 'navigateToChange', (...args) => {
+ assert.equal(args.length, 4);
+ assert.equal(args[1], 1); // patchNum
+ assert.equal(args[3], true); // opt_isEdit
+ done();
+ });
+
+ element.set('_change.revisions.rev2', {_number: 2});
+ element._patchRange = {patchNum: 1};
+ flushAsynchronousOperations();
+
+ fireEdit();
+ });
+
+ test('no edit exists in revisions, latest patchset', done => {
+ sandbox.stub(Gerrit.Nav, 'navigateToChange', (...args) => {
+ assert.equal(args.length, 4);
+ // No patch should be specified when patchNum == latest.
+ assert.isNotOk(args[1]); // patchNum
+ assert.equal(args[3], true); // opt_isEdit
+ done();
+ });
+
+ element.set('_change.revisions.rev2', {_number: 2});
+ element._patchRange = {patchNum: 2};
+ flushAsynchronousOperations();
+
+ fireEdit();
+ });
+ });
+
+ test('_handleStopEditTap', done => {
+ sandbox.stub(element.$.metadata, '_computeLabelNames');
+ navigateToChangeStub.restore();
+ sandbox.stub(element, 'computeLatestPatchNum').returns(1);
+ sandbox.stub(Gerrit.Nav, 'navigateToChange', (...args) => {
+ assert.equal(args.length, 2);
+ assert.equal(args[1], 1); // patchNum
+ done();
+ });
+
+ element._patchRange = {patchNum: 1};
+ element.$.actions.dispatchEvent(new CustomEvent('stop-edit-tap',
+ {bubbles: false}));
+ });
+
+ suite('plugin endpoints', () => {
+ test('endpoint params', done => {
+ element._change = {labels: {}};
+ element._selectedRevision = {};
+ let hookEl;
+ let plugin;
+ Gerrit.install(
+ p => {
+ plugin = p;
+ plugin.hook('change-view-integration').getLastAttached()
+ .then(
+ el => hookEl = el);
+ },
+ '0.1',
+ 'http://some/plugins/url.html');
+ flush(() => {
+ assert.strictEqual(hookEl.plugin, plugin);
+ assert.strictEqual(hookEl.change, element._change);
+ assert.strictEqual(hookEl.revision, element._selectedRevision);
+ done();
+ });
+ });
+ });
+
+ suite('_getMergeability', () => {
+ let getMergeableStub;
+
+ setup(() => {
+ element._change = {labels: {}};
+ getMergeableStub = sandbox.stub(element.$.restAPI, 'getMergeable')
+ .returns(Promise.resolve({mergeable: true}));
+ });
+
+ test('merged change', () => {
+ element._mergeable = null;
+ element._change.status = element.ChangeStatus.MERGED;
+ return element._getMergeability().then(() => {
+ assert.isFalse(element._mergeable);
+ assert.isFalse(getMergeableStub.called);
+ });
+ });
+
+ test('abandoned change', () => {
+ element._mergeable = null;
+ element._change.status = element.ChangeStatus.ABANDONED;
+ return element._getMergeability().then(() => {
+ assert.isFalse(element._mergeable);
+ assert.isFalse(getMergeableStub.called);
+ });
+ });
+
+ test('open change', () => {
+ element._mergeable = null;
+ return element._getMergeability().then(() => {
+ assert.isTrue(element._mergeable);
+ assert.isTrue(getMergeableStub.called);
+ });
+ });
+ });
+
+ test('_paramsChanged sets in projectLookup', () => {
+ sandbox.stub(element.$.relatedChanges, 'reload');
+ sandbox.stub(element, '_reload').returns(Promise.resolve());
+ const setStub = sandbox.stub(element.$.restAPI, 'setInProjectLookup');
+ element._paramsChanged({
+ view: Gerrit.Nav.View.CHANGE,
+ changeNum: 101,
+ project: 'test-project',
+ });
+ assert.isTrue(setStub.calledOnce);
+ assert.isTrue(setStub.calledWith(101, 'test-project'));
+ });
+
+ test('_handleToggleStar called when star is tapped', () => {
+ element._change = {
+ owner: {_account_id: 1},
+ starred: false,
+ };
+ element._loggedIn = true;
+ const stub = sandbox.stub(element, '_handleToggleStar');
+ flushAsynchronousOperations();
+
+ MockInteractions.tap(element.$.changeStar.shadowRoot
+ .querySelector('button'));
+ assert.isTrue(stub.called);
+ });
+
+ suite('gr-reporting tests', () => {
+ setup(() => {
+ element._patchRange = {
+ basePatchNum: 'PARENT',
+ patchNum: 1,
+ };
+ sandbox.stub(element, '_getChangeDetail').returns(Promise.resolve());
+ sandbox.stub(element, '_getProjectConfig').returns(Promise.resolve());
+ sandbox.stub(element, '_reloadComments').returns(Promise.resolve());
+ sandbox.stub(element, '_getMergeability').returns(Promise.resolve());
+ sandbox.stub(element, '_getLatestCommitMessage')
+ .returns(Promise.resolve());
+ });
+
+ test('don\'t report changedDisplayed on reply', done => {
+ const changeDisplayStub =
+ sandbox.stub(element.$.reporting, 'changeDisplayed');
+ const changeFullyLoadedStub =
+ sandbox.stub(element.$.reporting, 'changeFullyLoaded');
+ element._handleReplySent();
+ flush(() => {
+ assert.isFalse(changeDisplayStub.called);
+ assert.isFalse(changeFullyLoadedStub.called);
+ done();
+ });
+ });
+
+ test('report changedDisplayed on _paramsChanged', done => {
+ const changeDisplayStub =
+ sandbox.stub(element.$.reporting, 'changeDisplayed');
+ const changeFullyLoadedStub =
+ sandbox.stub(element.$.reporting, 'changeFullyLoaded');
+ element._paramsChanged({
+ view: Gerrit.Nav.View.CHANGE,
+ changeNum: 101,
+ project: 'test-project',
+ });
+ flush(() => {
+ assert.isTrue(changeDisplayStub.called);
+ assert.isTrue(changeFullyLoadedStub.called);
+ done();
+ });
+ });
+ });
+});
</script>