PHP
Laravel
laravel5.7

【Laravel5.7】テスト時にHTTPレスポンスからlaravel_sessionが取れず死んだ


laravel_sessionが取れない

Laravelでは、特に設定変更しなければlaravel_sessionというCookie1が発行され、それを使ってセッションを管理します。

テストからlaravel_sessionをチェックしたかったのだけれども、できなかったのでその記録をメモ。

なお解決はしていない。

class FooTest extends TestCase{

/**
* なんかリクエストするテスト
* @return void
*/

public function testFoobar(){
$response = $this->get('foo/bar');
$response->assertStatus(200)->assertCookieNotExpired('laravel_session');
}
}

なにひとつ失敗する要素がない。

1) Tests\Feature\FooTest::testFoobar

Cookie [laravel_session] not present on response.
Failed asserting that null is not null.

FAILURES!
Tests: 1, Assertions: 2, Failures: 1.

はい。

リクエストは成功しレスポンスコード200が返ってきている。

getContent()でレスポンス本体が取得できるが、それも想定通りの内容で、別のAPIをリクエストしていたということもない。

    var_dump($response->headers->getCookies());

array(0) {}

何も取得できていない。

どういうことなの。


なんか別のCookie出してみる

コントローラ

class FooController extends Controller{

public function barAction(Request $request){
return response()->cookie('hoge', 'fuga', -1);
}
}

ブラウザから確認。

Set-Cookie: hoge=xxx; expires=xxx; Max-Age=0; path=/; httponly

Set-Cookie: laravel_session=xxx; expires=xxx; Max-Age=7200; path=/; httponly

中身は暗号化されているため値が正しいかはわからないが、Cookie自体はきちんと発行されている。

テスト。

class FooTest extends TestCase{

public function testFoobar(){
$response = $this->get('foo/bar');
var_dump($response->headers->getCookies());
}
}

実行結果。

array(1) {

[0]=>
object(Symfony\Component\HttpFoundation\Cookie)#396 (10) {
["name":protected]=>
string(4) "hoge"
["value":protected]=>
string(192) "xxx"
["domain":protected]=>
NULL
["expire":protected]=>
int(9999999999)
["path":protected]=>
string(1) "/"
["secure":protected]=>
bool(false)
["httpOnly":protected]=>
bool(true)
["raw":"Symfony\Component\HttpFoundation\Cookie":private]=>
bool(false)
["sameSite":"Symfony\Component\HttpFoundation\Cookie":private]=>
NULL
["secureDefault":"Symfony\Component\HttpFoundation\Cookie":private]=>
bool(false)
}
}

追加で出力したhogeだけが取得できた。

つまり、laravel_sessionは自動的に隠蔽されるということなのか?


でもセッションは継続してる

テストを1項目追加。

class FooTest extends TestCase

{
/**
* テストを追加
* @return void
*/

public function testFoobar(){
$response = $this->get('foo/bar');

// foo/barが前提のリクエスト
$response2 = $this->get('foo/baz');
$response2->assertStatus(200);
}
}

コントローラ。

class FooController extends Controller{

public function barAction(Request $request){
$request->session()->put('hoge', 'fuga');
}

public function bazAction(Request $request){
if($request->session()->get('hoge') === 'fuga'){
return [];
}
abort(404);
}
}

foo/bazに来たときに、foo/barを経由していれば200、していなければ404が出力されることになる。

さて結果は?

OK (1 test, 1 assertion)

はい。

なぜなのか。


セッションデータは何処にあるの?

ここ。

class FooTest extends TestCase

{
public function testFoobar(){
$response = $this->get('foo/bar');
$response2 = $this->get('foo/baz');

// セッションデータはここ
var_dump($this->app['session']->all());
}
}

セッションIDではなく、["hoge"]=>"fuga"というデータそのものがここに入ってる。


laravel_sessionはどこにあるの?

どこでしょうね?


どうにかした

laravel_sessionではなく別のCookieを発行して、そちらに対してassertCookieXXXを行うことでお茶を濁した。

なお、"Cookieが発行されていること"そのものを見る必要がなく、セッションの中身だけ検証すればよいのであれば、最初からassertSessionXXXを使うといい。


感想

結局laravel_sessionが何処で消されているのかはわからなかった。

$response = $kernel->handle(

$request = Request::createFromBase($symfonyRequest)
);

とかのあたりね、そのね、全く意味がわからんのじゃけど。





  1. 実際はstrtolower(env('APP_NAME')).'_session'のような名前になる