Table of contents

Can I use Symfony Panther to test responsive web designs?

Yes, you can absolutely use Symfony Panther to test responsive web designs. Symfony Panther, which is built on top of ChromeDriver and supports both Chrome and Firefox, provides excellent capabilities for testing how your web applications behave across different screen sizes and devices. This makes it an ideal tool for ensuring your responsive designs work correctly.

Understanding Symfony Panther for Responsive Testing

Symfony Panther is a browser testing library for PHP that uses real browsers to execute tests, making it perfect for testing responsive behaviors that depend on CSS media queries, JavaScript interactions, and actual browser rendering. Unlike headless testing tools that simulate browsers, Panther executes tests in real browser environments, providing accurate results for responsive design testing.

Setting Up Viewport Testing

The primary method for testing responsive designs with Symfony Panther is manipulating the browser viewport. Here's how to configure different screen sizes:

Basic Viewport Configuration

<?php

use Symfony\Component\Panther\PantherTestCase;

class ResponsiveDesignTest extends PantherTestCase
{
    public function testMobileViewport(): void
    {
        $client = static::createPantherClient();

        // Set mobile viewport (iPhone 12 dimensions)
        $client->manage()->window()->setSize(new WebDriverDimension(390, 844));

        $crawler = $client->request('GET', '/');

        // Test mobile-specific elements
        $this->assertSelectorExists('.mobile-menu');
        $this->assertSelectorNotExists('.desktop-navigation');
    }

    public function testTabletViewport(): void
    {
        $client = static::createPantherClient();

        // Set tablet viewport (iPad dimensions)
        $client->manage()->window()->setSize(new WebDriverDimension(768, 1024));

        $crawler = $client->request('GET', '/');

        // Test tablet-specific layout
        $this->assertSelectorExists('.tablet-grid');
        $this->assertEquals(2, $crawler->filter('.product-card')->count());
    }

    public function testDesktopViewport(): void
    {
        $client = static::createPantherClient();

        // Set desktop viewport
        $client->manage()->window()->setSize(new WebDriverDimension(1920, 1080));

        $crawler = $client->request('GET', '/');

        // Test desktop-specific elements
        $this->assertSelectorExists('.desktop-navigation');
        $this->assertEquals(4, $crawler->filter('.product-card')->count());
    }
}

Testing Multiple Breakpoints

To thoroughly test responsive designs, you should test multiple breakpoints. Here's a comprehensive approach:

<?php

use Symfony\Component\Panther\PantherTestCase;
use Facebook\WebDriver\WebDriverDimension;

class MultiBreakpointTest extends PantherTestCase
{
    private const BREAKPOINTS = [
        'mobile' => ['width' => 320, 'height' => 568],
        'mobile-large' => ['width' => 414, 'height' => 896],
        'tablet' => ['width' => 768, 'height' => 1024],
        'desktop' => ['width' => 1024, 'height' => 768],
        'desktop-large' => ['width' => 1440, 'height' => 900],
        'desktop-xl' => ['width' => 1920, 'height' => 1080],
    ];

    /**
     * @dataProvider breakpointProvider
     */
    public function testResponsiveLayout(string $breakpoint, array $dimensions): void
    {
        $client = static::createPantherClient();
        $client->manage()->window()->setSize(
            new WebDriverDimension($dimensions['width'], $dimensions['height'])
        );

        $crawler = $client->request('GET', '/products');

        // Test layout changes based on breakpoint
        switch ($breakpoint) {
            case 'mobile':
            case 'mobile-large':
                $this->assertMobileLayout($crawler);
                break;
            case 'tablet':
                $this->assertTabletLayout($crawler);
                break;
            default:
                $this->assertDesktopLayout($crawler);
        }

        // Test common responsive elements
        $this->assertResponsiveImages($crawler);
        $this->assertResponsiveNavigation($crawler, $breakpoint);
    }

    public function breakpointProvider(): array
    {
        return array_map(
            fn($key, $value) => [$key, $value],
            array_keys(self::BREAKPOINTS),
            self::BREAKPOINTS
        );
    }

    private function assertMobileLayout($crawler): void
    {
        // Mobile-specific assertions
        $this->assertSelectorExists('.mobile-header');
        $this->assertSelectorExists('.hamburger-menu');
        $this->assertEquals(1, $crawler->filter('.product-grid .product-card')->count());
    }

    private function assertTabletLayout($crawler): void
    {
        // Tablet-specific assertions
        $this->assertSelectorExists('.tablet-navigation');
        $this->assertGreaterThanOrEqual(2, $crawler->filter('.product-grid .product-card')->count());
        $this->assertLessThanOrEqual(3, $crawler->filter('.product-grid .product-card')->count());
    }

