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); }); }); }); });