前置き
久々に投稿。
LaravelのテストでCookieを扱う際に、やり方が公式でも書いてあるのですが、そもそものやり方が事前にCookieを仕込んでおいてそれを読み取るという方法で、トークンなど動的に変わる値には対応できていません。
要はその、Cookie::queue
のテストが避けて通れない場合にどうするか、というのが今回のお題です。
ググっても全然ヒットしなかったので、今回頑張って検証してみました。
使用したバージョン
Laravel | ^9.0 |
PHP | ^8.0 |
公式のやり方
$response = $this->withCookie('color', 'blue')->get('/');
上記を、testCase内に書かないとCookieに書き込まれたことになりません。
対応方法
いきなり答えですが、
protected function saveCookies($cookies, $cookieNames)
{
$saveNameAndValues = [];
foreach ($cookies as $cookie) {
if (in_array($cookie->getName(), $cookieNames, true)) {
$decryptedString = decrypt($cookie->getValue(), false);
$arrayCookieValues = explode('|', $decryptedString);
$saveNameAndValues[$cookie->getName()] = $arrayCookieValues[1];
}
}
if (count($saveNameAndValues) > 0) {
$this->withCookies($saveNameAndValues);
}
}
これを
$response = $this->get('/test/hoge');
$response->assertStatus(200);
$this->saveCookies($response->headers->getCookies(), ['fuga', 'buga']);
こう呼び出します。
何をしているかというと
- ヘッダーのSet-Cookieを取得
- 暗号化されているので復号
- その中から平文だけ取得
- withCookiesでテスト環境のCookieに挿入
です。
これの呼び出し後は、テストするソース内にてCookie::get
で取得しているところは正常に値が取得できます。
なお上記のコード内でexplode
しているところは、Laravelのバージョンが変わると仕様も変わる可能性があるので、臨機応変に。
暗号化を無効にしている場合
暗号化を無効化している要素の場合なんですが、withCookies
で値を保存してもなぜか暗号化された状態で保存されてしまいます。
これも検索でヒットしたやり方では上手くいかなかったので、あれこれ試しました。
Laravelのバージョンにもよるのかも。
$this->disableCookieEncryption();
これをテストの1行目に書けば大丈夫です。
なおCookieが暗号化有効のものとそうでないものが混在していたらどうするのか、というところはまだ調べられておりませぬ。