    private function assertDesktopLayout($crawler): void
    {
        // Desktop-specific assertions
        $this->assertSelectorExists('.desktop-navigation');
        $this->assertSelectorNotExists('.hamburger-menu');
        $this->assertGreaterThanOrEqual(4, $crawler->filter('.product-grid .product-card')->count());
    }
}

Testing Responsive Images and Media

Responsive designs often include adaptive images and media. Here's how to test these elements:

<?php

class ResponsiveMediaTest extends PantherTestCase
{
    public function testResponsiveImages(): void
    {
        $client = static::createPantherClient();

        // Test mobile images
        $client->manage()->window()->setSize(new WebDriverDimension(375, 667));
        $crawler = $client->request('GET', '/gallery');

        $images = $crawler->filter('img[srcset]');
        $this->assertGreaterThan(0, $images->count());

        // Verify that appropriate image sources are loaded
        $firstImage = $images->first();
        $src = $firstImage->attr('src');
        $this->assertStringContains('mobile', $src);

        // Test desktop images
        $client->manage()->window()->setSize(new WebDriverDimension(1920, 1080));
        $client->reload();

        $crawler = $client->getCrawler();
        $images = $crawler->filter('img[srcset]');
        $firstImage = $images->first();
        $src = $firstImage->attr('src');
        $this->assertStringContains('desktop', $src);
    }

    public function testResponsiveVideos(): void
    {
        $client = static::createPantherClient();

        // Mobile viewport
        $client->manage()->window()->setSize(new WebDriverDimension(375, 667));
        $crawler = $client->request('GET', '/media');

        // Check if videos have responsive containers
        $this->assertSelectorExists('.video-responsive');

        // Verify video dimensions adapt to container
        $video = $crawler->filter('video')->first();
        $this->assertNotEmpty($video->attr('width'));
        $this->assertEquals('100%', $video->attr('width'));
    }
}

Testing Navigation and Menu Interactions

Responsive designs often feature different navigation patterns across devices. Here's how to test them:

<?php

class ResponsiveNavigationTest extends PantherTestCase
{
    public function testMobileMenuInteraction(): void
    {
        $client = static::createPantherClient();

        // Set mobile viewport
        $client->manage()->window()->setSize(new WebDriverDimension(375, 667));
        $crawler = $client->request('GET', '/');

        // Test hamburger menu functionality
        $this->assertSelectorExists('.hamburger-menu');
        $this->assertSelectorNotExists('.mobile-nav.open');

        // Click hamburger menu
        $client->clickLink('.hamburger-menu');
        $client->waitFor('.mobile-nav.open');

        $this->assertSelectorExists('.mobile-nav.open');

        // Test navigation links
        $navLinks = $crawler->filter('.mobile-nav a');
        $this->assertGreaterThan(0, $navLinks->count());
    }

    public function testDesktopNavigation(): void
    {
        $client = static::createPantherClient();

        // Set desktop viewport
        $client->manage()->window()->setSize(new WebDriverDimension(1200, 800));
        $crawler = $client->request('GET', '/');

        // Test desktop navigation visibility
        $this->assertSelectorExists('.desktop-nav');
        $this->assertSelectorNotExists('.hamburger-menu');

        // Test dropdown menus
        $client->getMouse()->mouseMove(
            $crawler->filter('.nav-item.has-dropdown')->getElement(0)
        );

        $client->waitFor('.dropdown-menu.visible');
        $this->assertSelectorExists('.dropdown-menu.visible');
    }
}

Advanced Responsive Testing Techniques

Testing CSS Media Queries

You can test specific CSS media query behaviors by checking computed styles:

<?php

class MediaQueryTest extends PantherTestCase
{
    public function testMediaQueryBehavior(): void
    {
        $client = static::createPantherClient();

        // Test mobile media query
        $client->manage()->window()->setSize(new WebDriverDimension(320, 568));
        $crawler = $client->request('GET', '/');

        // Execute JavaScript to check computed styles
        $display = $client->executeScript(
            "return window.getComputedStyle(document.querySelector('.desktop-only')).display;"
        );
        $this->assertEquals('none', $display);

        // Test desktop media query
        $client->manage()->window()->setSize(new WebDriverDimension(1200, 800));
        $client->reload();

        $display = $client->executeScript(
            "return window.getComputedStyle(document.querySelector('.desktop-only')).display;"
        );
        $this->assertNotEquals('none', $display);
    }
}

