Restructure omni services and add Chatwoot research snapshot

This commit is contained in:
Ruslan Bakiev
2026-02-21 11:11:27 +07:00
parent edea7a0034
commit b73babbbf6
7732 changed files with 978203 additions and 32 deletions

View File

@@ -0,0 +1,580 @@
import { utcToZonedTime } from 'date-fns-tz';
import {
isOpenAllDay,
isClosedAllDay,
isInWorkingHours,
findNextAvailableSlotDetails,
findNextAvailableSlotDiff,
isOnline,
} from '../availabilityHelpers';
// Mock date-fns-tz
vi.mock('date-fns-tz', () => ({
utcToZonedTime: vi.fn(),
}));
describe('availabilityHelpers', () => {
beforeEach(() => {
vi.clearAllMocks();
});
describe('isOpenAllDay', () => {
it('should return true when slot is marked as open_all_day', () => {
const mockDate = new Date('2024-01-15T10:00:00.000Z'); // Monday
mockDate.getDay = vi.fn().mockReturnValue(1);
vi.mocked(utcToZonedTime).mockReturnValue(mockDate);
const workingHours = [{ dayOfWeek: 1, openAllDay: true }];
expect(isOpenAllDay(new Date(), 'UTC', workingHours)).toBe(true);
});
it('should return false when slot is not open_all_day', () => {
const mockDate = new Date('2024-01-15T10:00:00.000Z');
mockDate.getDay = vi.fn().mockReturnValue(1);
vi.mocked(utcToZonedTime).mockReturnValue(mockDate);
const workingHours = [
{ dayOfWeek: 1, openHour: 9, closeHour: 17, openAllDay: false },
];
expect(isOpenAllDay(new Date(), 'UTC', workingHours)).toBe(false);
});
it('should return false when no config exists for the day', () => {
const mockDate = new Date('2024-01-15T10:00:00.000Z');
mockDate.getDay = vi.fn().mockReturnValue(1);
vi.mocked(utcToZonedTime).mockReturnValue(mockDate);
const workingHours = [
{ dayOfWeek: 2, openHour: 9, closeHour: 17 }, // Tuesday config
];
expect(isOpenAllDay(new Date(), 'UTC', workingHours)).toBe(false);
});
});
describe('isClosedAllDay', () => {
it('should return true when slot is marked as closed_all_day', () => {
const mockDate = new Date('2024-01-15T10:00:00.000Z');
mockDate.getDay = vi.fn().mockReturnValue(1);
vi.mocked(utcToZonedTime).mockReturnValue(mockDate);
const workingHours = [{ dayOfWeek: 1, closedAllDay: true }];
expect(isClosedAllDay(new Date(), 'UTC', workingHours)).toBe(true);
});
it('should return false when slot is not closed_all_day', () => {
const mockDate = new Date('2024-01-15T10:00:00.000Z');
mockDate.getDay = vi.fn().mockReturnValue(1);
vi.mocked(utcToZonedTime).mockReturnValue(mockDate);
const workingHours = [
{ dayOfWeek: 1, openHour: 9, closeHour: 17, closedAllDay: false },
];
expect(isClosedAllDay(new Date(), 'UTC', workingHours)).toBe(false);
});
it('should return false when no config exists for the day', () => {
const mockDate = new Date('2024-01-15T10:00:00.000Z');
mockDate.getDay = vi.fn().mockReturnValue(1);
vi.mocked(utcToZonedTime).mockReturnValue(mockDate);
const workingHours = [{ dayOfWeek: 2, openHour: 9, closeHour: 17 }];
expect(isClosedAllDay(new Date(), 'UTC', workingHours)).toBe(false);
});
});
describe('isInWorkingHours', () => {
it('should return false when no working hours are configured', () => {
expect(isInWorkingHours(new Date(), 'UTC', [])).toBe(false);
});
it('should return true when open_all_day is true', () => {
const mockDate = new Date('2024-01-15T10:00:00.000Z');
mockDate.getDay = vi.fn().mockReturnValue(1);
mockDate.getHours = vi.fn().mockReturnValue(10);
mockDate.getMinutes = vi.fn().mockReturnValue(0);
vi.mocked(utcToZonedTime).mockReturnValue(mockDate);
const workingHours = [{ dayOfWeek: 1, openAllDay: true }];
expect(isInWorkingHours(new Date(), 'UTC', workingHours)).toBe(true);
});
it('should return false when closed_all_day is true', () => {
const mockDate = new Date('2024-01-15T10:00:00.000Z');
mockDate.getDay = vi.fn().mockReturnValue(1);
mockDate.getHours = vi.fn().mockReturnValue(10);
mockDate.getMinutes = vi.fn().mockReturnValue(0);
vi.mocked(utcToZonedTime).mockReturnValue(mockDate);
const workingHours = [{ dayOfWeek: 1, closedAllDay: true }];
expect(isInWorkingHours(new Date(), 'UTC', workingHours)).toBe(false);
});
it('should return true when current time is within working hours', () => {
const mockDate = new Date('2024-01-15T10:00:00.000Z');
mockDate.getDay = vi.fn().mockReturnValue(1);
mockDate.getHours = vi.fn().mockReturnValue(10);
mockDate.getMinutes = vi.fn().mockReturnValue(0);
vi.mocked(utcToZonedTime).mockReturnValue(mockDate);
const workingHours = [
{
dayOfWeek: 1,
openHour: 9,
openMinutes: 0,
closeHour: 17,
closeMinutes: 0,
},
];
expect(isInWorkingHours(new Date(), 'UTC', workingHours)).toBe(true);
});
it('should return false when current time is before opening', () => {
const mockDate = new Date('2024-01-15T08:00:00.000Z');
mockDate.getDay = vi.fn().mockReturnValue(1);
mockDate.getHours = vi.fn().mockReturnValue(8);
mockDate.getMinutes = vi.fn().mockReturnValue(0);
vi.mocked(utcToZonedTime).mockReturnValue(mockDate);
const workingHours = [{ dayOfWeek: 1, openHour: 9, closeHour: 17 }];
expect(isInWorkingHours(new Date(), 'UTC', workingHours)).toBe(false);
});
it('should return false when current time is after closing', () => {
const mockDate = new Date('2024-01-15T18:00:00.000Z');
mockDate.getDay = vi.fn().mockReturnValue(1);
mockDate.getHours = vi.fn().mockReturnValue(18);
mockDate.getMinutes = vi.fn().mockReturnValue(0);
vi.mocked(utcToZonedTime).mockReturnValue(mockDate);
const workingHours = [{ dayOfWeek: 1, openHour: 9, closeHour: 17 }];
expect(isInWorkingHours(new Date(), 'UTC', workingHours)).toBe(false);
});
it('should handle minutes in time comparison', () => {
const mockDate = new Date('2024-01-15T09:30:00.000Z');
mockDate.getDay = vi.fn().mockReturnValue(1);
mockDate.getHours = vi.fn().mockReturnValue(9);
mockDate.getMinutes = vi.fn().mockReturnValue(30);
vi.mocked(utcToZonedTime).mockReturnValue(mockDate);
const workingHours = [
{
dayOfWeek: 1,
openHour: 9,
openMinutes: 15,
closeHour: 17,
closeMinutes: 30,
},
];
expect(isInWorkingHours(new Date(), 'UTC', workingHours)).toBe(true);
});
it('should return false when no config for current day', () => {
const mockDate = new Date('2024-01-15T10:00:00.000Z');
mockDate.getDay = vi.fn().mockReturnValue(1);
mockDate.getHours = vi.fn().mockReturnValue(10);
mockDate.getMinutes = vi.fn().mockReturnValue(0);
vi.mocked(utcToZonedTime).mockReturnValue(mockDate);
const workingHours = [
{ dayOfWeek: 2, openHour: 9, closeHour: 17 }, // Only Tuesday
];
expect(isInWorkingHours(new Date(), 'UTC', workingHours)).toBe(false);
});
});
describe('findNextAvailableSlotDetails', () => {
it('should return null when no open days exist', () => {
const mockDate = new Date('2024-01-15T10:00:00.000Z');
mockDate.getDay = vi.fn().mockReturnValue(1);
mockDate.getHours = vi.fn().mockReturnValue(10);
mockDate.getMinutes = vi.fn().mockReturnValue(0);
vi.mocked(utcToZonedTime).mockReturnValue(mockDate);
const workingHours = [
{ dayOfWeek: 0, closedAllDay: true },
{ dayOfWeek: 1, closedAllDay: true },
{ dayOfWeek: 2, closedAllDay: true },
{ dayOfWeek: 3, closedAllDay: true },
{ dayOfWeek: 4, closedAllDay: true },
{ dayOfWeek: 5, closedAllDay: true },
{ dayOfWeek: 6, closedAllDay: true },
];
expect(
findNextAvailableSlotDetails(new Date(), 'UTC', workingHours)
).toBe(null);
});
it('should return today slot when not opened yet', () => {
const mockDate = new Date('2024-01-15T08:00:00.000Z');
mockDate.getDay = vi.fn().mockReturnValue(1);
mockDate.getHours = vi.fn().mockReturnValue(8);
mockDate.getMinutes = vi.fn().mockReturnValue(0);
vi.mocked(utcToZonedTime).mockReturnValue(mockDate);
const workingHours = [
{ dayOfWeek: 1, openHour: 9, openMinutes: 30, closeHour: 17 },
];
const result = findNextAvailableSlotDetails(
new Date(),
'UTC',
workingHours
);
expect(result).toEqual({
config: workingHours[0],
minutesUntilOpen: 90, // 1.5 hours = 90 minutes
daysUntilOpen: 0,
dayOfWeek: 1,
});
});
it('should return tomorrow slot when today is past closing', () => {
const mockDate = new Date('2024-01-15T18:00:00.000Z');
mockDate.getDay = vi.fn().mockReturnValue(1);
mockDate.getHours = vi.fn().mockReturnValue(18);
mockDate.getMinutes = vi.fn().mockReturnValue(0);
vi.mocked(utcToZonedTime).mockReturnValue(mockDate);
const workingHours = [
{ dayOfWeek: 1, openHour: 9, closeHour: 17 },
{ dayOfWeek: 2, openHour: 9, closeHour: 17 },
];
const result = findNextAvailableSlotDetails(
new Date(),
'UTC',
workingHours
);
expect(result).toEqual({
config: workingHours[1],
minutesUntilOpen: 900, // 15 hours = 900 minutes
daysUntilOpen: 1,
dayOfWeek: 2,
});
});
it('should skip closed days and find next open day', () => {
const mockDate = new Date('2024-01-15T18:00:00.000Z'); // Monday evening
mockDate.getDay = vi.fn().mockReturnValue(1);
mockDate.getHours = vi.fn().mockReturnValue(18);
mockDate.getMinutes = vi.fn().mockReturnValue(0);
vi.mocked(utcToZonedTime).mockReturnValue(mockDate);
const workingHours = [
{ dayOfWeek: 1, openHour: 9, closeHour: 17 },
{ dayOfWeek: 2, closedAllDay: true },
{ dayOfWeek: 3, closedAllDay: true },
{ dayOfWeek: 4, openHour: 10, closeHour: 16 },
];
const result = findNextAvailableSlotDetails(
new Date(),
'UTC',
workingHours
);
// Monday 18:00 to Thursday 10:00
// Rest of Monday: 6 hours (18:00 to 24:00) = 360 minutes
// Tuesday: 24 hours = 1440 minutes
// Wednesday: 24 hours = 1440 minutes
// Thursday morning: 10 hours = 600 minutes
// Total: 360 + 1440 + 1440 + 600 = 3840 minutes
expect(result).toEqual({
config: workingHours[3],
minutesUntilOpen: 3840, // 64 hours = 3840 minutes
daysUntilOpen: 3,
dayOfWeek: 4,
});
});
it('should handle open_all_day slots', () => {
const mockDate = new Date('2024-01-15T18:00:00.000Z');
mockDate.getDay = vi.fn().mockReturnValue(1);
mockDate.getHours = vi.fn().mockReturnValue(18);
mockDate.getMinutes = vi.fn().mockReturnValue(0);
vi.mocked(utcToZonedTime).mockReturnValue(mockDate);
const workingHours = [
{ dayOfWeek: 1, openHour: 9, closeHour: 17 },
{ dayOfWeek: 2, openAllDay: true },
];
const result = findNextAvailableSlotDetails(
new Date(),
'UTC',
workingHours
);
expect(result).toEqual({
config: workingHours[1],
minutesUntilOpen: 360, // 6 hours to midnight = 360 minutes
daysUntilOpen: 1,
dayOfWeek: 2,
});
});
it('should wrap around week correctly', () => {
const mockDate = new Date('2024-01-20T18:00:00.000Z'); // Saturday evening
mockDate.getDay = vi.fn().mockReturnValue(6);
mockDate.getHours = vi.fn().mockReturnValue(18);
mockDate.getMinutes = vi.fn().mockReturnValue(0);
vi.mocked(utcToZonedTime).mockReturnValue(mockDate);
const workingHours = [
{ dayOfWeek: 1, openHour: 9, closeHour: 17 }, // Monday
];
const result = findNextAvailableSlotDetails(
new Date(),
'UTC',
workingHours
);
// Saturday 18:00 to Monday 9:00
// Rest of Saturday: 6 hours = 360 minutes
// Sunday: 24 hours = 1440 minutes
// Monday morning: 9 hours = 540 minutes
// Total: 360 + 1440 + 540 = 2340 minutes
expect(result).toEqual({
config: workingHours[0],
minutesUntilOpen: 2340, // 39 hours = 2340 minutes
daysUntilOpen: 2,
dayOfWeek: 1,
});
});
it('should handle today open_all_day correctly', () => {
const mockDate = new Date('2024-01-15T10:00:00.000Z');
mockDate.getDay = vi.fn().mockReturnValue(1);
mockDate.getHours = vi.fn().mockReturnValue(10);
mockDate.getMinutes = vi.fn().mockReturnValue(0);
vi.mocked(utcToZonedTime).mockReturnValue(mockDate);
const workingHours = [
{ dayOfWeek: 1, openAllDay: true },
{ dayOfWeek: 2, openHour: 9, closeHour: 17 },
];
// Should skip today since it's open_all_day and look for next slot
const result = findNextAvailableSlotDetails(
new Date(),
'UTC',
workingHours
);
expect(result).toEqual({
config: workingHours[1],
minutesUntilOpen: 1380, // Rest of today + 9 hours tomorrow = 1380 minutes
daysUntilOpen: 1,
dayOfWeek: 2,
});
});
});
describe('findNextAvailableSlotDiff', () => {
it('should return 0 when currently in working hours', () => {
const mockDate = new Date('2024-01-15T10:00:00.000Z');
mockDate.getDay = vi.fn().mockReturnValue(1);
mockDate.getHours = vi.fn().mockReturnValue(10);
mockDate.getMinutes = vi.fn().mockReturnValue(0);
vi.mocked(utcToZonedTime).mockReturnValue(mockDate);
const workingHours = [{ dayOfWeek: 1, openHour: 9, closeHour: 17 }];
expect(findNextAvailableSlotDiff(new Date(), 'UTC', workingHours)).toBe(
0
);
});
it('should return minutes until next slot when not in working hours', () => {
const mockDate = new Date('2024-01-15T08:00:00.000Z');
mockDate.getDay = vi.fn().mockReturnValue(1);
mockDate.getHours = vi.fn().mockReturnValue(8);
mockDate.getMinutes = vi.fn().mockReturnValue(0);
vi.mocked(utcToZonedTime).mockReturnValue(mockDate);
const workingHours = [{ dayOfWeek: 1, openHour: 9, closeHour: 17 }];
expect(findNextAvailableSlotDiff(new Date(), 'UTC', workingHours)).toBe(
60
);
});
it('should return null when no next slot available', () => {
const mockDate = new Date('2024-01-15T10:00:00.000Z');
mockDate.getDay = vi.fn().mockReturnValue(1);
mockDate.getHours = vi.fn().mockReturnValue(10);
mockDate.getMinutes = vi.fn().mockReturnValue(0);
vi.mocked(utcToZonedTime).mockReturnValue(mockDate);
const workingHours = [
{ dayOfWeek: 0, closedAllDay: true },
{ dayOfWeek: 1, closedAllDay: true },
{ dayOfWeek: 2, closedAllDay: true },
{ dayOfWeek: 3, closedAllDay: true },
{ dayOfWeek: 4, closedAllDay: true },
{ dayOfWeek: 5, closedAllDay: true },
{ dayOfWeek: 6, closedAllDay: true },
];
expect(findNextAvailableSlotDiff(new Date(), 'UTC', workingHours)).toBe(
null
);
});
});
describe('isOnline', () => {
it('should return agent status when working hours disabled', () => {
expect(isOnline(false, new Date(), 'UTC', [], true)).toBe(true);
expect(isOnline(false, new Date(), 'UTC', [], false)).toBe(false);
});
it('should check both working hours and agents when enabled', () => {
const mockDate = new Date('2024-01-15T10:00:00.000Z');
mockDate.getDay = vi.fn().mockReturnValue(1);
mockDate.getHours = vi.fn().mockReturnValue(10);
mockDate.getMinutes = vi.fn().mockReturnValue(0);
vi.mocked(utcToZonedTime).mockReturnValue(mockDate);
const workingHours = [{ dayOfWeek: 1, openHour: 9, closeHour: 17 }];
// In working hours + agents available = online
expect(isOnline(true, new Date(), 'UTC', workingHours, true)).toBe(true);
// In working hours but no agents = offline
expect(isOnline(true, new Date(), 'UTC', workingHours, false)).toBe(
false
);
});
it('should return false when outside working hours even with agents', () => {
const mockDate = new Date('2024-01-15T08:00:00.000Z');
mockDate.getDay = vi.fn().mockReturnValue(1);
mockDate.getHours = vi.fn().mockReturnValue(8);
mockDate.getMinutes = vi.fn().mockReturnValue(0);
vi.mocked(utcToZonedTime).mockReturnValue(mockDate);
const workingHours = [{ dayOfWeek: 1, openHour: 9, closeHour: 17 }];
expect(isOnline(true, new Date(), 'UTC', workingHours, true)).toBe(false);
});
it('should handle open_all_day with agents', () => {
const mockDate = new Date('2024-01-15T02:00:00.000Z');
mockDate.getDay = vi.fn().mockReturnValue(1);
mockDate.getHours = vi.fn().mockReturnValue(2);
mockDate.getMinutes = vi.fn().mockReturnValue(0);
vi.mocked(utcToZonedTime).mockReturnValue(mockDate);
const workingHours = [{ dayOfWeek: 1, openAllDay: true }];
expect(isOnline(true, new Date(), 'UTC', workingHours, true)).toBe(true);
expect(isOnline(true, new Date(), 'UTC', workingHours, false)).toBe(
false
);
});
it('should handle string date input', () => {
const mockDate = new Date('2024-01-15T10:00:00.000Z');
mockDate.getDay = vi.fn().mockReturnValue(1);
mockDate.getHours = vi.fn().mockReturnValue(10);
mockDate.getMinutes = vi.fn().mockReturnValue(0);
vi.mocked(utcToZonedTime).mockReturnValue(mockDate);
const workingHours = [{ dayOfWeek: 1, openHour: 9, closeHour: 17 }];
expect(
isOnline(true, '2024-01-15T10:00:00.000Z', 'UTC', workingHours, true)
).toBe(true);
});
});
describe('Timezone handling', () => {
it('should correctly handle different timezones', () => {
const mockDate = new Date('2024-01-15T15:30:00.000Z');
mockDate.getDay = vi.fn().mockReturnValue(1);
mockDate.getHours = vi.fn().mockReturnValue(15);
mockDate.getMinutes = vi.fn().mockReturnValue(30);
vi.mocked(utcToZonedTime).mockReturnValue(mockDate);
const workingHours = [{ dayOfWeek: 1, openHour: 9, closeHour: 17 }];
expect(isInWorkingHours(new Date(), 'Asia/Kolkata', workingHours)).toBe(
true
);
expect(vi.mocked(utcToZonedTime)).toHaveBeenCalledWith(
expect.any(String),
'Asia/Kolkata'
);
});
it('should handle UTC offset format', () => {
const mockDate = new Date('2024-01-15T10:00:00.000Z');
mockDate.getDay = vi.fn().mockReturnValue(1);
mockDate.getHours = vi.fn().mockReturnValue(10);
mockDate.getMinutes = vi.fn().mockReturnValue(0);
vi.mocked(utcToZonedTime).mockReturnValue(mockDate);
const workingHours = [{ dayOfWeek: 1, openHour: 9, closeHour: 17 }];
expect(isInWorkingHours(new Date(), '+05:30', workingHours)).toBe(true);
expect(vi.mocked(utcToZonedTime)).toHaveBeenCalledWith(
expect.any(String),
'+05:30'
);
});
});
describe('Edge cases', () => {
it('should handle working hours at exact boundaries', () => {
// Test at exact opening time
const mockDate1 = new Date('2024-01-15T09:00:00.000Z');
mockDate1.getDay = vi.fn().mockReturnValue(1);
mockDate1.getHours = vi.fn().mockReturnValue(9);
mockDate1.getMinutes = vi.fn().mockReturnValue(0);
vi.mocked(utcToZonedTime).mockReturnValue(mockDate1);
const workingHours = [{ dayOfWeek: 1, openHour: 9, closeHour: 17 }];
expect(isInWorkingHours(new Date(), 'UTC', workingHours)).toBe(true);
// Test at exact closing time
const mockDate2 = new Date('2024-01-15T17:00:00.000Z');
mockDate2.getDay = vi.fn().mockReturnValue(1);
mockDate2.getHours = vi.fn().mockReturnValue(17);
mockDate2.getMinutes = vi.fn().mockReturnValue(0);
vi.mocked(utcToZonedTime).mockReturnValue(mockDate2);
expect(isInWorkingHours(new Date(), 'UTC', workingHours)).toBe(false);
});
it('should handle one minute before closing', () => {
const mockDate = new Date('2024-01-15T16:59:00.000Z');
mockDate.getDay = vi.fn().mockReturnValue(1);
mockDate.getHours = vi.fn().mockReturnValue(16);
mockDate.getMinutes = vi.fn().mockReturnValue(59);
vi.mocked(utcToZonedTime).mockReturnValue(mockDate);
const workingHours = [{ dayOfWeek: 1, openHour: 9, closeHour: 17 }];
expect(isInWorkingHours(new Date(), 'UTC', workingHours)).toBe(true);
});
});
});

