Let's discuss a simple assertion of assertSee()
and a few alternative options. One of them is assertSeeText()
. What is the difference between those two?
AssertSee vs AssertSeeText
Let's imagine that you create a product with the name table
and use an assertSee
to check if that product exists on the screen seen on the page.
use App\Models\User;use App\Models\Product;use function Pest\Laravel\actingAs; beforeEach(function (): void { $this->user = User::factory()->create();}); test('homepage contains table product', function () { $product = Product::create([ 'name' => 'table', 'price' => 100, ]); actingAs($this->user) ->get('/products') ->assertStatus(200) ->assertSee($product->name);});
The trouble with that is that the asserted text includes HTML tags. Since it doesn't strip HTML tags, it asserts that the product name is seen in the HTML returned from the browser.
What is the possibility of the word "table" being included in HTML? Pretty high, right?
Launching that single test will pass because the word "table" is found and is seen as a product name in the View.
php artisan test --filter="homepage contains table product"
But what if I introduce a bug by removing the product name from the table?
<table> <thead> <tr> <th>Name</th> </tr> </thead> <tbody> @foreach($products as $product) <tr> <td> {{ $product->name }} </td> </tr> @endforeach </tbody></table>
I relaunched the test, which still passed because the <table>
HTML tag was found!
So, the test for string texts needs to be more accurate.
To avoid that problem, you should use assertSeeText()
.
use App\Models\User;use App\Models\Product;use function Pest\Laravel\actingAs; beforeEach(function (): void { $this->user = User::factory()->create();}); test('homepage contains table product', function () { $product = Product::create([ 'name' => 'table', 'price' => 100, ]); actingAs($this->user) ->get('/products') ->assertStatus(200) ->assertSee($product->name); ->assertSeeText($product->name); });
If we relaunch the test, it fails as it doesn't find the word table
anymore.
Now, let's return the product name to the table:
<table> <thead> <tr> <th>Name</th> </tr> </thead> <tbody> @foreach($products as $product) <tr> <td> {{ $product->name }} </td> </tr> @endforeach </tbody></table>
We see that the test now passes.
So, that is the difference between assertSee()
and assertSeeText()
.
AssertSeeInOrder
This is another very useful assertion. You can provide an array of strings to check if they appear on the page in precisely that order.
In the test, we created two products using a factory. Then, in the assertSeeInOrder()
array, we pass the products' names.
test('homepage contains products in order', function () { [$product1, $product2] = Product::factory(2)->create(); actingAs($this->user) ->get('/products') ->assertStatus(200) ->assertSeeInOrder([$product1->name, $product2->name]);});
After running this test, it should pass.
php artisan test --filter="homepage contains products in order"
However, if we change the order of the products, the test will fail as it will not find the provided product first.
PHPUnit example
In this course, we will try to provide examples with both Pest and PHPUnit. Many of them will be almost identical, but it is still helpful to see both.
For PHPUnit, assertions are used the same way. Only the syntax has a slight difference.
use App\Models\Product; class ProductsTest extends TestCase{ // ... public function test_homepage_contains_table_product(): void { $user = User::factory()->create(); $product = Product::create([ 'name' => 'table', 'price' => 100, ]); $response = $this->actingAs($user)->get('/products'); $response->assertStatus(200); $response->assertSeeText('table'); } public function test_homepage_contains_products_in_order(): void { $user = User::factory()->create(); [$product1, $product2] = Product::factory(2)->create(); $response = $this->actingAs($user)->get('/products'); $response->assertStatus(200); $response->assertSeeInOrder([$product1->name, $product2->name]); }}
No comments or questions yet...