Skip to content
Open
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
@@ -1,9 +1,17 @@
import { AIAssistantView } from '@ts/grids/grid_core/ai_assistant/m_ai_assistant_view';
import { AIAssistantViewController } from '@ts/grids/grid_core/ai_assistant/m_ai_assistant_view_controller';
import { AIAssistantView } from '@ts/grids/grid_core/ai_assistant/ai_assistant_view';
import { AIAssistantViewController } from '@ts/grids/grid_core/ai_assistant/ai_assistant_view_controller';

import gridCore from '../m_core';

gridCore.registerModule('aiAssistant', {
defaultOptions() {
return {
aiAssistant: {
enabled: false,
title: 'AI Assistant', // TODO add localization message
},
};
},
controllers: {
aiAssistant: AIAssistantViewController,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ import type { dxElementWrapper } from '@js/core/renderer';
import $ from '@js/core/renderer';
import wrapInstanceWithMocks from '@ts/grids/grid_core/__tests__/__mock__/helpers/wrapInstance';

import { AIChat } from '../ai_chat/ai_chat';
import { AIAssistantView } from './m_ai_assistant_view';
import { AIChat } from '../../ai_chat/ai_chat';
import type { AIChatOptions } from '../../ai_chat/types';
import { AIAssistantView } from '../ai_assistant_view';

jest.mock('../ai_chat/ai_chat', (): any => {
const original = jest.requireActual<any>('../ai_chat/ai_chat');
jest.mock('../../ai_chat/ai_chat', (): any => {
const original = jest.requireActual<any>('../../ai_chat/ai_chat');

return {
...original,
Expand Down Expand Up @@ -152,16 +153,22 @@ describe('AIAssistantView', () => {
});
});

describe('show', () => {
it('should delegate to AIChat show method', async () => {
describe('toggle', () => {
it('should delegate to AIChat toggle method', async () => {
const { aiAssistantView } = createAIAssistantView();

await aiAssistantView.show();
await aiAssistantView.toggle();

const aiChatInstance = (AIChat as jest.Mock)
.mock.results[0].value as { show: jest.Mock; hide: jest.Mock };
.mock.results[0].value as { toggle: jest.Mock };

expect(aiChatInstance.show).toHaveBeenCalledTimes(1);
expect(aiChatInstance.toggle).toHaveBeenCalledTimes(1);
});

it('should return resolved false promise when aiChatInstance is not created', () => {
const { aiAssistantView } = createAIAssistantView({ render: false });

return expect(aiAssistantView.toggle()).resolves.toBe(false);
});
});

Expand All @@ -172,25 +179,54 @@ describe('AIAssistantView', () => {
await aiAssistantView.hide();

const aiChatInstance = (AIChat as jest.Mock)
.mock.results[0].value as { show: jest.Mock; hide: jest.Mock };
.mock.results[0].value as { hide: jest.Mock };

expect(aiChatInstance.hide).toHaveBeenCalledTimes(1);
});
});

describe('show when not initialized', () => {
it('should return resolved false promise when aiChatInstance is not created', () => {
const { aiAssistantView } = createAIAssistantView({ render: false });

return expect(aiAssistantView.show()).resolves.toBe(false);
return expect(aiAssistantView.hide()).resolves.toBe(false);
});
});

describe('hide when not initialized', () => {
it('should return resolved false promise when aiChatInstance is not created', () => {
describe('isShown', () => {
it('should delegate to AIChat isShown method', () => {
const { aiAssistantView } = createAIAssistantView();

const aiChatInstance = (AIChat as jest.Mock)
.mock.results[0].value as { isShown: jest.Mock };

aiChatInstance.isShown.mockReturnValue(true);
expect(aiAssistantView.isShown()).toBe(true);

aiChatInstance.isShown.mockReturnValue(false);
expect(aiAssistantView.isShown()).toBe(false);
});

it('should return false when aiChatInstance is not created', () => {
const { aiAssistantView } = createAIAssistantView({ render: false });

return expect(aiAssistantView.hide()).resolves.toBe(false);
expect(aiAssistantView.isShown()).toBe(false);
});
});

describe('onVisibilityChanged', () => {
it('should fire onVisibilityChanged callback when popup visibility changes', () => {
const { aiAssistantView } = createAIAssistantView();
const callback = jest.fn();

aiAssistantView.onVisibilityChanged = callback;

const aiChatConfig = (AIChat as jest.Mock).mock.calls[0][0] as AIChatOptions;
aiChatConfig.onVisibilityChanged?.(true);

expect(callback).toHaveBeenCalledWith(true);

aiChatConfig.onVisibilityChanged?.(false);

expect(callback).toHaveBeenCalledWith(false);
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import {
afterEach,
beforeEach,
describe,
expect,
it,
jest,
} from '@jest/globals';
import type { Properties as DataGridProperties } from '@js/ui/data_grid';

import {
afterTest,
beforeTest,
createDataGrid as commonCreateDataGrid,
type DataGridInstance,
} from '../../__tests__/__mock__/helpers/utils';

// TODO remove when types added to public dts
interface AIAssistantDataGridProperties extends DataGridProperties {
aiAssistant?: {
enabled?: boolean;
title?: string;
};
}

// TODO remove when types added to public dts
const createDataGrid = (
options: AIAssistantDataGridProperties = {},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
): ReturnType<typeof commonCreateDataGrid> => commonCreateDataGrid(options as any);

const AI_ASSISTANT_BUTTON_SELECTOR = '.dx-datagrid-ai-assistant-button';
const HIDDEN_CLASS = 'dx-hidden';

const getAiAssistantButton = (
instance: DataGridInstance,
): Element | null => instance
.element()
.querySelector(AI_ASSISTANT_BUTTON_SELECTOR);

const isAiAssistantButtonVisible = (instance: DataGridInstance): boolean => {
const button = getAiAssistantButton(instance);

if (!button) {
return false;
}

return !button.closest(`.${HIDDEN_CLASS}`);
};

describe('AIAssistantViewController', () => {
beforeEach(beforeTest);
afterEach(afterTest);

describe('init', () => {
it('should register toolbar button when aiAssistant.enabled is true', async () => {
const { instance } = await createDataGrid({
dataSource: [{ id: 1 }],
aiAssistant: { enabled: true, title: 'AI Assistant' },
});

const button = getAiAssistantButton(instance);

expect(button).not.toBeNull();
});

it('should not register toolbar button when aiAssistant.enabled is false', async () => {
const { instance } = await createDataGrid({
dataSource: [{ id: 1 }],
aiAssistant: { enabled: false },
});

const button = getAiAssistantButton(instance);

expect(button).toBeNull();
});

it('should not register toolbar button when aiAssistant is not set', async () => {
const { instance } = await createDataGrid({
dataSource: [{ id: 1 }],
});

const button = getAiAssistantButton(instance);

expect(button).toBeNull();
});
});

describe('optionChanged', () => {
it('should add toolbar button when aiAssistant.enabled changes to true', async () => {
const { instance } = await createDataGrid({
dataSource: [{ id: 1 }],
aiAssistant: { enabled: false, title: 'AI Assistant' },
});

instance.option('aiAssistant.enabled', true);
jest.runAllTimers();
await Promise.resolve();
jest.runAllTimers();

const button = getAiAssistantButton(instance);

expect(button).not.toBeNull();
});

it('should hide ai assistant button when aiAssistant.enabled changes to false', async () => {
const { instance } = await createDataGrid({
dataSource: [{ id: 1 }],
aiAssistant: { enabled: true, title: 'AI Assistant' },
});

expect(isAiAssistantButtonVisible(instance)).toBe(true);

instance.option('aiAssistant.enabled', false);
jest.runAllTimers();
await Promise.resolve();
jest.runAllTimers();

expect(isAiAssistantButtonVisible(instance)).toBe(false);
});
});

describe('toolbar button', () => {
it('should have aria-haspopup dialog attribute', async () => {
const { instance } = await createDataGrid({
dataSource: [{ id: 1 }],
aiAssistant: { enabled: true, title: 'AI Assistant' },
});

const button = getAiAssistantButton(instance);

expect(button?.getAttribute('aria-haspopup')).toBe('dialog');
});

it('should have correct hint text from aiAssistant.title', async () => {
const { instance } = await createDataGrid({
dataSource: [{ id: 1 }],
aiAssistant: { enabled: true, title: 'My Custom Title' },
});

const button = getAiAssistantButton(instance);

expect(button?.getAttribute('title')).toBe('My Custom Title');
});
});
});
Loading
Loading