laravel-scout-array-driver icon indicating copy to clipboard operation
laravel-scout-array-driver copied to clipboard

Add an ability to fake search response data

Open Sti3bas opened this issue 1 year ago • 7 comments
trafficstars

It is still work in progress and there might be API changes.

Usage:

Search::fakeResponseData([
   'foo' => 'bar'
])->query('test');

$search = User::search('test')->raw();

$this->assertEquals('bar', $search['foo']);

It is possible to provide filters (supports all Laravel\Scout\Builder methods) to fake response data for a specific search:

Search::fakeResponseData([
   'foo' => 'bar'
])
   ->within('users')
   ->where('foo', 'bar'),
   ->whereIn('foo', ['bar', 'baz'])
   ->whereNotIn('foo', ['foo', 'bar'])
   ->withTrashed()
   ->onlyTrashed()
   ->take(50)
   ->orderBy('test', 'desc')
   ->latest('created_at')
   ->oldest('updated_at')
   ->options(['foo' => 'bar']);

TODO:

  • provide a way to specify global fake response data without having to specify filters
  • add more tests
  • test all edges cases

Sti3bas avatar Oct 08 '24 12:10 Sti3bas

lets say you have some that fetches from two diffrent scout models? Would you be able to fake both responses. So you would get one fake response for the User and the another for the company?

Search::fakeResponseData([ 'foo' => 'bar' ])->model(User::class);

Search::fakeResponseData([ 'foo' => 'abc' ])->model(Company::class);

// code in some class User::search(...)->raw() Company::search(...)->raw()

christian-nielsen avatar Oct 14 '24 09:10 christian-nielsen

@christian-nielsen yes, we have within method for that:

Search::fakeResponseData([
   'foo' => 'bar'
])->within('users');

Search::fakeResponseData([
   'foo' => 'baz'
])->within('posts'); // or $post->searchableAs()

If you don't call within then I think it would be nice if response would be faked for all indexes by default.

I'm not sure if it would be possible to use User::class as a value since index value is returned from searchableAs method so we need to have a model instance for that. Maybe it would be OK to use (new $className)->searchableAs() inside within method.

Sti3bas avatar Oct 14 '24 10:10 Sti3bas

What about also allowing class model name:

Search::fakeResponseData([
   'foo' => 'baz'
])->within(Post::class);

if you give it a class model name, it will do this underlaying: (new $className)->searchableAs()

christian-nielsen avatar Oct 15 '24 08:10 christian-nielsen

@christian-nielsen it might be fine for models which returns a static value, but in theory it might depend on some database fields. I think it would be nice to support all combinations: string, model instance, model class name.

Sti3bas avatar Oct 15 '24 08:10 Sti3bas

I tried the branch, If I set the hits-key, it not being set as the items.

Search::fakeResponseData([ 'hits' => [ [ 'id' => ..., ] ] ])->within('posts');

christian-nielsen avatar Feb 10 '25 13:02 christian-nielsen

@christian-nielsen you can already mock model records with fakeRecord method: https://github.com/Sti3bas/laravel-scout-array-driver?tab=readme-ov-file#fakerecordmodel-data-merge--true-index--null

fakeResponseData is intended to mock additional parameters beyond total and hits.

Sti3bas avatar Feb 10 '25 13:02 Sti3bas

@christian-nielsen you can already mock model records with fakeRecord method: https://github.com/Sti3bas/laravel-scout-array-driver?tab=readme-ov-file#fakerecordmodel-data-merge--true-index--null

fakeResponseData is intended to mock additional parameters beyond total and hits.

I understand. The reason why it did not work, is because I did not understand that it needed to match on all params:

$builder->wheres == $this->fakeBuilder->wheres &&
            $builder->whereIns == $this->fakeBuilder->whereIns &&
            $builder->whereNotIns == $this->fakeBuilder->whereNotIns &&
            $builder->limit == $this->fakeBuilder->limit &&
            $builder->orders == $this->fakeBuilder->orders &&
            $builder->options == $this->fakeBuilder->options &&
            $builder->query == $this->fakeBuilder->query;

A way to just force use an index and ignore other params would be nice

christian-nielsen avatar Feb 10 '25 14:02 christian-nielsen