Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Mink Zombie Driver Laravel Package

behat/mink-zombie-driver

Mink driver powered by Zombie.js for fast, headless browser testing with Node.js. Install Zombie via npm (v2+) and the driver via Composer, then run Mink sessions against real pages to interact with DOM, click, fill forms, and assert content.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup for Laravel

To integrate behat/mink-zombie-driver into a Laravel project, follow these steps:

  1. Install Dependencies Ensure Node.js (v12+) and npm are installed globally. Install Zombie.js:

    npm install -g zombie@2.0.0
    

    Install PHP dependencies via Composer:

    composer require --dev behat/mink behat/mink-zombie-driver
    
  2. Configure Mink in Laravel Create a custom test helper (e.g., tests/TestHelper.php) to initialize Mink with the Zombie driver:

    use Behat\Mink\Mink;
    use Behat\Mink\Session;
    use Behat\Mink\Driver\ZombieDriver;
    use Behat\Mink\Driver\NodeJS\Server\ZombieServer;
    
    function createZombieSession(): Session {
        $zombieServer = new ZombieServer('127.0.0.1', 8124, '/usr/local/bin/node');
        $driver = new ZombieDriver($zombieServer);
        $session = new Session($driver);
        $session->start();
        return $session;
    }
    
  3. First Test Case Use the session in a PHPUnit test:

    use Behat\Mink\Session;
    
    class ExampleTest extends \Tests\TestCase {
        public function testZombieDriver() {
            $session = createZombieSession();
            $session->visit('http://localhost:8000');
            $this->assertEquals('Home', $session->getPage()->find('css', 'h1')->getText());
            $session->quit();
        }
    }
    
  4. Run Tests Execute tests with PHPUnit:

    php artisan test --testdoxhtml
    

Where to Look First


Implementation Patterns

Common Workflows

1. Form Submission Testing

Test dynamic form behavior (e.g., AJAX submissions):

$session = createZombieSession();
$session->visit('/login');
$session->getPage()->fillField('email', 'user@example.com');
$session->getPage()->fillField('password', 'secret');
$session->getPage()->pressButton('Login');
$this->assertStringContainsString('Welcome', $session->getPage()->getText());

2. JavaScript Interaction

Execute JS and assert results:

$session->getPage()->executeScript('alert("Hello")');
$this->assertEquals('Hello', $session->evaluateScript('return window.prompt("Enter:")'));

3. Dynamic Content Assertions

Wait for AJAX-loaded content:

$session->wait(3000); // Wait 3 seconds (use sparingly)
$this->assertTrue($session->getPage()->find('css', '.dynamic-content')->isVisible());

4. Behat Integration

Extend a FeatureContext:

use Behat\MinkExtension\Context\MinkContext;

class CustomContext extends MinkContext {
    protected function getSession(): Session {
        return createZombieSession();
    }
}

Feature file example:

Scenario: Login via form
  Given I am on "/login"
  When I fill in "email" with "user@example.com"
  And I fill in "password" with "secret"
  And I press "Login"
  Then I should see "Welcome"

5. Parallel Testing

Reuse the same Zombie server across tests (but avoid race conditions):

$session1 = createZombieSession();
$session2 = createZombieSession();
$session1->visit('/page1');
$session2->visit('/page2');

Integration Tips

  • Laravel Artisan Commands: Use ZombieServer in a custom command for debugging:
    use Symfony\Component\Process\Process;
    
    class ZombieDebugCommand extends Command {
        protected function handle() {
            $process = new Process(['node', 'path/to/zombie', 'http://localhost:8000']);
            $process->start();
            $this->info('Zombie server running...');
        }
    }
    
  • Docker Setup: Containerize Node.js/Zombie.js for CI:
    FROM node:12
    RUN npm install -g zombie@2.0.0
    
  • Test Isolation: Reset the driver between tests to avoid state leaks:
    $session->reset();
    

Gotchas and Tips

Pitfalls

  1. Zombie.js Limitations

    • No WebDriver: Cannot interact with modern browser APIs (e.g., localStorage, Service Workers).
    • No WebSockets: Fails on apps using Socket.io or similar.
    • Slow Performance: Zombie.js (v2.x) is outdated; avoid for complex SPAs.
    • Flaky Selectors: Dynamic content may not render in time (use wait() cautiously).
  2. Configuration Quirks

    • Port Conflicts: Ensure the Zombie server port (8124 by default) is free.
    • Node.js Path: Hardcoding /usr/local/bin/node may fail on Windows/CI. Use:
      $nodeBinary = exec('which node'); // Linux/macOS
      // OR
      $nodeBinary = 'C:\Program Files\nodejs\node.exe'; // Windows
      
    • Memory Leaks: Zombie processes may linger. Always call $session->quit().
  3. Debugging Tips

    • Log Output: Enable Zombie.js debug logs:
      $zombieServer = new ZombieServer('127.0.0.1', 8124, $nodeBinary, [
          'debug' => true,
      ]);
      
    • Manual Testing: Use zombie CLI to test pages:
      zombie http://localhost:8000
      
    • Headless Mode: Run Zombie.js in headless mode (default) but verify with:
      $session->getPage()->executeScript('console.log("Test")');
      
  4. Common Errors

    • "Connection Refused": Zombie server not running. Check:
      • Node.js installed globally (npm -g list zombie).
      • Port not blocked by firewall.
    • Element Not Found: Use wait() or executeScript to trigger dynamic content:
      $session->executeScript('document.querySelector(".dynamic").style.display = "block"');
      
    • PHP Fatal Errors: Ensure sockets extension is enabled (php -m | grep sockets).

Extension Points

  1. Custom Zombie Scripts Override the default Zombie server script (e.g., for custom headers):

    $zombieServer = new ZombieServer(
        '127.0.0.1',
        8124,
        $nodeBinary,
        [],
        __DIR__ . '/custom-zombie-script.js'
    );
    

    Example custom-zombie-script.js:

    var Browser = require('zombie');
    var browser = new Browser({ headers: { 'X-Custom-Header': 'test' } });
    browser.visit(process.argv[2]);
    console.log(browser.html());
    
  2. Mink Event Listeners Extend Mink to log interactions:

    $mink = new Mink();
    $mink->getSession()->getDriver()->addListener(new class {
        public function onVisit(VisitEvent $event) {
            \Log::info('Visited: ' . $event->getUrl());
        }
    });
    
  3. Laravel Service Provider Register Mink/Zombie as a Laravel service:

    use Behat\Mink\Mink;
    
    class MinkServiceProvider extends ServiceProvider {
        public function register() {
            $this->app->singleton(Mink::class, function () {
                return new Mink([ 'zombie' => createZombieSession() ]);
            });
        }
    }
    

Pro Tips

  • Avoid Global State: Create a new session per test to prevent leaks.
  • Use evaluateScript for Debugging:
    $session->evaluateScript('console.log(JSON.stringify(document.body.innerHTML))');
    
  • Mock External APIs: Use Zombie.js to intercept requests:
    $session->getPage()->executeScript(<<<JS
        window.fetch
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours