Юнит-тестирование кода с Cash

Cash — это легковесная библиотека для работы с DOM в стиле jQuery, оптимизированная для современных браузеров. Она обеспечивает удобные методы манипуляции с элементами страницы, работу с событиями, анимациями и Ajax-запросами. В контексте юнит-тестирования важно понимать, что Cash предоставляет API, которое можно изолированно тестировать, проверяя поведение элементов DOM без необходимости полной загрузки страницы.

Cash использует цепочные вызовы и возвращает коллекцию элементов, что позволяет писать компактный и предсказуемый код. Методы библиотеки можно разделить на несколько категорий:

  • Манипуляция DOM: html(), text(), append(), prepend(), after(), before(), remove().
  • События: on(), off(), trigger().
  • Классы и атрибуты: addClass(), removeClass(), toggleClass(), attr(), removeAttr().
  • CSS и стили: css(), width(), height().
  • Ajax: $.ajax(), $.get(), $.post().

Настройка среды для тестирования

Для юнит-тестирования кода с Cash чаще всего используют библиотеки Jest или Mocha + Chai, а также среду, имитирующую DOM, например jsdom. Cash полностью совместима с jsdom, что позволяет тестировать манипуляции с DOM без реального браузера.

Пример настройки тестовой среды с Jest и jsdom:

import $ from 'cash-dom';

beforeEach(() => {
    document.body.innerHTML = `
        <div id="container">
            <button class="btn">Click me</button>
            <span class="label">Label</span>
        </div>
    `;
});

Тестирование манипуляций с DOM

Методы Cash для работы с DOM легко тестируются путем проверки состояния элементов до и после вызова метода.

Проверка изменения текста и HTML

test('метод html() изменяет содержимое элемента', () => {
    const $label = $('.label');
    $label.html('Новый текст');
    expect($label.html()).toBe('Новый текст');
});
test('метод text() изменяет текст элемента', () => {
    const $btn = $('.btn');
    $btn.text('Нажми');
    expect($btn.text()).toBe('Нажми');
});

Добавление и удаление элементов

test('append() добавляет элемент в контейнер', () => {
    const $container = $('#container');
    $container.append('<p class="new">Paragraph</p>');
    expect($container.find('.new').length).toBe(1);
});

test('remove() удаляет элемент', () => {
    const $label = $('.label');
    $label.remove();
    expect(document.querySelector('.label')).toBeNull();
});

Тестирование работы с классами и атрибутами

Методы управления классами и атрибутами позволяют изменять поведение элементов и их внешний вид, что важно проверять в тестах.

test('addClass() добавляет класс элементу', () => {
    const $btn = $('.btn');
    $btn.addClass('active');
    expect($btn.hasClass('active')).toBe(true);
});

test('removeClass() удаляет класс элементу', () => {
    const $btn = $('.btn');
    $btn.addClass('active').removeClass('active');
    expect($btn.hasClass('active')).toBe(false);
});

test('attr() изменяет атрибут элемента', () => {
    const $btn = $('.btn');
    $btn.attr('disabled', true);
    expect($btn.attr('disabled')).toBe('true');
});

Тестирование событий

Cash предоставляет удобные методы для работы с событиями. Тесты проверяют, вызываются ли обработчики в нужный момент.

test('on() и trigger() корректно работают с событиями', () => {
    const $btn = $('.btn');
    const mockHandler = jest.fn();
    $btn.on('click', mockHandler);
    
    $btn.trigger('click');
    
    expect(mockHandler).toHaveBeenCalledTimes(1);
});

test('off() удаляет обработчик события', () => {
    const $btn = $('.btn');
    const mockHandler = jest.fn();
    $btn.on('click', mockHandler);
    $btn.off('click', mockHandler);
    
    $btn.trigger('click');
    
    expect(mockHandler).not.toHaveBeenCalled();
});

Тестирование CSS и стилей

Изменение стилей с помощью Cash также поддается юнит-тестированию. Проверяется конкретное свойство CSS после применения метода css().

test('css() устанавливает стиль элемента', () => {
    const $btn = $('.btn');
    $btn.css('color', 'red');
    expect($btn.css('color')).toBe('red');
});

test('width() и height() корректно задают размеры', () => {
    const $btn = $('.btn');
    $btn.width(100).height(50);
    expect($btn.width()).toBe(100);
    expect($btn.height()).toBe(50);
});

Тестирование Ajax-запросов

Cash реализует методы для работы с Ajax, которые удобно тестировать с использованием моков.

import $ from 'cash-dom';

test('$.ajax() выполняет запрос и обрабатывает ответ', async () => {
    global.fetch = jest.fn(() =>
        Promise.resolve({
            json: () => Promise.resolve({ success: true }),
        })
    );

    const response = await $.ajax({
        url: '/api/test',
        method: 'GET',
        dataType: 'json',
    });

    expect(response.success).toBe(true);
    expect(global.fetch).toHaveBeenCalledWith('/api/test', expect.any(Object));
});

Стратегии структурирования тестов

  1. Изоляция элементов — каждый тест создает собственный DOM, чтобы изменения в одном тесте не влияли на другие.
  2. Использование моков и шпионов — для событий, Ajax-запросов и функций обратного вызова.
  3. Проверка состояния до и после — важно фиксировать начальное состояние и сравнивать его с конечным результатом.
  4. Минимизация зависимости от внешнего DOM — использование jsdom позволяет работать без браузера, ускоряя тесты.

Практические рекомендации

  • Методы цепочек ($('.btn').addClass('active').text('Нажми')) тестировать поэтапно или проверять результат конечного состояния.
  • Событийные тесты лучше оформлять через мок-функции, чтобы убедиться, что именно вызван нужный обработчик.
  • Для тестирования сложных манипуляций с DOM использовать селекторы и методы find(), children(), чтобы проверять вложенные элементы.
  • Ajax-запросы лучше изолировать и мокировать, чтобы тесты были быстрыми и предсказуемыми.

Юнит-тестирование кода с Cash позволяет проверять все ключевые аспекты работы с DOM, событиями, стилями и Ajax, обеспечивая надежность и предсказуемость фронтенд-кода.