Merge "Convert async-util_test to Typescript"
diff --git a/plugins/replication b/plugins/replication
index dc9bb2e..46cfb7d 160000
--- a/plugins/replication
+++ b/plugins/replication
@@ -1 +1 @@
-Subproject commit dc9bb2e946e4c6c31e8a4665f30eca6d00017523
+Subproject commit 46cfb7dd5b6891f991cfe66e72c08953487c1c81
diff --git a/polygerrit-ui/app/BUILD b/polygerrit-ui/app/BUILD
index fcf1cf4..4d0bb1f 100644
--- a/polygerrit-ui/app/BUILD
+++ b/polygerrit-ui/app/BUILD
@@ -109,7 +109,6 @@
"elements/checks/gr-hovercard-run_html.ts",
"elements/core/gr-main-header/gr-main-header_html.ts",
"elements/core/gr-search-bar/gr-search-bar_html.ts",
- "elements/core/gr-smart-search/gr-smart-search_html.ts",
"elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog_html.ts",
"elements/diff/gr-diff-builder/gr-diff-builder-element_html.ts",
"elements/diff/gr-diff-host/gr-diff-host_html.ts",
@@ -123,17 +122,14 @@
"elements/settings/gr-watched-projects-editor/gr-watched-projects-editor_html.ts",
"elements/shared/gr-account-list/gr-account-list_html.ts",
"elements/shared/gr-autocomplete/gr-autocomplete_html.ts",
- "elements/shared/gr-change-status/gr-change-status_html.ts",
"elements/shared/gr-comment-thread/gr-comment-thread_html.ts",
"elements/shared/gr-comment/gr-comment_html.ts",
"elements/shared/gr-confirm-delete-comment-dialog/gr-confirm-delete-comment-dialog_html.ts",
- "elements/shared/gr-copy-clipboard/gr-copy-clipboard_html.ts",
"elements/shared/gr-dialog/gr-dialog_html.ts",
"elements/shared/gr-diff-preferences/gr-diff-preferences_html.ts",
"elements/shared/gr-download-commands/gr-download-commands_html.ts",
"elements/shared/gr-dropdown-list/gr-dropdown-list_html.ts",
"elements/shared/gr-dropdown/gr-dropdown_html.ts",
- "elements/shared/gr-editable-content/gr-editable-content_html.ts",
"elements/shared/gr-hovercard-account/gr-hovercard-account_html.ts",
"elements/shared/gr-label-info/gr-label-info_html.ts",
"elements/shared/gr-labeled-autocomplete/gr-labeled-autocomplete_html.ts",
diff --git a/polygerrit-ui/app/elements/core/gr-smart-search/gr-smart-search.ts b/polygerrit-ui/app/elements/core/gr-smart-search/gr-smart-search.ts
index aa7e2e0..7419713 100644
--- a/polygerrit-ui/app/elements/core/gr-smart-search/gr-smart-search.ts
+++ b/polygerrit-ui/app/elements/core/gr-smart-search/gr-smart-search.ts
@@ -32,6 +32,12 @@
const SELF_EXPRESSION = 'self';
const ME_EXPRESSION = 'me';
+declare global {
+ interface HTMLElementEventMap {
+ 'handle-search': CustomEvent<SearchBarHandleSearchDetail>;
+ }
+}
+
@customElement('gr-smart-search')
export class GrSmartSearch extends PolymerElement {
static get template() {
@@ -39,7 +45,7 @@
}
@property({type: String})
- searchQuery?: string;
+ searchQuery = '';
@property({type: Object})
_config?: ServerInfo;
diff --git a/polygerrit-ui/app/elements/core/gr-smart-search/gr-smart-search_test.js b/polygerrit-ui/app/elements/core/gr-smart-search/gr-smart-search_test.js
deleted file mode 100644
index f3a9965..0000000
--- a/polygerrit-ui/app/elements/core/gr-smart-search/gr-smart-search_test.js
+++ /dev/null
@@ -1,137 +0,0 @@
-/**
- * @license
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import '../../../test/common-test-setup-karma.js';
-import './gr-smart-search.js';
-import {stubRestApi} from '../../../test/test-utils.js';
-
-const basicFixture = fixtureFromElement('gr-smart-search');
-
-suite('gr-smart-search tests', () => {
- let element;
-
- setup(() => {
- element = basicFixture.instantiate();
- });
-
- test('Autocompletes accounts', () => {
- stubRestApi('getSuggestedAccounts').callsFake(() =>
- Promise.resolve([
- {
- name: 'fred',
- email: 'fred@goog.co',
- },
- ])
- );
- return element._fetchAccounts('owner', 'fr').then(s => {
- assert.deepEqual(s[0], {text: 'owner:fred@goog.co', label: 'fred'});
- });
- });
-
- test('Inserts self as option when valid', () => {
- stubRestApi('getSuggestedAccounts').callsFake( () =>
- Promise.resolve([
- {
- name: 'fred',
- email: 'fred@goog.co',
- },
- ])
- );
- element._fetchAccounts('owner', 's')
- .then(s => {
- assert.deepEqual(s[0], {text: 'owner:fred@goog.co', label: 'fred'});
- assert.deepEqual(s[1], {text: 'owner:self'});
- })
- .then(() => element._fetchAccounts('owner', 'selfs'))
- .then(s => {
- assert.notEqual(s[0], {text: 'owner:self'});
- });
- });
-
- test('Inserts me as option when valid', () => {
- stubRestApi('getSuggestedAccounts').callsFake( () =>
- Promise.resolve([
- {
- name: 'fred',
- email: 'fred@goog.co',
- },
- ])
- );
- return element._fetchAccounts('owner', 'm')
- .then(s => {
- assert.deepEqual(s[0], {text: 'owner:fred@goog.co', label: 'fred'});
- assert.deepEqual(s[1], {text: 'owner:me'});
- })
- .then(() => element._fetchAccounts('owner', 'meme'))
- .then(s => {
- assert.notEqual(s[0], {text: 'owner:me'});
- });
- });
-
- test('Autocompletes groups', () => {
- stubRestApi('getSuggestedGroups').callsFake( () =>
- Promise.resolve({
- Polygerrit: 0,
- gerrit: 0,
- gerrittest: 0,
- })
- );
- return element._fetchGroups('ownerin', 'pol').then(s => {
- assert.deepEqual(s[0], {text: 'ownerin:Polygerrit'});
- });
- });
-
- test('Autocompletes projects', () => {
- stubRestApi('getSuggestedProjects').callsFake( () =>
- Promise.resolve({Polygerrit: 0}));
- return element._fetchProjects('project', 'pol').then(s => {
- assert.deepEqual(s[0], {text: 'project:Polygerrit'});
- });
- });
-
- test('Autocomplete doesnt override exact matches to input', () => {
- stubRestApi('getSuggestedGroups').callsFake( () =>
- Promise.resolve({
- Polygerrit: 0,
- gerrit: 0,
- gerrittest: 0,
- })
- );
- return element._fetchGroups('ownerin', 'gerrit').then(s => {
- assert.deepEqual(s[0], {text: 'ownerin:Polygerrit'});
- assert.deepEqual(s[1], {text: 'ownerin:gerrit'});
- assert.deepEqual(s[2], {text: 'ownerin:gerrittest'});
- });
- });
-
- test('Autocompletes accounts with no email', () => {
- stubRestApi('getSuggestedAccounts').callsFake( () =>
- Promise.resolve([{name: 'fred'}]));
- return element._fetchAccounts('owner', 'fr').then(s => {
- assert.deepEqual(s[0], {text: 'owner:"fred"', label: 'fred'});
- });
- });
-
- test('Autocompletes accounts with email', () => {
- stubRestApi('getSuggestedAccounts').callsFake( () =>
- Promise.resolve([{email: 'fred@goog.co'}]));
- return element._fetchAccounts('owner', 'fr').then(s => {
- assert.deepEqual(s[0], {text: 'owner:fred@goog.co', label: ''});
- });
- });
-});
-
diff --git a/polygerrit-ui/app/elements/core/gr-smart-search/gr-smart-search_test.ts b/polygerrit-ui/app/elements/core/gr-smart-search/gr-smart-search_test.ts
new file mode 100644
index 0000000..0218a8f
--- /dev/null
+++ b/polygerrit-ui/app/elements/core/gr-smart-search/gr-smart-search_test.ts
@@ -0,0 +1,143 @@
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import '../../../test/common-test-setup-karma';
+import './gr-smart-search';
+import {GrSmartSearch} from './gr-smart-search';
+import {stubRestApi} from '../../../test/test-utils';
+import {EmailAddress, GroupId, UrlEncodedRepoName} from '../../../types/common';
+
+const basicFixture = fixtureFromElement('gr-smart-search');
+
+suite('gr-smart-search tests', () => {
+ let element: GrSmartSearch;
+
+ setup(() => {
+ element = basicFixture.instantiate();
+ });
+
+ test('Autocompletes accounts', () => {
+ stubRestApi('getSuggestedAccounts').callsFake(() =>
+ Promise.resolve([
+ {
+ name: 'fred',
+ email: 'fred@goog.co' as EmailAddress,
+ },
+ ])
+ );
+ return element._fetchAccounts('owner', 'fr').then(s => {
+ assert.deepEqual(s[0], {text: 'owner:fred@goog.co', label: 'fred'});
+ });
+ });
+
+ test('Inserts self as option when valid', () => {
+ stubRestApi('getSuggestedAccounts').callsFake(() =>
+ Promise.resolve([
+ {
+ name: 'fred',
+ email: 'fred@goog.co' as EmailAddress,
+ },
+ ])
+ );
+ element
+ ._fetchAccounts('owner', 's')
+ .then(s => {
+ assert.deepEqual(s[0], {text: 'owner:fred@goog.co', label: 'fred'});
+ assert.deepEqual(s[1], {text: 'owner:self'});
+ })
+ .then(() => element._fetchAccounts('owner', 'selfs'))
+ .then(s => {
+ assert.notEqual(s[0], {text: 'owner:self'});
+ });
+ });
+
+ test('Inserts me as option when valid', () => {
+ stubRestApi('getSuggestedAccounts').callsFake(() =>
+ Promise.resolve([
+ {
+ name: 'fred',
+ email: 'fred@goog.co' as EmailAddress,
+ },
+ ])
+ );
+ return element
+ ._fetchAccounts('owner', 'm')
+ .then(s => {
+ assert.deepEqual(s[0], {text: 'owner:fred@goog.co', label: 'fred'});
+ assert.deepEqual(s[1], {text: 'owner:me'});
+ })
+ .then(() => element._fetchAccounts('owner', 'meme'))
+ .then(s => {
+ assert.notEqual(s[0], {text: 'owner:me'});
+ });
+ });
+
+ test('Autocompletes groups', () => {
+ stubRestApi('getSuggestedGroups').callsFake(() =>
+ Promise.resolve({
+ Polygerrit: {id: '4c97682e6ce61b7247f3381b6f1789356666de7f' as GroupId},
+ gerrit: {id: '4c97682e6ce61b7247f3381b6f1789356666de7f' as GroupId},
+ gerrittest: {id: '4c97682e6ce61b7247f3381b6f1789356666de7f' as GroupId},
+ })
+ );
+ return element._fetchGroups('ownerin', 'pol').then(s => {
+ assert.deepEqual(s[0], {text: 'ownerin:Polygerrit'});
+ });
+ });
+
+ test('Autocompletes projects', () => {
+ stubRestApi('getSuggestedProjects').callsFake(() =>
+ Promise.resolve({Polygerrit: {id: 'test' as UrlEncodedRepoName}})
+ );
+ return element._fetchProjects('project', 'pol').then(s => {
+ assert.deepEqual(s[0], {text: 'project:Polygerrit'});
+ });
+ });
+
+ test('Autocomplete doesnt override exact matches to input', () => {
+ stubRestApi('getSuggestedGroups').callsFake(() =>
+ Promise.resolve({
+ Polygerrit: {id: '4c97682e6ce61b7247f3381b6f1789356666de7f' as GroupId},
+ gerrit: {id: '4c97682e6ce61b7247f3381b6f1789356666de7f' as GroupId},
+ gerrittest: {id: '4c97682e6ce61b7247f3381b6f1789356666de7f' as GroupId},
+ })
+ );
+ return element._fetchGroups('ownerin', 'gerrit').then(s => {
+ assert.deepEqual(s[0], {text: 'ownerin:Polygerrit'});
+ assert.deepEqual(s[1], {text: 'ownerin:gerrit'});
+ assert.deepEqual(s[2], {text: 'ownerin:gerrittest'});
+ });
+ });
+
+ test('Autocompletes accounts with no email', () => {
+ stubRestApi('getSuggestedAccounts').callsFake(() =>
+ Promise.resolve([{name: 'fred'}])
+ );
+ return element._fetchAccounts('owner', 'fr').then(s => {
+ assert.deepEqual(s[0], {text: 'owner:"fred"', label: 'fred'});
+ });
+ });
+
+ test('Autocompletes accounts with email', () => {
+ stubRestApi('getSuggestedAccounts').callsFake(() =>
+ Promise.resolve([{email: 'fred@goog.co' as EmailAddress}])
+ );
+ return element._fetchAccounts('owner', 'fr').then(s => {
+ assert.deepEqual(s[0], {text: 'owner:fred@goog.co', label: ''});
+ });
+ });
+});
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.ts b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.ts
index eb50914..864fd79 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.ts
@@ -514,9 +514,7 @@
if (beforeNumber !== 'FILE' && beforeNumber !== 'LOST') {
const responsiveMode = getResponsiveMode(this._prefs, this._renderPrefs);
const lineLimit =
- responsiveMode !== 'FULL_RESPONSIVE'
- ? this._prefs.line_length
- : Infinity;
+ responsiveMode === 'NONE' ? this._prefs.line_length : Infinity;
const contentText = this._formatText(
line.text,
this._prefs.tab_size,
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/token-highlight-layer.ts b/polygerrit-ui/app/elements/diff/gr-diff-builder/token-highlight-layer.ts
index c8b3901..f418cfa 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/token-highlight-layer.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/token-highlight-layer.ts
@@ -23,7 +23,7 @@
lineNumberToNumber,
} from '../gr-diff/gr-diff-utils';
-const tokenMatcher = new RegExp(/[a-zA-Z0-9_-]+/g);
+const tokenMatcher = new RegExp(/[\w]+/g);
/** CSS class for all tokens. */
const CSS_TOKEN = 'token';
diff --git a/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status.ts b/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status.ts
index 65e8e9f..0bd02d5 100644
--- a/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status.ts
+++ b/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status.ts
@@ -77,11 +77,11 @@
@property({type: Object})
resolveWeblinks?: GeneratedWebLink[] = [];
- _computeStatusString(status: ChangeStates) {
+ _computeStatusString(status?: ChangeStates) {
if (status === ChangeStates.WIP && !this.flat) {
return 'Work in Progress';
}
- return status;
+ return status ?? '';
}
_toClassName(str?: ChangeStates) {
@@ -107,14 +107,14 @@
revertedChange?: ChangeInfo,
resolveWeblinks?: GeneratedWebLink[],
status?: ChangeStates
- ): string | undefined {
+ ): string {
if (revertedChange) {
return GerritNav.getUrlForSearchQuery(`${revertedChange._number}`);
}
if (status === ChangeStates.MERGE_CONFLICT && resolveWeblinks?.length) {
- return resolveWeblinks[0].url;
+ return resolveWeblinks[0].url ?? '';
}
- return undefined;
+ return '';
}
showResolveIcon(
diff --git a/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.ts b/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.ts
index 4a2bcee..36cffb7 100644
--- a/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.ts
+++ b/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.ts
@@ -20,6 +20,7 @@
import {IronIconElement} from '@polymer/iron-icon';
import {assertIsDefined, queryAndAssert} from '../../../utils/common-util';
import {classMap} from 'lit-html/directives/class-map';
+import {ifDefined} from 'lit-html/directives/if-defined';
import {css, customElement, html, property} from 'lit-element';
import {GrLitElement} from '../../lit/gr-lit-element';
import {GrButton} from '../gr-button/gr-button';
@@ -126,7 +127,7 @@
link=""
?has-tooltip=${this.hasTooltip}
class="copyToClipboard"
- title="${this.buttonTitle}"
+ title="${ifDefined(this.buttonTitle)}"
@click="${this._copyToClipboard}"
aria-label="Click to copy to clipboard"
>
diff --git a/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard_test.js b/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard_test.ts
similarity index 73%
rename from polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard_test.js
rename to polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard_test.ts
index 45847d7..ef62fe9 100644
--- a/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard_test.ts
@@ -15,14 +15,16 @@
* limitations under the License.
*/
-import '../../../test/common-test-setup-karma.js';
-import './gr-copy-clipboard.js';
-import {queryAndAssert} from '../../../test/test-utils.js';
+import '../../../test/common-test-setup-karma';
+import './gr-copy-clipboard';
+import {GrCopyClipboard} from './gr-copy-clipboard';
+import {queryAndAssert} from '../../../test/test-utils';
+import * as MockInteractions from '@polymer/iron-test-helpers/mock-interactions';
const basicFixture = fixtureFromElement('gr-copy-clipboard');
suite('gr-copy-clipboard tests', () => {
- let element;
+ let element: GrCopyClipboard;
setup(async () => {
element = basicFixture.instantiate();
@@ -33,35 +35,34 @@
test('copy to clipboard', () => {
const clipboardSpy = sinon.spy(navigator.clipboard, 'writeText');
- const copyBtn = element.shadowRoot
- .querySelector('.copyToClipboard');
+ const copyBtn = queryAndAssert(element, '.copyToClipboard');
MockInteractions.click(copyBtn);
assert.isTrue(clipboardSpy.called);
});
test('focusOnCopy', () => {
element.focusOnCopy();
- const activeElement = element.shadowRoot.activeElement;
- const button = element.shadowRoot.querySelector('.copyToClipboard');
+ const activeElement = element.shadowRoot!.activeElement;
+ const button = queryAndAssert(element, '.copyToClipboard');
assert.deepEqual(activeElement, button);
});
test('_handleInputClick', () => {
// iron-input as parent should never be hidden as copy won't work
// on nested hidden elements
- const ironInputElement = element.shadowRoot.querySelector('iron-input');
+ const ironInputElement = queryAndAssert(element, 'iron-input');
assert.notEqual(getComputedStyle(ironInputElement).display, 'none');
- const inputElement = element.shadowRoot.querySelector('input');
+ const inputElement = queryAndAssert(element, 'input') as HTMLInputElement;
MockInteractions.tap(inputElement);
assert.equal(inputElement.selectionStart, 0);
- assert.equal(inputElement.selectionEnd, element.text.length - 1);
+ assert.equal(inputElement.selectionEnd, element.text!.length! - 1);
});
test('hideInput', async () => {
// iron-input as parent should never be hidden as copy won't work
// on nested hidden elements
- const ironInputElement = element.shadowRoot.querySelector('iron-input');
+ const ironInputElement = queryAndAssert(element, 'iron-input');
assert.notEqual(getComputedStyle(ironInputElement).display, 'none');
const input = queryAndAssert(element, 'input');
@@ -76,10 +77,8 @@
divParent.appendChild(element);
const clickStub = sinon.stub();
divParent.addEventListener('click', clickStub);
- element.stopPropagation = true;
- const copyBtn = element.shadowRoot.querySelector('.copyToClipboard');
+ const copyBtn = queryAndAssert(element, '.copyToClipboard');
MockInteractions.tap(copyBtn);
assert.isFalse(clickStub.called);
});
});
-
diff --git a/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content.ts b/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content.ts
index 83cd380..592efba 100644
--- a/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content.ts
+++ b/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content.ts
@@ -106,13 +106,14 @@
_saveDisabled!: boolean;
@property({type: String, observer: '_newContentChanged'})
- _newContent?: string;
+ _newContent = '';
private readonly storage = appContext.storageService;
private readonly reporting = appContext.reportingService;
- private storeTask?: DelayedTask;
+ // Tests use this so needs to be non private
+ storeTask?: DelayedTask;
/** @override */
ready() {
diff --git a/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content_html.ts b/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content_html.ts
index c6ff903..7877a1f 100644
--- a/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content_html.ts
@@ -69,7 +69,7 @@
box-shadow: var(--elevation-level-1);
/* slightly up to cover rounded corner of the commit msg */
margin-top: calc(-1 * var(--spacing-xs));
- /* To make this bar pop over editor, since editor has relative position.
+ /* To make this bar pop over editor, since editor has relative position.
*/
position: relative;
}
diff --git a/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content_test.js b/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content_test.ts
similarity index 73%
rename from polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content_test.js
rename to polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content_test.ts
index 94a7b96..074678e 100644
--- a/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content_test.ts
@@ -15,13 +15,17 @@
* limitations under the License.
*/
-import '../../../test/common-test-setup-karma.js';
-import './gr-editable-content.js';
+import '../../../test/common-test-setup-karma';
+import './gr-editable-content';
+import {GrEditableContent} from './gr-editable-content';
+import {queryAndAssert, stubStorage} from '../../../test/test-utils';
+import * as MockInteractions from '@polymer/iron-test-helpers/mock-interactions';
+import {GrButton} from '../gr-button/gr-button';
const basicFixture = fixtureFromElement('gr-editable-content');
suite('gr-editable-content tests', () => {
- let element;
+ let element: GrEditableContent;
setup(() => {
element = basicFixture.instantiate();
@@ -33,8 +37,7 @@
const handler = sinon.spy();
element.addEventListener('editable-content-save', handler);
- MockInteractions.tap(element.shadowRoot
- .querySelector('gr-button[primary]'));
+ MockInteractions.tap(queryAndAssert(element, 'gr-button[primary]'));
assert.isTrue(handler.called);
assert.equal(handler.lastCall.args[0].detail.content, 'foo');
@@ -44,8 +47,7 @@
const handler = sinon.spy();
element.addEventListener('editable-content-cancel', handler);
- MockInteractions.tap(element.shadowRoot
- .querySelector('gr-button.cancel-button'));
+ MockInteractions.tap(queryAndAssert(element, 'gr-button.cancel-button'));
assert.isTrue(handler.called);
});
@@ -79,19 +81,22 @@
});
test('save button is disabled initially', () => {
- assert.isTrue(element.shadowRoot
- .querySelector('gr-button[primary]').disabled);
+ assert.isTrue(
+ queryAndAssert<GrButton>(element, 'gr-button[primary]').disabled
+ );
});
test('save button is enabled when content changes', () => {
element._newContent = 'new content';
- assert.isFalse(element.shadowRoot
- .querySelector('gr-button[primary]').disabled);
+ assert.isFalse(
+ queryAndAssert<GrButton>(element, 'gr-button[primary]').disabled
+ );
});
});
suite('storageKey and related behavior', () => {
- let dispatchSpy;
+ let dispatchSpy: sinon.SinonSpy;
+
setup(() => {
element.content = 'current content';
element.storageKey = 'test';
@@ -99,8 +104,10 @@
});
test('editing toggled to true, has stored data', () => {
- sinon.stub(element.storage, 'getEditableContentItem')
- .returns({message: 'stored content'});
+ stubStorage('getEditableContentItem').returns({
+ message: 'stored content',
+ updated: 0,
+ });
element.editing = true;
assert.equal(element._newContent, 'stored content');
@@ -109,8 +116,7 @@
});
test('editing toggled to true, has no stored data', () => {
- sinon.stub(element.storage, 'getEditableContentItem')
- .returns({});
+ stubStorage('getEditableContentItem').returns(null);
element.editing = true;
assert.equal(element._newContent, 'current content');
@@ -118,28 +124,26 @@
});
test('edits are cached', () => {
- const storeStub =
- sinon.stub(element.storage, 'setEditableContentItem');
- const eraseStub =
- sinon.stub(element.storage, 'eraseEditableContentItem');
+ const storeStub = stubStorage('setEditableContentItem');
+ const eraseStub = stubStorage('eraseEditableContentItem');
element.editing = true;
element._newContent = 'new content';
flush();
- element.storeTask.flush();
+ element.storeTask?.flush();
assert.isTrue(storeStub.called);
assert.deepEqual(
- [element.storageKey, element._newContent],
- storeStub.lastCall.args);
+ [element.storageKey, element._newContent],
+ storeStub.lastCall.args
+ );
element._newContent = '';
flush();
- element.storeTask.flush();
+ element.storeTask?.flush();
assert.isTrue(eraseStub.called);
assert.deepEqual([element.storageKey], eraseStub.lastCall.args);
});
});
});
-
diff --git a/polygerrit-ui/app/utils/date-util_test.js b/polygerrit-ui/app/utils/date-util_test.js
deleted file mode 100644
index 96d5bc1..0000000
--- a/polygerrit-ui/app/utils/date-util_test.js
+++ /dev/null
@@ -1,144 +0,0 @@
-/**
- * @license
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import '../test/common-test-setup-karma.js';
-import {isValidDate, parseDate, fromNow, isWithinDay, isWithinHalfYear, formatDate, wasYesterday} from './date-util.js';
-
-suite('date-util tests', () => {
- suite('parseDate', () => {
- test('parseDate server date', () => {
- const parsed = parseDate('2015-09-15 20:34:00.000000000');
- assert.equal('2015-09-15T20:34:00.000Z', parsed.toISOString());
- });
- });
-
- suite('isValidDate', () => {
- test('date is valid', () => {
- assert.isTrue(isValidDate(new Date()));
- });
- test('broken date is invalid', () => {
- assert.isFalse(isValidDate(new Date('xxx')));
- });
- });
-
- suite('fromNow', () => {
- test('test all variants', () => {
- const fakeNow = new Date('May 08 2020 12:00:00');
- sinon.useFakeTimers(fakeNow.getTime());
- assert.equal('just now', fromNow(new Date('May 08 2020 11:59:30')));
- assert.equal('1 minute ago', fromNow(new Date('May 08 2020 11:59:00')));
- assert.equal('5 minutes ago', fromNow(new Date('May 08 2020 11:55:00')));
- assert.equal('1 hour ago', fromNow(new Date('May 08 2020 11:00:00')));
- assert.equal(
- '1 hour 5 min ago', fromNow(new Date('May 08 2020 10:55:00')));
- assert.equal('3 hours ago', fromNow(new Date('May 08 2020 9:00:00')));
- assert.equal('1 day ago', fromNow(new Date('May 07 2020 12:00:00')));
- assert.equal('1 day 2 hr ago', fromNow(new Date('May 07 2020 10:00:00')));
- assert.equal('3 days ago', fromNow(new Date('May 05 2020 12:00:00')));
- assert.equal('1 month ago', fromNow(new Date('Apr 05 2020 12:00:00')));
- assert.equal('2 months ago', fromNow(new Date('Mar 05 2020 12:00:00')));
- assert.equal('1 year ago', fromNow(new Date('May 05 2019 12:00:00')));
- assert.equal('10 years ago', fromNow(new Date('May 05 2010 12:00:00')));
- });
- test('rounding error', () => {
- const fakeNow = new Date('May 08 2020 12:00:00');
- sinon.useFakeTimers(fakeNow.getTime());
- assert.equal('2 hours ago', fromNow(new Date('May 08 2020 9:30:00')));
- });
- });
-
- suite('isWithinDay', () => {
- test('basics works', () => {
- assert.isTrue(isWithinDay(new Date('May 08 2020 12:00:00'),
- new Date('May 08 2020 02:00:00')));
- assert.isFalse(isWithinDay(new Date('May 08 2020 12:00:00'),
- new Date('May 07 2020 12:00:00')));
- });
- });
-
- suite('wasYesterday', () => {
- test('less 24 hours', () => {
- assert.isFalse(wasYesterday(new Date('May 08 2020 12:00:00'),
- new Date('May 08 2020 02:00:00')));
- assert.isTrue(wasYesterday(new Date('May 08 2020 12:00:00'),
- new Date('May 07 2020 12:00:00')));
- });
- test('more 24 hours', () => {
- assert.isTrue(wasYesterday(new Date('May 08 2020 12:00:00'),
- new Date('May 07 2020 2:00:00')));
- assert.isFalse(wasYesterday(new Date('May 08 2020 12:00:00'),
- new Date('May 06 2020 14:00:00')));
- });
- });
-
- suite('isWithinHalfYear', () => {
- test('basics works', () => {
- assert.isTrue(isWithinHalfYear(new Date('May 08 2020 12:00:00'),
- new Date('Feb 08 2020 12:00:00')));
- assert.isFalse(isWithinHalfYear(new Date('May 08 2020 12:00:00'),
- new Date('Nov 07 2019 12:00:00')));
- });
- });
-
- suite('formatDate', () => {
- test('works for standard format', () => {
- const stdFormat = 'MMM DD, YYYY';
- assert.equal('May 08, 2020',
- formatDate(new Date('May 08 2020 12:00:00'), stdFormat));
- assert.equal('Feb 28, 2020',
- formatDate(new Date('Feb 28 2020 12:00:00'), stdFormat));
-
- const time24Format = 'HH:mm:ss';
- assert.equal('Feb 28, 2020 12:01:12',
- formatDate(new Date('Feb 28 2020 12:01:12'), stdFormat + ' '
- + time24Format));
- });
- test('works for euro format', () => {
- const euroFormat = 'DD.MM.YYYY';
- assert.equal('01.12.2019',
- formatDate(new Date('Dec 01 2019 12:00:00'), euroFormat));
- assert.equal('20.01.2002',
- formatDate(new Date('Jan 20 2002 12:00:00'), euroFormat));
-
- const time24Format = 'HH:mm:ss';
- assert.equal('28.02.2020 00:01:12',
- formatDate(new Date('Feb 28 2020 00:01:12'), euroFormat + ' '
- + time24Format));
- });
- test('works for iso format', () => {
- const isoFormat = 'YYYY-MM-DD';
- assert.equal('2015-01-01',
- formatDate(new Date('Jan 01 2015 12:00:00'), isoFormat));
- assert.equal('2013-07-03',
- formatDate(new Date('Jul 03 2013 12:00:00'), isoFormat));
-
- const timeFormat = 'h:mm:ss A';
- assert.equal('2013-07-03 5:00:00 AM',
- formatDate(new Date('Jul 03 2013 05:00:00'), isoFormat + ' '
- + timeFormat));
- assert.equal('2013-07-03 5:00:00 PM',
- formatDate(new Date('Jul 03 2013 17:00:00'), isoFormat + ' '
- + timeFormat));
- });
- test('h:mm:ss A shows correctly midnight and midday', () => {
- const timeFormat = 'h:mm A';
- assert.equal('12:14 PM',
- formatDate(new Date('Jul 03 2013 12:14:00'), timeFormat));
- assert.equal('12:15 AM',
- formatDate(new Date('Jul 03 2013 00:15:00'), timeFormat));
- });
- });
-});
diff --git a/polygerrit-ui/app/utils/date-util_test.ts b/polygerrit-ui/app/utils/date-util_test.ts
new file mode 100644
index 0000000..f17ced3
--- /dev/null
+++ b/polygerrit-ui/app/utils/date-util_test.ts
@@ -0,0 +1,219 @@
+/**
+ * @license
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import {Timestamp} from '../types/common';
+import '../test/common-test-setup-karma';
+import {
+ isValidDate,
+ parseDate,
+ fromNow,
+ isWithinDay,
+ isWithinHalfYear,
+ formatDate,
+ wasYesterday,
+} from './date-util';
+
+suite('date-util tests', () => {
+ suite('parseDate', () => {
+ test('parseDate server date', () => {
+ const parsed = parseDate('2015-09-15 20:34:00.000000000' as Timestamp);
+ assert.equal('2015-09-15T20:34:00.000Z', parsed.toISOString());
+ });
+ });
+
+ suite('isValidDate', () => {
+ test('date is valid', () => {
+ assert.isTrue(isValidDate(new Date()));
+ });
+ test('broken date is invalid', () => {
+ assert.isFalse(isValidDate(new Date('xxx')));
+ });
+ });
+
+ suite('fromNow', () => {
+ test('test all variants', () => {
+ const fakeNow = new Date('May 08 2020 12:00:00');
+ sinon.useFakeTimers(fakeNow.getTime());
+ assert.equal('just now', fromNow(new Date('May 08 2020 11:59:30')));
+ assert.equal('1 minute ago', fromNow(new Date('May 08 2020 11:59:00')));
+ assert.equal('5 minutes ago', fromNow(new Date('May 08 2020 11:55:00')));
+ assert.equal('1 hour ago', fromNow(new Date('May 08 2020 11:00:00')));
+ assert.equal(
+ '1 hour 5 min ago',
+ fromNow(new Date('May 08 2020 10:55:00'))
+ );
+ assert.equal('3 hours ago', fromNow(new Date('May 08 2020 9:00:00')));
+ assert.equal('1 day ago', fromNow(new Date('May 07 2020 12:00:00')));
+ assert.equal('1 day 2 hr ago', fromNow(new Date('May 07 2020 10:00:00')));
+ assert.equal('3 days ago', fromNow(new Date('May 05 2020 12:00:00')));
+ assert.equal('1 month ago', fromNow(new Date('Apr 05 2020 12:00:00')));
+ assert.equal('2 months ago', fromNow(new Date('Mar 05 2020 12:00:00')));
+ assert.equal('1 year ago', fromNow(new Date('May 05 2019 12:00:00')));
+ assert.equal('10 years ago', fromNow(new Date('May 05 2010 12:00:00')));
+ });
+ test('rounding error', () => {
+ const fakeNow = new Date('May 08 2020 12:00:00');
+ sinon.useFakeTimers(fakeNow.getTime());
+ assert.equal('2 hours ago', fromNow(new Date('May 08 2020 9:30:00')));
+ });
+ });
+
+ suite('isWithinDay', () => {
+ test('basics works', () => {
+ assert.isTrue(
+ isWithinDay(
+ new Date('May 08 2020 12:00:00'),
+ new Date('May 08 2020 02:00:00')
+ )
+ );
+ assert.isFalse(
+ isWithinDay(
+ new Date('May 08 2020 12:00:00'),
+ new Date('May 07 2020 12:00:00')
+ )
+ );
+ });
+ });
+
+ suite('wasYesterday', () => {
+ test('less 24 hours', () => {
+ assert.isFalse(
+ wasYesterday(
+ new Date('May 08 2020 12:00:00'),
+ new Date('May 08 2020 02:00:00')
+ )
+ );
+ assert.isTrue(
+ wasYesterday(
+ new Date('May 08 2020 12:00:00'),
+ new Date('May 07 2020 12:00:00')
+ )
+ );
+ });
+ test('more 24 hours', () => {
+ assert.isTrue(
+ wasYesterday(
+ new Date('May 08 2020 12:00:00'),
+ new Date('May 07 2020 2:00:00')
+ )
+ );
+ assert.isFalse(
+ wasYesterday(
+ new Date('May 08 2020 12:00:00'),
+ new Date('May 06 2020 14:00:00')
+ )
+ );
+ });
+ });
+
+ suite('isWithinHalfYear', () => {
+ test('basics works', () => {
+ assert.isTrue(
+ isWithinHalfYear(
+ new Date('May 08 2020 12:00:00'),
+ new Date('Feb 08 2020 12:00:00')
+ )
+ );
+ assert.isFalse(
+ isWithinHalfYear(
+ new Date('May 08 2020 12:00:00'),
+ new Date('Nov 07 2019 12:00:00')
+ )
+ );
+ });
+ });
+
+ suite('formatDate', () => {
+ test('works for standard format', () => {
+ const stdFormat = 'MMM DD, YYYY';
+ assert.equal(
+ 'May 08, 2020',
+ formatDate(new Date('May 08 2020 12:00:00'), stdFormat)
+ );
+ assert.equal(
+ 'Feb 28, 2020',
+ formatDate(new Date('Feb 28 2020 12:00:00'), stdFormat)
+ );
+
+ const time24Format = 'HH:mm:ss';
+ assert.equal(
+ 'Feb 28, 2020 12:01:12',
+ formatDate(
+ new Date('Feb 28 2020 12:01:12'),
+ stdFormat + ' ' + time24Format
+ )
+ );
+ });
+ test('works for euro format', () => {
+ const euroFormat = 'DD.MM.YYYY';
+ assert.equal(
+ '01.12.2019',
+ formatDate(new Date('Dec 01 2019 12:00:00'), euroFormat)
+ );
+ assert.equal(
+ '20.01.2002',
+ formatDate(new Date('Jan 20 2002 12:00:00'), euroFormat)
+ );
+
+ const time24Format = 'HH:mm:ss';
+ assert.equal(
+ '28.02.2020 00:01:12',
+ formatDate(
+ new Date('Feb 28 2020 00:01:12'),
+ euroFormat + ' ' + time24Format
+ )
+ );
+ });
+ test('works for iso format', () => {
+ const isoFormat = 'YYYY-MM-DD';
+ assert.equal(
+ '2015-01-01',
+ formatDate(new Date('Jan 01 2015 12:00:00'), isoFormat)
+ );
+ assert.equal(
+ '2013-07-03',
+ formatDate(new Date('Jul 03 2013 12:00:00'), isoFormat)
+ );
+
+ const timeFormat = 'h:mm:ss A';
+ assert.equal(
+ '2013-07-03 5:00:00 AM',
+ formatDate(
+ new Date('Jul 03 2013 05:00:00'),
+ isoFormat + ' ' + timeFormat
+ )
+ );
+ assert.equal(
+ '2013-07-03 5:00:00 PM',
+ formatDate(
+ new Date('Jul 03 2013 17:00:00'),
+ isoFormat + ' ' + timeFormat
+ )
+ );
+ });
+ test('h:mm:ss A shows correctly midnight and midday', () => {
+ const timeFormat = 'h:mm A';
+ assert.equal(
+ '12:14 PM',
+ formatDate(new Date('Jul 03 2013 12:14:00'), timeFormat)
+ );
+ assert.equal(
+ '12:15 AM',
+ formatDate(new Date('Jul 03 2013 00:15:00'), timeFormat)
+ );
+ });
+ });
+});
diff --git a/polygerrit-ui/app/utils/path-list-util_test.js b/polygerrit-ui/app/utils/path-list-util_test.js
deleted file mode 100644
index 4d06344..0000000
--- a/polygerrit-ui/app/utils/path-list-util_test.js
+++ /dev/null
@@ -1,161 +0,0 @@
-/**
- * @license
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import '../test/common-test-setup-karma.js';
-import {SpecialFilePath} from '../constants/constants.js';
-import {
- addUnmodifiedFiles,
- computeDisplayPath,
- isMagicPath,
- specialFilePathCompare, truncatePath,
-} from './path-list-util.js';
-
-suite('path-list-utl tests', () => {
- test('special sort', () => {
- const testFiles = [
- '/a.h',
- '/MERGE_LIST',
- '/a.cpp',
- '/COMMIT_MSG',
- '/asdasd',
- '/mrPeanutbutter.py',
- ];
- assert.deepEqual(
- testFiles.sort(specialFilePathCompare),
- [
- '/COMMIT_MSG',
- '/MERGE_LIST',
- '/a.h',
- '/a.cpp',
- '/asdasd',
- '/mrPeanutbutter.py',
- ]);
- });
-
- test('special file path sorting', () => {
- assert.deepEqual(
- ['.b', '/COMMIT_MSG', '.a', 'file'].sort(
- specialFilePathCompare),
- ['/COMMIT_MSG', '.a', '.b', 'file']);
-
- assert.deepEqual(
- ['.b', '/COMMIT_MSG', 'foo/bar/baz.cc', 'foo/bar/baz.h'].sort(
- specialFilePathCompare),
- ['/COMMIT_MSG', '.b', 'foo/bar/baz.h', 'foo/bar/baz.cc']);
-
- assert.deepEqual(
- ['.b', '/COMMIT_MSG', 'foo/bar/baz.cc', 'foo/bar/baz.hpp'].sort(
- specialFilePathCompare),
- ['/COMMIT_MSG', '.b', 'foo/bar/baz.hpp', 'foo/bar/baz.cc']);
-
- assert.deepEqual(
- ['.b', '/COMMIT_MSG', 'foo/bar/baz.cc', 'foo/bar/baz.hxx'].sort(
- specialFilePathCompare),
- ['/COMMIT_MSG', '.b', 'foo/bar/baz.hxx', 'foo/bar/baz.cc']);
-
- assert.deepEqual(
- ['foo/bar.h', 'foo/bar.hxx', 'foo/bar.hpp'].sort(
- specialFilePathCompare),
- ['foo/bar.h', 'foo/bar.hpp', 'foo/bar.hxx']);
-
- // Regression test for Issue 4448.
- assert.deepEqual(
- [
- 'minidump/minidump_memory_writer.cc',
- 'minidump/minidump_memory_writer.h',
- 'minidump/minidump_thread_writer.cc',
- 'minidump/minidump_thread_writer.h',
- ].sort(specialFilePathCompare),
- [
- 'minidump/minidump_memory_writer.h',
- 'minidump/minidump_memory_writer.cc',
- 'minidump/minidump_thread_writer.h',
- 'minidump/minidump_thread_writer.cc',
- ]);
-
- // Regression test for Issue 4545.
- assert.deepEqual(
- [
- 'task_test.go',
- 'task.go',
- ].sort(specialFilePathCompare),
- [
- 'task.go',
- 'task_test.go',
- ]);
- });
-
- test('file display name', () => {
- assert.equal(computeDisplayPath('/foo/bar/baz'), '/foo/bar/baz');
- assert.equal(computeDisplayPath('/foobarbaz'), '/foobarbaz');
- assert.equal(computeDisplayPath('/COMMIT_MSG'), 'Commit message');
- assert.equal(computeDisplayPath('/MERGE_LIST'), 'Merge list');
- });
-
- test('isMagicPath', () => {
- assert.isFalse(isMagicPath(undefined));
- assert.isFalse(isMagicPath('/foo.cc'));
- assert.isTrue(isMagicPath('/COMMIT_MSG'));
- assert.isTrue(isMagicPath('/MERGE_LIST'));
- });
-
- test('patchset level comments are hidden', () => {
- const commentedPaths = {
- [SpecialFilePath.PATCHSET_LEVEL_COMMENTS]: true,
- 'file1.txt': true,
- };
-
- const files = {'file2.txt': {status: 'M'}};
- addUnmodifiedFiles(files, commentedPaths);
- assert.equal(files['file1.txt'].status, 'U');
- assert.equal(files['file2.txt'].status, 'M');
- assert.isFalse(files.hasOwnProperty(
- SpecialFilePath.PATCHSET_LEVEL_COMMENTS));
- });
-
- test('truncatePath with long path should add ellipsis', () => {
- let path = 'level1/level2/level3/level4/file.js';
- let shortenedPath = truncatePath(path);
- // The expected path is truncated with an ellipsis.
- const expectedPath = '\u2026/file.js';
- assert.equal(shortenedPath, expectedPath);
-
- path = 'level2/file.js';
- shortenedPath = truncatePath(path);
- assert.equal(shortenedPath, expectedPath);
- });
-
- test('truncatePath with opt_threshold', () => {
- let path = 'level1/level2/level3/level4/file.js';
- let shortenedPath = truncatePath(path, 2);
- // The expected path is truncated with an ellipsis.
- const expectedPath = '\u2026/level4/file.js';
- assert.equal(shortenedPath, expectedPath);
-
- path = 'level2/file.js';
- shortenedPath = truncatePath(path, 2);
- assert.equal(shortenedPath, path);
- });
-
- test('truncatePath with short path should not add ellipsis', () => {
- const path = 'file.js';
- const expectedPath = 'file.js';
- const shortenedPath = truncatePath(path);
- assert.equal(shortenedPath, expectedPath);
- });
-});
-
diff --git a/polygerrit-ui/app/utils/path-list-util_test.ts b/polygerrit-ui/app/utils/path-list-util_test.ts
new file mode 100644
index 0000000..79b5f09
--- /dev/null
+++ b/polygerrit-ui/app/utils/path-list-util_test.ts
@@ -0,0 +1,170 @@
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import '../test/common-test-setup-karma';
+import {FileInfoStatus, SpecialFilePath} from '../constants/constants';
+import {
+ addUnmodifiedFiles,
+ computeDisplayPath,
+ isMagicPath,
+ specialFilePathCompare,
+ truncatePath,
+} from './path-list-util';
+import {FileInfo} from '../api/rest-api';
+import {hasOwnProperty} from './common-util';
+
+suite('path-list-utl tests', () => {
+ test('special sort', () => {
+ const testFiles = [
+ '/a.h',
+ '/MERGE_LIST',
+ '/a.cpp',
+ '/COMMIT_MSG',
+ '/asdasd',
+ '/mrPeanutbutter.py',
+ ];
+ assert.deepEqual(testFiles.sort(specialFilePathCompare), [
+ '/COMMIT_MSG',
+ '/MERGE_LIST',
+ '/a.h',
+ '/a.cpp',
+ '/asdasd',
+ '/mrPeanutbutter.py',
+ ]);
+ });
+
+ test('special file path sorting', () => {
+ assert.deepEqual(
+ ['.b', '/COMMIT_MSG', '.a', 'file'].sort(specialFilePathCompare),
+ ['/COMMIT_MSG', '.a', '.b', 'file']
+ );
+
+ assert.deepEqual(
+ ['.b', '/COMMIT_MSG', 'foo/bar/baz.cc', 'foo/bar/baz.h'].sort(
+ specialFilePathCompare
+ ),
+ ['/COMMIT_MSG', '.b', 'foo/bar/baz.h', 'foo/bar/baz.cc']
+ );
+
+ assert.deepEqual(
+ ['.b', '/COMMIT_MSG', 'foo/bar/baz.cc', 'foo/bar/baz.hpp'].sort(
+ specialFilePathCompare
+ ),
+ ['/COMMIT_MSG', '.b', 'foo/bar/baz.hpp', 'foo/bar/baz.cc']
+ );
+
+ assert.deepEqual(
+ ['.b', '/COMMIT_MSG', 'foo/bar/baz.cc', 'foo/bar/baz.hxx'].sort(
+ specialFilePathCompare
+ ),
+ ['/COMMIT_MSG', '.b', 'foo/bar/baz.hxx', 'foo/bar/baz.cc']
+ );
+
+ assert.deepEqual(
+ ['foo/bar.h', 'foo/bar.hxx', 'foo/bar.hpp'].sort(specialFilePathCompare),
+ ['foo/bar.h', 'foo/bar.hpp', 'foo/bar.hxx']
+ );
+
+ // Regression test for Issue 4448.
+ assert.deepEqual(
+ [
+ 'minidump/minidump_memory_writer.cc',
+ 'minidump/minidump_memory_writer.h',
+ 'minidump/minidump_thread_writer.cc',
+ 'minidump/minidump_thread_writer.h',
+ ].sort(specialFilePathCompare),
+ [
+ 'minidump/minidump_memory_writer.h',
+ 'minidump/minidump_memory_writer.cc',
+ 'minidump/minidump_thread_writer.h',
+ 'minidump/minidump_thread_writer.cc',
+ ]
+ );
+
+ // Regression test for Issue 4545.
+ assert.deepEqual(['task_test.go', 'task.go'].sort(specialFilePathCompare), [
+ 'task.go',
+ 'task_test.go',
+ ]);
+ });
+
+ test('file display name', () => {
+ assert.equal(computeDisplayPath('/foo/bar/baz'), '/foo/bar/baz');
+ assert.equal(computeDisplayPath('/foobarbaz'), '/foobarbaz');
+ assert.equal(computeDisplayPath('/COMMIT_MSG'), 'Commit message');
+ assert.equal(computeDisplayPath('/MERGE_LIST'), 'Merge list');
+ });
+
+ test('isMagicPath', () => {
+ assert.isFalse(isMagicPath(undefined));
+ assert.isFalse(isMagicPath('/foo.cc'));
+ assert.isTrue(isMagicPath('/COMMIT_MSG'));
+ assert.isTrue(isMagicPath('/MERGE_LIST'));
+ });
+
+ test('patchset level comments are hidden', () => {
+ const commentedPaths = {
+ [SpecialFilePath.PATCHSET_LEVEL_COMMENTS]: true,
+ 'file1.txt': true,
+ };
+
+ const files: {[filename: string]: FileInfo} = {
+ 'file2.txt': {
+ status: FileInfoStatus.REWRITTEN,
+ size_delta: 10,
+ size: 10,
+ },
+ };
+ addUnmodifiedFiles(files, commentedPaths);
+ assert.equal(files['file1.txt'].status, FileInfoStatus.UNMODIFIED);
+ assert.equal(files['file2.txt'].status, FileInfoStatus.REWRITTEN);
+ assert.isFalse(
+ hasOwnProperty(files, SpecialFilePath.PATCHSET_LEVEL_COMMENTS)
+ );
+ });
+
+ test('truncatePath with long path should add ellipsis', () => {
+ let path = 'level1/level2/level3/level4/file.js';
+ let shortenedPath = truncatePath(path);
+ // The expected path is truncated with an ellipsis.
+ const expectedPath = '\u2026/file.js';
+ assert.equal(shortenedPath, expectedPath);
+
+ path = 'level2/file.js';
+ shortenedPath = truncatePath(path);
+ assert.equal(shortenedPath, expectedPath);
+ });
+
+ test('truncatePath with opt_threshold', () => {
+ let path = 'level1/level2/level3/level4/file.js';
+ let shortenedPath = truncatePath(path, 2);
+ // The expected path is truncated with an ellipsis.
+ const expectedPath = '\u2026/level4/file.js';
+ assert.equal(shortenedPath, expectedPath);
+
+ path = 'level2/file.js';
+ shortenedPath = truncatePath(path, 2);
+ assert.equal(shortenedPath, path);
+ });
+
+ test('truncatePath with short path should not add ellipsis', () => {
+ const path = 'file.js';
+ const expectedPath = 'file.js';
+ const shortenedPath = truncatePath(path);
+ assert.equal(shortenedPath, expectedPath);
+ });
+});
diff --git a/polygerrit-ui/app/utils/url-util_test.js b/polygerrit-ui/app/utils/url-util_test.ts
similarity index 66%
rename from polygerrit-ui/app/utils/url-util_test.js
rename to polygerrit-ui/app/utils/url-util_test.ts
index 5cd4bb4..63dc81d 100644
--- a/polygerrit-ui/app/utils/url-util_test.js
+++ b/polygerrit-ui/app/utils/url-util_test.ts
@@ -15,7 +15,9 @@
* limitations under the License.
*/
-import '../test/common-test-setup-karma.js';
+import {ServerInfo} from '../api/rest-api';
+import '../test/common-test-setup-karma';
+import {createGerritInfo, createServerInfo} from '../test/test-data-generators';
import {
getBaseUrl,
getDocsBaseUrl,
@@ -25,11 +27,13 @@
toPath,
toPathname,
toSearchParams,
-} from './url-util.js';
+} from './url-util';
+import {appContext} from '../services/app-context';
+import {stubRestApi} from '../test/test-utils';
suite('url-util tests', () => {
suite('getBaseUrl tests', () => {
- let originalCanonicalPath;
+ let originalCanonicalPath: string | undefined;
suiteSetup(() => {
originalCanonicalPath = window.CANONICAL_PATH;
@@ -51,43 +55,50 @@
});
test('null config', async () => {
- const mockRestApi = {
- probePath: sinon.stub().returns(Promise.resolve(true)),
- };
- const docsBaseUrl = await getDocsBaseUrl(null, mockRestApi);
- assert.isTrue(
- mockRestApi.probePath.calledWith('/Documentation/index.html'));
+ const probePathMock = stubRestApi('probePath').resolves(true);
+ const docsBaseUrl = await getDocsBaseUrl(
+ undefined,
+ appContext.restApiService
+ );
+ assert.isTrue(probePathMock.calledWith('/Documentation/index.html'));
assert.equal(docsBaseUrl, '/Documentation');
});
test('no doc config', async () => {
- const mockRestApi = {
- probePath: sinon.stub().returns(Promise.resolve(true)),
+ const probePathMock = stubRestApi('probePath').resolves(true);
+ const config: ServerInfo = {
+ ...createServerInfo(),
+ gerrit: createGerritInfo(),
};
- const config = {gerrit: {}};
- const docsBaseUrl = await getDocsBaseUrl(config, mockRestApi);
- assert.isTrue(
- mockRestApi.probePath.calledWith('/Documentation/index.html'));
+ const docsBaseUrl = await getDocsBaseUrl(
+ config,
+ appContext.restApiService
+ );
+ assert.isTrue(probePathMock.calledWith('/Documentation/index.html'));
assert.equal(docsBaseUrl, '/Documentation');
});
test('has doc config', async () => {
- const mockRestApi = {
- probePath: sinon.stub().returns(Promise.resolve(true)),
+ const probePathMock = stubRestApi('probePath').resolves(true);
+ const config: ServerInfo = {
+ ...createServerInfo(),
+ gerrit: {...createGerritInfo(), doc_url: 'foobar'},
};
- const config = {gerrit: {doc_url: 'foobar'}};
- const docsBaseUrl = await getDocsBaseUrl(config, mockRestApi);
- assert.isFalse(mockRestApi.probePath.called);
+ const docsBaseUrl = await getDocsBaseUrl(
+ config,
+ appContext.restApiService
+ );
+ assert.isFalse(probePathMock.called);
assert.equal(docsBaseUrl, 'foobar');
});
test('no probe', async () => {
- const mockRestApi = {
- probePath: sinon.stub().returns(Promise.resolve(false)),
- };
- const docsBaseUrl = await getDocsBaseUrl(null, mockRestApi);
- assert.isTrue(
- mockRestApi.probePath.calledWith('/Documentation/index.html'));
+ const probePathMock = stubRestApi('probePath').resolves(false);
+ const docsBaseUrl = await getDocsBaseUrl(
+ undefined,
+ appContext.restApiService
+ );
+ assert.isTrue(probePathMock.calledWith('/Documentation/index.html'));
assert.isNotOk(docsBaseUrl);
});
});
@@ -144,7 +155,9 @@
assert.equal(toPath('asdf', params), 'asdf');
params.set('qwer', 'zxcv');
assert.equal(toPath('asdf', params), 'asdf?qwer=zxcv');
- assert.equal(toPath(toPathname('asdf?qwer=zxcv'),
- toSearchParams('asdf?qwer=zxcv')), 'asdf?qwer=zxcv');
+ assert.equal(
+ toPath(toPathname('asdf?qwer=zxcv'), toSearchParams('asdf?qwer=zxcv')),
+ 'asdf?qwer=zxcv'
+ );
});
});