Upgrades the frontend toolchain to Vite 6 and tidies up the build config along the way. Behavior is unchanged for end users; this is dev/build infra. ## What changed - `vite` 5.4 → 6.4, `@vitejs/plugin-vue` → 5.2, `vite-plugin-ruby` → 5.2 (with matching `vite_rails`/`vite_ruby` gem bumps). - Dropped the `vite-node` 2.0.1 pnpm override — no longer needed now that vitest 3 runs on Vite 6 directly. - Split the single `vite.config.ts` into: - `vite.config.ts` (app), `vite.lib.config.ts` (SDK), `vite.shared.ts` (aliases / Vue options), `vitest.config.ts` (tests). - `pnpm build:sdk` now selects the SDK config explicitly instead of branching on `BUILD_MODE=library`. SDK output path is unchanged (`public/packs/js/sdk.js`). No changes needed to Docker images, deployment scripts, or CI — Node 24 and pnpm 10 are already past Vite 6's floor, and the rake `assets:precompile` hook still drives the SDK build via `pnpm`. ## How to test - `pnpm dev` and verify the dashboard, widget, and survey routes load and HMR works. - Load a Chatwoot site widget on a test page and confirm `sdk.js` is served and the widget mounts. - `RAILS_ENV=production bundle exec rake assets:precompile` and confirm `public/packs/js/sdk.js` plus the rest of the manifest are produced. - `pnpm test` for the JS suite. --------- Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> Co-authored-by: Sony Mathew <2040199+sony-mathew@users.noreply.github.com>
175 lines
4.9 KiB
JavaScript
175 lines
4.9 KiB
JavaScript
import { useCaptain } from '../useCaptain';
|
|
import {
|
|
useFunctionGetter,
|
|
useMapGetter,
|
|
useStore,
|
|
} from 'dashboard/composables/store';
|
|
import { useAccount } from 'dashboard/composables/useAccount';
|
|
import { useConfig } from 'dashboard/composables/useConfig';
|
|
import { useI18n } from 'vue-i18n';
|
|
import TasksAPI from 'dashboard/api/captain/tasks';
|
|
|
|
vi.mock('dashboard/composables/store');
|
|
vi.mock('dashboard/composables/useAccount');
|
|
vi.mock('dashboard/composables/useConfig');
|
|
vi.mock('vue-i18n');
|
|
vi.mock('dashboard/api/captain/tasks');
|
|
vi.mock('dashboard/helper/AnalyticsHelper/index', async importOriginal => {
|
|
const actual = await importOriginal();
|
|
return {
|
|
...actual,
|
|
default: {
|
|
track: vi.fn(),
|
|
},
|
|
};
|
|
});
|
|
vi.mock('dashboard/helper/AnalyticsHelper/events', () => ({
|
|
CAPTAIN_EVENTS: {
|
|
TEST_EVENT: 'captain_test_event',
|
|
},
|
|
}));
|
|
|
|
describe('useCaptain', () => {
|
|
const mockStore = {
|
|
dispatch: vi.fn(),
|
|
};
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
useStore.mockReturnValue(mockStore);
|
|
useFunctionGetter.mockReturnValue({ value: 'Draft message' });
|
|
useMapGetter.mockImplementation(getter => {
|
|
const mockValues = {
|
|
'accounts/getUIFlags': { isFetchingLimits: false },
|
|
getSelectedChat: { id: '123' },
|
|
'draftMessages/getReplyEditorMode': 'reply',
|
|
};
|
|
return { value: mockValues[getter] };
|
|
});
|
|
useI18n.mockReturnValue({ t: vi.fn() });
|
|
useAccount.mockReturnValue({
|
|
isCloudFeatureEnabled: vi.fn().mockReturnValue(true),
|
|
currentAccount: { value: { limits: { captain: {} } } },
|
|
});
|
|
useConfig.mockReturnValue({
|
|
isEnterprise: false,
|
|
});
|
|
});
|
|
|
|
it('initializes computed properties correctly', async () => {
|
|
const { captainEnabled, captainTasksEnabled, currentChat, draftMessage } =
|
|
useCaptain();
|
|
|
|
expect(captainEnabled.value).toBe(true);
|
|
expect(captainTasksEnabled.value).toBe(true);
|
|
expect(currentChat.value).toEqual({ id: '123' });
|
|
expect(draftMessage.value).toBe('Draft message');
|
|
});
|
|
|
|
it('rewrites content', async () => {
|
|
TasksAPI.rewrite.mockResolvedValue({
|
|
data: { message: 'Rewritten content', follow_up_context: { id: 'ctx1' } },
|
|
});
|
|
|
|
const { rewriteContent } = useCaptain();
|
|
const result = await rewriteContent('Original content', 'improve', {});
|
|
|
|
expect(TasksAPI.rewrite).toHaveBeenCalledWith(
|
|
{
|
|
content: 'Original content',
|
|
operation: 'improve',
|
|
conversationId: '123',
|
|
},
|
|
undefined
|
|
);
|
|
expect(result).toEqual({
|
|
message: 'Rewritten content',
|
|
followUpContext: { id: 'ctx1' },
|
|
});
|
|
});
|
|
|
|
it('summarizes conversation', async () => {
|
|
TasksAPI.summarize.mockResolvedValue({
|
|
data: { message: 'Summary', follow_up_context: { id: 'ctx2' } },
|
|
});
|
|
|
|
const { summarizeConversation } = useCaptain();
|
|
const result = await summarizeConversation({});
|
|
|
|
expect(TasksAPI.summarize).toHaveBeenCalledWith('123', undefined);
|
|
expect(result).toEqual({
|
|
message: 'Summary',
|
|
followUpContext: { id: 'ctx2' },
|
|
});
|
|
});
|
|
|
|
it('gets reply suggestion', async () => {
|
|
TasksAPI.replySuggestion.mockResolvedValue({
|
|
data: { message: 'Reply suggestion', follow_up_context: { id: 'ctx3' } },
|
|
});
|
|
|
|
const { getReplySuggestion } = useCaptain();
|
|
const result = await getReplySuggestion({});
|
|
|
|
expect(TasksAPI.replySuggestion).toHaveBeenCalledWith('123', undefined);
|
|
expect(result).toEqual({
|
|
message: 'Reply suggestion',
|
|
followUpContext: { id: 'ctx3' },
|
|
});
|
|
});
|
|
|
|
it('sends follow-up message', async () => {
|
|
TasksAPI.followUp.mockResolvedValue({
|
|
data: {
|
|
message: 'Follow-up response',
|
|
follow_up_context: { id: 'ctx4' },
|
|
},
|
|
});
|
|
|
|
const { followUp } = useCaptain();
|
|
const result = await followUp({
|
|
followUpContext: { id: 'ctx3' },
|
|
message: 'Make it shorter',
|
|
});
|
|
|
|
expect(TasksAPI.followUp).toHaveBeenCalledWith(
|
|
{
|
|
followUpContext: { id: 'ctx3' },
|
|
message: 'Make it shorter',
|
|
conversationId: '123',
|
|
},
|
|
undefined
|
|
);
|
|
expect(result).toEqual({
|
|
message: 'Follow-up response',
|
|
followUpContext: { id: 'ctx4' },
|
|
});
|
|
});
|
|
|
|
it('processes event and routes to correct method', async () => {
|
|
TasksAPI.summarize.mockResolvedValue({
|
|
data: { message: 'Summary' },
|
|
});
|
|
TasksAPI.replySuggestion.mockResolvedValue({
|
|
data: { message: 'Reply' },
|
|
});
|
|
TasksAPI.rewrite.mockResolvedValue({
|
|
data: { message: 'Rewritten' },
|
|
});
|
|
|
|
const { processEvent } = useCaptain();
|
|
|
|
// Test summarize
|
|
await processEvent('summarize', '', {});
|
|
expect(TasksAPI.summarize).toHaveBeenCalled();
|
|
|
|
// Test reply_suggestion
|
|
await processEvent('reply_suggestion', '', {});
|
|
expect(TasksAPI.replySuggestion).toHaveBeenCalled();
|
|
|
|
// Test rewrite (improve)
|
|
await processEvent('improve', 'content', {});
|
|
expect(TasksAPI.rewrite).toHaveBeenCalled();
|
|
});
|
|
});
|