Testing Touch vs Mouse Interactions

Similar to how Puppeteer handles different interaction methods, Symfony Panther can test touch-specific behaviors:

<?php

class TouchInteractionTest extends PantherTestCase
{
    public function testTouchScrolling(): void
    {
        $client = static::createPantherClient([
            'browser' => static::CHROME,
            'external_base_uri' => 'http://127.0.0.1:9080',
        ]);

        // Emulate mobile device
        $client->manage()->window()->setSize(new WebDriverDimension(375, 667));

        // Enable touch events
        $client->executeScript(
            "Object.defineProperty(navigator, 'maxTouchPoints', {value: 5});"
        );

        $crawler = $client->request('GET', '/long-page');

        // Test touch scroll behavior
        $client->executeScript('window.scrollTo(0, 500);');

        // Verify scroll position
        $scrollY = $client->executeScript('return window.scrollY;');
        $this->assertEquals(500, $scrollY);
    }
}

Integration with Device Emulation

For more comprehensive responsive testing, you can configure Panther to emulate specific devices:

<?php

use Symfony\Component\Panther\PantherTestCase;
use Symfony\Component\Panther\Client;

class DeviceEmulationTest extends PantherTestCase
{
    public function testIPhoneEmulation(): void
    {
        $client = static::createPantherClient([
            'browser' => static::CHROME,
            'chromeDriverOptions' => [
                '--user-agent=Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15',
                '--window-size=375,812',
            ],
        ]);

        $crawler = $client->request('GET', '/');

        // Test iPhone-specific behaviors
        $this->assertStringContains('iPhone', $client->executeScript('return navigator.userAgent;'));

        // Test touch-specific CSS classes
        $this->assertSelectorExists('.touch-device');
    }

    public function testTabletEmulation(): void
    {
        $client = static::createPantherClient([
            'browser' => static::CHROME,
            'chromeDriverOptions' => [
                '--user-agent=Mozilla/5.0 (iPad; CPU OS 14_0 like Mac OS X) AppleWebKit/605.1.15',
                '--window-size=768,1024',
            ],
        ]);

        $crawler = $client->request('GET', '/');

        // Test tablet-specific behaviors
        $this->assertStringContains('iPad', $client->executeScript('return navigator.userAgent;'));
    }
}

Performance Testing Across Devices

Responsive testing should also include performance considerations:

<?php

class ResponsivePerformanceTest extends PantherTestCase
{
    public function testMobilePageLoadPerformance(): void
    {
        $client = static::createPantherClient();

        // Simulate slower mobile connection
        $client->manage()->window()->setSize(new WebDriverDimension(375, 667));

        $startTime = microtime(true);
        $crawler = $client->request('GET', '/');

        // Wait for page to fully load
        $client->waitFor('body.loaded');

        $loadTime = microtime(true) - $startTime;

        // Assert reasonable load time for mobile
        $this->assertLessThan(3.0, $loadTime, 'Mobile page should load within 3 seconds');

        // Test that mobile-optimized resources are loaded
        $imageCount = $crawler->filter('img')->count();
        $this->assertLessThan(10, $imageCount, 'Mobile page should have fewer images');
    }
}

Console Commands for Automated Testing

You can create Symfony console commands to run your responsive tests:

# Run all responsive design tests
php bin/console app:test-responsive

# Test specific breakpoint
php bin/console app:test-responsive --breakpoint=mobile

# Generate responsive test report
php bin/console app:test-responsive --report
<?php
// src/Command/ResponsiveTestCommand.php

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class ResponsiveTestCommand extends Command
{
    protected static $defaultName = 'app:test-responsive';

    protected function configure(): void
    {
        $this
            ->setDescription('Run responsive design tests')
            ->addOption('breakpoint', 'b', InputOption::VALUE_OPTIONAL, 'Test specific breakpoint')
            ->addOption('report', 'r', InputOption::VALUE_NONE, 'Generate test report');
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $breakpoint = $input->getOption('breakpoint');
        $generateReport = $input->getOption('report');

        // Execute responsive tests based on options
        // Implementation details...

        return Command::SUCCESS;
    }
}

Best Practices for Responsive Testing

  1. Test Critical Breakpoints: Focus on your design's major breakpoints rather than testing every possible screen size.

  2. Test Interactive Elements: Ensure buttons, forms, and navigation work correctly across all viewports.

  3. Verify Content Adaptation: Check that text, images, and layout elements adapt appropriately to different screen sizes.

  4. Test Orientation Changes: Some responsive designs behave differently in portrait vs landscape orientations.

  5. Performance Considerations: Similar to viewport optimization techniques in Puppeteer, ensure your responsive designs maintain good performance across all device sizes.