View File

@@ -0,0 +1,18 @@
export default [
{
id: 1,
trigger_only_during_business_hours: false,
trigger_rules: {
time_on_page: 3,
url: 'https://www.chatwoot.com/pricing',
},
},
{
id: 2,
trigger_only_during_business_hours: false,
trigger_rules: {
time_on_page: 6,
url: 'https://www.chatwoot.com/about',
},
},
];

View File

@@ -0,0 +1,143 @@
import {
formatCampaigns,
filterCampaigns,
isPatternMatchingWithURL,
} from '../campaignHelper';
import campaigns from './campaignFixtures';
global.chatwootWebChannel = {
workingHoursEnabled: false,
};
describe('#Campaigns Helper', () => {
describe('#isPatternMatchingWithURL', () => {
it('returns correct value if a valid URL is passed', () => {
expect(
isPatternMatchingWithURL(
'https://chatwoot.com/pricing*',
'https://chatwoot.com/pricing/'
)
).toBe(true);
expect(
isPatternMatchingWithURL(
'https://*.chatwoot.com/pricing/',
'https://app.chatwoot.com/pricing/'
)
).toBe(true);
expect(
isPatternMatchingWithURL(
'https://{*.}?chatwoot.com/pricing?test=true',
'https://app.chatwoot.com/pricing/?test=true'
)
).toBe(true);
expect(
isPatternMatchingWithURL(
'https://{*.}?chatwoot.com/pricing*\\?*',
'https://chatwoot.com/pricing/?test=true'
)
).toBe(true);
});
});
describe('formatCampaigns', () => {
it('should return formatted campaigns if campaigns are passed', () => {
expect(formatCampaigns({ campaigns })).toStrictEqual([
{
id: 1,
timeOnPage: 3,
triggerOnlyDuringBusinessHours: false,
url: 'https://www.chatwoot.com/pricing',
},
{
id: 2,
triggerOnlyDuringBusinessHours: false,
timeOnPage: 6,
url: 'https://www.chatwoot.com/about',
},
]);
});
});
describe('filterCampaigns', () => {
it('should return filtered campaigns if formatted campaigns are passed', () => {
expect(
filterCampaigns({
campaigns: [
{
id: 1,
timeOnPage: 3,
url: 'https://www.chatwoot.com/pricing',
triggerOnlyDuringBusinessHours: false,
},
{
id: 2,
timeOnPage: 6,
url: 'https://www.chatwoot.com/about',
triggerOnlyDuringBusinessHours: false,
},
],
currentURL: 'https://www.chatwoot.com/about/',
})
).toStrictEqual([
{
id: 2,
timeOnPage: 6,
url: 'https://www.chatwoot.com/about',
triggerOnlyDuringBusinessHours: false,
},
]);
});
it('should return filtered campaigns if formatted campaigns are passed and business hours enabled', () => {
expect(
filterCampaigns({
campaigns: [
{
id: 1,
timeOnPage: 3,
url: 'https://www.chatwoot.com/pricing',
triggerOnlyDuringBusinessHours: false,
},
{
id: 2,
timeOnPage: 6,
url: 'https://www.chatwoot.com/about',
triggerOnlyDuringBusinessHours: true,
},
],
currentURL: 'https://www.chatwoot.com/about/',
isInBusinessHours: true,
})
).toStrictEqual([
{
id: 2,
timeOnPage: 6,
url: 'https://www.chatwoot.com/about',
triggerOnlyDuringBusinessHours: true,
},
]);
});
it('should return empty campaigns if formatted campaigns are passed and business hours disabled', () => {
expect(
filterCampaigns({
campaigns: [
{
id: 1,
timeOnPage: 3,
url: 'https://www.chatwoot.com/pricing',
triggerOnlyDuringBusinessHours: true,
},
{
id: 2,
timeOnPage: 6,
url: 'https://www.chatwoot.com/about',
triggerOnlyDuringBusinessHours: true,
},
],
currentURL: 'https://www.chatwoot.com/about/',
isInBusinessHours: false,
})
).toStrictEqual([]);
});
});
});

