Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import type { Message } from '@js/ui/chat';
import { AI_ASSISTANT_AUTHOR_ID, MessageStatus } from '../const';
import {
getMessageStatus,
hasAbortedCommands,
hasCommandErrors,
isAIMessage,
isChatOptions,
isEnabledOption,
Expand Down Expand Up @@ -119,6 +121,61 @@ describe('isChatOptions', () => {
});
});

describe('hasCommandErrors', () => {
it('should return true when commands contain failure status', () => {
const commands = [
{ status: 'success' as const, message: 'OK' },
{ status: 'failure' as const, message: 'Failed' },
];

expect(hasCommandErrors(commands)).toBe(true);
});

it('should return false when all commands are successful', () => {
const commands = [
{ status: 'success' as const, message: 'OK' },
];

expect(hasCommandErrors(commands)).toBe(false);
});

it('should return false when commands is undefined', () => {
expect(hasCommandErrors(undefined)).toBe(false);
});

it('should return false when commands contain only aborted status', () => {
const commands = [
{ status: 'aborted' as const, message: 'Aborted' },
];

expect(hasCommandErrors(commands)).toBe(false);
});
});

describe('hasAbortedCommands', () => {
it('should return true when commands contain aborted status', () => {
const commands = [
{ status: 'success' as const, message: 'OK' },
{ status: 'aborted' as const, message: 'Aborted' },
];

expect(hasAbortedCommands(commands)).toBe(true);
});

it('should return false when no commands are aborted', () => {
const commands = [
{ status: 'success' as const, message: 'OK' },
{ status: 'failure' as const, message: 'Failed' },
];

expect(hasAbortedCommands(commands)).toBe(false);
});

it('should return false when commands is undefined', () => {
expect(hasAbortedCommands(undefined)).toBe(false);
});
});

