| /** |
| * @license |
| * Copyright 2020 Google LLC |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| import '../../../test/common-test-setup'; |
| import {fixture, assert} from '@open-wc/testing'; |
| import {html} from 'lit'; |
| import './gr-hovercard-account'; |
| import {GrHovercardAccount} from './gr-hovercard-account'; |
| import { |
| mockPromise, |
| query, |
| queryAndAssert, |
| stubRestApi, |
| } from '../../../test/test-utils'; |
| import { |
| AccountDetailInfo, |
| AccountId, |
| EmailAddress, |
| ReviewerState, |
| } from '../../../api/rest-api'; |
| import { |
| createAccountDetailWithId, |
| createChange, |
| createDetailedLabelInfo, |
| } from '../../../test/test-data-generators'; |
| import {GrButton} from '../gr-button/gr-button'; |
| import {EventType} from '../../../types/events'; |
| |
| suite('gr-hovercard-account tests', () => { |
| let element: GrHovercardAccount; |
| |
| const ACCOUNT: AccountDetailInfo = { |
| ...createAccountDetailWithId(31), |
| email: 'kermit@gmail.com' as EmailAddress, |
| username: 'kermit', |
| name: 'Kermit The Frog', |
| status: 'I am a frog', |
| _account_id: 31415926535 as AccountId, |
| }; |
| |
| setup(async () => { |
| const change = { |
| ...createChange(), |
| attention_set: {}, |
| reviewers: {}, |
| owner: {...ACCOUNT}, |
| }; |
| element = await fixture<GrHovercardAccount>( |
| html`<gr-hovercard-account |
| class="hovered" |
| .account=${ACCOUNT} |
| .change=${change} |
| > |
| </gr-hovercard-account>` |
| ); |
| await element.show({}); |
| element.userModel.setAccount({...ACCOUNT}); |
| await element.updateComplete; |
| }); |
| |
| teardown(async () => { |
| element.mouseHide(new MouseEvent('click')); |
| await element.updateComplete; |
| }); |
| |
| test('renders', () => { |
| assert.shadowDom.equal( |
| element, |
| /* HTML */ ` |
| <div id="container" role="tooltip" tabindex="-1"> |
| <div class="top"> |
| <div class="avatar"> |
| <gr-avatar hidden="" imagesize="56"></gr-avatar> |
| </div> |
| <div class="account"> |
| <h3 class="heading-3 name">Kermit The Frog</h3> |
| <div class="email">kermit@gmail.com</div> |
| </div> |
| </div> |
| <gr-endpoint-decorator name="hovercard-status"> |
| <gr-endpoint-param name="account"></gr-endpoint-param> |
| </gr-endpoint-decorator> |
| <div class="status"> |
| <span class="title">About me:</span> |
| <span class="value">I am a frog</span> |
| </div> |
| <div class="links"> |
| <gr-icon icon="link" class="linkIcon"></gr-icon> |
| <a href="/q/owner:kermit%2540gmail.com">Changes</a> |
| · |
| <a href="/dashboard/31415926535">Dashboard</a> |
| </div> |
| </div> |
| ` |
| ); |
| }); |
| |
| test('renders without change data', async () => { |
| const elementWithoutChange = await fixture<GrHovercardAccount>( |
| html`<gr-hovercard-account class="hovered" .account=${ACCOUNT}> |
| </gr-hovercard-account>` |
| ); |
| await elementWithoutChange.show({}); |
| assert.shadowDom.equal( |
| elementWithoutChange, |
| /* HTML */ ` |
| <div id="container" role="tooltip" tabindex="-1"> |
| <div class="top"> |
| <div class="avatar"> |
| <gr-avatar hidden="" imagesize="56"> </gr-avatar> |
| </div> |
| <div class="account"> |
| <h3 class="heading-3 name">Kermit The Frog</h3> |
| <div class="email">kermit@gmail.com</div> |
| </div> |
| </div> |
| <gr-endpoint-decorator name="hovercard-status"> |
| <gr-endpoint-param name="account"> </gr-endpoint-param> |
| </gr-endpoint-decorator> |
| <div class="status"> |
| <span class="title"> About me: </span> |
| <span class="value"> I am a frog </span> |
| </div> |
| <div class="links"> |
| <gr-icon class="linkIcon" icon="link"> </gr-icon> |
| <a href="/q/owner:kermit%2540gmail.com"> Changes </a> |
| · |
| <a href="/dashboard/31415926535"> Dashboard </a> |
| </div> |
| </div> |
| ` |
| ); |
| elementWithoutChange.mouseHide(new MouseEvent('click')); |
| await elementWithoutChange.updateComplete; |
| }); |
| |
| test('account name is shown', () => { |
| const name = queryAndAssert<HTMLHeadingElement>(element, '.name'); |
| assert.equal(name.innerText, 'Kermit The Frog'); |
| }); |
| |
| test('computePronoun', async () => { |
| element.account = createAccountDetailWithId(1); |
| element.selfAccount = createAccountDetailWithId(1); |
| await element.updateComplete; |
| assert.equal(element.computePronoun(), 'Your'); |
| element.account = createAccountDetailWithId(2); |
| await element.updateComplete; |
| assert.equal(element.computePronoun(), 'Their'); |
| }); |
| |
| test('account status is not shown if the property is not set', async () => { |
| element.account = {...ACCOUNT, status: undefined}; |
| await element.updateComplete; |
| assert.isUndefined(query(element, '.status')); |
| }); |
| |
| test('account status is displayed', () => { |
| const status = queryAndAssert<HTMLSpanElement>(element, '.status .value'); |
| assert.equal(status.innerText, 'I am a frog'); |
| }); |
| |
| test('voteable div is not shown if the property is not set', () => { |
| assert.isUndefined(query(element, '.voteable')); |
| }); |
| |
| test('voteable div is displayed', async () => { |
| element.change = { |
| ...createChange(), |
| labels: { |
| Foo: { |
| ...createDetailedLabelInfo(), |
| all: [ |
| { |
| _account_id: 7 as AccountId, |
| permitted_voting_range: {max: 2, min: 0}, |
| }, |
| ], |
| }, |
| Bar: { |
| ...createDetailedLabelInfo(), |
| all: [ |
| { |
| ...createAccountDetailWithId(1), |
| permitted_voting_range: {max: 1, min: 0}, |
| }, |
| { |
| _account_id: 7 as AccountId, |
| permitted_voting_range: {max: 1, min: 0}, |
| }, |
| ], |
| }, |
| FooBar: { |
| ...createDetailedLabelInfo(), |
| all: [{_account_id: 7 as AccountId, value: 0}], |
| }, |
| }, |
| permitted_labels: { |
| Foo: ['-1', ' 0', '+1', '+2'], |
| FooBar: ['-1', ' 0'], |
| }, |
| }; |
| element.account = createAccountDetailWithId(1); |
| |
| await element.updateComplete; |
| const voteableEl = queryAndAssert<HTMLSpanElement>( |
| element, |
| '.voteable .value' |
| ); |
| assert.equal(voteableEl.innerText, 'Bar: +1'); |
| }); |
| |
| test('remove reviewer', async () => { |
| element.change = { |
| ...createChange(), |
| removable_reviewers: [ACCOUNT], |
| reviewers: { |
| [ReviewerState.REVIEWER]: [ACCOUNT], |
| }, |
| }; |
| await element.updateComplete; |
| stubRestApi('removeChangeReviewer').returns( |
| Promise.resolve({...new Response(), ok: true}) |
| ); |
| const reloadListener = sinon.spy(); |
| element._target?.addEventListener('reload', reloadListener); |
| const button = queryAndAssert<GrButton>(element, '.removeReviewerOrCC'); |
| assert.isOk(button); |
| assert.equal(button.innerText, 'Remove Reviewer'); |
| button.click(); |
| await element.updateComplete; |
| assert.isTrue(reloadListener.called); |
| }); |
| |
| test('move reviewer to cc', async () => { |
| element.change = { |
| ...createChange(), |
| removable_reviewers: [ACCOUNT], |
| reviewers: { |
| [ReviewerState.REVIEWER]: [ACCOUNT], |
| }, |
| }; |
| await element.updateComplete; |
| const saveReviewStub = stubRestApi('saveChangeReview').returns( |
| Promise.resolve({...new Response(), ok: true}) |
| ); |
| stubRestApi('removeChangeReviewer').returns( |
| Promise.resolve({...new Response(), ok: true}) |
| ); |
| const reloadListener = sinon.spy(); |
| element._target?.addEventListener('reload', reloadListener); |
| |
| const button = queryAndAssert<GrButton>(element, '.changeReviewerOrCC'); |
| |
| assert.isOk(button); |
| assert.equal(button.innerText, 'Move Reviewer to CC'); |
| button.click(); |
| await element.updateComplete; |
| assert.isTrue(saveReviewStub.called); |
| assert.isTrue(reloadListener.called); |
| }); |
| |
| test('move reviewer to cc', async () => { |
| element.change = { |
| ...createChange(), |
| removable_reviewers: [ACCOUNT], |
| reviewers: { |
| [ReviewerState.REVIEWER]: [], |
| }, |
| }; |
| await element.updateComplete; |
| const saveReviewStub = stubRestApi('saveChangeReview').returns( |
| Promise.resolve({...new Response(), ok: true}) |
| ); |
| stubRestApi('removeChangeReviewer').returns( |
| Promise.resolve({...new Response(), ok: true}) |
| ); |
| const reloadListener = sinon.spy(); |
| element._target?.addEventListener('reload', reloadListener); |
| |
| const button = queryAndAssert<GrButton>(element, '.changeReviewerOrCC'); |
| assert.isOk(button); |
| assert.equal(button.innerText, 'Move CC to Reviewer'); |
| |
| button.click(); |
| await element.updateComplete; |
| assert.isTrue(saveReviewStub.called); |
| assert.isTrue(reloadListener.called); |
| }); |
| |
| test('remove cc', async () => { |
| element.change = { |
| ...createChange(), |
| removable_reviewers: [ACCOUNT], |
| reviewers: { |
| [ReviewerState.REVIEWER]: [], |
| }, |
| }; |
| await element.updateComplete; |
| stubRestApi('removeChangeReviewer').returns( |
| Promise.resolve({...new Response(), ok: true}) |
| ); |
| const reloadListener = sinon.spy(); |
| element._target?.addEventListener('reload', reloadListener); |
| |
| const button = queryAndAssert<GrButton>(element, '.removeReviewerOrCC'); |
| |
| assert.equal(button.innerText, 'Remove CC'); |
| assert.isOk(button); |
| button.click(); |
| await element.updateComplete; |
| assert.isTrue(reloadListener.called); |
| }); |
| |
| test('add to attention set', async () => { |
| const apiPromise = mockPromise<Response>(); |
| const apiSpy = stubRestApi('addToAttentionSet').returns(apiPromise); |
| element.highlightAttention = true; |
| element._target = document.createElement('div'); |
| await element.updateComplete; |
| const showAlertListener = sinon.spy(); |
| const hideAlertListener = sinon.spy(); |
| const updatedListener = sinon.spy(); |
| element._target.addEventListener(EventType.SHOW_ALERT, showAlertListener); |
| element._target.addEventListener('hide-alert', hideAlertListener); |
| element._target.addEventListener('attention-set-updated', updatedListener); |
| |
| const button = queryAndAssert<GrButton>(element, '.addToAttentionSet'); |
| assert.isOk(button); |
| assert.isTrue(element._isShowing, 'hovercard is showing'); |
| button.click(); |
| |
| assert.equal(Object.keys(element.change?.attention_set ?? {}).length, 1); |
| const attention_set_info = Object.values( |
| element.change?.attention_set ?? {} |
| )[0]; |
| assert.equal( |
| attention_set_info.reason, |
| `Added by <GERRIT_ACCOUNT_${ACCOUNT._account_id}>` + |
| ' using the hovercard menu' |
| ); |
| assert.equal( |
| attention_set_info.reason_account?._account_id, |
| ACCOUNT._account_id |
| ); |
| assert.isTrue(showAlertListener.called, 'showAlertListener was called'); |
| assert.isTrue(updatedListener.called, 'updatedListener was called'); |
| assert.isFalse(element._isShowing, 'hovercard is hidden'); |
| |
| apiPromise.resolve({...new Response(), ok: true}); |
| await element.updateComplete; |
| assert.isTrue(apiSpy.calledOnce); |
| assert.equal( |
| apiSpy.lastCall.args[2], |
| `Added by <GERRIT_ACCOUNT_${ACCOUNT._account_id}>` + |
| ' using the hovercard menu' |
| ); |
| assert.isTrue(hideAlertListener.called, 'hideAlertListener was called'); |
| }); |
| |
| test('remove from attention set', async () => { |
| const apiPromise = mockPromise<Response>(); |
| const apiSpy = stubRestApi('removeFromAttentionSet').returns(apiPromise); |
| element.highlightAttention = true; |
| element.change = { |
| ...createChange(), |
| attention_set: { |
| '31415926535': {account: ACCOUNT, reason: 'a good reason'}, |
| }, |
| reviewers: {}, |
| owner: {...ACCOUNT}, |
| }; |
| element._target = document.createElement('div'); |
| await element.updateComplete; |
| const showAlertListener = sinon.spy(); |
| const hideAlertListener = sinon.spy(); |
| const updatedListener = sinon.spy(); |
| element._target.addEventListener(EventType.SHOW_ALERT, showAlertListener); |
| element._target.addEventListener('hide-alert', hideAlertListener); |
| element._target.addEventListener('attention-set-updated', updatedListener); |
| |
| const button = queryAndAssert<GrButton>(element, '.removeFromAttentionSet'); |
| assert.isOk(button); |
| assert.isTrue(element._isShowing, 'hovercard is showing'); |
| button.click(); |
| |
| assert.isDefined(element.change?.attention_set); |
| assert.equal(Object.keys(element.change?.attention_set ?? {}).length, 0); |
| assert.isTrue(showAlertListener.called, 'showAlertListener was called'); |
| assert.isTrue(updatedListener.called, 'updatedListener was called'); |
| assert.isFalse(element._isShowing, 'hovercard is hidden'); |
| |
| apiPromise.resolve({...new Response(), ok: true}); |
| await element.updateComplete; |
| |
| assert.isTrue(apiSpy.calledOnce); |
| assert.equal( |
| apiSpy.lastCall.args[2], |
| `Removed by <GERRIT_ACCOUNT_${ACCOUNT._account_id}>` + |
| ' using the hovercard menu' |
| ); |
| assert.isTrue(hideAlertListener.called, 'hideAlertListener was called'); |
| }); |
| }); |