Skip to content

Commit 6378076

Browse files
author
kim
committed
test: add tests
1 parent b2e496b commit 6378076

File tree

9 files changed

+185
-13
lines changed

9 files changed

+185
-13
lines changed

cypress/e2e/builder/main.cy.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ const PROMPT_TEXT_AREA = '[name="Chatbot Prompt"]';
1414
const CUE_TEXT_AREA = '[name="Conversation Starter"]';
1515
const CHATBOT_NAME_INPUT = '[name="Chatbot Name"]';
1616

17+
const ADD_STARTER_SUGGESTION_BUTTON = '[title="Add starter suggestion"]';
18+
const buildStarterSuggestionInput = (idx: number) =>
19+
`[name="Starter suggestion number ${idx}"]`;
20+
1721
describe('Builder View', () => {
1822
it('Results table', () => {
1923
cy.setUpApi(
@@ -109,4 +113,63 @@ describe('Builder View', () => {
109113
.should('not.contain', 'The conversation starter is empty')
110114
.should('contain', cue);
111115
});
116+
117+
it('Show starter suggestions and edit', () => {
118+
cy.setUpApi(
119+
{ appSettings: [] },
120+
{
121+
context: Context.Builder,
122+
permission: PermissionLevel.Admin,
123+
},
124+
);
125+
cy.visit('/');
126+
127+
cy.get(buildDataCy(TAB_SETTINGS_VIEW_CYPRESS)).click();
128+
129+
cy.get(EDIT_SETTINGS_BUTTON).click();
130+
131+
// change prompt
132+
const prompt = 'my new prompt';
133+
cy.get(PROMPT_TEXT_AREA).clear().type(prompt);
134+
135+
const newSuggestions = ['Hello', 'Hello1', 'Hello2'];
136+
137+
// add suggestions
138+
newSuggestions.forEach((s, idx) => {
139+
cy.get(ADD_STARTER_SUGGESTION_BUTTON).click();
140+
cy.get(buildStarterSuggestionInput(idx)).type(s);
141+
});
142+
143+
cy.get(SAVE_SETTINGS_BUTTON).click();
144+
145+
// show starter suggestions
146+
for (const s of newSuggestions) {
147+
cy.get(`li:contains('${s}')`).should('be.visible');
148+
}
149+
150+
cy.wait(1000);
151+
cy.get(EDIT_SETTINGS_BUTTON).click();
152+
153+
// edit suggestions
154+
const editedSuggestions = ['newHello0', 'newHello1', 'newHello2'];
155+
editedSuggestions.forEach((s, idx) => {
156+
cy.get(buildStarterSuggestionInput(idx)).clear().type(s);
157+
});
158+
159+
// delete second suggestion
160+
cy.get(`[title="Delete suggestion number 1"]`).click();
161+
162+
// expect remaining suggestions
163+
const remainingSuggestions = [editedSuggestions[0], editedSuggestions[2]];
164+
for (const s of remainingSuggestions) {
165+
cy.get(`[value="${s}"]`).should('be.visible');
166+
}
167+
168+
cy.get(SAVE_SETTINGS_BUTTON).click();
169+
170+
// show starter suggestions
171+
for (const s of remainingSuggestions) {
172+
cy.get(`li:contains('${s}')`).should('be.visible');
173+
}
174+
});
112175
});

cypress/e2e/player/main.cy.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,4 +138,36 @@ describe('Player View', () => {
138138
cy.get('#root').should('contain', 'November 18, 2024');
139139
cy.get('#root').should('contain', 'November 18, 2025');
140140
});
141+
142+
it.only('Use a starter suggestion', () => {
143+
cy.setUpApi(
144+
{
145+
appData: [],
146+
appSettings: [MOCK_APP_SETTING],
147+
},
148+
{
149+
context: Context.Player,
150+
permission: PermissionLevel.Write,
151+
},
152+
);
153+
cy.visit('/');
154+
155+
const suggestion = MOCK_APP_SETTING.data.starterSuggestions[0];
156+
// click suggestion
157+
cy.get(`button:contains("${suggestion}")`).click();
158+
159+
// expect user message
160+
cy.get(buildDataCy(buildCommentContainerDataCy('2'))).should(
161+
'contain',
162+
suggestion,
163+
);
164+
165+
// expect chatbot message
166+
cy.get(buildDataCy(buildCommentContainerDataCy('3'))).should(
167+
'contain',
168+
'i am a bot', // default return value of the mocked chatbot
169+
);
170+
171+
cy.get(`button:contains("${suggestion}")`).should('not.be.visible');
172+
});
141173
});

cypress/fixtures/mockSettings.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@ export const MOCK_APP_SETTING = {
1212
chatbotCue: 'cue',
1313
chatbotName: 'name',
1414
initialPrompt: 'prompt',
15+
starterSuggestions: ['Can you spell it for me?', 'Can you explain this?'],
1516
},
1617
};

