> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Pruebas HTTP

> Guía de las funciones de pruebas HTTP de Laravel: simular peticiones, aserciones, tests de autenticación y de subida de archivos.

## Introducción

Laravel ofrece una API muy completa para simular peticiones HTTP y verificar sus respuestas.
Puedes reproducir las peticiones dentro de los tests sin necesidad de levantar un servidor HTTP real.

<CodeGroup>
  ```php Pest theme={null}
  <?php

  test('la aplicación devuelve una respuesta correcta', function () {
      $response = $this->get('/');

      $response->assertStatus(200);
  });
  ```

  ```php PHPUnit theme={null}
  <?php

  namespace Tests\Feature;

  use Tests\TestCase;

  class ExampleTest extends TestCase
  {
      public function test_the_application_returns_a_successful_response(): void
      {
          $response = $this->get('/');

          $response->assertStatus(200);
      }
  }
  ```
</CodeGroup>

El método `get()` envía una petición `GET` a la aplicación y `assertStatus()` valida el código HTTP de la respuesta.

<Info>
  Durante las pruebas el middleware CSRF se desactiva automáticamente. No hace falta desactivarlo de forma explícita.
</Info>

## Cómo crear peticiones

Dentro de los tests puedes enviar peticiones con los métodos `get`, `post`, `put`, `patch` y `delete`.
Estos métodos no realizan una petición real por la red: simulan la petición internamente en la aplicación.
El valor devuelto es una instancia de `Illuminate\Testing\TestResponse`, que expone muchos métodos de aserción.

<CodeGroup>
  ```php Pest theme={null}
  <?php

  test('petición básica', function () {
      $response = $this->get('/');

      $response->assertStatus(200);
  });
  ```

  ```php PHPUnit theme={null}
  <?php

  namespace Tests\Feature;

  use Tests\TestCase;

  class ExampleTest extends TestCase
  {
      public function test_a_basic_request(): void
      {
          $response = $this->get('/');

          $response->assertStatus(200);
      }
  }
  ```
</CodeGroup>

<Warning>
  Se recomienda enviar una única petición por cada método de test. Ejecutar varias peticiones dentro del mismo test puede provocar comportamientos inesperados.
</Warning>

### Personalizar cabeceras

Con `withHeaders()` puedes personalizar las cabeceras de la petición.

<CodeGroup>
  ```php Pest theme={null}
  <?php

  test('petición con cabeceras', function () {
      $response = $this->withHeaders([
          'X-Header' => 'Value',
      ])->post('/user', ['name' => 'Sally']);

      $response->assertStatus(201);
  });
  ```

  ```php PHPUnit theme={null}
  <?php

  namespace Tests\Feature;

  use Tests\TestCase;

  class ExampleTest extends TestCase
  {
      public function test_interacting_with_headers(): void
      {
          $response = $this->withHeaders([
              'X-Header' => 'Value',
          ])->post('/user', ['name' => 'Sally']);

          $response->assertStatus(201);
      }
  }
  ```
</CodeGroup>

### Cookies

Los métodos `withCookie()` o `withCookies()` permiten definir cookies antes de la petición.

<CodeGroup>
  ```php Pest theme={null}
  <?php

  test('petición con cookies', function () {
      $response = $this->withCookie('color', 'blue')->get('/');

      $response = $this->withCookies([
          'color' => 'blue',
          'name'  => 'Taylor',
      ])->get('/');
  });
  ```

  ```php PHPUnit theme={null}
  <?php

  namespace Tests\Feature;

  use Tests\TestCase;

  class ExampleTest extends TestCase
  {
      public function test_interacting_with_cookies(): void
      {
          $response = $this->withCookie('color', 'blue')->get('/');

          $response = $this->withCookies([
              'color' => 'blue',
              'name'  => 'Taylor',
          ])->get('/');
      }
  }
  ```
</CodeGroup>

### Sesión y autenticación

Con `withSession()` puedes preparar los datos de sesión antes de la petición.

