jpmg's avatar
Level 13

theory question in pest test.

hello everyone.

I have a theory question. I am doing pest testing with the following configuration. in my TestCase.php

  abstract class TestCase extends BaseTestCase
   {
       use CreatesApplication;
       use LazilyRefreshDatabase;
  }

I testing an a Livewire component something like this.

	use function Pest\Livewire\livewire;
    uses()->group('user_form');
    beforeEach(function () {
            $this->user = User::factory()->create();
     });
     it('render component RegUsuario', function () {
         $this->actingAs($this->user);
         . . . . . . . 
     });
    it('has the main attributes in datauser array', function () {
      $this->actingAs($this->user);
         . . . . . . . 
    });
   it('can call listGender values', function () {
         $this->actingAs($this->user);
           . . . . . . . 
    });
   it('check if a Branch exists', function () {
        $this->actingAs($this->user);
        Branch::truncate();
        State::truncate();
        $newState = State::factory()->create();
        Branch::factory()->recycle($newState)->create();
        $component = callMainComponent();
        $arrayBranch = $component->viewData('listBranch');
        expect(count($arrayBranch))->toBeGreaterThanOrEqual(1);
  });

These would be my questions.

  1. I am using LazilyRefreshDatabase to fresh database, so why each time I call $this->actingAs($this->user) It effectively cleans the tables but when creating, for example, State::factory, the record begins with the id of 4 instead of 1, this happens when I run all the tests, but not when I run a specific one. why?

  2. In my test 'check if a Branch exists' I using a scope in my Branch model.

     public function scopeLisBrach(Builder $query): Builder
     {
       return $query->where('state_id', 1)->orderBy('branch_name');
    }
    

where state_id = 1 is Active and in my livewire component it looks like this.

public function render()
 {
     return view('livewire.principal.reg-usuario', [
          'listGender' => Gender::all()->sortBy('id'),
          'listIdentity' => Identity::all()->sortBy('id'),
          'listBranch' => Branch::lisBrach()->get(),
    ])
        ->extends('layouts.app', ['title' => 'Usuario'])
        ->section('workspace');
}

So to make it work for me by calling all the tests I did the following.

		Branch::truncate();
        State::truncate();
        $newState = State::factory()->create();
        Branch::factory()->recycle($newState)->create();

since I need the state_id =1 to be able to see all the active branches, but if I call the test 'check if a Branch exists' directly I don't need any of those codes.

Please someone can guide me or I don't know if I have the theory wrong. thank you

0 likes
1 reply
LaryAI's avatar
Level 58

It seems like you have two main questions here. Let's address each one separately.

  1. LazilyRefreshDatabase and ID sequencing:

When you use LazilyRefreshDatabase, it refreshes the database lazily, meaning it does not refresh the database before each test method. Instead, it starts a transaction before each test and rolls back after each test. This is why when you run a single test, you see the IDs starting from 1, because the database is fresh.

However, when you run all tests together, the IDs do not reset to 1 for each test because the database is not being dropped and recreated; it's just rolling back transactions. The auto-increment value for IDs in the database is not reset by a transaction rollback. This is why you see IDs starting from 4 or some other number after running multiple tests.

If you want to reset the IDs, you would need to refresh the database completely, which you can do by using RefreshDatabase instead of LazilyRefreshDatabase. However, this will slow down your tests because the database will be migrated for each test.

  1. Scope and test setup:

Regarding your scope and the test setup, it seems like you are trying to ensure that there is a State with id = 1 because your scope is looking for branches with state_id = 1. When you run all tests, the state with id = 1 might be created by a different test, and when you run the single test, it's not there, so you need to create it manually.

To ensure consistency, you can modify your test setup to always create a state with id = 1 before running your tests. You can do this by manually setting the ID when creating the state, assuming your database allows manual ID insertion:

State::truncate();
$newState = State::factory()->create(['id' => 1]);

Make sure that your database is set up to allow manual insertion of IDs, and be aware that this could interfere with other tests if they also expect to create a state with id = 1.

In summary, for consistent behavior across all tests, you may need to explicitly set up your database state before each test, and be aware of how the LazilyRefreshDatabase trait works with regard to database transactions and auto-incrementing IDs.

Please or to participate in this conversation.