src/config/appActions.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ export const AppActionsType = {
66
Reply: 'reply_comment',
77
// chatbot actions
88
AskChatbot: 'ask_chatbot',
9+
UseStarter: 'use_starter',
910
} as const;

src/langs/en.json

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,14 @@
2929
"CHATBOT_PROMPT_HELPER_LABEL": "In-depth technical description",
3030
"CHATBOT_PROMPT_HELPER": "This defines the chatbot's personality and how it should behave.",
3131
"CHATBOT_PROMPT_FORMAT_HELPER": "To describe the initial situation, create an object at the start of the array with 2 keys: 'role' and 'content'. For the initial description the role must be 'system'. Place your description of the initial situation in the 'content' key. Add interaction examples after that. Add one object per message with the role corresponding to either 'assistant' or 'user'.",
32+
"CHATBOT_STARTER_SUGGESTIONS_LABEL": "Starter Suggestions",
33+
"CHATBOT_STARTER_SUGGESTIONS_EMPTY_MESSAGE": "-",
3234
"CHATBOT_PROMPT_FORMAT_EXAMPLE": "Here is an example",
3335
"CHATBOT_PROMPT_API_REFERENCE": "See the API reference",
3436
"CHATBOT_CUE_LABEL": "Conversation Starter",
3537
"CHATBOT_STARTER_SUGGESTION_LABEL": "Starter Suggestions",
3638
"CHATBOT_CUE_HELPER": "This defines the content of the first message of the chatbot. You can change it to better orient the conversation.",
37-
"CHATBOT_CUE_EMPTY_MESSAGE": "The conversation starter is empty.",
39+
"CHATBOT_CUE_EMPTY_MESSAGE": "-",
3840
"SAVE_LABEL": "Save",
3941
"SAVED_LABEL": "Saved",
4042
"GENERAL_SETTING_TITLE": "General",
@@ -66,6 +68,12 @@
6668
"CLOSE": "Close",
6769
"SIGN_OUT_ALERT": "You should be signed in to interact with the chatbot",
6870
"ANALYTICS_CONVERSATION_MEMBER": "Conversation",
69-
"CHATBOT_STARTER_SUGGESTION_HELPER": "This defines suggested messages the user can send at the beginning of the conversation to the chatbot. You can change it to give ideas of interactions."
71+
"CHATBOT_STARTER_SUGGESTION_HELPER": "This defines suggested messages the user can send at the beginning of the conversation to the chatbot. You can change it to give ideas of interactions.",
72+
"ADD_STARTER_SUGGESTION_BUTTON": "Add",
73+
"ADD_STARTER_SUGGESTION_BUTTON_TITLE": "Add starter suggestion",
74+
"STARTER_SUGGESTION_NAME": "Starter suggestion number {{nb}}",
75+
"DELETE_STARTER_SUGGESTION_BUTTON_TITLE": "Delete suggestion number {{nb}}",
76+
"STARTER_SUGGESTION_PLACEHOLDER": "Write a suggestion here",
77+
"STARTER_SUGGESTION_PLAYER_BUTTON_ARIA_LABEL": "Ask {{suggestion}}"
7078
}
7179
}

