From cc09af2193a5b5e2bf03dc7c4121e701fe365453 Mon Sep 17 00:00:00 2001 From: Thadd Trinh Date: Mon, 30 Sep 2024 15:36:19 -0700 Subject: [PATCH 1/3] chore(ai): initial ai conversation e2e tests --- packages/e2e/cypress/integration/common/ai.ts | 22 ++++++++++++++ .../ui/components/ai/conversation.feature | 29 +++++++++++++++++++ packages/e2e/package.json | 1 + 3 files changed, 52 insertions(+) create mode 100644 packages/e2e/cypress/integration/common/ai.ts create mode 100644 packages/e2e/features/ui/components/ai/conversation.feature diff --git a/packages/e2e/cypress/integration/common/ai.ts b/packages/e2e/cypress/integration/common/ai.ts new file mode 100644 index 00000000000..aec587f52a0 --- /dev/null +++ b/packages/e2e/cypress/integration/common/ai.ts @@ -0,0 +1,22 @@ +import { Then } from '@badeball/cypress-cucumber-preprocessor'; +import { escapeRegExp } from 'cypress/types/lodash'; + +Then('I type {string}', (message: string) => { + cy.wait(1000); // todo: remove this once we figure out what's causing re-render + cy.findByTestId('text-input').type(message); +}); + +Then('I click the send message button', () => { + cy.get("[type='submit']").click(); +}); + +Then('I see {string} in the text input', (message: string) => { + cy.findByTestId('text-input').should('include', message); +}); + +Then('I click the {string} prompt', (name: string) => { + cy.wait(1000); // todo: remove this once we figure out what's causing re-render + cy.findByRole('button', { + name: new RegExp(`^${escapeRegExp(name)}$`, 'i'), + }).click(); +}); diff --git a/packages/e2e/features/ui/components/ai/conversation.feature b/packages/e2e/features/ui/components/ai/conversation.feature new file mode 100644 index 00000000000..8b579119139 --- /dev/null +++ b/packages/e2e/features/ui/components/ai/conversation.feature @@ -0,0 +1,29 @@ +Feature: AI Conversation + + Test AI Conversation component + + Background: + Given I'm running the example "ui/components/ai/ai-conversation" + + @react + Scenario: See conversation window + When I type my "email" with status "CONFIRMED" + Then I type my password + Then I click the "Sign in" button + Then I see "how are you?" + Then I see "text-input" element + Then I type "What is your name?" + Then I click the send message button + Then I see "Argh the time be round" + + @react + Scenario: See conversation window and suggested prompts + When I type my "email" with status "CONFIRMED" + Then I type my password + Then I click the "Sign in" button + Then I see "how are you?" + Then I click the "how are you?" prompt + Then I see "how are you?" in the text input + Then I click the send message button + Then I see "Argh the time be round" + diff --git a/packages/e2e/package.json b/packages/e2e/package.json index ec3add085a4..32e414fe5e2 100644 --- a/packages/e2e/package.json +++ b/packages/e2e/package.json @@ -6,6 +6,7 @@ "scripts": { "clean": "rimraf node_modules", "dev": "cypress open", + "test:ai": "cypress run --spec 'features/ui/components/ai/*.feature' --browser chrome", "test:examples": "cypress run --spec 'features/ui/hooks/*.feature','features/ui/components/**/*.feature' --browser chrome", "test:authenticator": "cypress run --spec 'features/ui/components/authenticator/*.feature' --browser chrome", "test:hooks": "cypress run --spec 'features/ui/hooks/*.feature' --browser chrome", From 06d3937b497eb88b29b4b3011a62ea2251c0bdc3 Mon Sep 17 00:00:00 2001 From: Thadd Trinh Date: Tue, 1 Oct 2024 09:29:06 -0700 Subject: [PATCH 2/3] fix import --- packages/e2e/cypress/integration/common/ai.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/e2e/cypress/integration/common/ai.ts b/packages/e2e/cypress/integration/common/ai.ts index aec587f52a0..9a0f58fe460 100644 --- a/packages/e2e/cypress/integration/common/ai.ts +++ b/packages/e2e/cypress/integration/common/ai.ts @@ -1,5 +1,5 @@ import { Then } from '@badeball/cypress-cucumber-preprocessor'; -import { escapeRegExp } from 'cypress/types/lodash'; +import { escapeRegExp } from 'lodash'; Then('I type {string}', (message: string) => { cy.wait(1000); // todo: remove this once we figure out what's causing re-render From c573370b97a38332f0fbe7315550954cf2a995d0 Mon Sep 17 00:00:00 2001 From: Thadd Trinh Date: Thu, 3 Oct 2024 14:16:29 -0700 Subject: [PATCH 3/3] fix? --- .../ai/ai-conversation/index.page.tsx | 32 ++++++++---- packages/e2e/cypress/integration/common/ai.ts | 7 +-- .../AIConversation/AIConversation.tsx | 51 +++++++++++-------- 3 files changed, 56 insertions(+), 34 deletions(-) diff --git a/examples/next/pages/ui/components/ai/ai-conversation/index.page.tsx b/examples/next/pages/ui/components/ai/ai-conversation/index.page.tsx index e043a999150..17eab7d2b85 100644 --- a/examples/next/pages/ui/components/ai/ai-conversation/index.page.tsx +++ b/examples/next/pages/ui/components/ai/ai-conversation/index.page.tsx @@ -7,6 +7,7 @@ import '@aws-amplify/ui-react-ai/ai-conversation-styles.css'; import outputs from './amplify_outputs'; import type { Schema } from '@environments/ai/gen2/amplify/data/resource'; import { Authenticator, Card } from '@aws-amplify/ui-react'; +import React from 'react'; const client = generateClient({ authMode: 'userPool' }); const { useAIConversation } = createAIHooks(client); @@ -29,23 +30,32 @@ function Chat() { sendMessage, ] = useAIConversation('pirateChat'); + const displayText = React.useMemo(() => { + return { getMessageTimestampText: formatDate }; + }, []); + + const suggestedPrompts = React.useMemo( + () => [ + { + inputText: 'hello', + header: 'hello', + }, + { + inputText: 'how are you?', + header: 'how are you?', + }, + ], + [] + ); + return ( diff --git a/packages/e2e/cypress/integration/common/ai.ts b/packages/e2e/cypress/integration/common/ai.ts index 9a0f58fe460..70e84daa9a5 100644 --- a/packages/e2e/cypress/integration/common/ai.ts +++ b/packages/e2e/cypress/integration/common/ai.ts @@ -2,7 +2,6 @@ import { Then } from '@badeball/cypress-cucumber-preprocessor'; import { escapeRegExp } from 'lodash'; Then('I type {string}', (message: string) => { - cy.wait(1000); // todo: remove this once we figure out what's causing re-render cy.findByTestId('text-input').type(message); }); @@ -11,11 +10,13 @@ Then('I click the send message button', () => { }); Then('I see {string} in the text input', (message: string) => { - cy.findByTestId('text-input').should('include', message); + cy.get('[data-testid="text-input"]') + .find('textarea') + .should('have.value', message); }); Then('I click the {string} prompt', (name: string) => { - cy.wait(1000); // todo: remove this once we figure out what's causing re-render + cy.wait(2500); // todo: remove this once we figure out what's causing re-render cy.findByRole('button', { name: new RegExp(`^${escapeRegExp(name)}$`, 'i'), }).click(); diff --git a/packages/react-ai/src/components/AIConversation/AIConversation.tsx b/packages/react-ai/src/components/AIConversation/AIConversation.tsx index b60f3166b07..9bf40dc9382 100644 --- a/packages/react-ai/src/components/AIConversation/AIConversation.tsx +++ b/packages/react-ai/src/components/AIConversation/AIConversation.tsx @@ -43,26 +43,37 @@ function AIConversationBase({ }, }; - const Provider = createProvider({ - elements: { - Text: React.forwardRef( - function _Text(props, ref) { - return ; - } - ), - }, - actions, - suggestedPrompts, - responseComponents, - variant, - controls: { - MessageList, - PromptList, - Form, - ...controls, - }, - displayText, - }); + const Provider = React.useMemo( + () => + createProvider({ + elements: { + Text: React.forwardRef( + function _Text(props, ref) { + return ; + } + ), + }, + actions, + suggestedPrompts, + responseComponents, + variant, + controls: { + MessageList, + PromptList, + Form, + ...controls, + }, + displayText, + }), + [ + actions, + controls, + displayText, + responseComponents, + suggestedPrompts, + variant, + ] + ); const providerProps = { messages,