diff --git a/e2e/src/testData/expectedConstants.ts b/e2e/src/testData/expectedConstants.ts index c142d3bf09..ff4728cb07 100644 --- a/e2e/src/testData/expectedConstants.ts +++ b/e2e/src/testData/expectedConstants.ts @@ -29,6 +29,7 @@ export const ExpectedConstants = { backgroundColorPattern: /(rgba\(\d+,\s*\d+,\s*\d+),\s*\d+\.*\d+\)/, sendMessageTooltip: 'Please type a message', selectedPromptOptionAttribute: 'bg-blue-500/20', + noResults: 'No results found', }; export enum Groups { diff --git a/e2e/src/testData/expectedMessages.ts b/e2e/src/testData/expectedMessages.ts index d2803d3218..907331f95d 100644 --- a/e2e/src/testData/expectedMessages.ts +++ b/e2e/src/testData/expectedMessages.ts @@ -156,4 +156,6 @@ export enum ExpectedMessages { playbackMessageIsInViewport = 'Playback message is in viewport', playbackNextMessageIsScrollable = 'Playback next message is scrollable', playbackNextMessageIsHidden = 'Playback next message is hidden', + searchResultCountIsValid = 'Search results count is valid', + noResultsFound = 'No results found is displayed', } diff --git a/e2e/src/testData/prompts/promptData.ts b/e2e/src/testData/prompts/promptData.ts index da3cecd3a6..f707ac436d 100644 --- a/e2e/src/testData/prompts/promptData.ts +++ b/e2e/src/testData/prompts/promptData.ts @@ -24,8 +24,10 @@ export class PromptData extends FolderData { this.resetFolderData(); } - public prepareDefaultPrompt() { - return this.promptBuilder.withName(GeneratorUtil.randomString(10)).build(); + public prepareDefaultPrompt(name?: string) { + return this.promptBuilder + .withName(name ?? GeneratorUtil.randomString(10)) + .build(); } public prepareNestedFolder(nestedLevel: number) { diff --git a/e2e/src/tests/chatBarConversation.test.ts b/e2e/src/tests/chatBarConversation.test.ts index 51cb3850b5..4b2bd3055b 100644 --- a/e2e/src/tests/chatBarConversation.test.ts +++ b/e2e/src/tests/chatBarConversation.test.ts @@ -8,15 +8,20 @@ import { ExpectedConstants, ExpectedMessages, MenuOptions, + ModelIds, } from '@/e2e/src/testData'; import { Colors } from '@/e2e/src/ui/domData'; import { GeneratorUtil } from '@/e2e/src/utils'; import { expect } from '@playwright/test'; let gpt35Model: OpenAIEntityModel; +let gpt4Model: OpenAIEntityModel; +let bisonModel: OpenAIEntityModel; test.beforeAll(async () => { gpt35Model = ModelsUtil.getDefaultModel()!; + gpt4Model = ModelsUtil.getModel(ModelIds.GPT_4)!; + bisonModel = ModelsUtil.getModel(ModelIds.BISON_001)!; }); test( @@ -371,11 +376,8 @@ test( await chat.regenerateResponse(); let todayConversations = await conversations.getTodayConversations(); expect - .soft( - todayConversations.includes(yesterdayConversation.name), - ExpectedMessages.conversationOfToday, - ) - .toBeTruthy(); + .soft(todayConversations.length, ExpectedMessages.conversationOfToday) + .toBe(1); const messageToEdit = lastWeekConversation.messages[0].content; await conversations.selectConversation(lastWeekConversation.name); @@ -383,11 +385,8 @@ test( await chatMessages.editMessage('updated message'); todayConversations = await conversations.getTodayConversations(); expect - .soft( - todayConversations.includes(lastWeekConversation.name), - ExpectedMessages.conversationOfToday, - ) - .toBeTruthy(); + .soft(todayConversations.length, ExpectedMessages.conversationOfToday) + .toBe(2); await conversations.selectConversation(lastMonthConversation.name); await chat.sendRequestWithButton('one more test message'); @@ -785,3 +784,84 @@ test('Chat sorting. Sections can be collapsed and expanded', async ({ .toBe(1); }); }); + +test('Search conversation when no folders', async ({ + dialHomePage, + conversations, + conversationData, + localStorageManager, + chatBar, + setTestIds, +}) => { + setTestIds('EPMRTC-1188'); + const request = 'What is epam official name?'; + const notMatchingSearchTerm = 'abc'; + const firstSearchTerm = 'EPAM'; + const secondSearchTerm = 'epam official'; + const specialSymbolsSearchTerm = '@'; + + await test.step('Prepare conversations with different content', async () => { + const firstConversation = + conversationData.prepareModelConversationBasedOnRequests(gpt35Model, [ + request, + ]); + conversationData.resetData(); + + const secondConversation = + conversationData.prepareModelConversationBasedOnRequests( + gpt4Model, + ['What is AI?'], + 'epam official name', + ); + conversationData.resetData(); + + const thirdConversation = + conversationData.prepareModelConversationBasedOnRequests( + bisonModel, + [request], + 'Chat_!@#$%^&*()+=\':",.<>', + ); + + await localStorageManager.setConversationHistory( + firstConversation, + secondConversation, + thirdConversation, + ); + }); + + await test.step('Type not matching search term is "Search chat..." field and verify no results found', async () => { + await dialHomePage.openHomePage(); + await dialHomePage.waitForPageLoaded({ isNewConversationVisible: true }); + await chatBar.searchChat.fill(notMatchingSearchTerm); + const noResult = await chatBar.noResultFoundIcon.getElementInnerContent(); + expect + .soft(noResult, ExpectedMessages.noResultsFound) + .toBe(ExpectedConstants.noResults); + }); + + await test.step('Clear search field and verify all conversations are displayed', async () => { + await chatBar.searchChat.fill(''); + const results = await conversations.getTodayConversations(); + expect + .soft(results.length, ExpectedMessages.searchResultCountIsValid) + .toBe(4); + }); + + await test.step('Search by first term and verify search results are correct', async () => { + for (const term of [firstSearchTerm, secondSearchTerm]) { + await chatBar.searchChat.fill(term); + const results = await conversations.getTodayConversations(); + expect + .soft(results.length, ExpectedMessages.searchResultCountIsValid) + .toBe(3); + } + }); + + await test.step('Search by special symbol and verify search results are correct', async () => { + await chatBar.searchChat.fill(specialSymbolsSearchTerm); + const results = await conversations.getTodayConversations(); + expect + .soft(results.length, ExpectedMessages.searchResultCountIsValid) + .toBe(1); + }); +}); diff --git a/e2e/src/tests/compareMode.test.ts b/e2e/src/tests/compareMode.test.ts index 1252b0c857..1a4cad79c9 100644 --- a/e2e/src/tests/compareMode.test.ts +++ b/e2e/src/tests/compareMode.test.ts @@ -106,7 +106,7 @@ test( ); await conversationDropdownMenu.selectMenuOption(MenuOptions.compare); - const chatsCount = await compare.gerChatMessagesCount(); + const chatsCount = await compare.getChatMessagesCount(); expect.soft(chatsCount, ExpectedMessages.compareModeOpened).toBe(1); const isConversationToCompareVisible = @@ -464,16 +464,22 @@ test('Generate new response for two chats in compare mode. Bison and GPT-4-32 wh localStorageManager, }) => { setTestIds('EPMRTC-553'); - + const request = ['beautiful']; let firstConversation: Conversation; let secondConversation: Conversation; await test.step('Prepare two conversations for comparing', async () => { - firstConversation = conversationData.prepareDefaultConversation(bisonModel); + firstConversation = + conversationData.prepareModelConversationBasedOnRequests( + bisonModel, + request, + ); conversationData.resetData(); - secondConversation = conversationData.prepareDefaultConversation( - ModelsUtil.getModel(ModelIds.GPT_4_32K), - ); + secondConversation = + conversationData.prepareModelConversationBasedOnRequests( + ModelsUtil.getModel(ModelIds.GPT_4_32K)!, + request, + ); await localStorageManager.setConversationHistory( firstConversation, secondConversation, @@ -487,11 +493,15 @@ test('Generate new response for two chats in compare mode. Bison and GPT-4-32 wh await test.step('Send new message in compare chat and verify regenerate is not available until both responses received', async () => { await dialHomePage.openHomePage(); await dialHomePage.waitForPageLoaded(); - await chat.sendRequestInCompareMode('write down 20 adjectives', { - rightEntity: firstConversation.model.id, - leftEntity: secondConversation.model.id, - }); - await chatMessages.waitForOneCompareConversationResponseReceived(); + + await chat.sendRequestInCompareMode( + 'write down 20 adjectives about person', + { + rightEntity: firstConversation.model.id, + leftEntity: secondConversation.model.id, + }, + ); + await chatMessages.waitForCompareMessageJumpingIconDisappears(Side.left); const isRegenerateButtonVisible = await chat.regenerate.isVisible(); expect .soft(isRegenerateButtonVisible, ExpectedMessages.regenerateNotAvailable) @@ -764,3 +774,179 @@ test( }); }, ); + +test( + 'Search chat in Select conversation drop down.\n' + + 'Select chat from search results in Select conversation drop down', + async ({ + dialHomePage, + setTestIds, + conversationDropdownMenu, + conversations, + conversationData, + localStorageManager, + compareConversationSelector, + rightChatHeader, + }) => { + setTestIds('EPMRTC-536', 'EPMRTC-1168'); + const request = 'What is epam official name?'; + const firstSearchTerm = 'epam'; + const secondSearchTerm = 'systems'; + const thirdSearchTerm = 'epam official'; + const underscoreSearchTerm = '_'; + const noResultSearchTerm = 'epaQ'; + + let firstConversation: Conversation; + let secondConversation: Conversation; + let thirdConversation: Conversation; + let fourthConversation: Conversation; + const matchedConversations: string[] = []; + + await test.step('Prepare 4 conversations with the same request but different names', async () => { + firstConversation = + conversationData.prepareModelConversationBasedOnRequests( + defaultModel, + [request], + request, + ); + conversationData.resetData(); + secondConversation = + conversationData.prepareModelConversationBasedOnRequests( + defaultModel, + [request], + request, + ); + conversationData.resetData(); + thirdConversation = + conversationData.prepareModelConversationBasedOnRequests( + defaultModel, + [request], + 'Renamed epam systems', + ); + conversationData.resetData(); + fourthConversation = + conversationData.prepareModelConversationBasedOnRequests( + defaultModel, + [request], + 'epam_systems !@#$%^&*()+=\':",.<>', + ); + + await localStorageManager.setConversationHistory( + firstConversation, + secondConversation, + thirdConversation, + fourthConversation, + ); + await localStorageManager.setSelectedConversation(firstConversation); + matchedConversations.push( + secondConversation.name, + thirdConversation.name, + fourthConversation.name, + ); + }); + + await test.step('Open compare mode for the 1st chat and verify all chats are available for comparison in dropdown list', async () => { + await dialHomePage.openHomePage(); + await dialHomePage.waitForPageLoaded(); + await conversations.openConversationDropdownMenu(firstConversation.name); + await conversationDropdownMenu.selectMenuOption(MenuOptions.compare); + await compareConversationSelector.click(); + const conversationsList = + await compareConversationSelector.getListOptions(); + expect + .soft( + conversationsList, + ExpectedMessages.conversationsToCompareOptionsValid, + ) + .toEqual(matchedConversations); + }); + + await test.step('Type first search term and verify all chats are available for comparison in dropdown list', async () => { + for (const term of [firstSearchTerm, firstSearchTerm.toUpperCase()]) { + await compareConversationSelector.fillInput(term); + const conversationsList = + await compareConversationSelector.getListOptions(); + expect + .soft( + conversationsList, + ExpectedMessages.conversationsToCompareOptionsValid, + ) + .toEqual(matchedConversations); + } + }); + + await test.step('Type second search term and verify chat 3 and 4 are available for comparison in dropdown list', async () => { + await compareConversationSelector.fillInput(secondSearchTerm); + const conversationsList = + await compareConversationSelector.getListOptions(); + expect + .soft( + conversationsList, + ExpectedMessages.conversationsToCompareOptionsValid, + ) + .toEqual([thirdConversation.name, fourthConversation.name]); + }); + + await test.step('Type third search term and verify chat 2 is available for comparison in dropdown list', async () => { + await compareConversationSelector.fillInput(thirdSearchTerm); + const conversationsList = + await compareConversationSelector.getListOptions(); + expect + .soft( + conversationsList, + ExpectedMessages.conversationsToCompareOptionsValid, + ) + .toEqual([secondConversation.name]); + }); + + await test.step('Type underscore and verify chat 4 is available for comparison in dropdown list', async () => { + await compareConversationSelector.fillInput(underscoreSearchTerm); + const conversationsList = + await compareConversationSelector.getListOptions(); + expect + .soft( + conversationsList, + ExpectedMessages.conversationsToCompareOptionsValid, + ) + .toEqual([fourthConversation.name]); + }); + + await test.step('Type not matching search term and verify no chats available for comparison in dropdown list', async () => { + await compareConversationSelector.fillInput(noResultSearchTerm); + const conversationsList = + await compareConversationSelector.getListOptions(); + expect + .soft( + conversationsList, + ExpectedMessages.conversationsToCompareOptionsValid, + ) + .toEqual([]); + }); + + await test.step('Delete search term and verify all chats are available for comparison in dropdown list', async () => { + await compareConversationSelector.fillInput(''); + const conversationsList = + await compareConversationSelector.getListOptions(); + expect + .soft( + conversationsList, + ExpectedMessages.conversationsToCompareOptionsValid, + ) + .toEqual(matchedConversations); + }); + + await test.step('Select any chat and verify it shown in the input, dropdown list is closed', async () => { + const chatToSelect = + GeneratorUtil.randomArrayElement(matchedConversations); + await compareConversationSelector.selectModel(chatToSelect, true); + await compareConversationSelector.waitForState({ + state: 'hidden', + }); + const rightHeaderTitle = + await rightChatHeader.chatTitle.getElementContent(); + expect + .soft(rightHeaderTitle, ExpectedMessages.headerTitleCorrespondRequest) + .toBe(chatToSelect); + }); + }, +); diff --git a/e2e/src/tests/defaultModelSettings.test.ts b/e2e/src/tests/defaultModelSettings.test.ts index 2ea590413e..25052ea305 100644 --- a/e2e/src/tests/defaultModelSettings.test.ts +++ b/e2e/src/tests/defaultModelSettings.test.ts @@ -303,3 +303,81 @@ test('Recent "Talk to" list is updated', async ({ .soft(recentTalkTo[0], ExpectedMessages.talkToEntityIsSelected) .toBe(bison.name); }); + +test('Search "Talk to" item in "See full list..."', async ({ + dialHomePage, + chatBar, + talkToSelector, + modelsDialog, + setTestIds, +}) => { + setTestIds('EPMRTC-408'); + const randomEntity = GeneratorUtil.randomArrayElement( + ModelsUtil.getOpenAIEntities().filter((m) => m.name.length >= 3), + ); + const searchTerm = randomEntity.name.substring(0, 3); + const matchedModels = ModelsUtil.getModels().filter((m) => + m.name.toLowerCase().includes(searchTerm.toLowerCase()), + ); + const matchedApplications = ModelsUtil.getApplications().filter((a) => + a.name.toLowerCase().includes(searchTerm.toLowerCase()), + ); + const matchedAssistants = ModelsUtil.getAssistants().filter((a) => + a.name.toLowerCase().includes(searchTerm.toLowerCase()), + ); + + await test.step('Create new conversation and click "See full list.." link', async () => { + await dialHomePage.openHomePage(); + await dialHomePage.waitForPageLoaded({ isNewConversationVisible: true }); + await chatBar.createNewConversation(); + await talkToSelector.seeFullList(); + }); + + await test.step('Type first search term and verify search result is correct', async () => { + await modelsDialog.searchInput.fillInInput(searchTerm); + const resultsCount = await modelsDialog.groupEntity.getElementsCount(); + expect + .soft(resultsCount, ExpectedMessages.searchResultCountIsValid) + .toBe( + matchedModels.length + + matchedApplications.length + + matchedAssistants.length, + ); + }); + + await test.step('Click on entity tabs one by one and verify search results are correct', async () => { + await modelsDialog.modelsTab.click(); + const assistantsPlusAppResultsCount = + await modelsDialog.groupEntity.getElementsCount(); + expect + .soft( + assistantsPlusAppResultsCount, + ExpectedMessages.searchResultCountIsValid, + ) + .toBe(matchedApplications.length + matchedAssistants.length); + + await modelsDialog.assistantsTab.click(); + const appResultsCount = await modelsDialog.groupEntity.getElementsCount(); + expect + .soft(appResultsCount, ExpectedMessages.searchResultCountIsValid) + .toBe(matchedApplications.length); + + await modelsDialog.applicationsTab.click(); + const noResult = + await modelsDialog.noResultFoundIcon.getElementInnerContent(); + expect + .soft(noResult, ExpectedMessages.noResultsFound) + .toBe(ExpectedConstants.noResults); + }); + + await test.step('Clear search input and verify all entities are displayed', async () => { + await modelsDialog.searchInput.fillInInput(''); + await modelsDialog.modelsTab.click(); + await modelsDialog.assistantsTab.click(); + await modelsDialog.applicationsTab.click(); + const resultsCount = await modelsDialog.groupEntity.getElementsCount(); + expect + .soft(resultsCount, ExpectedMessages.searchResultCountIsValid) + .toBe(ModelsUtil.getOpenAIEntities().length); + }); +}); diff --git a/e2e/src/tests/folderPrompts.test.ts b/e2e/src/tests/folderPrompts.test.ts index d793b0626d..7fd242f995 100644 --- a/e2e/src/tests/folderPrompts.test.ts +++ b/e2e/src/tests/folderPrompts.test.ts @@ -5,6 +5,7 @@ import test from '@/e2e/src/core/fixtures'; import { ExpectedConstants, ExpectedMessages, + FolderPrompt, MenuOptions, } from '@/e2e/src/testData'; import { GeneratorUtil } from '@/e2e/src/utils'; @@ -454,3 +455,54 @@ test('Delete nested prompt folder with prompt', async ({ } }); }); + +test('Search prompt located in folders', async ({ + dialHomePage, + localStorageManager, + promptData, + promptBar, + folderPrompts, + setTestIds, + setIssueIds, +}) => { + setTestIds('EPMRTC-1174'); + setIssueIds('175'); + let firstFolderPrompt: FolderPrompt; + let secondFolderPrompts: FolderPrompt; + + const promptContent = 'Prompt search test'; + const searchTerm = 'test'; + + await test.step('Prepare prompts in folders with different content', async () => { + firstFolderPrompt = promptData.prepareDefaultPromptInFolder(); + firstFolderPrompt.prompts[0].name = promptContent; + promptData.resetData(); + + secondFolderPrompts = promptData.preparePromptsInFolder(3); + secondFolderPrompts.prompts[0].description = promptContent; + secondFolderPrompts.prompts[1].content = promptContent; + + await localStorageManager.setFolders( + firstFolderPrompt.folders, + secondFolderPrompts.folders, + ); + await localStorageManager.setPrompts( + ...firstFolderPrompt.prompts, + ...secondFolderPrompts.prompts, + ); + }); + + await test.step('Type search term in the field and verify all prompts displayed', async () => { + await dialHomePage.openHomePage(); + await dialHomePage.waitForPageLoaded({ isNewConversationVisible: true }); + await promptBar.searchPrompt.fill(searchTerm); + const resultCount = await folderPrompts.getFolderPromptsCount(); + expect.soft(resultCount, ExpectedMessages.searchResultCountIsValid).toBe(3); + }); + + await test.step('Clear search field and verify all prompts displayed', async () => { + await promptBar.searchPrompt.fill(''); + const resultCount = await folderPrompts.getFolderPromptsCount(); + expect.soft(resultCount, ExpectedMessages.searchResultCountIsValid).toBe(4); + }); +}); diff --git a/e2e/src/tests/prompts.test.ts b/e2e/src/tests/prompts.test.ts index 2022e2201c..5784e9d788 100644 --- a/e2e/src/tests/prompts.test.ts +++ b/e2e/src/tests/prompts.test.ts @@ -1,3 +1,5 @@ +import { Prompt } from '@/src/types/prompt'; + import test from '@/e2e/src/core/fixtures'; import { ExpectedConstants, @@ -586,3 +588,77 @@ test('Check that all parameters in prompt are required', async ({ .soft(actualMessage, ExpectedMessages.promptApplied) .toBe(promptContent(firstVariableValue, secondVariableValue)); }); + +test('Search prompt when no folders', async ({ + dialHomePage, + localStorageManager, + prompts, + promptData, + promptBar, + setTestIds, +}) => { + setTestIds('EPMRTC-1173'); + let firstPrompt: Prompt; + let secondPrompt: Prompt; + let thirdPrompt: Prompt; + let fourthPrompt: Prompt; + let fifthPrompt: Prompt; + const promptContent = 'Prompt search test'; + const notMatchingSearchTerm = 'abc'; + const searchTerm = 'test'; + const specialSymbolSearchTerm = '@'; + + await test.step('Prepare prompts with different content', async () => { + firstPrompt = promptData.prepareDefaultPrompt(promptContent); + promptData.resetData(); + secondPrompt = promptData.preparePrompt('', promptContent); + promptData.resetData(); + thirdPrompt = promptData.preparePrompt(promptContent); + promptData.resetData(); + fourthPrompt = promptData.prepareDefaultPrompt(); + promptData.resetData(); + fifthPrompt = promptData.prepareDefaultPrompt( + 'Prompt_!@#$%^&*()+=\':",.<>', + ); + + await localStorageManager.setPrompts( + firstPrompt, + secondPrompt, + thirdPrompt, + fourthPrompt, + fifthPrompt, + ); + }); + + await test.step('Type not matching search term and in "Search prompt.." field and verify no results found', async () => { + await dialHomePage.openHomePage(); + await dialHomePage.waitForPageLoaded({ isNewConversationVisible: true }); + await promptBar.searchPrompt.fill(notMatchingSearchTerm); + const noResult = await promptBar.noResultFoundIcon.getElementInnerContent(); + expect + .soft(noResult, ExpectedMessages.noResultsFound) + .toBe(ExpectedConstants.noResults); + }); + + await test.step('Clear search field and verify all prompts displayed', async () => { + await promptBar.searchPrompt.fill(''); + const resultCount = await prompts.getPromptsCount(); + expect.soft(resultCount, ExpectedMessages.searchResultCountIsValid).toBe(5); + }); + + await test.step('Type search term in the field and verify all prompts displayed', async () => { + for (const term of [searchTerm, searchTerm.toUpperCase()]) { + await promptBar.searchPrompt.fill(term); + const resultCount = await prompts.getPromptsCount(); + expect + .soft(resultCount, ExpectedMessages.searchResultCountIsValid) + .toBe(3); + } + }); + + await test.step('Type search term in the field and verify all prompts displayed', async () => { + await promptBar.searchPrompt.fill(specialSymbolSearchTerm); + const resultCount = await prompts.getPromptsCount(); + expect.soft(resultCount, ExpectedMessages.searchResultCountIsValid).toBe(1); + }); +}); diff --git a/e2e/src/ui/selectors/chatSelectors.ts b/e2e/src/ui/selectors/chatSelectors.ts index 9d29785a1c..3bfe6a7558 100644 --- a/e2e/src/ui/selectors/chatSelectors.ts +++ b/e2e/src/ui/selectors/chatSelectors.ts @@ -69,4 +69,5 @@ export const ChatSelectors = { replayAsIs: '[data-qa="replay-as-is"]', replayAsIsLabel: '[data-qa="info-as-is"]', iconAnimation: '.animate-bounce', + noResultFound: '[data-qa="no-data"]', }; diff --git a/e2e/src/ui/selectors/dialogSelectors.ts b/e2e/src/ui/selectors/dialogSelectors.ts index 7607fe5642..c50b67d0e3 100644 --- a/e2e/src/ui/selectors/dialogSelectors.ts +++ b/e2e/src/ui/selectors/dialogSelectors.ts @@ -33,6 +33,10 @@ export const ModelDialog = { groupEntityDescr: '[data-qa="group-entity-descr"]', expandGroupEntity: '[data-qa="expand-group-entity"]', closeDialog: '[data-qa="close-models-dialog"]', + searchInput: '[name="titleInput"]', + modelsTab: '[data-qa="models-tab"]', + assistantsTab: '[data-qa="assistants-tab"]', + applicationsTab: '[data-qa="applications-tab"]', }; export const AddonDialog = { diff --git a/e2e/src/ui/webElements/chatBar.ts b/e2e/src/ui/webElements/chatBar.ts index 40c20fe5e8..24e25326e9 100644 --- a/e2e/src/ui/webElements/chatBar.ts +++ b/e2e/src/ui/webElements/chatBar.ts @@ -1,4 +1,8 @@ -import { ChatBarSelectors, SideBarSelectors } from '../selectors'; +import { + ChatBarSelectors, + ChatSelectors, + SideBarSelectors, +} from '../selectors'; import { BaseElement } from './baseElement'; import { Conversations } from './conversations'; @@ -19,6 +23,10 @@ export class ChatBar extends BaseElement { this.page, ChatBarSelectors.newConversationButton, ); + public searchChat = this.getElementByPlaceholder('Search chat...'); + public noResultFoundIcon = this.getChildElementBySelector( + ChatSelectors.noResultFound, + ); public newFolderButton = new BaseElement( this.page, ChatBarSelectors.newFolder, diff --git a/e2e/src/ui/webElements/chatHeader.ts b/e2e/src/ui/webElements/chatHeader.ts index 1966655edf..0e55e56e9f 100644 --- a/e2e/src/ui/webElements/chatHeader.ts +++ b/e2e/src/ui/webElements/chatHeader.ts @@ -12,7 +12,7 @@ export class ChatHeader extends BaseElement { super(page, '', elementLocator); } - public chatTitle = new BaseElement(this.page, ChatSelectors.chatTitle); + public chatTitle = this.getChildElementBySelector(ChatSelectors.chatTitle); public icons = this.getChildElementBySelector(ChatSelectors.chatIcon); public chatModel = this.getChildElementBySelector(ChatSelectors.chatModel); public removeConversationFromComparison = this.getChildElementBySelector( diff --git a/e2e/src/ui/webElements/chatMessages.ts b/e2e/src/ui/webElements/chatMessages.ts index 48b6c74d15..07e6f55cfa 100644 --- a/e2e/src/ui/webElements/chatMessages.ts +++ b/e2e/src/ui/webElements/chatMessages.ts @@ -49,13 +49,6 @@ export class ChatMessages extends BaseElement { } } - public async waitForOneCompareConversationResponseReceived() { - const loadingCursorCount = await this.loadingCursor.getElementsCount(); - if (loadingCursorCount === 2) { - await this.waitForOneCompareConversationResponseReceived(); - } - } - public async isResponseLoading() { const loadingCursorCount = await this.loadingCursor.getElementsCount(); return loadingCursorCount > 0; @@ -95,6 +88,17 @@ export class ChatMessages extends BaseElement { }; } + public async waitForCompareMessageJumpingIconDisappears( + comparedMessageSide: Side, + ) { + const compareRowMessage = + await this.getCompareRowMessage(comparedMessageSide); + await compareRowMessage + .locator(ChatSelectors.iconAnimation) + .locator(ChatSelectors.chatIcon) + .waitFor({ state: 'detached' }); + } + public async getMessageJumpingIcon(index?: number) { const messagesCount = await this.chatMessages.getElementsCount(); return this.chatMessages diff --git a/e2e/src/ui/webElements/compare.ts b/e2e/src/ui/webElements/compare.ts index 599727f863..f54ae19c3c 100644 --- a/e2e/src/ui/webElements/compare.ts +++ b/e2e/src/ui/webElements/compare.ts @@ -67,7 +67,7 @@ export class Compare extends BaseElement { ); } - public async gerChatMessagesCount() { + public async getChatMessagesCount() { return this.getChatMessages().getElementsCount(); } diff --git a/e2e/src/ui/webElements/modelSelector.ts b/e2e/src/ui/webElements/modelSelector.ts index 1488a98606..7426ccfadc 100644 --- a/e2e/src/ui/webElements/modelSelector.ts +++ b/e2e/src/ui/webElements/modelSelector.ts @@ -38,6 +38,10 @@ export class ModelSelector extends BaseElement { return this.modelInput.getAttribute(Attributes.placeholder); } + public async fillInput(text: string) { + await this.modelInput.fillInInput(text); + } + public async getOptionsIconAttributes() { const allIcons: Icons[] = []; const optionsCount = await this.listOptions.getElementsCount(); @@ -45,9 +49,8 @@ export class ModelSelector extends BaseElement { const option = await this.listOptions.getNthElement(i); const customIconOption = await option.locator(ChatSelectors.chatIcon); if (await customIconOption.isVisible()) { - const iconAttributes = await this.getElementIconAttributes( - customIconOption, - ); + const iconAttributes = + await this.getElementIconAttributes(customIconOption); allIcons.push(iconAttributes); } else { const defaultIconAttributes = diff --git a/e2e/src/ui/webElements/modelsDialog.ts b/e2e/src/ui/webElements/modelsDialog.ts index 3d2ce03125..0d7a45eca6 100644 --- a/e2e/src/ui/webElements/modelsDialog.ts +++ b/e2e/src/ui/webElements/modelsDialog.ts @@ -11,6 +11,8 @@ export class ModelsDialog extends BaseElement { super(page, ModelDialog.modelDialog); } + public searchInput = this.getChildElementBySelector(ModelDialog.searchInput); + public group = (group: Groups) => this.getChildElementBySelector( ModelDialog.talkToGroup, @@ -18,6 +20,16 @@ export class ModelsDialog extends BaseElement { public groupEntity = this.getChildElementBySelector(ModelDialog.groupEntity); public closeButton = this.getChildElementBySelector(ModelDialog.closeDialog); + public noResultFoundIcon = this.getChildElementBySelector( + ChatSelectors.noResultFound, + ); + public modelsTab = this.getChildElementBySelector(ModelDialog.modelsTab); + public assistantsTab = this.getChildElementBySelector( + ModelDialog.assistantsTab, + ); + public applicationsTab = this.getChildElementBySelector( + ModelDialog.applicationsTab, + ); public entityOptionByGroup = (group: Groups, option: string) => this.group(group).locator( @@ -101,9 +113,8 @@ export class ModelsDialog extends BaseElement { const entity = await this.groupEntity.getNthElement(i); const customIconEntity = await entity.locator(ChatSelectors.chatIcon); if (await customIconEntity.isVisible()) { - const iconAttributes = await this.getElementIconAttributes( - customIconEntity, - ); + const iconAttributes = + await this.getElementIconAttributes(customIconEntity); allIcons.push(iconAttributes); } else { const defaultIconEntity = await entity.locator( diff --git a/e2e/src/ui/webElements/promptBar.ts b/e2e/src/ui/webElements/promptBar.ts index b26cce207e..f0c6184122 100644 --- a/e2e/src/ui/webElements/promptBar.ts +++ b/e2e/src/ui/webElements/promptBar.ts @@ -1,5 +1,6 @@ import { ChatBarSelectors, + ChatSelectors, PromptBarSelectors, SideBarSelectors, } from '../selectors'; @@ -18,6 +19,10 @@ export class PromptBar extends BaseElement { private prompts!: Prompts; private folderPrompts!: FolderPrompts; + public searchPrompt = this.getElementByPlaceholder('Search prompt...'); + public noResultFoundIcon = this.getChildElementBySelector( + ChatSelectors.noResultFound, + ); public exportButton = new BaseElement( this.page, ChatBarSelectors.exportPrompts, diff --git a/src/components/Chat/ModelsDialog.tsx b/src/components/Chat/ModelsDialog.tsx index 2c9bb7ea5d..ab7f05243e 100644 --- a/src/components/Chat/ModelsDialog.tsx +++ b/src/components/Chat/ModelsDialog.tsx @@ -289,6 +289,7 @@ export const ModelsDialog: FC = ({ onClick={() => { handleFilterType(EntityType.Model); }} + data-qa="models-tab" > {t('Models')} @@ -302,6 +303,7 @@ export const ModelsDialog: FC = ({ onClick={() => { handleFilterType(EntityType.Assistant); }} + data-qa="assistants-tab" > {t('Assistants')} @@ -315,6 +317,7 @@ export const ModelsDialog: FC = ({ onClick={() => { handleFilterType(EntityType.Application); }} + data-qa="applications-tab" > {t('Applications')} diff --git a/src/components/Common/NoResultsFound.tsx b/src/components/Common/NoResultsFound.tsx index 506252090d..8d48671c15 100644 --- a/src/components/Common/NoResultsFound.tsx +++ b/src/components/Common/NoResultsFound.tsx @@ -5,7 +5,10 @@ import Magnifier from '../../../public/images/icons/search-alt.svg'; export const NoResultsFound = () => { const { t } = useTranslation('common'); return ( -
+
{t('No results found')}