Skip to content

Commit

Permalink
Add more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Dayana Ilieva committed Mar 14, 2024
1 parent 7baa908 commit cca4d69
Show file tree
Hide file tree
Showing 13 changed files with 1,294 additions and 944 deletions.
2 changes: 1 addition & 1 deletion __mocks__/socket.io-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ function emit(event, ...args) {
EVENTS[event].forEach(func => func(...args));
}

const socket = {
export const socket = {
connected: true,
on(event, func) {
if (EVENTS[event]) {
Expand Down
4 changes: 3 additions & 1 deletion __tests__/feature/chat-closing.spec.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,11 @@ describe('Close button closes chat', () => {
test('chat.closed is true after close button is clicked an href is being used correctly when set', async () => {
// Arrange
jest.useFakeTimers();
const closeConfig = { visible: true, href: '/test' };
act(() => {
root = renderWithProviders(
<div id="chatbot-container">
<AppBase config={getInitialConfig({ id: uuidV4(), purpose: '', close: { visible: true, href: '/test' } })} />
<AppBase config={getInitialConfig({ id: uuidV4(), purpose: '', close: closeConfig })} />
</div>
);
root.store.dispatch(setConnected(true));
Expand Down Expand Up @@ -117,6 +118,7 @@ describe('Close button closes chat', () => {
expect(document.body.classList).not.toContain(SCROLL_STOP_CLASS);
expect(ioCloseSpy).toHaveBeenCalled();
expect(window.location.href).toBe(config.close.href);
expect(window.location.href).toBe(closeConfig.href);
jest.useRealTimers();
});
});
311 changes: 275 additions & 36 deletions __tests__/feature/chat-history.spec.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,65 @@ import renderWithProviders from '../../src/utils/storeMockWrapper';
import { setConnected } from '../../src/store/slices/chat';
import { serverSocket } from '../../__mocks__/socket.io-client';
import { Events, Roles, chat as getInitialConfig, initialMessage } from '../../src/config';
import { io } from 'socket.io-client';
import { Intentions } from '../../src/config/enums';

const textProbe = () => ({ 'type': 'text', 'text': faker.lorem.text(), 'sequence': 2 });
const contentMock = {
text: [textProbe(), textProbe()],
email: [
textProbe(),
{ 'type': 'email', 'email': faker.lorem.text(), 'sequence': 2 },
],
payment: [
textProbe(),
{ 'type': 'payment', 'payment': faker.lorem.text(), 'sequence': 2 },
],
};

const serverData = {
"region": faker.location.country(),
"history": [],
"errors": [],
}

jest.useFakeTimers();

let root;
const chatConfig = getInitialConfig({ id: uuidV4(), purpose: '', close: { visible: true } });
describe('Chat-history event works and visualizes items accordingly', () => {
beforeEach(() => {
serverData.history = [];
serverData.errors = [];
serverData.region = faker.location.country();
})
afterEach(localTearDown);

test('loader is visible on initiation and not connected to socket', () => {
// Arrange
act(() => {
root = renderWithProviders(
<div id="chatbot-container">
<AppBase config={getInitialConfig({ id: uuidV4(), purpose: '', close: {} })} />
</div>
);
});

// Assert
const historyElements = root.container.querySelectorAll('[data-e2e="history-item"]');
const userFormElement = root.container.querySelector('[data-e2e="user-form"]');
const emailFormElement = root.container.querySelector('[data-e2e="email-form"]');
expect(root.container.querySelector('[data-e2e="stream-response-loader"]')).toBeVisible();
expect(userFormElement).toBeNull();
expect(emailFormElement).toBeNull();

const { chat } = root.store.getState();
expect(chat.isLoading).toBe(true);
expect(historyElements.length).toEqual(chat.historyIds.length);
});

test('on chat-history event state is shown and saved properly', async () => {
jest.spyOn(intent.core, 'emit');
// Arrange
act(() => {
root = renderWithProviders(
<div id="chatbot-container">
Expand All @@ -29,24 +78,14 @@ describe('Chat-history event works and visualizes items accordingly', () => {
root.store.dispatch(setConnected(true));
});

serverData.history = [{
id: uuidV4(),
role: Roles.assistant,
time: new Date().getTime(),
content: contentMock.text,
}];

// Act
const serverData = {
"region": faker.location.country(),
"history": [
{
id: uuidV4(),
role: Roles.assistant,
time: new Date().getTime(),
content: [
{
'type': 'text',
'text': 'Do you want to lose weight?', 'sequence': 2
},
]
},
],
"errors": []
}
act(() => {
serverSocket.emit(Events.chatHistory, serverData);
jest.advanceTimersByTime((initialMessage.length * 1000) * initialMessage.length - 1);
Expand All @@ -59,39 +98,35 @@ describe('Chat-history event works and visualizes items accordingly', () => {

// Assert
expect(dateElement).not.toBeNull();
expect(userFormElement).not.toBeNull();
expect(userFormElement).toBeVisible();
expect(emailFormElement).toBeNull();

const { meta, config, chat } = root.store.getState();
expect(meta.region).toStrictEqual(serverData.region);
expect(historyElements.length).toEqual(chat.historyIds.length);
expect(meta.region).toStrictEqual(serverData.region);
expect(config.aiProfile).toStrictEqual(chatConfig.app.aiProfile);
expect(config.translations).toStrictEqual(chatConfig.app.translations);
});

test('on click payment button intent is being emitted and button is disabled', async () => {
jest.spyOn(intent.core, 'emit');
act(() => {
root = renderWithProviders(<div id="chatbot-container"><AppBase config={getInitialConfig({ id: uuidV4(), purpose: '', close: { visible: true } })} /></div>);
root = renderWithProviders(<div id="chatbot-container">
<AppBase config={getInitialConfig({ id: uuidV4(), purpose: '', close: { visible: true } })} />
</div>);
root.store.dispatch(setConnected(true));
});

// Act
const serverData = {
"region": faker.location.country(),
"history": [
{
id: uuidV4(),
role: Roles.assistant,
time: new Date().getTime(),
content: [
{ 'type': 'text', 'text': 'Do you want to lose weight?', 'sequence': 2 },
{ 'type': 'payment', 'payment': 'Do you want to lose weight?', 'sequence': 2 },
]
},
],
"errors": []
}
serverData.history = [
{
id: uuidV4(),
role: Roles.assistant,
time: new Date().getTime(),
content: contentMock.payment
},
];

act(() => {
serverSocket.emit(Events.chatHistory, serverData);
jest.advanceTimersByTime((initialMessage.length * 1000) * initialMessage.length - 1);
Expand All @@ -104,4 +139,208 @@ describe('Chat-history event works and visualizes items accordingly', () => {
expect(intent.core.emit).toHaveBeenCalledTimes(1);
expect(paymentButtonElement).toBeDisabled();
});

test('email form is visualized when last message contains type: email', async () => {
act(() => {
root = renderWithProviders(<div id="chatbot-container">
<AppBase config={getInitialConfig({ id: uuidV4(), purpose: '', close: { visible: true } })} />
</div>);
root.store.dispatch(setConnected(true));
});

// Act
serverData.history = [
{
id: uuidV4(),
role: Roles.assistant,
time: new Date().getTime(),
content: contentMock.email
},
];

act(() => {
serverSocket.emit(Events.chatHistory, serverData);
jest.advanceTimersByTime((initialMessage.length * 1000) * initialMessage.length - 1);
});

const userFormElement = root.container.querySelector('[data-e2e="user-form"]');
const emailFormElement = root.container.querySelector('[data-e2e="email-form"]');
const loaderElement = root.container.querySelector('[data-e2e="stream-response-loader"]');
const ctaElement = root.container.querySelector('[data-e2e="quiz-trigger-btn"]');

// Assert
expect(userFormElement).toBeNull();
expect(emailFormElement).toBeVisible();
expect(loaderElement).toBeNull();
expect(ctaElement).toBeNull();

const { chat } = root.store.getState();
expect(chat.isLoading).toBe(false);
expect(chat.isStreaming).toBe(false);
});

test('email form submitted does not submit the email when the field is empty', async () => {
jest.spyOn(intent.core, 'emit');
act(() => {
root = renderWithProviders(<div id="chatbot-container">
<AppBase config={getInitialConfig({ id: uuidV4(), purpose: '', close: { visible: true } })} />
</div>);
root.store.dispatch(setConnected(true));
});

// Act
serverData.history = [
{
id: uuidV4(),
role: Roles.assistant,
time: new Date().getTime(),
content: contentMock.email
},
];

act(() => {
serverSocket.emit(Events.chatHistory, serverData);
jest.advanceTimersByTime((initialMessage.length * 1000) * initialMessage.length - 1);
});

const emailFormElement = root.container.querySelector('[data-e2e="email-form"]');
fireEvent.submit(emailFormElement)
// Assert
expect(intent.core.emit).toHaveBeenCalledTimes(0);
});

test('email form submitted: emits email and sets state properly', async () => {
const currentEmail = faker.internet.email();
jest.spyOn(intent.core, 'emit');
act(() => {
root = renderWithProviders(<div id="chatbot-container">
<AppBase config={getInitialConfig({ id: uuidV4(), purpose: '', close: { visible: true } })} />
</div>);
root.store.dispatch(setConnected(true));
});

// Act
serverData.history = [
{
id: uuidV4(),
role: Roles.assistant,
time: new Date().getTime(),
content: contentMock.email
},
];

act(() => {
serverSocket.emit(Events.chatHistory, serverData);
jest.advanceTimersByTime((initialMessage.length * 1000) * initialMessage.length - 1);
});

const emailFormElement = root.container.querySelector('[data-e2e="email-form"]');
const emailInputElement = root.container.querySelector('[data-e2e="email-input"]');
fireEvent.input(emailInputElement, { target: { value: currentEmail } });
fireEvent.submit(emailFormElement);

// Assert
const { intentions } = root.store.getState()
expect(intent.core.emit).toHaveBeenCalledWith(Intentions.email, { email: currentEmail });
expect(intentions.email.isLoading).toBe(true);
expect(intentions.email.current).toBe(currentEmail);
});

test('on chat-history last message is of type: text footer props are set correctly and visualized response field', async () => {
act(() => {
root = renderWithProviders(
<div id="chatbot-container">
<AppBase config={getInitialConfig({ id: uuidV4(), purpose: '', close: { visible: true } })} />
</div>
);
root.store.dispatch(setConnected(true));
});
serverData.history = [
{
id: uuidV4(),
role: Roles.assistant,
time: new Date().getTime(),
content: contentMock.text,
}]

// Act
act(() => {
serverSocket.emit(Events.chatHistory, serverData);
jest.advanceTimersByTime((initialMessage.length * 1000) * initialMessage.length - 1);
});

const dateElement = root.container.querySelector('[data-e2e="stream-assistant-msg-date"]');
const userFormElement = root.container.querySelector('[data-e2e="user-form"]');
const emailFormElement = root.container.querySelector('[data-e2e="email-form"]');
const loaderElement = root.container.querySelector('[data-e2e="stream-response-loader"]');
const ctaElement = root.container.querySelector('[data-e2e="quiz-trigger-btn"]');

// Assert
expect(dateElement).not.toBeNull();
expect(userFormElement).toBeVisible();
expect(emailFormElement).toBeNull();
expect(loaderElement).toBeNull();
expect(ctaElement).toBeNull();

const { chat } = root.store.getState();
expect(chat.isLoading).toBe(false);
expect(chat.isStreaming).toBe(false);
});

test('on chat-history event with errors in the callback visualizes the error', async () => {
act(() => {
root = renderWithProviders(
<div id="chatbot-container">
<AppBase config={getInitialConfig({ id: uuidV4(), purpose: '', close: { visible: true } })} />
</div>
);
root.store.dispatch(setConnected(true));
});

// Act
serverData.history = [
{
id: uuidV4(),
role: Roles.assistant,
time: new Date().getTime(),
content: contentMock.text,
},
];
serverData.errors = [faker.lorem.text()];

act(() => {
serverSocket.emit(Events.chatHistory, serverData);
jest.advanceTimersByTime((initialMessage.length * 1000) * initialMessage.length - 1);
});

// Assert
const errorElement = root.container.querySelector('[data-e2e="error-message"]');
const userFormElement = root.container.querySelector('[data-e2e="user-form"]');
const emailFormElement = root.container.querySelector('[data-e2e="email-form"]');
expect(errorElement).toBeVisible();
expect(errorElement.textContent).toBe(serverData.errors[0]);
expect(userFormElement).toBeNull();
expect(emailFormElement).toBeNull();
});

test('on chat-history no history received from the server must send the configured initial messages and visualize them', async () => {
const ioEmitSpy = jest.spyOn(io.connect(), 'emit');
act(() => {
root = renderWithProviders(
<div id="chatbot-container">
<AppBase config={getInitialConfig({ id: uuidV4(), purpose: '', close: { visible: true } })} />
</div>
);
root.store.dispatch(setConnected(true));
});

// Act
act(() => {
serverSocket.emit(Events.chatHistory, serverData);
jest.advanceTimersByTime((initialMessage.length * 1000) * initialMessage.length - 1);
});

// Assert
expect(ioEmitSpy).toHaveBeenCalledTimes(initialMessage.length);
});
});
Loading

0 comments on commit cca4d69

Please sign in to comment.