<CodeGroup>
  ```php Pest theme={null}
  <?php

  test('petición con sesión', function () {
      $response = $this->withSession(['banned' => false])->get('/');
  });
  ```

  ```php PHPUnit theme={null}
  <?php

  namespace Tests\Feature;

  use Tests\TestCase;

  class ExampleTest extends TestCase
  {
      public function test_interacting_with_the_session(): void
      {
          $response = $this->withSession(['banned' => false])->get('/');
      }
  }
  ```
</CodeGroup>

`actingAs()` envía la petición como un usuario autenticado. Se combina con las factorías de modelos.

<CodeGroup>
  ```php Pest theme={null}
  <?php

  use App\Models\User;

  test('acción que requiere autenticación', function () {
      $user = User::factory()->create();

      $response = $this->actingAs($user)
          ->withSession(['banned' => false])
          ->get('/');
  });
  ```

  ```php PHPUnit theme={null}
  <?php

  namespace Tests\Feature;

  use App\Models\User;
  use Tests\TestCase;

  class ExampleTest extends TestCase
  {
      public function test_an_action_that_requires_authentication(): void
      {
          $user = User::factory()->create();

          $response = $this->actingAs($user)
              ->withSession(['banned' => false])
              ->get('/');
      }
  }
  ```
</CodeGroup>

Si pasas el nombre de un guard como segundo argumento de `actingAs()`, se autenticará con ese guard. Además, ese guard pasa a ser el predeterminado durante la prueba.

```php theme={null}
$this->actingAs($user, 'web');
```

Para enviar una petición sin autenticar utiliza `actingAsGuest()`.

```php theme={null}
$this->actingAsGuest();
```

### Depurar la respuesta

Cuando quieras inspeccionar el contenido de la respuesta durante un test, usa `dump`, `dumpHeaders` o `dumpSession`.

<CodeGroup>
  ```php Pest theme={null}
  <?php

  test('depurar respuesta', function () {
      $response = $this->get('/');

      $response->dump();
      $response->dumpHeaders();
      $response->dumpSession();
  });
  ```

  ```php PHPUnit theme={null}
  <?php

  namespace Tests\Feature;

  use Tests\TestCase;

  class ExampleTest extends TestCase
  {
      public function test_debug_response(): void
      {
          $response = $this->get('/');

          $response->dump();
          $response->dumpHeaders();
          $response->dumpSession();
      }
  }
  ```
</CodeGroup>

Para detener la ejecución al mismo tiempo, utiliza `dd`, `ddHeaders`, `ddBody`, `ddJson` y `ddSession`.

```php theme={null}
$response->dd();
$response->ddHeaders();
$response->ddBody();
$response->ddJson();
$response->ddSession();
```

### Probar excepciones

Para comprobar que se lanza una excepción concreta, utiliza el facade `Exceptions`.

<CodeGroup>
  ```php Pest theme={null}
  <?php

  use App\Exceptions\InvalidOrderException;
  use Illuminate\Support\Facades\Exceptions;

  test('se lanza una excepción', function () {
      Exceptions::fake();

      $response = $this->get('/order/1');

      // Se ha lanzado la excepción
      Exceptions::assertReported(InvalidOrderException::class);

      // Verificar el contenido de la excepción
      Exceptions::assertReported(function (InvalidOrderException $e) {
          return $e->getMessage() === 'The order was invalid.';
      });
  });
  ```

  ```php PHPUnit theme={null}
  <?php

  namespace Tests\Feature;

  use App\Exceptions\InvalidOrderException;
  use Illuminate\Support\Facades\Exceptions;
  use Tests\TestCase;

  class ExampleTest extends TestCase
  {
      public function test_exception_is_thrown(): void
      {
          Exceptions::fake();

          $response = $this->get('/');

          Exceptions::assertReported(InvalidOrderException::class);

          Exceptions::assertReported(function (InvalidOrderException $e) {
              return $e->getMessage() === 'The order was invalid.';
          });
      }
  }
  ```
</CodeGroup>

Para comprobar que no se ha lanzado una excepción utiliza `assertNotReported` o `assertNothingReported`.

