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
Test Critical Breakpoints: Focus on your design's major breakpoints rather than testing every possible screen size.
Test Interactive Elements: Ensure buttons, forms, and navigation work correctly across all viewports.
Verify Content Adaptation: Check that text, images, and layout elements adapt appropriately to different screen sizes.
Test Orientation Changes: Some responsive designs behave differently in portrait vs landscape orientations.
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.