Hi there! I'm using PestPHP in order to feature test my API.
I've got the following test in order to check whether an user is synced with the external service:
it('should sync data when external_id present', function () {
app()->singleton('ExternalService', function () {
return new MockExternalService();
});
$user = user(Role::USER, fake()->uuid());
$response = $this->actingAs($user, 'api')
->json('GET', '/api/users/me');
$response->assertStatus(200);
expect($response->getData())
->toBeObject()
->first_name->not->toBe($user->first_name)
->name->not->toBe($user->name);
});
The MockExternalService overwrites the function getContact() so that the external service is not actually called.
class MockExternalService
{
public function getContact(string $uuid)
{
$response = [
"firstName" => fake()->firstName(),
"lastName" => fake()->lastName(),
];
// Contact is a DTO
return Contact::from($response);
}
}
I've got a User model which uses the trait "Syncable.php". This trait contains the following code in order to sync the object when it's retrieved:
trait Syncable
{
protected static function bootSyncable()
{
static::retrieved(function ($object) {
$data = $object->fetch() ?? [];
$object->sync($data);
});
}
public function sync($data = null)
{
if ($data) {
$this->updateQuietly(array_merge($data, ['synced_at' => Carbon::now()]));
}
}
}
On my User model I have the fetch() function that retrieves and returns the data from an external service if an external_id exists and 15 minutes have elapsed:
public function fetch()
{
if ($this->external_id && ($this->synced_at ? Carbon::now()->sub('minutes', 15)->isAfter($this->synced_at) : true)) {
$data = ExternalService::getContact($this->external_id);
// serialize() transforms the data of the DTO to data that the user model can work with
return $data->serialize();
}
else {
return [];
}
}
The issue: It looks like the retrieved model event is never fired. When retrieving the current user manually, it sync's the user perfectly. When retrieving the user via the test, the first_name and name property remain the same.
Also executing $user->fetch() in the test will return the mock data that differs from the initial user first_name and name.
Thanks in advance for any help!