```php theme={null}
Exceptions::assertNotReported(InvalidOrderException::class);

Exceptions::assertNothingReported();
```

Para enviar la petición desactivando el manejo de excepciones, utiliza `withoutExceptionHandling()`.

```php theme={null}
$response = $this->withoutExceptionHandling()->get('/');
```

Para probar si el código dentro de una closure lanza una excepción, utiliza `assertThrows()`.

```php theme={null}
$this->assertThrows(
    fn () => (new ProcessOrder)->execute(),
    OrderInvalid::class
);

// Comprobando también el contenido de la excepción
$this->assertThrows(
    fn () => (new ProcessOrder)->execute(),
    fn (OrderInvalid $e) => $e->orderId() === 123
);
```

Para comprobar que no se lanza excepción, utiliza `assertDoesntThrow()`.

```php theme={null}
$this->assertDoesntThrow(fn () => (new ProcessOrder)->execute());
```

## Pruebas de API JSON

Laravel ofrece muchos helpers para probar APIs JSON.
Utiliza los métodos `json`, `getJson`, `postJson`, `putJson`, `patchJson`, `deleteJson` y `optionsJson`.

<CodeGroup>
  ```php Pest theme={null}
  <?php

  test('petición a la API', function () {
      $response = $this->postJson('/api/user', ['name' => 'Sally']);

      $response
          ->assertStatus(201)
          ->assertJson([
              'created' => true,
          ]);
  });
  ```

  ```php PHPUnit theme={null}
  <?php

  namespace Tests\Feature;

  use Tests\TestCase;

  class ExampleTest extends TestCase
  {
      public function test_making_an_api_request(): void
      {
          $response = $this->postJson('/api/user', ['name' => 'Sally']);

          $response
              ->assertStatus(201)
              ->assertJson([
                  'created' => true,
              ]);
      }
  }
  ```
</CodeGroup>

Los datos de la respuesta JSON son accesibles como si fueran un array.

<CodeGroup>
  ```php Pest theme={null}
  expect($response['created'])->toBeTrue();
  ```

  ```php PHPUnit theme={null}
  $this->assertTrue($response['created']);
  ```
</CodeGroup>

<Info>
  `assertJson()` convierte la respuesta a array y comprueba que el array indicado esté contenido en la respuesta JSON. Aunque la respuesta contenga otras propiedades, la prueba pasa si aparece el fragmento indicado.
</Info>

### Aserción de coincidencia exacta

Con `assertExactJson()` verificas que el JSON devuelto coincide **exactamente** con el array indicado.

<CodeGroup>
  ```php Pest theme={null}
  <?php

  test('aserción JSON exacta', function () {
      $response = $this->postJson('/user', ['name' => 'Sally']);

      $response
          ->assertStatus(201)
          ->assertExactJson([
              'created' => true,
          ]);
  });
  ```

  ```php PHPUnit theme={null}
  <?php

  namespace Tests\Feature;

  use Tests\TestCase;

  class ExampleTest extends TestCase
  {
      public function test_asserting_an_exact_json_match(): void
      {
          $response = $this->postJson('/user', ['name' => 'Sally']);

          $response
              ->assertStatus(201)
              ->assertExactJson([
                  'created' => true,
              ]);
      }
  }
  ```
</CodeGroup>

### Aserción por path JSON

Con `assertJsonPath()` verificas el valor en un path concreto.

<CodeGroup>
  ```php Pest theme={null}
  <?php

  test('aserción por path JSON', function () {
      $response = $this->postJson('/user', ['name' => 'Sally']);

      $response
          ->assertStatus(201)
          ->assertJsonPath('team.owner.name', 'Darian');
  });
  ```

  ```php PHPUnit theme={null}
  <?php

  namespace Tests\Feature;

  use Tests\TestCase;

  class ExampleTest extends TestCase
  {
      public function test_asserting_a_json_paths_value(): void
      {
          $response = $this->postJson('/user', ['name' => 'Sally']);

          $response
              ->assertStatus(201)
              ->assertJsonPath('team.owner.name', 'Darian');
      }
  }
  ```
