Apple SiliconのMacでLaravel Duskを動かす
背景
Laravel DuskのテストをLaravelを組み込んだdockerのコンテナでphp artisan serveして行っていたのですが、
他開発者(IntelのMac)なら成功するのに、自分のM1 Macでは何故かエラーになりました。なぜぇええええと悶絶していると、どうもApple Silicon PCではエラーになってしまう時がありそうでした。
以下を実行したときにエラーになり、もしやと気づきました(必要なパッケージの一部がarm用でまだ無く、Chorme Driverが適切に動いていない?)。
$ ./vendor/laravel/dusk/bin/chromedriver-linux
qemu-x86_64: Could not open '/lib64/ld-linux-x86-64.so.2': No such file or directory
色々試してseleniumのDockerコンテナを作成して、やっとうまく行ったので、次苦戦しないようにメモを残しておこうと思います。
環境
PC
機種 : MacBook Pro 2021(M1 Max)
OS : Monterey(12.2.1)
Laravel Sail
PHP version : 8.1.9
Laravel version : 9.25.1
※実際に問題にひっかかったのはphp:8.1.9-apacheのDockerイメージですが、同じものを準備するのが面倒なのでSailでやってみます。
Laravel Sailを立ち上げ
curlコマンドを打ち込みます。
curl -s "https://laravel.build/example-app?with=mysql,redis" | bash
seleniumのDockerコンテナを作成する
docker-compose.ymlを以下のようにしてみます。seleniarm/standalone-chromium
でないと動かないようなのでこちらを利用します。
ローカルマシンに Apple Silicon チップが搭載されている場合、seleniumサービスにはseleniarm/standalone-chromiumイメージを使用する必要があります。
+ selenium:
+ image: 'seleniarm/standalone-chromium'
+ ports:
+ - '4444:4444'
+ - '7900:7900'
+ - '5900:5900'
+ volumes:
+ - '/dev/shm:/dev/shm'
+ networks:
+ - sail
ちなみによ〜くみると
selenium
seleniarm
と微妙にスペルが異なります。
何が違うんだってばよ!と思い調べてみると、seleniarmはseleniumからフォークしてarm系でも動くようにし,
M1 MacでnoVNCを使えるようにしたdockerイメージのようです(解釈間違ってたらご指摘ください)。
Dockerコンテナ起動
コンテナを起動します。
$ cd example-app
$ ./vendor/bin/sail down
$ ./vendor/bin/sail up -d
DuskTestCase.phpを修正する
seleniumコンテナでテストを行うようにDuskTestCase.phpを修正して向き先を変更します。.env.dusk.{environment}というenvファイルを作成することもできるので、変数にしてそちらに記述しても良いです。
seleniumとlaravel.testはdocker-compose.ymlに記述したサービス名です。
return RemoteWebDriver::create(
- $_ENV['DUSK_DRIVER_URL'] ?? 'http://localhost:9515',
+ $_ENV['DUSK_DRIVER_URL'] ?? 'http://selenium:4444/wd/hub',
DesiredCapabilities::chrome()->setCapability(
ChromeOptions::CAPABILITY, $options
)
);
+ protected function baseUrl()
+ {
+ return 'http://laravel.test:80';
+ }
最終的には次のようになります。
<?php
namespace Tests;
use Facebook\WebDriver\Chrome\ChromeOptions;
use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Laravel\Dusk\TestCase as BaseTestCase;
abstract class DuskTestCase extends BaseTestCase
{
use CreatesApplication;
/**
* Prepare for Dusk test execution.
*
* @beforeClass
* @return void
*/
public static function prepare()
{
if (! static::runningInSail()) {
static::startChromeDriver();
}
}
/**
* Create the RemoteWebDriver instance.
*
* @return \Facebook\WebDriver\Remote\RemoteWebDriver
*/
protected function driver()
{
$options = (new ChromeOptions)->addArguments(collect([
$this->shouldStartMaximized() ? '--start-maximized' : '--window-size=1920,1080',
])->unless($this->hasHeadlessDisabled(), function ($items) {
return $items->merge([
'--disable-gpu',
'--headless',
]);
})->all());
return RemoteWebDriver::create(
$_ENV['DUSK_DRIVER_URL'] ?? 'http://selenium:4444/wd/hub',
DesiredCapabilities::chrome()->setCapability(
ChromeOptions::CAPABILITY, $options
)
);
}
/**
* Determine whether the Dusk command has disabled headless mode.
*
* @return bool
*/
protected function hasHeadlessDisabled()
{
return isset($_SERVER['DUSK_HEADLESS_DISABLED']) ||
isset($_ENV['DUSK_HEADLESS_DISABLED']);
}
/**
* Determine if the browser window should start maximized.
*
* @return bool
*/
protected function shouldStartMaximized()
{
return isset($_SERVER['DUSK_START_MAXIMIZED']) ||
isset($_ENV['DUSK_START_MAXIMIZED']);
}
protected function baseUrl()
{
return 'http://laravel.test:80';
}
}
テストを実行する
Duskに必要なパッケージをインストールします。
$ ./vendor/bin/sail composer require --dev laravel/dusk
$ ./vendor/bin/sail php artisan dusk:install
テストを実行して、成功すれば完了です。
$ ./vendor/bin/sail php artisan dusk
PHPUnit 9.5.22 #StandWithUkraine
. 1 / 1 (100%)
Time: 00:00.976, Memory: 22.00 MB
VNCとnoVNCでテストの途中状態を確認する
--headless
の部分をコメントアウトしておきます。これをしておかないとchromiumのブラウザが表示されません。
protected function driver()
{
$options = (new ChromeOptions)->addArguments(collect([
$this->shouldStartMaximized() ? '--start-maximized' : '--window-size=1920,1080',
])->unless($this->hasHeadlessDisabled(), function ($items) {
return $items->merge([
'--disable-gpu',
+// '--headless',
]);
})->all());
docker-compose.ymlで指定した5900と7900ポートは以下の方法でVNC、noVNCを利用できます。
seleniumの画面を表示した状態で./vendor/bin/sail php artisan dusk
を実行すると途中状態を確認できます。
Discussion