8e687f99c1
Путь человека рвался пополам: лендинг и кабинет считали разные счётчики,
а вход и регистрация не писались вообще. Почему люди бросают регистрацию,
узнать было нельзя.
Счётчик лендинга 110476275 становится счётчиком полного пути и грузится
на всех страницах кабинета. Прежний счётчик кабинета 110494416 не тронут,
его история цела, на страницах кабинета работают оба.
Что сделано:
- загрузчик Метрики поднимает счётчики по области: public или app
- белый список раскладок: новая раскладка Метрику НЕ получает по умолчанию
- формы входа и регистрации закрыты от записи классом ym-hide-content
- метка utm не теряется при заходе сразу в кабинет минуя лендинг
Найдено при исполнении и закрыто:
- почта выводится в заголовке ДВУХ экранов, то есть вне формы: класс на форме
её не накрывал, утекла бы в записи открытым текстом. Замаскирована точечно
- Метрика, единожды запустившись, пишет дальше сама и роутером не выключается.
Админ входит через общий /login и идёт в админку к чужим телефонам.
Корни админки и портала продаж закрыты ym-hide-content
- ключ metrika в config/services.php был объявлен ДВАЖДЫ: раздвоил его мой
же merge 42e907c8 от 14.07. PHP молча берёт последний, правка первого блока
не дала бы ничего и не выругалась. Дубль вычищен, прочие конфиги проверены
В кабинете Метрики включена галочка «включая поддомены»: счётчик принимал
данные только с liderra.ru и молча выбрасывал бы всё из кабинета.
Заодно погашен долг по статанализу: 63 ошибки держали коммит. Все до одной
в тестах, в боевом коде ноль. Природа ложная — анализатор не понимает
устройство Pest и ругается на обычный вызов внутри теста. Их гасят списком
игнора, а список пересобирали 18.07, тогда как тесты добавлялись 19-20.07,
в том числе мои по рекламной аудитории. Список пересобран, стало 0 ошибок.
Долг накопился в том числе потому, что вчера я обошёл эту проверку.
Тесты: 27 новых, все проверены вырезанием защиты. Полный набор 202 файла зелёный.
План: docs/superpowers/plans/2026-07-20-skvoznoy-put-do-vebvizora.md
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
138 lines
5.1 KiB
TypeScript
138 lines
5.1 KiB
TypeScript
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
|
|
/**
|
|
* Тесты ленивого загрузчика Яндекс.Метрики (resources/js/plugins/metrika.ts).
|
|
* Загрузчик грузится только из роутера при входе в кабинет (см. router/index.ts).
|
|
*/
|
|
describe('metrika loader', () => {
|
|
beforeEach(() => {
|
|
document.head.innerHTML = '';
|
|
document.body.innerHTML = '';
|
|
delete window.ym;
|
|
vi.resetModules();
|
|
});
|
|
|
|
it('без meta-тега ничего не грузит и не падает', async () => {
|
|
const { ensureLoaded } = await import('../../resources/js/plugins/metrika');
|
|
ensureLoaded('app');
|
|
expect(document.querySelector('script[src*="mc.yandex.ru"]')).toBeNull();
|
|
});
|
|
|
|
it('с meta-тегом инжектит tag.js один раз (идемпотентно)', async () => {
|
|
const meta = document.createElement('meta');
|
|
meta.name = 'metrika-id';
|
|
meta.content = '99999999';
|
|
document.head.appendChild(meta);
|
|
|
|
const { ensureLoaded } = await import('../../resources/js/plugins/metrika');
|
|
ensureLoaded('app');
|
|
ensureLoaded('app');
|
|
const scripts = document.querySelectorAll('script[src*="mc.yandex.ru/metrika/tag.js"]');
|
|
expect(scripts.length).toBe(1);
|
|
});
|
|
|
|
it('область public грузит только счётчик полного пути', async () => {
|
|
const path = document.createElement('meta');
|
|
path.name = 'metrika-path-id';
|
|
path.content = '110476275';
|
|
document.head.appendChild(path);
|
|
|
|
const cabinet = document.createElement('meta');
|
|
cabinet.name = 'metrika-id';
|
|
cabinet.content = '110494416';
|
|
document.head.appendChild(cabinet);
|
|
|
|
const ym = vi.fn();
|
|
window.ym = ym;
|
|
|
|
const { ensureLoaded } = await import('../../resources/js/plugins/metrika');
|
|
ensureLoaded('public');
|
|
|
|
const inits = ym.mock.calls.filter((c) => c[1] === 'init').map((c) => c[0]);
|
|
expect(inits).toEqual([110476275]);
|
|
});
|
|
|
|
it('область app грузит оба счётчика', async () => {
|
|
const path = document.createElement('meta');
|
|
path.name = 'metrika-path-id';
|
|
path.content = '110476275';
|
|
document.head.appendChild(path);
|
|
|
|
const cabinet = document.createElement('meta');
|
|
cabinet.name = 'metrika-id';
|
|
cabinet.content = '110494416';
|
|
document.head.appendChild(cabinet);
|
|
|
|
const ym = vi.fn();
|
|
window.ym = ym;
|
|
|
|
const { ensureLoaded } = await import('../../resources/js/plugins/metrika');
|
|
ensureLoaded('app');
|
|
|
|
const inits = ym.mock.calls.filter((c) => c[1] === 'init').map((c) => c[0]);
|
|
expect(inits).toEqual([110476275, 110494416]);
|
|
});
|
|
|
|
it('повторный вызов не инициализирует счётчик второй раз', async () => {
|
|
const path = document.createElement('meta');
|
|
path.name = 'metrika-path-id';
|
|
path.content = '110476275';
|
|
document.head.appendChild(path);
|
|
|
|
const ym = vi.fn();
|
|
window.ym = ym;
|
|
|
|
const { ensureLoaded } = await import('../../resources/js/plugins/metrika');
|
|
ensureLoaded('public');
|
|
ensureLoaded('public');
|
|
|
|
const inits = ym.mock.calls.filter((c) => c[1] === 'init').map((c) => c[0]);
|
|
expect(inits).toEqual([110476275]);
|
|
});
|
|
|
|
it('переход из public в app до-инициализирует кабинетный счётчик', async () => {
|
|
const path = document.createElement('meta');
|
|
path.name = 'metrika-path-id';
|
|
path.content = '110476275';
|
|
document.head.appendChild(path);
|
|
|
|
const cabinet = document.createElement('meta');
|
|
cabinet.name = 'metrika-id';
|
|
cabinet.content = '110494416';
|
|
document.head.appendChild(cabinet);
|
|
|
|
const ym = vi.fn();
|
|
window.ym = ym;
|
|
|
|
const { ensureLoaded } = await import('../../resources/js/plugins/metrika');
|
|
ensureLoaded('public');
|
|
ensureLoaded('app');
|
|
|
|
const inits = ym.mock.calls.filter((c) => c[1] === 'init').map((c) => c[0]);
|
|
expect(inits).toEqual([110476275, 110494416]);
|
|
});
|
|
|
|
it('hit() шлёт заход во все поднятые счётчики', async () => {
|
|
const path = document.createElement('meta');
|
|
path.name = 'metrika-path-id';
|
|
path.content = '110476275';
|
|
document.head.appendChild(path);
|
|
|
|
const cabinet = document.createElement('meta');
|
|
cabinet.name = 'metrika-id';
|
|
cabinet.content = '110494416';
|
|
document.head.appendChild(cabinet);
|
|
|
|
const ym = vi.fn();
|
|
window.ym = ym;
|
|
|
|
const { ensureLoaded, hit } = await import('../../resources/js/plugins/metrika');
|
|
ensureLoaded('app');
|
|
ym.mockClear();
|
|
hit('/dashboard');
|
|
|
|
expect(ym).toHaveBeenCalledWith(110476275, 'hit', '/dashboard');
|
|
expect(ym).toHaveBeenCalledWith(110494416, 'hit', '/dashboard');
|
|
});
|
|
});
|