Files
portal/app/tests/Frontend/tenantActivityFormatters.spec.ts
T

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('нет данных');
});
});