</CodeGroup>

También puedes pasar una closure para una validación más flexible.

```php theme={null}
$response->assertJsonPath('team.owner.name', fn (string $name) => strlen($name) >= 3);
```

### Pruebas JSON fluidas

Pasando una closure a `assertJson()` puedes escribir aserciones fluidas mediante una instancia de `AssertableJson`.

<CodeGroup>
  ```php Pest theme={null}
  use Illuminate\Testing\Fluent\AssertableJson;

  test('prueba JSON fluida', function () {
      $response = $this->getJson('/users/1');

      $response
          ->assertJson(fn (AssertableJson $json) =>
              $json->where('id', 1)
                  ->where('name', 'Victoria Faith')
                  ->where('email', fn (string $email) => str($email)->is('victoria@gmail.com'))
                  ->whereNot('status', 'pending')
                  ->missing('password')
                  ->etc()
          );
  });
  ```

  ```php PHPUnit theme={null}
  use Illuminate\Testing\Fluent\AssertableJson;

  public function test_fluent_json(): void
  {
      $response = $this->getJson('/users/1');

      $response
          ->assertJson(fn (AssertableJson $json) =>
              $json->where('id', 1)
                  ->where('name', 'Victoria Faith')
                  ->where('email', fn (string $email) => str($email)->is('victoria@gmail.com'))
                  ->whereNot('status', 'pending')
                  ->missing('password')
                  ->etc()
          );
  }
  ```
</CodeGroup>

<Tip>
  El método `etc()` permite que existan propiedades no aseveradas. Si no se usa `etc()`, la aserción falla si aparecen propiedades no verificadas. Así se evita filtrar accidentalmente información sensible en la respuesta.
</Tip>

Para comprobar la presencia o ausencia de propiedades utiliza `has()` y `missing()`.

```php theme={null}
$response->assertJson(fn (AssertableJson $json) =>
    $json->has('data')
        ->missing('message')
);
```

Para varias propiedades a la vez, `hasAll()` y `missingAll()`.

```php theme={null}
$response->assertJson(fn (AssertableJson $json) =>
    $json->hasAll(['status', 'data'])
        ->missingAll(['message', 'code'])
);
```

#### Aserciones sobre colecciones JSON

Cuando la ruta devuelve una respuesta con varios elementos, `has()` permite comprobar el número de elementos y el contenido de la colección.

```php theme={null}
$response
    ->assertJson(fn (AssertableJson $json) =>
        $json->has(3)
            ->first(fn (AssertableJson $json) =>
                $json->where('id', 1)
                    ->where('name', 'Victoria Faith')
                    ->missing('password')
                    ->etc()
            )
    );
```

Para aplicar la misma aserción a todos los elementos, usa `each()`.

```php theme={null}
$response
    ->assertJson(fn (AssertableJson $json) =>
        $json->has(3)
            ->each(fn (AssertableJson $json) =>
                $json->whereType('id', 'integer')
                    ->whereType('name', 'string')
                    ->whereType('email', 'string')
                    ->missing('password')
                    ->etc()
            )
    );
```

#### Aserción de tipos JSON

Con `whereType()` y `whereAllType()` puedes validar el tipo de las propiedades.

```php theme={null}
$response->assertJson(fn (AssertableJson $json) =>
    $json->whereType('id', 'integer')
        ->whereAllType([
            'users.0.name' => 'string',
            'meta' => 'array'
        ])
);
```

Se pueden combinar varios tipos con `|`. La aserción pasa si el valor coincide con alguno.

```php theme={null}
$response->assertJson(fn (AssertableJson $json) =>
    $json->whereType('name', 'string|null')
        ->whereType('id', ['string', 'integer'])
);
```

Los tipos disponibles son `string`, `integer`, `double`, `boolean`, `array` y `null`.

## Tests de autenticación

Con `actingAs()` puedes enviar peticiones como usuario autenticado.

