Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

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'のような名前になる 

rana_kualu
不労所得で生きたい。
https://twitter.com/rana_kualu
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away