src/modules/common/CommentEditor.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ function CommentEditor({
8787
value={text}
8888
onChange={handleTextChange}
8989
role="textbox"
90-
disabled={sendMessageLoading || askChatbotLoading}
90+
disabled={isLoading}
9191
// use default font instead of textarea's monospace font
9292
style={{ fontFamily: 'unset' }}
9393
/>

src/modules/common/Suggestions.tsx

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,56 @@
1+
import { useTranslation } from 'react-i18next';
2+
13
import { Button, Stack, styled } from '@mui/material';
24

5+
import { AppActionsType } from '@/config/appActions';
36
import { ChatbotPromptSettings } from '@/config/appSetting';
7+
import { mutations } from '@/config/queryClient';
8+
import { showErrorToast } from '@/utils/toast';
49

510
import { useSendMessageAndAskChatbot } from './useSendMessageAndAskChatbot';
611

7-
const StyledButton = styled(Button)(({ theme }) => ({
12+
const StyledButton = styled(Button)({
813
borderRadius: 100,
914
textTransform: 'unset',
10-
}));
15+
});
1116

1217
export function Suggestions({
1318
suggestions,
1419
chatbotPrompt,
15-
}: {
20+
}: Readonly<{
1621
chatbotPrompt: ChatbotPromptSettings;
1722
suggestions: string[];
18-
}) {
23+
}>) {
24+
const { t } = useTranslation();
25+
const { mutateAsync: postAction } = mutations.usePostAppAction();
1926
const { send } = useSendMessageAndAskChatbot({ chatbotPrompt });
2027

28+
const onClick = async (suggestion: string) => {
29+
try {
30+
await send(suggestion);
31+
await postAction({
32+
type: AppActionsType.UseStarter,
33+
data: { value: suggestion },
34+
});
35+
} catch (e: unknown) {
36+
if (e instanceof Error) {
37+
showErrorToast(e.message);
38+
}
39+
console.error(e);
40+
}
41+
};
42+
2143
return (
2244
<Stack direction="row" gap={2} justifyContent="right">
2345
{suggestions.map((s) => (
2446
<span key={s}>
25-
<StyledButton onClick={() => send(s)} variant="contained">
47+
<StyledButton
48+
aria-label={t('STARTER_SUGGESTION_PLAYER_BUTTON_ARIA_LABEL', {
49+
suggestion: s,
50+
})}
51+
onClick={() => onClick(s)}
52+
variant="contained"
53+
>
2654
{s}
2755
</StyledButton>
2856
</span>

src/modules/settings/ChatbotSettings.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
Grid2,
1111
Stack,
1212
Typography,
13+
useTheme,
1314
} from '@mui/material';
1415

1516
import { Edit, Undo2 } from 'lucide-react';
@@ -69,6 +70,7 @@ const useChatbotSetting = () => {
6970
};
7071

7172
function ChatbotSettings() {
73+
const theme = useTheme();
7274
const { t } = useTranslation();
7375

7476
const {
@@ -196,6 +198,29 @@ function ChatbotSettings() {
196198
</Typography>
197199
)}
198200
</Grid2>
201+
202+
<Grid2 size={{ xs: 12, sm: 4 }}>
203+
<FormLabel sx={{ fontWeight: 'bold' }}>
204+
{t('CHATBOT_STARTER_SUGGESTIONS_LABEL')}
205+
</FormLabel>
206+
</Grid2>
207+
<Grid2 size={{ xs: 12, sm: 8 }}>
208+
{starterSuggestions.length ? (
209+
<ul
210+
style={{ marginBlock: 0, paddingInline: theme.spacing(2) }}
211+
>
212+
{starterSuggestions.map((s) => (
213+
<Typography key={s} variant="body1" component="li">
214+
{s}
215+
</Typography>
216+
))}
217+
</ul>
218+
) : (
219+
<Typography color="text.disabled" fontStyle="italic">
220+
{t('CHATBOT_STARTER_SUGGESTIONS_EMPTY_MESSAGE')}
221+
</Typography>
222+
)}
223+
</Grid2>
199224
</Grid2>
200225
</CardContent>
201226
</Card>

src/modules/settings/chatbot/StarterSuggestions.tsx

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { useTranslation } from 'react-i18next';
2+
13
import { Button, IconButton, Stack, TextField } from '@mui/material';
24

35
import { PlusIcon, TrashIcon } from 'lucide-react';
@@ -11,10 +13,12 @@ function StarterSuggestions({
1113
starterSuggestions: InternalSuggestion[];
1214
onChange: (args: InternalSuggestion[]) => void;
1315
}>) {
16+
const { t } = useTranslation();
17+
1418
const add = () => {
1519
// increase id based on last one
1620
// this works as long as we don't reorder
17-
const lastId = starterSuggestions.at(-1)?.id ?? 0;
21+
const lastId = starterSuggestions.at(-1)?.id ?? -1;
1822
onChange([
1923
...starterSuggestions,
2024
{
@@ -43,18 +47,28 @@ function StarterSuggestions({
4347
<TextField
4448
size="small"
4549
fullWidth
46-
placeholder="Write a suggestion here"
50+
placeholder={t('STARTER_SUGGESTION_PLACEHOLDER')}
4751
defaultValue={value}
4852
onChange={(e) => edit(e.target.value, id)}
53+
name={t('STARTER_SUGGESTION_NAME', { nb: id })}
4954
/>
50-
<IconButton color="error" onClick={() => remove(id)}>
55+
<IconButton
56+
title={t('DELETE_STARTER_SUGGESTION_BUTTON_TITLE', { nb: id })}
57+
color="error"
58+
onClick={() => remove(id)}
59+
>
5160
<TrashIcon />
5261
</IconButton>
5362
</Stack>
5463
))}
5564
<span>
56-
<Button startIcon={<PlusIcon />} color="primary" onClick={add}>
57-
Add
65+
<Button
66+
startIcon={<PlusIcon />}
67+
color="primary"
68+
onClick={add}
69+
title={t('ADD_STARTER_SUGGESTION_BUTTON_TITLE')}
70+
>
71+
{t('ADD_STARTER_SUGGESTION_BUTTON')}
5872
</Button>
5973
</span>
6074
</Stack>

0 commit comments

Comments
 (0)