<CodeGroup>
  ```php Pest theme={null}
  <?php

  use App\Models\User;
  use Illuminate\Foundation\Testing\RefreshDatabase;

  uses(RefreshDatabase::class);

  test('un usuario autenticado puede ver el dashboard', function () {
      $user = User::factory()->create();

      $response = $this->actingAs($user)->get('/dashboard');

      $response->assertStatus(200);
  });

  test('los usuarios no autenticados son redirigidos', function () {
      $response = $this->get('/dashboard');

      $response->assertRedirect('/login');
  });
  ```

  ```php PHPUnit theme={null}
  <?php

  namespace Tests\Feature;

  use App\Models\User;
  use Illuminate\Foundation\Testing\RefreshDatabase;
  use Tests\TestCase;

  class DashboardTest extends TestCase
  {
      use RefreshDatabase;

      public function test_authenticated_users_can_view_the_dashboard(): void
      {
          $user = User::factory()->create();

          $response = $this->actingAs($user)->get('/dashboard');

          $response->assertStatus(200);
      }

      public function test_unauthenticated_users_are_redirected(): void
      {
          $response = $this->get('/dashboard');

          $response->assertRedirect('/login');
      }
  }
  ```
</CodeGroup>

Para autenticar con un guard concreto, pasa su nombre como segundo argumento.

```php theme={null}
$this->actingAs($user, 'api');
```

### Ejemplo: prueba del flujo de registro de usuarios

Ejemplo de test del endpoint de registro de usuarios.

<CodeGroup>
  ```php Pest theme={null}
  <?php

  use App\Models\User;
  use Illuminate\Foundation\Testing\RefreshDatabase;

  uses(RefreshDatabase::class);

  test('un usuario puede registrarse', function () {
      $response = $this->post('/register', [
          'name'                  => 'Test User',
          'email'                 => 'test@example.com',
          'password'              => 'password',
          'password_confirmation' => 'password',
      ]);

      $response->assertRedirect('/dashboard');
      $this->assertDatabaseHas('users', ['email' => 'test@example.com']);
  });

  test('no se puede registrar con un email duplicado', function () {
      User::factory()->create(['email' => 'test@example.com']);

      $response = $this->post('/register', [
          'name'                  => 'Test User',
          'email'                 => 'test@example.com',
          'password'              => 'password',
          'password_confirmation' => 'password',
      ]);

      $response->assertSessionHasErrors('email');
  });
  ```

  ```php PHPUnit theme={null}
  <?php

  namespace Tests\Feature;

  use App\Models\User;
  use Illuminate\Foundation\Testing\RefreshDatabase;
  use Tests\TestCase;

  class RegistrationTest extends TestCase
  {
      use RefreshDatabase;

      public function test_user_can_register(): void
      {
          $response = $this->post('/register', [
              'name'                  => 'Test User',
              'email'                 => 'test@example.com',
              'password'              => 'password',
              'password_confirmation' => 'password',
          ]);

          $response->assertRedirect('/dashboard');
          $this->assertDatabaseHas('users', ['email' => 'test@example.com']);
      }

      public function test_duplicate_email_cannot_register(): void
      {
          User::factory()->create(['email' => 'test@example.com']);

          $response = $this->post('/register', [
              'name'                  => 'Test User',
              'email'                 => 'test@example.com',
              'password'              => 'password',
              'password_confirmation' => 'password',
          ]);

          $response->assertSessionHasErrors('email');
      }
  }
  ```
</CodeGroup>

## Pruebas de sesión

Con `withSession()` puedes preparar la sesión antes de la petición.
Con `assertSessionHas()` compruebas la existencia de valores en la sesión.

<CodeGroup>
  ```php Pest theme={null}
  <?php

  test('validar valor de sesión', function () {
      $response = $this->withSession(['locale' => 'es'])->get('/');

      $response->assertSessionHas('locale', 'es');
  });
  ```

  ```php PHPUnit theme={null}
  <?php

  namespace Tests\Feature;

  use Tests\TestCase;

  class SessionTest extends TestCase
  {
      public function test_session_value(): void
      {
          $response = $this->withSession(['locale' => 'es'])->get('/');

          $response->assertSessionHas('locale', 'es');
      }
  }
  ```
