E2E (End-to-End) тестирование представляет собой проверку полного пользовательского сценария работы приложения от начала до конца. В отличие от модульных тестов, которые изолированно проверяют отдельные функции, и интеграционных тестов, ориентированных на взаимодействие компонентов, E2E-тесты имитируют реальные действия пользователя в браузере.
Для библиотеки Pikaday такой подход особенно важен, поскольку календарь тесно взаимодействует с DOM, пользовательским вводом, событиями браузера и внешними компонентами интерфейса.
Типичные сценарии E2E-тестирования включают:
Основная цель заключается в подтверждении того, что пользователь способен успешно выполнить бизнес-сценарий независимо от внутренней реализации компонентов.
Многие ошибки невозможно обнаружить при помощи unit-тестов.
Например:
const picker = new Pikaday({
field: document.getElementById('date')
});
Модульный тест может подтвердить успешное создание экземпляра:
expect(picker).toBeDefined();
Однако он не покажет:
Именно подобные проблемы выявляются посредством E2E-проверок.
Наиболее популярными решениями являются:
Особенности:
Пример:
cy.get('#date').click();
cy.get('.pika-day').contains('15').click();
cy.get('#date').should('have.value', '2025-05-15');
Современный инструмент от Microsoft.
Преимущества:
Пример:
await page.click('#date');
await page.click('text=15');
await expect(
page.locator('#date')
).toHaveValue('2025-05-15');
Классическое решение для автоматизации браузеров.
Подходит для:
Пример:
driver.findElement(
By.id('date')
).click();
Типичная HTML-разметка:
<input id="date">
<script>
new Pikaday({
field: document.getElementById('date'),
format: 'YYYY-MM-DD'
});
</script>
Такой пример служит основой для большинства сценариев автоматизированной проверки.
Первый пользовательский сценарий заключается в отображении календаря после взаимодействия с полем.
Пример Cypress:
describe('Pikaday', () => {
it('opens calendar', () => {
cy.visit('/');
cy.get('#date').click();
cy.get('.pika-single')
.should('be.visible');
});
});
Проверяются:
Основная функция Pikaday — выбор даты.
Пример:
cy.get('#date').click();
cy.contains('.pika-button', '15')
.click();
cy.get('#date')
.should('have.value', '2025-05-15');
После выполнения теста подтверждается:
Во многих интерфейсах календарь скрывается после выбора даты.
Проверка:
cy.get('#date').click();
cy.contains('.pika-button', '15')
.click();
cy.get('.pika-single')
.should('not.be.visible');
Подобный тест защищает от регрессий после обновления версии библиотеки.
Навигация между месяцами является одним из ключевых элементов интерфейса.
Пример:
cy.get('#date').click();
cy.get('.pika-next')
.click();
cy.get('.pika-label')
.should('contain', 'June');
Проверяется корректность:
cy.get('.pika-prev')
.click();
cy.get('.pika-label')
.should('contain', 'April');
Такие тесты особенно полезны при кастомизации интерфейса.
Настройка:
new Pikaday({
field: dateField,
minDate: new Date(2025, 0, 10)
});
Проверка:
cy.get('#date').click();
cy.get('.is-disabled')
.should('exist');
Дополнительно:
cy.get('.is-disabled')
.first()
.click({ force: true });
cy.get('#date')
.should('have.value', '');
Подтверждается невозможность выбора запрещённых дат.
Конфигурация:
new Pikaday({
field: dateField,
maxDate: new Date(2025, 11, 31)
});
Проверка:
cy.get('.is-disabled')
.should('exist');
Подобные сценарии критически важны для систем бронирования и оформления заказов.
Многие приложения позволяют вводить дату напрямую.
Тест:
cy.get('#date')
.type('2025-05-15');
cy.get('#date')
.should('have.value', '2025-05-15');
Дополнительно проверяется синхронизация состояния календаря и поля ввода.
Некорректные данные должны обрабатываться безопасно.
Пример:
cy.get('#date')
.type('invalid date');
cy.get('#date')
.blur();
Далее проверяется логика приложения:
cy.get('.error')
.should('be.visible');
Либо:
cy.get('#date')
.should('have.value', '');
Конфигурация:
new Pikaday({
field: dateField,
i18n: {
previousMonth: 'Назад',
nextMonth: 'Вперёд',
months: [
'Январь',
'Февраль',
'Март',
'Апрель',
'Май',
'Июнь',
'Июль',
'Август',
'Сентябрь',
'Октябрь',
'Ноябрь',
'Декабрь'
]
}
});
Проверка:
cy.get('#date').click();
cy.get('.pika-label')
.should('contain', 'Май');
Также проверяются:
Частый сценарий — выбор диапазона дат.
Пример:
<input id="start">
<input id="end">
Тест:
cy.get('#start').click();
cy.contains('.pika-button', '10')
.click();
cy.get('#end').click();
cy.contains('.pika-button', '20')
.click();
cy.get('#start')
.should('have.value', '2025-05-10');
cy.get('#end')
.should('have.value', '2025-05-20');
Проверяется независимость экземпляров Pikaday.
Пользовательский сценарий обычно завершается отправкой формы.
Пример:
cy.get('#date').click();
cy.contains('.pika-button', '15')
.click();
cy.get('form')
.submit();
Проверка:
cy.url()
.should('include', '/success');
Либо:
cy.intercept('POST', '/booking')
.as('booking');
cy.get('form')
.submit();
cy.wait('@booking');
На мобильных устройствах календарь может вести себя иначе.
Playwright:
test.use({
viewport: {
width: 390,
height: 844
}
});
Тест:
await page.click('#date');
await expect(
page.locator('.pika-single')
).toBeVisible();
Проверяется:
Некоторые проекты требуют полной поддержки клавиатурной навигации.
Пример:
await page.focus('#date');
await page.keyboard.press('Enter');
Проверка:
await expect(
page.locator('.pika-single')
).toBeVisible();
Навигация:
await page.keyboard.press('ArrowRight');
await page.keyboard.press('Enter');
Подтверждается доступность интерфейса для пользователей клавиатуры.
После выбора даты календарь должен сохранять корректное состояние.
Пример:
cy.get('#date').click();
cy.contains('.pika-button', '15')
.click();
cy.get('#date').click();
cy.get('.is-selected')
.should('exist');
Проверяется сохранение выбранного значения.
Во многих SPA-приложениях календарь создаётся после загрузки данных.
Пример:
cy.visit('/');
cy.wait('@settings');
cy.get('#date')
.click();
Проверка:
cy.get('.pika-single')
.should('be.visible');
Тест подтверждает корректность работы после динамического создания компонента.
Во время выполнения сценариев полезно отслеживать исключения браузера.
Пример Cypress:
Cypress.on(
'uncaught:exception',
(err) => {
expect(err).to.be.null;
return false;
}
);
Либо:
cy.window().then((win) => {
cy.spy(win.console, 'error');
});
Подобные проверки позволяют обнаруживать скрытые проблемы даже при внешне корректной работе интерфейса.
Распространённая структура проекта:
cypress/
├── e2e/
│ ├── date-selection.cy.js
│ ├── localization.cy.js
│ ├── navigation.cy.js
│ ├── forms.cy.js
│ └── accessibility.cy.js
Разделение по функциональным областям облегчает сопровождение тестового набора.
Избегать жёстких задержек
Плохо:
cy.wait(3000);
Хорошо:
cy.get('.pika-single')
.should('be.visible');
Использовать устойчивые селекторы
Плохо:
cy.get('div:nth-child(5)');
Хорошо:
cy.get('[data-testid="date-input"]');
Изолировать сценарии
Каждый тест должен выполняться независимо:
beforeEach(() => {
cy.visit('/');
});
Проверять бизнес-результат
Вместо проверки только DOM:
cy.get('.pika-button')
.click();
целесообразно проверять итоговое состояние:
cy.get('#date')
.should('have.value', '2025-05-15');
Такой подход обеспечивает надёжную проверку полного пользовательского взаимодействия с Pikaday, включая интерфейс календаря, обработку событий, интеграцию с формами, локализацию, ограничения дат, адаптивность и реальные сценарии эксплуатации приложения в браузере.