diff --git a/src/Console/FirefoxDriverCommand.php b/src/Console/FirefoxDriverCommand.php index 170b0aa..39d0a3b 100644 --- a/src/Console/FirefoxDriverCommand.php +++ b/src/Console/FirefoxDriverCommand.php @@ -39,7 +39,7 @@ class FirefoxDriverCommand extends Command * * @var string */ - protected $latestVersion = 'v0.29.0'; + protected $latestVersion = 'v0.29.1'; /** * URL to discover latest release version. @@ -130,9 +130,10 @@ protected function binaryStubNames() return collect([ 'linux' => 'linux64.tar.gz', 'mac' => 'macos.tar.gz', + 'mac-arm' => 'macos-aarch64.tar.gz', 'win' => 'win64.zip', ])->unless($this->option('all'), function ($items) { - return $items->only(OperatingSystem::parentId()); + return $items->only(OperatingSystem::geckodriverId()); })->all(); } diff --git a/src/Firefox/FirefoxProcess.php b/src/Firefox/FirefoxProcess.php index 4f0c881..8f57354 100644 --- a/src/Firefox/FirefoxProcess.php +++ b/src/Firefox/FirefoxProcess.php @@ -2,7 +2,7 @@ namespace Derekmd\Dusk\Firefox; -use Laravel\Dusk\OperatingSystem; +use Derekmd\Dusk\OperatingSystem; use RuntimeException; use Symfony\Component\Process\Process; @@ -38,12 +38,13 @@ public function toProcess(array $arguments = []) { if ($this->driver) { $driver = $this->driver; - } elseif ($this->onWindows()) { - $driver = __DIR__.'/../../bin/geckodriver-win.exe'; - } elseif ($this->onMac()) { - $driver = __DIR__.'/../../bin/geckodriver-mac'; } else { - $driver = __DIR__.'/../../bin/geckodriver-linux'; + $driver = __DIR__.'/../../bin/'.[ + 'linux' => 'geckodriver-linux', + 'mac' => 'geckodriver-mac', + 'mac-arm' => 'geckodriver-mac-arm', + 'win' => 'geckodriver-win.exe', + ][$this->operatingSystemId()]; } $this->driver = realpath($driver); @@ -104,4 +105,14 @@ protected function onMac() { return OperatingSystem::onMac(); } + + /** + * Determine OS ID. + * + * @return string + */ + protected function operatingSystemId() + { + return OperatingSystem::geckodriverId(); + } } diff --git a/src/OperatingSystem.php b/src/OperatingSystem.php index 6e8f8f6..21aa829 100644 --- a/src/OperatingSystem.php +++ b/src/OperatingSystem.php @@ -7,13 +7,26 @@ class OperatingSystem extends BaseOperatingSystem { /** - * Get the identifier of the current operating system, exclusive of - * the architecture that OperatingSystem::id() returns. + * Get the identifier of the current operating system for Geckodriver + * binary discovery. This excludes 'mac-intel' that OperatorSystem::id() + * returns for Chromedriver. * * @return string */ - public static function parentId() + public static function geckodriverId() { - return static::onWindows() ? 'win' : (static::onMac() ? 'mac' : 'linux'); + if (static::onWindows()) { + return 'win'; + } + + if (static::onMac()) { + if (php_uname('m') === 'arm64') { + return 'mac-arm'; + } + + return 'mac'; + } + + return 'linux'; } } diff --git a/tests/FirefoxDriverCommandTest.php b/tests/FirefoxDriverCommandTest.php index 1d03326..758ee01 100644 --- a/tests/FirefoxDriverCommandTest.php +++ b/tests/FirefoxDriverCommandTest.php @@ -51,6 +51,10 @@ protected function archiveFilename() case 'Windows': return 'geckodriver-'.static::VERSION.'-win64.zip'; case 'Darwin': + if (php_uname('m') === 'arm64') { + return 'geckodriver-'.static::VERSION.'-macos-aarch64.tar.gz'; + } + return 'geckodriver-'.static::VERSION.'-macos.tar.gz'; default: return 'geckodriver-'.static::VERSION.'-linux64.tar.gz'; @@ -63,6 +67,10 @@ protected function binaryFilename() case 'Windows': return 'geckodriver-win.exe'; case 'Darwin': + if (php_uname('m') === 'arm64') { + return 'geckodriver-mac-arm'; + } + return 'geckodriver-mac'; default: return 'geckodriver-linux'; @@ -75,6 +83,10 @@ protected function os() case 'Windows': return 'win'; case 'Darwin': + if (php_uname('m') === 'arm64') { + return 'mac-arm'; + } + return 'mac'; default: return 'linux'; @@ -185,6 +197,17 @@ public function test_it_can_download_geckodriver_for_linux_mac_and_windows() return $this->copyMockBinary('geckodriver-'.static::VERSION.'-macos.tar.gz'); }); + $http->shouldReceive('request')->with( + 'GET', + vsprintf('https://github.com/mozilla/geckodriver/releases/download/%s/geckodriver-%s-macos-aarch64.tar.gz', [ + static::VERSION, + static::VERSION, + ]), + ['sink' => $this->tempDir.'/geckodriver-'.static::VERSION.'-macos-aarch64.tar.gz'] + )->andReturnUsing(function () { + return $this->copyMockBinary('geckodriver-'.static::VERSION.'-macos-aarch64.tar.gz'); + }); + $http->shouldReceive('request')->with( 'GET', vsprintf('https://github.com/mozilla/geckodriver/releases/download/%s/geckodriver-%s-linux64.tar.gz', [ @@ -209,6 +232,9 @@ public function test_it_can_download_geckodriver_for_linux_mac_and_windows() $this->assertFileDoesNotExist($this->tempDir.'/geckodriver-'.static::VERSION.'-macos.tar.gz'); $this->assertStringEqualsFile($this->tempDir.'/geckodriver-mac', 'foo'); + $this->assertFileDoesNotExist($this->tempDir.'/geckodriver-'.static::VERSION.'-macos-aarch64.tar.gz'); + $this->assertStringEqualsFile($this->tempDir.'/geckodriver-mac-arm', 'foo'); + $this->assertFileDoesNotExist($this->tempDir.'/geckodriver-'.static::VERSION.'-linux64.tar.gz'); $this->assertStringEqualsFile($this->tempDir.'/geckodriver-linux', 'foo'); } diff --git a/tests/FirefoxProcessTest.php b/tests/FirefoxProcessTest.php index 5b5fd92..8a63146 100644 --- a/tests/FirefoxProcessTest.php +++ b/tests/FirefoxProcessTest.php @@ -35,6 +35,14 @@ public function test_build_process_for_darwin() $this->assertStringContainsString('geckodriver-mac', $process->getCommandLine()); } + public function test_build_process_for_mac_arm_m1() + { + $process = (new FirefoxProcessM1)->toProcess(); + + $this->assertInstanceOf(Process::class, $process); + $this->assertStringContainsString('geckodriver-mac-arm', $process->getCommandLine()); + } + public function test_build_process_for_linux() { $process = (new FirefoxProcessLinux)->toProcess(); @@ -61,6 +69,11 @@ protected function onWindows() { return true; } + + protected function operatingSystemId() + { + return 'win'; + } } class FirefoxProcessDarwin extends FirefoxProcess @@ -74,6 +87,29 @@ protected function onWindows() { return false; } + + protected function operatingSystemId() + { + return 'mac'; + } +} + +class FirefoxProcessM1 extends FirefoxProcess +{ + protected function onMac() + { + return true; + } + + protected function onWindows() + { + return false; + } + + protected function operatingSystemId() + { + return 'mac-arm'; + } } class FirefoxProcessLinux extends FirefoxProcess @@ -87,4 +123,9 @@ protected function onWindows() { return false; } + + protected function operatingSystemId() + { + return 'linux'; + } } diff --git a/tests/fixtures/geckodriver-missing-binary-macos-aarch64.tar.gz b/tests/fixtures/geckodriver-missing-binary-macos-aarch64.tar.gz new file mode 100644 index 0000000..8279c7e Binary files /dev/null and b/tests/fixtures/geckodriver-missing-binary-macos-aarch64.tar.gz differ diff --git a/tests/fixtures/geckodriver-v0.29.0-macos-aarch64.tar.gz b/tests/fixtures/geckodriver-v0.29.0-macos-aarch64.tar.gz new file mode 100644 index 0000000..20f69d6 Binary files /dev/null and b/tests/fixtures/geckodriver-v0.29.0-macos-aarch64.tar.gz differ