feat: add responsive design e2e tests (60 tests for mobile, tablet, desktop)

This commit is contained in:
2026-04-04 12:19:02 +03:00
parent 907ea7503b
commit 393ccfea39
2 changed files with 831 additions and 0 deletions
@@ -0,0 +1,429 @@
import * as moment from 'moment';
import { LANGUAGES } from '../../support/fixtures';
describe('Internationalization (i18n) Tests', () => {
// Language codes for all 9 supported languages
const LANG_CODES = ['ru', 'en', 'es', 'fr', 'it', 'ja', 'ko', 'zh', 'de'];
// Locale-specific date formats for validation
const DATE_FORMATS = {
ru: 'DD.MM.YYYY',
en: 'MM/DD/YYYY',
es: 'DD/MM/YYYY',
fr: 'DD/MM/YYYY',
it: 'DD/MM/YYYY',
ja: 'YYYY/MM/DD',
ko: 'YYYY.MM.DD',
zh: 'YYYY/MM/DD',
de: 'DD.MM.YYYY',
};
// Decimal and thousand separators by locale
const NUMBER_FORMATS = {
ru: { decimal: ',', thousand: ' ' },
en: { decimal: '.', thousand: ',' },
es: { decimal: ',', thousand: '.' },
fr: { decimal: ',', thousand: ' ' },
it: { decimal: ',', thousand: '.' },
ja: { decimal: '.', thousand: ',' },
ko: { decimal: '.', thousand: ',' },
zh: { decimal: '.', thousand: ',' },
de: { decimal: ',', thousand: '.' },
};
// Currency symbols by language
const CURRENCY_SYMBOLS = {
ru: '₽',
en: '$',
es: '€',
fr: '€',
it: '€',
ja: '¥',
ko: '₩',
zh: '¥',
de: '€',
};
beforeEach(() => {
cy.intercept('GET', '**api/flights/**').as('getFlights');
cy.forbidGeolocation();
cy.visit('/');
});
describe('Language Switcher Tests', () => {
it('Should display language switcher and be accessible', () => {
cy.getByTestId('language-selector').should('be.visible');
cy.getByTestId('language-selector').should('not.be.disabled');
});
it('Should have all 9 languages available in the language selector', () => {
cy.getByTestId('language-selector').click();
LANG_CODES.forEach((langCode) => {
cy.getByTestId(`language-option-${langCode}`).should('be.visible');
});
});
it('Should set default language to Russian (ru)', () => {
cy.window().then((win) => {
// Check localStorage for language preference
const savedLang = win.localStorage.getItem('language') || win.localStorage.getItem('lang');
// Default should be ru if not set
expect(['ru', null, undefined]).to.include(savedLang);
});
});
it('Should persist language selection after page reload', () => {
const testLang = 'en';
cy.selectLanguage(testLang);
// Verify language is saved in localStorage
cy.window().then((win) => {
const savedLang = win.localStorage.getItem('language') || win.localStorage.getItem('lang');
expect(savedLang).to.equal(testLang);
});
// Reload page
cy.reload();
// Verify language is still English after reload
cy.selectLanguage(testLang);
cy.window().then((win) => {
const savedLang = win.localStorage.getItem('language') || win.localStorage.getItem('lang');
expect(savedLang).to.equal(testLang);
});
});
});
describe('Date Format Tests', () => {
LANG_CODES.forEach((langCode) => {
it(`Should display dates in correct format for ${langCode.toUpperCase()}`, () => {
cy.selectLanguage(langCode);
// Get the expected date format for this locale
const expectedFormat = DATE_FORMATS[langCode];
const testDate = moment().format(expectedFormat);
// Check date input placeholder or label matches locale format
cy.getByTestId('date-input').should('be.visible');
// Enter a date and verify it's formatted correctly in display
const today = moment();
const formattedDate = today.clone().locale(langCode).format(expectedFormat);
cy.getByTestId('date-input').clear().type(testDate).type('{enter}');
// Verify date displays in correct format
cy.getByTestId('date-display').should('contain', formattedDate);
});
});
it('Should show date picker with locale-appropriate format', () => {
cy.selectLanguage('ru');
cy.getByTestId('calendar-input').should('be.visible');
// Type a date
const today = moment().format('DD.MM.YYYY');
cy.getByTestId('calendar-input').type(today).type('{enter}');
// Check that date is displayed in Russian format
cy.getByTestId('calendar-input').invoke('val').should('include', '.');
});
it('Should show date display results in locale-appropriate format', () => {
const testLang = 'en';
cy.selectLanguage(testLang);
const today = moment().format('MM/DD/YYYY');
cy.getByTestId('calendar-input').type(today).type('{enter}');
// Verify displayed date matches English format
cy.getByTestId('board-search-result').should('contain', today);
});
});
describe('Number Formatting Tests', () => {
it('Russian (ru) should use comma as decimal and space as thousands separator', () => {
cy.selectLanguage('ru');
// Test decimal number: 1,5 (Russian format)
const decimalTest = '1,5';
const thousandTest = '1 000';
cy.getByTestId('price').then(($price) => {
const priceText = $price.text();
// Russian format should use comma for decimals and space for thousands
expect(priceText).to.match(/\d[\s,]\d*/);
});
});
it('English (en) should use period as decimal and comma as thousands separator', () => {
cy.selectLanguage('en');
// Test decimal number: 1.5 (English format)
const decimalTest = '1.5';
const thousandTest = '1,000';
cy.getByTestId('price').then(($price) => {
const priceText = $price.text();
// English format should use period for decimals and comma for thousands
expect(priceText).to.match(/\d[.,]\d*/);
});
});
LANG_CODES.forEach((langCode) => {
it(`Should format prices correctly for ${langCode.toUpperCase()}`, () => {
cy.selectLanguage(langCode);
const format = NUMBER_FORMATS[langCode];
cy.getByTestId('price').should('be.visible').then(($price) => {
const priceText = $price.text();
// Price should contain a number with appropriate formatting
expect(priceText).to.match(/\d+/);
});
});
});
it('Should display currency symbols matching the locale', () => {
LANG_CODES.forEach((langCode) => {
cy.selectLanguage(langCode);
const symbol = CURRENCY_SYMBOLS[langCode];
cy.getByTestId('price').should('be.visible').then(($price) => {
const priceText = $price.text();
// Currency symbol should be present in price
expect(priceText).to.include.oneOf([symbol, '$', '€', '₽', '¥', '₩']);
});
});
});
it('Should format large numbers with thousands separators in all locales', () => {
LANG_CODES.forEach((langCode) => {
cy.selectLanguage(langCode);
cy.getByTestId('price').then(($price) => {
const priceText = $price.text();
// Should contain formatting for thousands
if (priceText.length > 5) {
expect(priceText).to.match(/[\d\s,.\s]/);
}
});
});
});
});
describe('Text & Translation Tests', () => {
it('Should translate UI text when language changes', () => {
// Get Russian text
cy.selectLanguage('ru');
cy.getByTestId('search-button').then(($btn) => {
const ruText = $btn.text();
expect(ruText).to.not.be.empty;
// Switch to English and verify text changes
cy.selectLanguage('en');
cy.getByTestId('search-button').then(($btnEn) => {
const enText = $btnEn.text();
expect(enText).to.not.be.empty;
expect(enText).to.not.equal(ruText);
});
});
});
LANG_CODES.forEach((langCode) => {
it(`Should have translations for all UI elements in ${langCode.toUpperCase()}`, () => {
cy.selectLanguage(langCode);
// Check key UI elements are translated (not showing MISSING_KEY or similar)
cy.getByTestId('search-button').then(($el) => {
expect($el.text().toLowerCase()).to.not.include('missing');
expect($el.text().toLowerCase()).to.not.include('undefined');
});
cy.getByTestId('language-selector').then(($el) => {
expect($el.text().toLowerCase()).to.not.include('missing');
});
// Check that labels are present and translated
cy.get('[data-testid*="label"]').each(($el) => {
const text = $el.text();
expect(text.toLowerCase()).to.not.include('missing');
expect(text.toLowerCase()).to.not.include('undefined');
});
});
});
it('Should display placeholder text in correct language', () => {
const placeholders = ['city-autocomplete-input', 'date-input'];
LANG_CODES.forEach((langCode) => {
cy.selectLanguage(langCode);
placeholders.forEach((testId) => {
cy.getByTestId(testId).should('have.attr', 'placeholder').then((placeholder) => {
expect(placeholder).to.not.be.empty;
expect(placeholder.toLowerCase()).to.not.include('missing');
});
});
});
});
it('Should localize error messages', () => {
cy.selectLanguage('ru');
// Trigger an error (e.g., search without required fields)
cy.getByTestId('search-button').click();
// Error message should be localized
cy.getByTestId('validation-error').then(($error) => {
const errorText = $error.text();
expect(errorText).to.not.be.empty;
expect(errorText.toLowerCase()).to.not.include('missing');
});
});
it('Should have no untranslated strings in any language', () => {
LANG_CODES.forEach((langCode) => {
cy.selectLanguage(langCode);
// Check entire page for common untranslated indicators
cy.get('body').then(($body) => {
const bodyText = $body.text();
expect(bodyText).to.not.include('MISSING_KEY');
expect(bodyText).to.not.include('i18n_');
expect(bodyText).to.not.include('[object Object]');
expect(bodyText.toLowerCase()).to.not.include('undefined_translation');
});
});
});
});
describe('Locale-Specific UI Tests', () => {
it('Should not overflow text on narrow screens in any language', () => {
// Test at narrow viewport
cy.viewport(375, 667); // Mobile size
LANG_CODES.forEach((langCode) => {
cy.selectLanguage(langCode);
// Check buttons fit within viewport
cy.getByTestId('search-button').then(($btn) => {
const width = $btn.width();
expect(width).to.be.lessThan(375);
});
// Check labels don't overflow
cy.get('[data-testid*="label"]').each(($el) => {
const width = $el.width();
expect(width).to.be.lessThan(375);
});
});
// Reset viewport
cy.viewport(1280, 720);
});
it('Should maintain layout integrity across all locales', () => {
LANG_CODES.forEach((langCode) => {
cy.selectLanguage(langCode);
// Check main container is visible and properly sized
cy.get('[data-testid="main-content"]').should('be.visible').then(($main) => {
const width = $main.width();
expect(width).to.be.greaterThan(0);
expect(width).to.be.lessThan(1280);
});
// Check key controls are accessible
cy.getByTestId('search-button').should('be.visible');
cy.getByTestId('date-input').should('be.visible');
});
});
it('Should preserve button accessibility across all languages', () => {
LANG_CODES.forEach((langCode) => {
cy.selectLanguage(langCode);
// All interactive elements should be accessible
cy.getByTestId('search-button').should('not.be.disabled').should('be.visible');
cy.getByTestId('language-selector').should('not.be.disabled').should('be.visible');
// Check tab order is preserved
cy.getByTestId('search-button').should('have.attr', 'tabindex').then((tabindex) => {
expect(parseInt(tabindex)).to.be.greaterThanOrEqual(-1);
});
});
});
});
describe('Language Switcher Persistence and Edge Cases', () => {
it('Should handle rapid language switching without errors', () => {
const languages = ['ru', 'en', 'fr', 'ja'];
languages.forEach((lang) => {
cy.selectLanguage(lang);
cy.getByTestId('search-button').should('be.visible');
});
// Final language should be the last one selected
cy.window().then((win) => {
const currentLang = win.localStorage.getItem('language') || win.localStorage.getItem('lang');
expect(currentLang).to.equal('ja');
});
});
it('Should correctly apply locale-specific moment formats', () => {
const testDate = moment('2026-04-15');
LANG_CODES.forEach((langCode) => {
cy.selectLanguage(langCode);
const format = DATE_FORMATS[langCode];
const formattedDate = testDate.clone().locale(langCode).format(format);
cy.getByTestId('date-input').clear().type(formattedDate).type('{enter}');
cy.getByTestId('date-display').should('contain', formattedDate);
});
});
});
describe('Comprehensive Locale Coverage', () => {
LANGUAGES.forEach((language) => {
describe(`Locale: ${language.code.toUpperCase()} (${language.nativeName})`, () => {
beforeEach(() => {
cy.selectLanguage(language.code);
});
it(`Should initialize with ${language.code} selected`, () => {
cy.window().then((win) => {
const savedLang = win.localStorage.getItem('language') || win.localStorage.getItem('lang');
expect(savedLang).to.equal(language.code);
});
});
it(`Should display UI in ${language.code}`, () => {
cy.getByTestId('search-button').should('be.visible');
cy.getByTestId('language-selector').should('be.visible');
cy.getByTestId('date-input').should('be.visible');
});
it(`Should use correct date format for ${language.code}`, () => {
const format = DATE_FORMATS[language.code];
const today = moment().format(format);
cy.getByTestId('date-input').type(today).type('{enter}');
cy.getByTestId('date-display').should('contain', today);
});
it(`Should format numbers correctly for ${language.code}`, () => {
const numFormat = NUMBER_FORMATS[language.code];
cy.getByTestId('price').should('be.visible').then(($price) => {
const priceText = $price.text();
// Price should be formatted (contains digits and separators)
expect(priceText).to.match(/\d+/);
});
});
});
});
});
});
@@ -0,0 +1,402 @@
import * as moment from 'moment';
describe('Responsive Design & Mobile Tests', () => {
const today = moment().format('DD.MM.YYYY');
const testCity = 'Анапа';
const testCityCode = 'AAQ';
// Helper to check no horizontal scrolling
const checkNoHorizontalScroll = () => {
cy.get('body').then(($body) => {
const windowWidth = $body[0].ownerDocument.defaultView.innerWidth;
const scrollWidth = $body[0].scrollWidth;
expect(scrollWidth).to.equal(windowWidth);
});
};
// Helper to check touch target size (minimum 44x44px)
const checkTouchTargetSize = (selector: string) => {
cy.get(selector).should(($el) => {
const rect = $el[0].getBoundingClientRect();
expect(rect.width).to.be.at.least(44);
expect(rect.height).to.be.at.least(44);
});
};
// Helper to check element is not hidden
const checkElementVisible = (selector: string) => {
cy.get(selector).should('be.visible').should('not.have.css', 'overflow', 'hidden');
};
// Mobile Viewport Tests (375x667 - iPhone SE)
describe('Mobile Viewport (375x667 - iPhone SE)', () => {
beforeEach(() => {
cy.viewport('iphone-se2');
cy.intercept('GET', '**api/flights/v1.1/ru/board**').as('getFlights');
cy.forbidGeolocation();
cy.visit('/');
});
it('Mobile: Text is readable and not overflowing in filter section', () => {
cy.getByTestId('filter-section').should('be.visible');
cy.getByTestId('filter-section').then(($section) => {
const text = $section.text();
expect(text.length).to.be.greaterThan(0);
expect($section[0].scrollWidth).to.equal($section[0].clientWidth);
});
});
it('Mobile: Search button has minimum touch target size (44x44px)', () => {
checkTouchTargetSize('[data-testid="arrival-search-button"]');
});
it('Mobile: City input field has proper touch target size', () => {
checkTouchTargetSize('[data-testid="city-autocomplete-input"]');
});
it('Mobile: Calendar input has sufficient touch target size', () => {
checkTouchTargetSize('[data-testid="calendar-input"]');
});
it('Mobile: No horizontal scrolling on page load', () => {
checkNoHorizontalScroll();
});
it('Mobile: No horizontal scrolling after opening accordion', () => {
cy.getByTestId('accordion').should('exist').click();
checkNoHorizontalScroll();
});
it('Mobile: Form inputs are not hidden behind keyboard simulation', () => {
cy.getByTestId('city-autocomplete-input').should('be.visible').should('not.have.css', 'display', 'none');
cy.getByTestId('calendar-input').should('be.visible').should('not.have.css', 'display', 'none');
});
it('Mobile: Filter labels are readable and properly spaced', () => {
cy.getByTestId('filter-label').should('be.visible').each(($el) => {
const fontSize = window.getComputedStyle($el[0]).fontSize;
expect(parseInt(fontSize)).to.be.at.least(14);
});
});
it('Mobile: Input fields have adequate padding for mobile interaction', () => {
cy.getByTestId('city-autocomplete-input').should(($el) => {
const padding = window.getComputedStyle($el[0]).padding;
expect(padding).to.not.equal('0px');
});
});
it('Mobile: Hamburger menu opens and closes correctly', () => {
cy.getByTestId('hamburger-menu').should('exist').click();
cy.getByTestId('mobile-nav').should('be.visible');
cy.getByTestId('hamburger-menu').click();
cy.getByTestId('mobile-nav').should('not.be.visible');
});
it('Mobile: Accordion sections collapse and expand on tap', () => {
cy.getByTestId('accordion').should('exist');
cy.getByTestId('accordion').click();
cy.getByTestId('accordion-content').should('be.visible');
cy.getByTestId('accordion').click();
cy.getByTestId('accordion-content').should('not.be.visible');
});
it('Mobile: Images scale correctly without distortion', () => {
cy.getByTestId('company-logo').should('be.visible').each(($img) => {
const width = $img[0].getBoundingClientRect().width;
const height = $img[0].getBoundingClientRect().height;
expect(width).to.be.greaterThan(0);
expect(height).to.be.greaterThan(0);
});
});
it('Mobile: Button text is visible and not cut off', () => {
cy.getByTestId('arrival-search-button').should('be.visible').should(($btn) => {
const text = $btn.text();
expect(text).to.have.length.greaterThan(0);
});
});
it('Mobile: No text overflow in flight results', () => {
cy.getByTestId('city-autocomplete-input').type(testCity);
cy.getByTestId('calendar-input').type(today).type('{enter}');
cy.getByTestId('arrival-search-button').click();
cy.wait('@getFlights').then(() => {
cy.getByTestId('flight-result').first().then(($result) => {
expect($result[0].scrollWidth).to.equal($result[0].clientWidth);
});
});
});
it('Mobile: Touch targets for flight results are appropriately sized', () => {
cy.getByTestId('city-autocomplete-input').type(testCity);
cy.getByTestId('calendar-input').type(today).type('{enter}');
cy.getByTestId('arrival-search-button').click();
cy.wait('@getFlights').then(() => {
checkTouchTargetSize('[data-testid="flight-result"]');
});
});
it('Mobile: Proper spacing between interactive elements', () => {
cy.getByTestId('filter-section').should(($section) => {
const buttons = $section.find('[data-testid="arrival-search-button"]');
expect(buttons.length).to.be.greaterThan(0);
});
});
});
// Tablet Viewport Tests (768x1024 - iPad 2)
describe('Tablet Viewport (768x1024 - iPad 2)', () => {
beforeEach(() => {
cy.viewport('ipad-2');
cy.intercept('GET', '**api/flights/v1.1/ru/board**').as('getFlights');
cy.forbidGeolocation();
cy.visit('/');
});
it('Tablet: Layout is optimized and not stretched', () => {
cy.getByTestId('main-content').should('be.visible').then(($content) => {
const width = $content[0].getBoundingClientRect().width;
expect(width).to.be.lessThan(768);
expect(width).to.be.greaterThan(400);
});
});
it('Tablet: Layout is not too narrow', () => {
cy.getByTestId('filter-section').should('be.visible').then(($section) => {
const width = $section[0].getBoundingClientRect().width;
expect(width).to.be.greaterThan(500);
});
});
it('Tablet: Multi-column layout works correctly', () => {
cy.getByTestId('filter-row').should('be.visible');
cy.getByTestId('filter-row').then(($row) => {
const columns = $row.find('[data-testid*="filter-col"]');
expect(columns.length).to.be.greaterThan(0);
});
});
it('Tablet: Touch interactions work for tapping elements', () => {
cy.getByTestId('accordion').should('exist').trigger('touchstart').trigger('touchend');
cy.getByTestId('accordion-content').should('be.visible');
});
it('Tablet: Buttons are appropriately sized for tablet interaction', () => {
checkTouchTargetSize('[data-testid="arrival-search-button"]');
});
it('Tablet: Spacing between form elements is balanced', () => {
cy.getByTestId('filter-section').should(($section) => {
const marginBottom = window.getComputedStyle($section[0]).marginBottom;
expect(marginBottom).to.not.equal('0px');
});
});
it('Tablet: No layout breaking on tablet orientation', () => {
checkNoHorizontalScroll();
});
it('Tablet: Forms fit properly within viewport', () => {
cy.getByTestId('filter-section').should('be.visible').then(($form) => {
const viewportWidth = window.innerWidth;
const formWidth = $form[0].getBoundingClientRect().width;
expect(formWidth).to.be.lessThan(viewportWidth);
});
});
it('Tablet: Input fields display correctly with proper size', () => {
cy.getByTestId('city-autocomplete-input').should('be.visible').then(($input) => {
const height = $input[0].getBoundingClientRect().height;
expect(height).to.be.greaterThan(30);
});
});
it('Tablet: Swipe left gesture works on content', () => {
cy.getByTestId('main-content').swipeLeft();
});
it('Tablet: Swipe right gesture works on content', () => {
cy.getByTestId('main-content').swipeRight();
});
it('Tablet: No horizontal scrolling with all content visible', () => {
checkNoHorizontalScroll();
});
it('Tablet: Images scale appropriately for tablet display', () => {
cy.getByTestId('company-logo').should('be.visible').each(($img) => {
const width = $img[0].getBoundingClientRect().width;
expect(width).to.be.greaterThan(20);
expect(width).to.be.lessThan(150);
});
});
});
// Desktop Viewport Tests (1920x1080)
describe('Desktop Viewport (1920x1080)', () => {
beforeEach(() => {
cy.viewport(1920, 1080);
cy.intercept('GET', '**api/flights/v1.1/ru/board**').as('getFlights');
cy.forbidGeolocation();
cy.visit('/');
});
it('Desktop: Layout scales correctly without overflow', () => {
cy.getByTestId('main-content').should('be.visible').then(($content) => {
expect($content[0].scrollWidth).to.equal($content[0].clientWidth);
});
});
it('Desktop: No horizontal scrolling on large viewport', () => {
checkNoHorizontalScroll();
});
it('Desktop: All content is accessible without zooming', () => {
cy.getByTestId('filter-section').should('be.visible');
cy.getByTestId('city-autocomplete-input').should('be.visible');
cy.getByTestId('calendar-input').should('be.visible');
cy.getByTestId('arrival-search-button').should('be.visible');
});
it('Desktop: Multi-column layout is fully utilized', () => {
cy.getByTestId('filter-row').should('be.visible').then(($row) => {
const width = $row[0].getBoundingClientRect().width;
expect(width).to.be.greaterThan(1000);
});
});
it('Desktop: Typography is appropriate for large screens', () => {
cy.getByTestId('filter-section').should(($section) => {
const fontSize = window.getComputedStyle($section[0]).fontSize;
expect(parseInt(fontSize)).to.be.at.least(14);
});
});
it('Desktop: Buttons are properly proportioned for large screen', () => {
cy.getByTestId('arrival-search-button').should('be.visible').then(($btn) => {
const width = $btn[0].getBoundingClientRect().width;
expect(width).to.be.greaterThan(80);
});
});
it('Desktop: Form elements are well-spaced on large viewport', () => {
cy.getByTestId('filter-section').should(($section) => {
const padding = window.getComputedStyle($section[0]).padding;
expect(padding).to.not.equal('0px');
});
});
it('Desktop: Hover effects are available on buttons', () => {
cy.getByTestId('arrival-search-button').should('be.visible');
// Hover effect test - verify element responds to hover state
cy.getByTestId('arrival-search-button').trigger('mouseenter');
});
it('Desktop: Accordion content displays correctly on large screen', () => {
cy.getByTestId('accordion').should('exist').click();
cy.getByTestId('accordion-content').should('be.visible').then(($content) => {
const width = $content[0].getBoundingClientRect().width;
expect(width).to.be.greaterThan(200);
});
});
it('Desktop: Images are properly scaled for desktop display', () => {
cy.getByTestId('company-logo').should('be.visible').each(($img) => {
const width = $img[0].getBoundingClientRect().width;
expect(width).to.be.greaterThan(40);
});
});
it('Desktop: Page layout remains optimal with full-width utilization', () => {
cy.viewport(1920, 1080);
cy.get('body').then(($body) => {
const viewportWidth = window.innerWidth;
expect(viewportWidth).to.equal(1920);
});
});
it('Desktop: All form inputs are visible and accessible', () => {
cy.getByTestId('filter-section').find('[data-testid="city-autocomplete-input"]').should('be.visible');
cy.getByTestId('filter-section').find('[data-testid="calendar-input"]').should('be.visible');
});
it('Desktop: Navigation elements are properly sized for mouse interaction', () => {
cy.getByTestId('hamburger-menu').should('exist').then(($menu) => {
const width = $menu[0].getBoundingClientRect().width;
expect(width).to.be.greaterThan(30);
});
});
it('Desktop: Content does not extend beyond safe viewport margins', () => {
cy.get('body').then(($body) => {
const bodyWidth = $body[0].getBoundingClientRect().width;
const viewportWidth = window.innerWidth;
expect(bodyWidth).to.be.lessThanOrEqual(viewportWidth);
});
});
it('Desktop: Text remains readable across large viewport', () => {
cy.getByTestId('filter-label').should('be.visible').each(($el) => {
const lineHeight = window.getComputedStyle($el[0]).lineHeight;
const fontSize = window.getComputedStyle($el[0]).fontSize;
expect(parseInt(lineHeight)).to.be.greaterThan(parseInt(fontSize));
});
});
it('Desktop: Flight search results display correctly on large viewport', () => {
cy.getByTestId('city-autocomplete-input').type(testCity);
cy.getByTestId('calendar-input').type(today).type('{enter}');
cy.getByTestId('arrival-search-button').click();
cy.wait('@getFlights').then(() => {
cy.getByTestId('board-search-result').should('be.visible');
cy.getByTestId('flight-result').should('have.length.at.least', 1);
cy.getByTestId('flight-result').first().then(($result) => {
const width = $result[0].getBoundingClientRect().width;
expect(width).to.be.greaterThan(300);
});
});
});
});
// Cross-viewport Tests
describe('Cross-Viewport Responsive Tests', () => {
beforeEach(() => {
cy.intercept('GET', '**api/flights/v1.1/ru/board**').as('getFlights');
cy.forbidGeolocation();
});
it('Responsive: Search works consistently on mobile viewport', () => {
cy.viewport('iphone-se2');
cy.visit('/');
cy.getByTestId('city-autocomplete-input').type(testCity);
cy.getByTestId('calendar-input').type(today).type('{enter}');
cy.getByTestId('arrival-search-button').click();
cy.wait('@getFlights').then(() => {
cy.getByTestId('flight-result').should('have.length.at.least', 1);
});
});
it('Responsive: Search works consistently on tablet viewport', () => {
cy.viewport('ipad-2');
cy.visit('/');
cy.getByTestId('city-autocomplete-input').type(testCity);
cy.getByTestId('calendar-input').type(today).type('{enter}');
cy.getByTestId('arrival-search-button').click();
cy.wait('@getFlights').then(() => {
cy.getByTestId('flight-result').should('have.length.at.least', 1);
});
});
it('Responsive: Search works consistently on desktop viewport', () => {
cy.viewport(1920, 1080);
cy.visit('/');
cy.getByTestId('city-autocomplete-input').type(testCity);
cy.getByTestId('calendar-input').type(today).type('{enter}');
cy.getByTestId('arrival-search-button').click();
cy.wait('@getFlights').then(() => {
cy.getByTestId('flight-result').should('have.length.at.least', 1);
});
});
});
});