View File

@@ -0,0 +1,51 @@
import {
buildSearchParamsWithLocale,
getLocale,
buildPopoutURL,
} from '../urlParamsHelper';
describe('#buildSearchParamsWithLocale', () => {
it('returns correct search params', () => {
let windowSpy = vi.spyOn(window, 'window', 'get');
windowSpy.mockImplementation(() => ({
WOOT_WIDGET: {
$root: {
$i18n: {
locale: 'el',
},
},
},
}));
expect(buildSearchParamsWithLocale('?test=1234')).toEqual(
'?test=1234&locale=el'
);
expect(buildSearchParamsWithLocale('')).toEqual('?locale=el');
windowSpy.mockRestore();
});
});
describe('#getLocale', () => {
it('returns correct locale', () => {
expect(getLocale('?test=1&cw_conv=2&locale=fr')).toEqual('fr');
expect(getLocale('?test=1&locale=fr')).toEqual('fr');
expect(getLocale('?test=1&cw_conv=2&website_token=3&locale=fr')).toEqual(
'fr'
);
expect(getLocale('')).toEqual(null);
});
});
describe('#buildPopoutURL', () => {
it('returns popout URL', () => {
expect(
buildPopoutURL({
origin: 'https://chatwoot.com',
conversationCookie: 'random-jwt-token',
websiteToken: 'random-website-token',
locale: 'ar',
})
).toEqual(
'https://chatwoot.com/widget?cw_conversation=random-jwt-token&website_token=random-website-token&locale=ar'
);
});
});

View File

@@ -0,0 +1,39 @@
import { IFrameHelper } from '../utils';
vi.mock('vue', () => ({
config: {
lang: 'el',
},
}));
describe('#IFrameHelper', () => {
describe('#isAValidEvent', () => {
it('returns if the event is valid', () => {
expect(
IFrameHelper.isAValidEvent({
data: 'chatwoot-widget:{"event":"config-set","locale":"fr","position":"left","hideMessageBubble":false,"showPopoutButton":true}',
})
).toEqual(true);
expect(
IFrameHelper.isAValidEvent({
data: '{"event":"config-set","locale":"fr","position":"left","hideMessageBubble":false,"showPopoutButton":true}',
})
).toEqual(false);
});
});
describe('#getMessage', () => {
it('returns parsed message', () => {
expect(
IFrameHelper.getMessage({
data: 'chatwoot-widget:{"event":"config-set","locale":"fr","position":"left","hideMessageBubble":false,"showPopoutButton":true}',
})
).toEqual({
event: 'config-set',
locale: 'fr',
position: 'left',
hideMessageBubble: false,
showPopoutButton: true,
});
});
});
});