</CodeGroup>

### Aserciones sobre la sesión

| Método                                  | Descripción                                      |
| --------------------------------------- | ------------------------------------------------ |
| `assertSessionHas($key, $value)`        | La sesión contiene la clave y el valor indicados |
| `assertSessionHasAll([...])`            | La sesión contiene varios pares clave/valor      |
| `assertSessionHasErrors($keys)`         | La sesión contiene errores de validación         |
| `assertSessionHasErrorsIn($bag, $keys)` | Existen errores en el error bag indicado         |
| `assertSessionHasNoErrors()`            | La sesión no contiene errores de validación      |
| `assertSessionDoesntHaveErrors()`       | La sesión no contiene errores de validación      |
| `assertSessionMissing($key)`            | La sesión no contiene la clave indicada          |

## Pruebas de subida de archivos

El método `fake()` de la clase `Illuminate\Http\UploadedFile` genera archivos e imágenes ficticios.
Combinado con `Storage::fake()` puedes probar la subida de archivos con facilidad.

<CodeGroup>
  ```php Pest theme={null}
  <?php

  use Illuminate\Http\UploadedFile;
  use Illuminate\Support\Facades\Storage;

  test('se puede subir un avatar', function () {
      Storage::fake('avatars');

      $file = UploadedFile::fake()->image('avatar.jpg');

      $response = $this->post('/avatar', [
          'avatar' => $file,
      ]);

      Storage::disk('avatars')->assertExists($file->hashName());
  });
  ```

  ```php PHPUnit theme={null}
  <?php

  namespace Tests\Feature;

  use Illuminate\Http\UploadedFile;
  use Illuminate\Support\Facades\Storage;
  use Tests\TestCase;

  class AvatarTest extends TestCase
  {
      public function test_avatars_can_be_uploaded(): void
      {
          Storage::fake('avatars');

          $file = UploadedFile::fake()->image('avatar.jpg');

          $response = $this->post('/avatar', [
              'avatar' => $file,
          ]);

          Storage::disk('avatars')->assertExists($file->hashName());
      }
  }
  ```
</CodeGroup>

Para comprobar que un archivo no existe utiliza `assertMissing()`.

```php theme={null}
Storage::disk('avatars')->assertMissing('missing.jpg');
```

### Personalizar el archivo ficticio

Puedes indicar el tamaño de la imagen y del archivo, útil para probar reglas de validación.

```php theme={null}
// Ancho, alto y tamaño (en KB)
UploadedFile::fake()->image('avatar.jpg', $width, $height)->size(100);

// Crear un archivo de cualquier tipo
UploadedFile::fake()->create('document.pdf', $sizeInKilobytes);

// Indicar el MIME de forma explícita
UploadedFile::fake()->create(
    'document.pdf', $sizeInKilobytes, 'application/pdf'
);
```

## Pruebas de vistas

Puedes probar vistas renderizándolas directamente sin simular la petición HTTP.
`view()` acepta el nombre de la vista y, opcionalmente, un array de datos, y devuelve una instancia de `Illuminate\Testing\TestView`.

<CodeGroup>
  ```php Pest theme={null}
  <?php

  test('la vista welcome se renderiza', function () {
      $view = $this->view('welcome', ['name' => 'Taylor']);

      $view->assertSee('Taylor');
  });
  ```

  ```php PHPUnit theme={null}
  <?php

  namespace Tests\Feature;

  use Tests\TestCase;

  class ViewTest extends TestCase
  {
      public function test_a_welcome_view_can_be_rendered(): void
      {
          $view = $this->view('welcome', ['name' => 'Taylor']);

          $view->assertSee('Taylor');
      }
  }
  ```
</CodeGroup>

La clase `TestView` expone los siguientes métodos de aserción.

