107 lines
4.8 KiB
TypeScript
107 lines
4.8 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import type { TenantActivityItem } from '../../resources/js/composables/mockTenantDetail';
|
|
import {
|
|
activityPhrase,
|
|
alivenessColor,
|
|
alivenessShortLabel,
|
|
alivenessTitle,
|
|
deviceLabel,
|
|
} from '../../resources/js/composables/tenantActivityFormatters';
|
|
|
|
/**
|
|
* Неразрывный пробел — им русская локаль Intl разделяет разряды («1 000 ₽»).
|
|
* Записан кодом нарочно: невидимый символ в исходнике теряется при правках,
|
|
* и тест начинает падать «на ровном месте», хотя на экране всё одинаково.
|
|
*/
|
|
const NBSP = String.fromCharCode(160);
|
|
|
|
function item(patch: Partial<TenantActivityItem>): TenantActivityItem {
|
|
return {
|
|
id: 'ops-1',
|
|
at: '2026-08-05T07:34:48+00:00',
|
|
kind: 'project',
|
|
event: 'project.created',
|
|
actor: 'client@example.test',
|
|
subject: 'Двери',
|
|
amountRub: null,
|
|
bulkCount: 0,
|
|
...patch,
|
|
};
|
|
}
|
|
|
|
describe('фразы ленты', () => {
|
|
it('пишет название проекта, а не номер', () => {
|
|
expect(activityPhrase(item({}))).toBe('создал проект «Двери»');
|
|
});
|
|
|
|
it('пишет, сколько проектов задето групповым действием', () => {
|
|
expect(activityPhrase(item({ event: 'project.bulk_pause', subject: null, bulkCount: 3 })))
|
|
.toBe('остановил проекты: 3');
|
|
});
|
|
|
|
it('пишет номер сделки', () => {
|
|
expect(activityPhrase(item({ kind: 'deal', event: 'deal.status_changed', subject: '555' })))
|
|
.toBe('сменил статус сделки #555');
|
|
});
|
|
|
|
it('пишет сумму пополнения', () => {
|
|
expect(activityPhrase(item({ kind: 'money', event: 'balance.topup', subject: null, amountRub: 1000 })))
|
|
.toBe(`пополнил баланс на 1${NBSP}000 ₽`);
|
|
});
|
|
|
|
it('не падает на незнакомом событии', () => {
|
|
expect(activityPhrase(item({ event: 'nechto.strannoe', subject: null }))).toBe('nechto.strannoe');
|
|
});
|
|
});
|
|
|
|
describe('расшифровка устройства', () => {
|
|
it('узнаёт Windows и Chrome', () => {
|
|
expect(deviceLabel('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0 Safari/537.36'))
|
|
.toBe('Windows/Chrome');
|
|
});
|
|
|
|
it('узнаёт айфон и Safari', () => {
|
|
expect(deviceLabel('Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 Version/17.5 Mobile/15E148 Safari/604.1'))
|
|
.toBe('iPhone/Safari');
|
|
});
|
|
|
|
it('честно молчит, когда не знает', () => {
|
|
expect(deviceLabel(null)).toBe('устройство неизвестно');
|
|
expect(deviceLabel('curl/8.4.0')).toBe('устройство неизвестно');
|
|
});
|
|
});
|
|
|
|
describe('вердикт', () => {
|
|
it('зелёный, когда заходил на днях', () => {
|
|
expect(alivenessColor('active')).toBe('success');
|
|
expect(alivenessTitle('active', 0)).toBe('Заходил сегодня');
|
|
expect(alivenessTitle('active', 1)).toBe('Заходил вчера');
|
|
expect(alivenessTitle('active', 3)).toBe('Заходил 3 дня назад');
|
|
});
|
|
|
|
it('жёлтый, когда остывает', () => {
|
|
expect(alivenessColor('cooling')).toBe('warning');
|
|
expect(alivenessTitle('cooling', 6)).toBe('Не заходил 6 дней');
|
|
});
|
|
|
|
it('красный, когда пропал или ни разу не заходил', () => {
|
|
expect(alivenessColor('lost')).toBe('error');
|
|
expect(alivenessTitle('lost', 21)).toBe('Не заходил 21 день');
|
|
expect(alivenessColor('never_logged_in')).toBe('error');
|
|
expect(alivenessTitle('never_logged_in', null)).toBe('Ни разу не заходил после регистрации');
|
|
});
|
|
|
|
it('серый, когда данных нет', () => {
|
|
expect(alivenessColor('no_data')).toBe('grey');
|
|
expect(alivenessTitle('no_data', null)).toBe('Нет данных о входах');
|
|
});
|
|
|
|
it('даёт короткую подпись для подсказки в списке', () => {
|
|
expect(alivenessShortLabel('active')).toBe('заходит');
|
|
expect(alivenessShortLabel('cooling')).toBe('остывает');
|
|
expect(alivenessShortLabel('lost')).toBe('пропал');
|
|
expect(alivenessShortLabel('never_logged_in')).toBe('ни разу не заходил');
|
|
expect(alivenessShortLabel('no_data')).toBe('нет данных');
|
|
});
|
|
});
|