Laravel по-русски

Русское сообщество разработки на PHP-фреймворке Laravel.

Ты не вошёл. Вход тут.

#1 15.12.2021 08:48:28

Помогите с написание теста

Все привет! Подскажите что я делаю не так. Тестирую метод контроллера

public function editUserGeneralInfo(Request $request, User $user)
    {
        if  (Gate::denies('can-edit-info', [$request])) {
            $request->session()->flash('error', 'Доступ запрещен');
            return redirect('/users');
        };

        User::where('id', $request->input('id'))->update([
            'name'=>$request->input('name'),
            'workplace'=>$request->input('workplace'),
            'mobile'=>$request->input('mobile'),
            'adress'=>$request->input('adress')
        ]);
        $request->session()->flash('status', 'Данные успешно обновлены');
        return redirect('/users');
    }

//Тест

    public function testEditUserGeneralInfo()
    {
        $response = $this->actingAs($this->user)
            ->withSession(['foo' => 'bar'])
            ->post('/editUserGeneralInfo', [
                '_token'=>'kHwQvTEH6mRxCgKDyJtEb2op6vxtCxKRJyqXK61w',
                'id'=>'2',
                'name'=>'asdasdasd'
            ]);

        dd($response->status());
    }

Сам маршрут: Route::post('/editUserGeneralInfo', 'UserController@editUserGeneralInfo')->name('editUserGeneralInfo');

Всегда получаю статус 419, как я понял это статус как правило ошибки проверки CSRF. Если отключить CSRF защиту то статус 302.
Версия ларавер 5.6. OpenServer

Изменено markelovd (15.12.2021 08:58:29)

Не в сети

#2 15.12.2021 09:57:44

Re: Помогите с написание теста

Основной вопрос снят, правильно приходит 302, там в методах редиректы. Но теперь другая проблема как в гейт через тест передать id пользователя сам гейт выглядит так

        Gate::define('can-edit-info', function (User $user, Request $request) {
            return
                $user->id == $request->route('id') ||
                $user->role == 1 ||
                $user->id == $request->input('id');
        });

В логи все верно залетает если вывести через инфо $user->id - id зарегистрированного пользователя. Соответственно проблема в том что бы сделать проверку $user->id == $request->input('id')

Не в сети

#3 Сегодня 11:30:22

Re: Помогите с написание теста

Вы абсолютно правы: статус 419 в Laravel почти всегда указывает на ошибку CSRF-токена (Cross-Site Request Forgery).

В вашем коде теста вы явно передаете статическое значение '_token'=>'kHwQvTEH6mRxCgKDyJtEb2op6vxtCxKRJyqXK61w'. Это не сработает, потому что Laravel ожидает, что токен в сессии будет соответствовать токену, переданному в запросе.

Что делать:

Удалите статическую строку токена из запроса.

Используйте метод withToken() перед отправкой POST-запроса, чтобы Laravel автоматически сгенерировал и прикрепил действительный CSRF-токен к сессии и запросу.

Исправленный код теста:

PHP

public function testEditUserGeneralInfo()
{
    $response = $this->actingAs($this->user)
        ->withSession(['foo' => 'bar'])
        // Используйте withToken(), чтобы Laravel корректно обработал CSRF
        ->withHeaders([
            'X-CSRF-TOKEN' => csrf_token(), // Или просто используйте withToken()
        ])
        ->post('/editUserGeneralInfo', [
            // Удалите '_token' => '...' отсюда
            'id'=>'2',
            'name'=>'asdasdasd',
            'workplace'=>'test',
            'mobile'=>'12345',
            'adress'=>'test address'
        ]);

    // Если тест проходит, вы получите статус 302 (редирект после успешного обновления)
    dd($response->status());
}

// ПРИМЕЧАНИЕ: Самый простой способ в тестах — использовать withHeaders:

public function testEditUserGeneralInfo()
{
    $response = $this->actingAs($this->user)
        // Laravel автоматически добавит валидный токен в заголовки
        ->followingRedirects() // Удобно для проверки итогового статуса 200/403
        ->post('/editUserGeneralInfo', [
            'id' => '2',
            'name' => 'asdasdasd',
            // ... другие поля
        ]);

    dd($response->status()); // Ожидаем 302 (если Gate проходит)
}
Используйте метод withToken() или, что еще проще, просто отправляйте POST-запрос без поля _token в данных, но с заголовком X-CSRF-TOKEN, который Laravel часто обрабатывает автоматически в тестах. Если withHeaders не работает, просто попробуйте убрать статичный токен:

PHP

public function testEditUserGeneralInfo()
{
    $response = $this->actingAs($this->user)
        ->post('/editUserGeneralInfo', [
            // Удалите статичный токен! Laravel сам его обработает в тестах.
            // '_token'=>'kHwQvTEH6mRxCgKDyJtEb2op6vxtCxKRJyqXK61w',
            'id'=>'2',
            'name'=>'asdasdasd'
        ]);

    dd($response->status());
}
После этого вы должны увидеть статус 302 (редирект), который вы ожидали. https://www.hha-exchange.com

Не в сети

Подвал раздела