describe('getMessageStatus', () => {
it('should return Success when all commands are successful', () => {
const commands = [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { isObject } from '@js/core/utils/type';
import type { Message } from '@js/ui/chat';

import { hasAbortedCommands, hasCommandErrors } from '../ai_chat/utils';
import { AI_ASSISTANT_AUTHOR_ID, MessageStatus } from './const';
import type { AIMessage, CommandResults } from './types';
import type { AIMessage, CommandResult } from './types';

export const isAIMessage = (
message: Message,
Expand All @@ -21,7 +20,15 @@ export const isPopupOptions = (optionName: string, value: unknown): boolean => o
export const isChatOptions = (optionName: string, value: unknown): boolean => optionName.startsWith('aiAssistant.chat')
|| (optionName === 'aiAssistant' && isObject(value) && 'chat' in value);

export const getMessageStatus = (commands: CommandResults): MessageStatus => {
export const hasCommandErrors = (
commands: CommandResult[] | undefined,
): boolean => !!commands?.some(({ status }) => status === 'failure');

export const hasAbortedCommands = (
commands: CommandResult[] | undefined,
): boolean => !!commands?.some(({ status }) => status === 'aborted');

export const getMessageStatus = (commands: CommandResult[]): MessageStatus => {
if (hasCommandErrors(commands) || hasAbortedCommands(commands)) {
return MessageStatus.Failure;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -394,26 +394,6 @@ describe('AIChat', () => {
expect(icons[2].textContent).toBe(ABORTED_ITEM_EMOJI);
});

it('should render error icon when commands contain errors', () => {
createAIChat();
triggerContentTemplate();

const chatConfig = getChatConfig();
const container = document.createElement('div');

renderMessageTemplate(chatConfig, {
author: { id: AI_ASSISTANT_AUTHOR_ID, name: 'AI Assistant' },
text: 'Mixed',
status: 'success',
commands: [
{ status: 'success', message: 'OK' },
{ status: 'failure', message: 'Failed' },
],
}, container);

expect(container.querySelector(`.${CLASSES.messageIcon}`)?.classList.contains('dx-icon-errorcircle')).toBe(true);
});

it('should not render regenerate button when all commands succeed', () => {
const onRegenerate = jest.fn();
createAIChat({ onRegenerate });
Expand All @@ -432,30 +412,6 @@ describe('AIChat', () => {
expect(container.querySelector(`.${CLASSES.messageRegenerateButton}`)).toBeNull();
});

it('should render regenerate button when commands contain errors', () => {
const onRegenerate = jest.fn();
createAIChat({ onRegenerate });
triggerContentTemplate();

const chatConfig = getChatConfig();
const container = document.createElement('div');

renderMessageTemplate(chatConfig, {
author: { id: AI_ASSISTANT_AUTHOR_ID, name: 'AI Assistant' },
text: 'Mixed results',
status: 'success',
commands: [
{ status: 'success', message: 'OK' },
{ status: 'failure', message: 'Failed' },
],
}, container);

const regenerateButton = container.querySelector(`.${CLASSES.messageRegenerateButton}`);

expect(regenerateButton).not.toBeNull();
expect(regenerateButton?.classList.contains(`dx-icon-${REGENERATE_ICON}`)).toBe(true);
});

it('should not render command list when commands array is empty', () => {
createAIChat();
triggerContentTemplate();
Expand Down Expand Up @@ -632,50 +588,6 @@ describe('AIChat', () => {
expect(icons).toHaveLength(1);
expect(icons[0].textContent).toBe(ABORTED_ITEM_EMOJI);
});

it('should render error icon when commands contain aborted items', () => {
createAIChat();
triggerContentTemplate();

const chatConfig = getChatConfig();
const container = document.createElement('div');

renderMessageTemplate(chatConfig, {
author: { id: AI_ASSISTANT_AUTHOR_ID, name: 'AI Assistant' },
text: 'Aborted',
status: 'success',
commands: [
{ status: 'success', message: 'OK' },
{ status: 'aborted', message: 'Aborted' },
],
}, container);

expect(container.querySelector(`.${CLASSES.messageIcon}`)?.classList.contains('dx-icon-errorcircle')).toBe(true);
});

it('should render regenerate button when commands contain aborted items', () => {
const onRegenerate = jest.fn();
createAIChat({ onRegenerate });
triggerContentTemplate();

const chatConfig = getChatConfig();
const container = document.createElement('div');

renderMessageTemplate(chatConfig, {
author: { id: AI_ASSISTANT_AUTHOR_ID, name: 'AI Assistant' },
text: 'Aborted results',
status: 'success',
commands: [
{ status: 'success', message: 'OK' },
{ status: 'aborted', message: 'Aborted' },
],
}, container);

const regenerateButton = container.querySelector(`.${CLASSES.messageRegenerateButton}`);

expect(regenerateButton).not.toBeNull();
expect(regenerateButton?.classList.contains(`dx-icon-${REGENERATE_ICON}`)).toBe(true);
});
});

describe('general', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,92 +10,17 @@ import {
import {
getCommandItemStyle,
getMessageIconName,
hasAbortedCommands,
hasCommandErrors,
needToRenderCommandList,
needToShowRegenerateButton,
} from './utils';

describe('hasCommandErrors', () => {
it('should return true when commands contain failure status', () => {
const commands = [
{ status: 'success' as const, message: 'OK' },
{ status: 'failure' as const, message: 'Failed' },
];

expect(hasCommandErrors(commands)).toBe(true);
});

it('should return false when all commands are successful', () => {
const commands = [
{ status: 'success' as const, message: 'OK' },
];

expect(hasCommandErrors(commands)).toBe(false);
});

it('should return false when commands is undefined', () => {
expect(hasCommandErrors(undefined)).toBe(false);
});

it('should return false when commands contain only aborted status', () => {
const commands = [
{ status: 'aborted' as const, message: 'Aborted' },
];

expect(hasCommandErrors(commands)).toBe(false);
});
});

describe('hasAbortedCommands', () => {
it('should return true when commands contain aborted status', () => {
const commands = [
{ status: 'success' as const, message: 'OK' },
{ status: 'aborted' as const, message: 'Aborted' },
];

expect(hasAbortedCommands(commands)).toBe(true);
});

it('should return false when no commands are aborted', () => {
const commands = [
{ status: 'success' as const, message: 'OK' },
{ status: 'failure' as const, message: 'Failed' },
];

expect(hasAbortedCommands(commands)).toBe(false);
});

it('should return false when commands is undefined', () => {
expect(hasAbortedCommands(undefined)).toBe(false);
});
});

describe('getMessageIconName', () => {
it('should return errorcircle when message status is failure', () => {
const message = { status: MessageStatus.Failure } as Message;

expect(getMessageIconName(message)).toBe('errorcircle');
});

it('should return errorcircle when commands contain errors', () => {
const message = {
status: MessageStatus.Success,
commands: [{ status: 'failure', message: 'Failed' }],
} as Message;

expect(getMessageIconName(message)).toBe('errorcircle');
});

it('should return errorcircle when commands contain aborted items', () => {
const message = {
status: MessageStatus.Success,
commands: [{ status: 'aborted', message: 'Aborted' }],
} as Message;

expect(getMessageIconName(message)).toBe('errorcircle');
});

it('should return checkmarkcirclefilled when message status is success', () => {
const message = { status: MessageStatus.Success } as Message;

Expand All @@ -110,31 +35,22 @@ describe('getMessageIconName', () => {
});

describe('needToShowRegenerateButton', () => {
it('should return true when message status is failure', () => {
it('should return true when message status is failure and has no commands', () => {
const message = { status: MessageStatus.Failure } as Message;

expect(needToShowRegenerateButton(message)).toBe(true);
});

it('should return true when commands contain errors', () => {
it('should return false when message status is failure and has commands', () => {
const message = {
status: MessageStatus.Success,
status: MessageStatus.Failure,
commands: [{ status: 'failure', message: 'Failed' }],
} as Message;

expect(needToShowRegenerateButton(message)).toBe(true);
});

it('should return true when commands contain aborted items', () => {
const message = {
status: MessageStatus.Success,
commands: [{ status: 'aborted', message: 'Aborted' }],
} as Message;

expect(needToShowRegenerateButton(message)).toBe(true);
expect(needToShowRegenerateButton(message)).toBe(false);
});

it('should return false when message is successful without errors', () => {
it('should return false when message is successful', () => {
const message = {
status: MessageStatus.Success,
commands: [{ status: 'success', message: 'OK' }],
Expand Down Expand Up @@ -174,38 +90,35 @@ describe('getCommandItemStyle', () => {
});

describe('needToRenderCommandList', () => {
it('should return true when message status is success', () => {
const message = { status: MessageStatus.Success } as Message;

expect(needToRenderCommandList(message)).toBe(true);
});

it('should return true when commands contain errors', () => {
it('should return true when message has commands', () => {
const message = {
status: MessageStatus.Failure,
commands: [{ status: 'failure', message: 'Failed' }],
status: MessageStatus.Success,
commands: [{ status: 'success', message: 'OK' }],
} as Message;

expect(needToRenderCommandList(message)).toBe(true);
});

it('should return true when commands contain aborted items', () => {
it('should return true when message has failed commands', () => {
const message = {
status: MessageStatus.Failure,
commands: [{ status: 'aborted', message: 'Aborted' }],
commands: [{ status: 'failure', message: 'Failed' }],
} as Message;

expect(needToRenderCommandList(message)).toBe(true);
});

it('should return false when message is pending without commands', () => {
const message = { status: MessageStatus.Pending } as Message;
it('should return false when message has no commands', () => {
const message = { status: MessageStatus.Success } as Message;

expect(needToRenderCommandList(message)).toBe(false);
});

it('should return false when message is failure without commands', () => {
const message = { status: MessageStatus.Failure } as Message;
it('should return false when commands is empty array', () => {
const message = {
status: MessageStatus.Success,
commands: [],
} as unknown as Message;

expect(needToRenderCommandList(message)).toBe(false);
});
Expand Down
Loading
Loading