Integration with CI/CD Pipelines

You can integrate responsive testing into your continuous integration workflow:

# .github/workflows/responsive-tests.yml
name: Responsive Design Tests

on: [push, pull_request]

jobs:
  responsive-tests:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2

    - name: Setup PHP
      uses: shivammathur/setup-php@v2
      with:
        php-version: '8.1'

    - name: Install dependencies
      run: composer install

    - name: Install Chrome
      run: |
        wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -
        echo 'deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main' | tee /etc/apt/sources.list.d/google-chrome.list
        apt-get update
        apt-get install google-chrome-stable

    - name: Run responsive tests
      run: |
        php bin/phpunit tests/ResponsiveDesignTest.php
        php bin/console app:test-responsive --report

Testing with Real-World Scenarios

Consider testing common responsive patterns:

<?php

class RealWorldResponsiveTest extends PantherTestCase
{
    public function testEcommerceProductGrid(): void
    {
        $testCases = [
            ['width' => 320, 'expectedColumns' => 1],   // Mobile
            ['width' => 768, 'expectedColumns' => 2],   // Tablet
            ['width' => 1024, 'expectedColumns' => 3],  // Small desktop
            ['width' => 1440, 'expectedColumns' => 4],  // Large desktop
        ];

        foreach ($testCases as $case) {
            $client = static::createPantherClient();
            $client->manage()->window()->setSize(
                new WebDriverDimension($case['width'], 800)
            );

            $crawler = $client->request('GET', '/products');

            // Calculate actual columns based on product card positioning
            $products = $crawler->filter('.product-card');
            $firstProduct = $products->first();
            $secondProduct = $products->eq(1);

            $firstLeft = $client->executeScript(
                "return arguments[0].getBoundingClientRect().left;",
                $firstProduct->getElement(0)
            );
            $secondLeft = $client->executeScript(
                "return arguments[0].getBoundingClientRect().left;",
                $secondProduct->getElement(0)
            );

            // If second product is on same row, we have multiple columns
            if ($firstLeft === $secondLeft) {
                $actualColumns = 1;
            } else {
                // Calculate columns based on container width and product positioning
                $containerWidth = $client->executeScript(
                    "return document.querySelector('.product-grid').offsetWidth;"
                );
                $productWidth = $client->executeScript(
                    "return arguments[0].offsetWidth;",
                    $firstProduct->getElement(0)
                );
                $actualColumns = floor($containerWidth / $productWidth);
            }

            $this->assertEquals(
                $case['expectedColumns'],
                $actualColumns,
                "Expected {$case['expectedColumns']} columns at {$case['width']}px width"
            );
        }
    }
}

Conclusion

Symfony Panther provides robust capabilities for testing responsive web designs through viewport manipulation, device emulation, and real browser testing. By implementing comprehensive test suites that cover multiple breakpoints, interactive elements, and performance considerations, you can ensure your responsive designs work correctly across all target devices and screen sizes.

The key to effective responsive testing with Symfony Panther is combining viewport testing with real user interaction simulation, making it an excellent choice for validating responsive web applications in a PHP development environment. Whether you're testing simple layout changes or complex interactive behaviors, Symfony Panther's browser automation capabilities make it possible to thoroughly validate your responsive designs.

Try WebScraping.AI for Your Web Scraping Needs

Looking for a powerful web scraping solution? WebScraping.AI provides an LLM-powered API that combines Chromium JavaScript rendering with rotating proxies for reliable data extraction.

Key Features:

  • AI-powered extraction: Ask questions about web pages or extract structured data fields
  • JavaScript rendering: Full Chromium browser support for dynamic content
  • Rotating proxies: Datacenter and residential proxies from multiple countries
  • Easy integration: Simple REST API with SDKs for Python, Ruby, PHP, and more
  • Reliable & scalable: Built for developers who need consistent results

Getting Started:

Get page content with AI analysis:

curl "https://api.webscraping.ai/ai/question?url=https://example.com&question=What is the main topic?&api_key=YOUR_API_KEY"

Extract structured data:

curl "https://api.webscraping.ai/ai/fields?url=https://example.com&fields[title]=Page title&fields[price]=Product price&api_key=YOUR_API_KEY"

Try in request builder

Related Questions

Get Started Now

WebScraping.AI provides rotating proxies, Chromium rendering and built-in HTML parser for web scraping
Icon