| Método                        | Descripción                                          |
| ----------------------------- | ---------------------------------------------------- |
| `assertSee($value)`           | La vista contiene la cadena indicada                 |
| `assertSeeInOrder([...])`     | La vista contiene las cadenas indicadas en ese orden |
| `assertSeeText($value)`       | El texto de la vista contiene la cadena indicada     |
| `assertSeeTextInOrder([...])` | El texto contiene las cadenas indicadas en ese orden |
| `assertDontSee($value)`       | La vista no contiene la cadena indicada              |
| `assertDontSeeText($value)`   | El texto no contiene la cadena indicada              |

Para obtener el HTML renderizado como cadena, castea la instancia `TestView`.

```php theme={null}
$contents = (string) $this->view('welcome');
```

Para pasar errores de validación a la vista utiliza `withViewErrors()`.

```php theme={null}
$view = $this->withViewErrors([
    'name' => ['Introduce un nombre válido.']
])->view('form');

$view->assertSee('Introduce un nombre válido.');
```

### Probar componentes

Con `blade()` puedes renderizar una plantilla Blade en bruto.

```php theme={null}
$view = $this->blade(
    '<x-component :name="$name" />',
    ['name' => 'Taylor']
);

$view->assertSee('Taylor');
```

Con `component()` renderizas un componente Blade y obtienes una instancia de `Illuminate\Testing\TestComponent`.

```php theme={null}
$view = $this->component(Profile::class, ['name' => 'Taylor']);

$view->assertSee('Taylor');
```

## Lista de aserciones sobre la respuesta

Métodos principales que ofrece la clase `Illuminate\Testing\TestResponse`.

### Estado HTTP

| Método                           | Descripción               |
| -------------------------------- | ------------------------- |
| `assertOk()`                     | 200 OK                    |
| `assertCreated()`                | 201 Created               |
| `assertAccepted()`               | 202 Accepted              |
| `assertNoContent($status = 204)` | 204 No Content            |
| `assertBadRequest()`             | 400 Bad Request           |
| `assertUnauthorized()`           | 401 Unauthorized          |
| `assertForbidden()`              | 403 Forbidden             |
| `assertNotFound()`               | 404 Not Found             |
| `assertUnprocessable()`          | 422 Unprocessable Entity  |
| `assertTooManyRequests()`        | 429 Too Many Requests     |
| `assertInternalServerError()`    | 500 Internal Server Error |
| `assertStatus($code)`            | El código indicado        |
| `assertSuccessful()`             | Cualquier 2xx             |
| `assertClientError()`            | Cualquier 4xx             |
| `assertServerError()`            | Cualquier 5xx             |

### Redirecciones

| Método                                        | Descripción                                       |
| --------------------------------------------- | ------------------------------------------------- |
| `assertRedirect($uri)`                        | Redirige a la URI indicada                        |
| `assertRedirectContains($string)`             | La URI de redirección contiene la cadena indicada |
| `assertRedirectToRoute($name, $params)`       | Redirige a la ruta con nombre indicada            |
| `assertRedirectToSignedRoute($name, $params)` | Redirige a la ruta firmada indicada               |
| `assertRedirectBack()`                        | Redirige a la URL anterior                        |

### Contenido

| Método                               | Descripción                                |
| ------------------------------------ | ------------------------------------------ |
| `assertSee($value, $escaped = true)` | La respuesta contiene el valor indicado    |
| `assertSeeInOrder(array $values)`    | Los valores aparecen en ese orden          |
| `assertSeeText($value)`              | La respuesta contiene el texto indicado    |
| `assertDontSee($value)`              | La respuesta no contiene el valor indicado |
| `assertDontSeeText($value)`          | La respuesta no contiene el texto indicado |
| `assertContent($value)`              | El cuerpo coincide con el valor indicado   |
| `assertDownload($filename)`          | Es una respuesta de descarga               |

### JSON

