blob: 07f168b82ad2223e95a65e9a35717244fd8ba2dc [file] [log] [blame]
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import '../../test/common-test-setup';
import {assert, fixture, html} from '@open-wc/testing';
import './chat-header';
import {ChatHeader} from './chat-header';
import {
ChatModel,
chatModelToken,
ChatPanelMode,
} from '../../models/chat/chat-model';
import sinon from 'sinon';
import {testResolver} from '../../test/common-test-setup';
import {pluginLoaderToken} from '../shared/gr-js-api-interface/gr-plugin-loader';
import {changeModelToken} from '../../models/change/change-model';
import {chatProvider, createChange} from '../../test/test-data-generators';
import {ParsedChangeInfo} from '../../types/types';
suite('chat-header tests', () => {
let element: ChatHeader;
let chatModel: ChatModel;
setup(async () => {
const pluginLoader = testResolver(pluginLoaderToken);
pluginLoader.pluginsModel.aiCodeReviewRegister({
pluginName: 'test-plugin',
provider: chatProvider,
});
const changeModel = testResolver(changeModelToken);
changeModel.updateState({
change: createChange() as ParsedChangeInfo,
});
element = await fixture(html`<chat-header></chat-header>`);
chatModel = testResolver(chatModelToken);
await element.updateComplete;
});
test('renders', () => {
assert.shadowDom.equal(
element,
/* HTML */ `
<gr-icon class="gemini-icon" icon="robot_2"></gr-icon>
<md-text-button
id="selectModelTrigger"
class="select-model-trigger"
value=""
>
<div class="title-group">
<span class="title">Review Agent</span>
<div class="subtitle">
<span class="subtitle-text">Gemini Pro</span>
<md-icon aria-hidden="true" class="arrow-drop-down"
>arrow_drop_down</md-icon
>
</div>
</div>
</md-text-button>
<md-icon-button
class="history-button first-right-button"
data-aria-label="Show history"
title="Show history"
value=""
>
<md-icon aria-hidden="true">history</md-icon>
</md-icon-button>
<md-icon-button
id="moreActionsTrigger"
class="more-actions-trigger"
data-aria-label="More actions"
title="More"
value=""
>
<md-icon aria-hidden="true">more_vert</md-icon>
</md-icon-button>
<md-icon-button
class="clear-history-button"
title="Start a new conversation"
data-aria-label="Start a new conversation"
value=""
>
<md-icon aria-hidden="true">add</md-icon>
</md-icon-button>
<md-icon-button
class="close-button"
title="Close Review Agent panel"
data-aria-label="Close Review Agent panel"
value=""
>
<md-icon aria-hidden="true">clear</md-icon>
</md-icon-button>
<md-menu
id="selectModelMenu"
anchor="selectModelTrigger"
class="select-model-menu"
aria-hidden="true"
>
<md-menu-item md-menu-item="" tabindex="0">
<md-icon slot="start" style="visibility:visible;" aria-hidden="true"
>done</md-icon
>
Gemini Pro
</md-menu-item>
<md-menu-item md-menu-item="" tabindex="-1">
<md-icon slot="start" style="visibility:hidden;" aria-hidden="true"
>done</md-icon
>
Gemini Ultra
</md-menu-item>
</md-menu>
<md-menu
id="moreActionsMenu"
anchor="moreActionsTrigger"
class="more-actions-menu"
menu-corner="start-end"
anchor-corner="end-end"
aria-hidden="true"
>
<a
href="http://doc.url"
target="_blank"
rel="noopener noreferrer"
style="text-decoration: none;"
>
<md-menu-item md-menu-item="">
<md-icon slot="start" aria-hidden="true">help_outline</md-icon>
Documentation
</md-menu-item>
</a>
</md-menu>
`
);
});
test('renders history mode', async () => {
chatModel.setMode(ChatPanelMode.HISTORY);
await element.updateComplete;
const backButton = element.shadowRoot?.querySelector('.back-arrow');
assert.isOk(backButton);
const title = element.shadowRoot?.querySelector('.title');
assert.equal(title?.textContent?.trim(), 'History');
});
test('handles switching model', async () => {
const menuItems = element.shadowRoot?.querySelectorAll(
'#selectModelMenu md-menu-item'
);
assert.equal(menuItems?.length, 2);
assert.equal(element.selectedModel?.model_id, 'gemini-pro');
(menuItems![1] as HTMLElement).click();
await element.updateComplete;
assert.equal(element.selectedModel?.model_id, 'gemini-ultra');
});
test('handles show history', async () => {
assert.equal(element.mode, ChatPanelMode.CONVERSATION);
const historyButton = element.shadowRoot?.querySelector(
'.history-button'
) as HTMLElement;
historyButton.click();
await element.updateComplete;
assert.equal(element.mode, ChatPanelMode.HISTORY);
});
test('handles back to chat', async () => {
chatModel.setMode(ChatPanelMode.HISTORY);
await element.updateComplete;
assert.equal(element.mode, ChatPanelMode.HISTORY);
const backButton = element.shadowRoot?.querySelector(
'.back-arrow'
) as HTMLElement;
backButton.click();
await element.updateComplete;
assert.equal(element.mode, ChatPanelMode.CONVERSATION);
});
test('handles start new conversation', async () => {
const addButton = element.shadowRoot?.querySelector(
'.clear-history-button'
) as HTMLElement;
addButton.click();
await element.updateComplete;
assert.equal(element.mode, ChatPanelMode.CONVERSATION);
assert.equal(chatModel.getState().turns.length, 0);
});
test('handles close panel', async () => {
const spy = sinon.spy();
element.addEventListener('close-chat-panel', spy);
const closeButton = element.shadowRoot?.querySelector(
'.close-button'
) as HTMLElement;
closeButton.click();
assert.isTrue(spy.called);
});
});