mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-09-13 08:13:09 +00:00
test(landing): закрепить отправку слага кампании при гостевой покупке
Покрытия у слага не было вовсе. Пиним два инварианта: слаг попадает в тело запроса покупки и читается БЕЗ потребления — очистка на этом шаге лишила бы привязки того же клиента, если он позже войдёт в кабинет. Компоненты в репозитории не рендерятся (vitest на node, без jsdom), поэтому отправка фиксируется по исходнику; поведение самих хелперов проверяется обычными тестами с подменённым localStorage.
This commit is contained in:
91
src/utils/campaign.test.ts
Normal file
91
src/utils/campaign.test.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { consumeCampaignSlug, getPendingCampaignSlug } from './campaign';
|
||||
|
||||
const CAMPAIGN_KEY = 'campaign_slug';
|
||||
const CAMPAIGN_TTL_KEY = 'campaign_slug_ttl';
|
||||
const HOUR = 60 * 60 * 1000;
|
||||
|
||||
function fakeLocalStorage(): Storage {
|
||||
const store = new Map<string, string>();
|
||||
return {
|
||||
get length() {
|
||||
return store.size;
|
||||
},
|
||||
clear: () => store.clear(),
|
||||
getItem: (key: string) => store.get(key) ?? null,
|
||||
key: (index: number) => [...store.keys()][index] ?? null,
|
||||
removeItem: (key: string) => void store.delete(key),
|
||||
setItem: (key: string, value: string) => void store.set(key, value),
|
||||
} as Storage;
|
||||
}
|
||||
|
||||
function storeSlug(slug: string, expiresInMs = 24 * HOUR): void {
|
||||
localStorage.setItem(CAMPAIGN_KEY, slug);
|
||||
localStorage.setItem(CAMPAIGN_TTL_KEY, String(Date.now() + expiresInMs));
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
vi.stubGlobal('localStorage', fakeLocalStorage());
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
|
||||
describe('getPendingCampaignSlug', () => {
|
||||
it('returns the stored slug', () => {
|
||||
storeSlug('summer_sale');
|
||||
|
||||
expect(getPendingCampaignSlug()).toBe('summer_sale');
|
||||
});
|
||||
|
||||
// Гостевая покупка на лендинге читает слаг этим геттером. Если он начнёт
|
||||
// очищать хранилище, тот же клиент, зайдя потом в кабинет, потеряет
|
||||
// привязку к кампании — auth-флоу уже ничего не найдёт.
|
||||
it('does not consume the slug', () => {
|
||||
storeSlug('summer_sale');
|
||||
|
||||
getPendingCampaignSlug();
|
||||
|
||||
expect(getPendingCampaignSlug()).toBe('summer_sale');
|
||||
expect(localStorage.getItem(CAMPAIGN_KEY)).toBe('summer_sale');
|
||||
});
|
||||
|
||||
it('drops an expired slug', () => {
|
||||
storeSlug('summer_sale', -HOUR);
|
||||
|
||||
expect(getPendingCampaignSlug()).toBeNull();
|
||||
expect(localStorage.getItem(CAMPAIGN_TTL_KEY)).toBeNull();
|
||||
});
|
||||
|
||||
it('returns null when nothing was captured', () => {
|
||||
expect(getPendingCampaignSlug()).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('consumeCampaignSlug', () => {
|
||||
it('clears the slug after reading it once', () => {
|
||||
storeSlug('summer_sale');
|
||||
|
||||
expect(consumeCampaignSlug()).toBe('summer_sale');
|
||||
expect(consumeCampaignSlug()).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
// Компоненты в этом репозитории не рендерятся в тестах (vitest на node, без
|
||||
// jsdom), поэтому отправку слага фиксируем по исходнику: без неё покупка
|
||||
// гостем не попадает в статистику кампании и не даёт её бонус.
|
||||
describe('QuickPurchase source', () => {
|
||||
const source = readFileSync(new URL('../pages/QuickPurchase.tsx', import.meta.url), 'utf8');
|
||||
|
||||
it('puts the campaign slug into the purchase payload', () => {
|
||||
expect(source).toContain('data.campaign_slug = campaignSlug');
|
||||
});
|
||||
|
||||
it('reads the slug without consuming it', () => {
|
||||
expect(source).toContain('getPendingCampaignSlug()');
|
||||
expect(source).not.toContain('consumeCampaignSlug');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user