| Método                                     | Descripción                                               |
| ------------------------------------------ | --------------------------------------------------------- |
| `assertJson(array $data)`                  | La respuesta JSON contiene los datos indicados            |
| `assertExactJson(array $data)`             | La respuesta JSON coincide exactamente                    |
| `assertJsonPath($path, $value)`            | El valor del path indicado coincide                       |
| `assertJsonMissingPath($path)`             | El path indicado no existe                                |
| `assertJsonStructure(array $structure)`    | La respuesta tiene la estructura indicada                 |
| `assertJsonCount($count, $key)`            | La clave contiene el número indicado de elementos         |
| `assertJsonFragment(array $data)`          | La respuesta contiene el fragmento indicado               |
| `assertJsonMissing(array $data)`           | La respuesta no contiene los datos indicados              |
| `assertJsonIsArray()`                      | La respuesta es un array                                  |
| `assertJsonIsObject()`                     | La respuesta es un objeto                                 |
| `assertJsonValidationErrors($keys)`        | Contiene errores de validación en las claves indicadas    |
| `assertJsonMissingValidationErrors($keys)` | No contiene errores de validación en las claves indicadas |

### Cabeceras y cookies

| Método                              | Descripción                          |
| ----------------------------------- | ------------------------------------ |
| `assertHeader($headerName, $value)` | Existe la cabecera indicada          |
| `assertHeaderMissing($headerName)`  | No existe la cabecera indicada       |
| `assertCookie($name, $value)`       | Existe la cookie indicada            |
| `assertCookieExpired($name)`        | La cookie indicada está expirada     |
| `assertCookieMissing($name)`        | No existe la cookie indicada         |
| `assertPlainCookie($name, $value)`  | Existe la cookie sin cifrar indicada |

### Vistas

| Método                          | Descripción                                 |
| ------------------------------- | ------------------------------------------- |
| `assertViewIs($value)`          | Se devolvió la vista indicada               |
| `assertViewHas($key, $value)`   | La vista contiene el dato indicado          |
| `assertViewHasAll(array $data)` | La vista contiene todos los datos indicados |
| `assertViewMissing($key)`       | La vista no contiene la clave indicada      |

### Validación

| Método                 | Descripción                                          |
| ---------------------- | ---------------------------------------------------- |
| `assertValid($keys)`   | No hay errores de validación en las claves indicadas |
| `assertInvalid($keys)` | Hay errores de validación en las claves indicadas    |

## Recomendaciones para hacer TDD

<Tip>
  Las pruebas HTTP encajan muy bien con TDD (desarrollo guiado por tests). Ten en cuenta los siguientes puntos para sacarles el máximo partido.
</Tip>

<AccordionGroup>
  <Accordion title="Empieza por tests de tipo Feature">
    Los tests HTTP se sitúan en `tests/Feature/`. Empezar por el comportamiento externo (petición → respuesta) deja claro qué funcionalidad debes implementar.
  </Accordion>

  <Accordion title="Usa RefreshDatabase">
    En los tests que usen base de datos, aplica el trait `RefreshDatabase`. La base de datos se reinicia tras cada prueba y se evitan interferencias entre tests, lo que permite construir una suite estable independiente del orden de ejecución.
  </Accordion>

  <Accordion title="Aprovecha las factorías">
    Con `User::factory()->create()` y demás factorías es muy fácil crear datos de prueba. Definir estados (state) para casos concretos mejora mucho la legibilidad.
  </Accordion>

  <Accordion title="Un test, una aserción">
    Cada método de test debería verificar, en la medida de lo posible, una única cosa. Así resulta más fácil identificar la causa cuando falla. Aplicar el patrón AAA (Arrange, Act, Assert) hace los tests más legibles.
  </Accordion>

  <Accordion title="No olvides los tests de autenticación">
    En las rutas que requieran autenticación, cubre siempre tanto el caso «autenticado» como el «no autenticado». Detectarás pronto problemas de seguridad.
  </Accordion>
</AccordionGroup>

## Páginas relacionadas

<Card title="Introducción a los tests" icon="flask" href="/es/testing">
  Repasa los fundamentos del testing en Laravel y el uso de `php artisan test`.
</Card>


## Related topics

- [Introducción a las pruebas](/es/testing.md)
- [Pruebas avanzadas con Pest](/es/advanced/testing-pest.md)
- [Cliente HTTP](/es/http-client.md)
- [Pruebas de consola](/es/console-tests.md)
- [Pruebas de navegador (Dusk)](/es/dusk.md)
