diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 121e0041..6890e295 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -48,3 +48,45 @@ jobs: - name: Execute tests run: vendor/bin/phpunit --verbose + + tests-using-meilisearch: + runs-on: ubuntu-22.04 + + services: + meilisearch: + image: getmeili/meilisearch:latest + ports: + - 7700:7700 + env: + MEILI_MASTER_KEY: masterKey + MEILI_NO_ANALYTICS: true + + strategy: + fail-fast: true + matrix: + php: ['8.0', 8.1, 8.2, 8.3] + + name: PHP ${{ matrix.php }} using Meilisearch + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: dom, curl, libxml, mbstring, zip + ini-values: error_reporting=E_ALL + tools: composer:v2 + coverage: none + + - name: Install dependencies + run: | + composer update --prefer-dist --no-interaction --no-progress + + - name: Execute tests + run: vendor/bin/phpunit --verbose --group external-network,meilisearch + env: + MEILISEARCH_HOST: "http://localhost:7700" + MEILISEARCH_KEY: 'masterKey' diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 8357487f..7ac4f3c2 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -18,11 +18,25 @@ ./tests/Feature + + ./tests/Integration + + + + external-network + + + + diff --git a/testbench.yaml b/testbench.yaml index 91cd677b..5511d482 100644 --- a/testbench.yaml +++ b/testbench.yaml @@ -2,3 +2,6 @@ providers: - Laravel\Scout\ScoutServiceProvider migrations: true + +workbench: + install: true diff --git a/tests/Feature/MeilisearchEngineTest.php b/tests/Feature/MeilisearchEngineTest.php index 7ea798b1..60726b40 100644 --- a/tests/Feature/MeilisearchEngineTest.php +++ b/tests/Feature/MeilisearchEngineTest.php @@ -12,7 +12,10 @@ class MeilisearchEngineTest extends TestCase protected function defineEnvironment($app) { - $app->make('config')->set('scout.driver', 'meilisearch'); + $app->make('config')->set([ + 'scout.driver' => 'meilisearch', + 'scout.meilisearch.host' => 'http://localhost:7700', + ]); } public function test_the_meilisearch_client_can_be_initialized() diff --git a/tests/Fixtures/User.php b/tests/Fixtures/User.php new file mode 100644 index 00000000..908961f9 --- /dev/null +++ b/tests/Fixtures/User.php @@ -0,0 +1,24 @@ + + */ + public function toSearchableArray(): array + { + return [ + 'id' => (int) $this->id, + 'name' => $this->name, + ]; + } +} diff --git a/tests/Integration/AlgoliaSearchableTest.php b/tests/Integration/AlgoliaSearchableTest.php new file mode 100644 index 00000000..42c1b23c --- /dev/null +++ b/tests/Integration/AlgoliaSearchableTest.php @@ -0,0 +1,171 @@ +markTestSkipped(); + } + + $this->defineScoutEnvironment($app); + } + + /** + * Define database migrations. + * + * @return void + */ + protected function defineDatabaseMigrations() + { + $this->defineScoutDatabaseMigrations(); + } + + /** + * Perform any work that should take place once the database has finished refreshing. + * + * @return void + */ + protected function afterRefreshingDatabase() + { + $this->importScoutIndexFrom(User::class); + } + + public function test_it_can_use_basic_search() + { + $results = $this->itCanUseBasicSearch(); + + $this->assertSame([ + 11 => 'Larry Casper', + 1 => 'Laravel Framework', + 44 => 'Amos Larson Sr.', + 43 => 'Dana Larson Sr.', + 42 => 'Dax Larkin', + 41 => 'Gudrun Larkin', + 40 => 'Otis Larson MD', + 39 => 'Linkwood Larkin', + 20 => 'Prof. Larry Prosacco DVM', + 12 => 'Reta Larkin', + ], $results->pluck('name', 'id')->all()); + } + + public function test_it_can_use_basic_search_with_query_callback() + { + $results = $this->itCanUseBasicSearchWithQueryCallback(); + + $this->assertSame([ + 1 => 'Laravel Framework', + 44 => 'Amos Larson Sr.', + 43 => 'Dana Larson Sr.', + 42 => 'Dax Larkin', + 41 => 'Gudrun Larkin', + 40 => 'Otis Larson MD', + 12 => 'Reta Larkin', + ], $results->pluck('name', 'id')->all()); + } + + public function test_it_can_use_basic_search_to_fetch_keys() + { + $results = $this->itCanUseBasicSearchToFetchKeys(); + + $this->assertSame([ + '11', + '1', + '44', + '43', + '42', + '41', + '40', + '39', + '20', + '12', + ], $results->all()); + } + + public function test_it_can_use_basic_search_with_query_callback_to_fetch_keys() + { + $results = $this->itCanUseBasicSearchWithQueryCallbackToFetchKeys(); + + $this->assertSame([ + '11', + '1', + '44', + '43', + '42', + '41', + '40', + '39', + '20', + '12', + ], $results->all()); + } + + public function test_it_return_same_keys_with_query_callback() + { + $this->assertSame( + $this->itCanUseBasicSearchToFetchKeys()->all(), + $this->itCanUseBasicSearchWithQueryCallbackToFetchKeys()->all() + ); + } + + public function test_it_can_use_paginated_search() + { + [$page1, $page2] = $this->itCanUsePaginatedSearch(); + + $this->assertSame([ + 11 => 'Larry Casper', + 1 => 'Laravel Framework', + 44 => 'Amos Larson Sr.', + 43 => 'Dana Larson Sr.', + 42 => 'Dax Larkin', + ], $page1->pluck('name', 'id')->all()); + + $this->assertSame([ + 41 => 'Gudrun Larkin', + 40 => 'Otis Larson MD', + 39 => 'Linkwood Larkin', + 20 => 'Prof. Larry Prosacco DVM', + 12 => 'Reta Larkin', + ], $page2->pluck('name', 'id')->all()); + } + + public function test_it_can_use_paginated_search_with_query_callback() + { + [$page1, $page2] = $this->itCanUsePaginatedSearchWithQueryCallback(); + + $this->assertSame([ + 1 => 'Laravel Framework', + 44 => 'Amos Larson Sr.', + 43 => 'Dana Larson Sr.', + 42 => 'Dax Larkin', + ], $page1->pluck('name', 'id')->all()); + + $this->assertSame([ + 41 => 'Gudrun Larkin', + 40 => 'Otis Larson MD', + 12 => 'Reta Larkin', + ], $page2->pluck('name', 'id')->all()); + } + + protected static function scoutDriver(): string + { + return 'algolia'; + } +} diff --git a/tests/Integration/CollectionSearchableTest.php b/tests/Integration/CollectionSearchableTest.php new file mode 100644 index 00000000..04d19baf --- /dev/null +++ b/tests/Integration/CollectionSearchableTest.php @@ -0,0 +1,39 @@ +defineScoutEnvironment($app); + } + + public function test_it_can_use_basic_search_with_query_callback_to_fetch_keys() + { + $results = $this->itCanUseBasicSearchWithQueryCallbackToFetchKeys(); + + $this->assertNotSame([ + 44, + 43, + 42, + 41, + 40, + 12, + 1, + ], $results->all()); + + $this->assertSame($this->itCanUseBasicSearchToFetchKeys()->all(), $results->all()); + } + + protected static function scoutDriver(): string + { + return 'collection'; + } +} diff --git a/tests/Integration/DatabaseSearchableTest.php b/tests/Integration/DatabaseSearchableTest.php new file mode 100644 index 00000000..be35871d --- /dev/null +++ b/tests/Integration/DatabaseSearchableTest.php @@ -0,0 +1,137 @@ +defineScoutEnvironment($app); + } + + /** + * Define database migrations. + */ + protected function defineDatabaseMigrations(): void + { + $this->defineScoutDatabaseMigrations(); + } + + public function test_it_can_use_basic_search() + { + $results = $this->itCanUseBasicSearch(); + + $this->assertSame([ + 44 => 'Amos Larson Sr.', + 43 => 'Dana Larson Sr.', + 42 => 'Dax Larkin', + 41 => 'Gudrun Larkin', + 40 => 'Otis Larson MD', + 39 => 'Linkwood Larkin', + 20 => 'Prof. Larry Prosacco DVM', + 12 => 'Reta Larkin', + 11 => 'Larry Casper', + 1 => 'Laravel Framework', + ], $results->pluck('name', 'id')->all()); + } + + public function test_it_can_use_basic_search_with_query_callback() + { + $results = $this->itCanUseBasicSearchWithQueryCallback(); + + $this->assertSame([ + 44 => 'Amos Larson Sr.', + 43 => 'Dana Larson Sr.', + 42 => 'Dax Larkin', + 41 => 'Gudrun Larkin', + 40 => 'Otis Larson MD', + 12 => 'Reta Larkin', + 1 => 'Laravel Framework', + ], $results->pluck('name', 'id')->all()); + } + + public function test_it_can_use_basic_search_to_fetch_keys() + { + $results = $this->itCanUseBasicSearchToFetchKeys(); + + $this->assertSame([ + 44, + 43, + 42, + 41, + 40, + 39, + 20, + 12, + 11, + 1, + ], $results->all()); + } + + public function test_it_can_use_basic_search_with_query_callback_to_fetch_keys() + { + $results = $this->itCanUseBasicSearchWithQueryCallbackToFetchKeys(); + + $this->assertSame([ + 44, + 43, + 42, + 41, + 40, + 12, + 1, + ], $results->all()); + } + + public function test_it_can_use_paginated_search() + { + [$page1, $page2] = $this->itCanUsePaginatedSearch(); + + $this->assertSame([ + 44 => 'Amos Larson Sr.', + 43 => 'Dana Larson Sr.', + 42 => 'Dax Larkin', + 41 => 'Gudrun Larkin', + 40 => 'Otis Larson MD', + ], $page1->pluck('name', 'id')->all()); + + $this->assertSame([ + 39 => 'Linkwood Larkin', + 20 => 'Prof. Larry Prosacco DVM', + 12 => 'Reta Larkin', + 11 => 'Larry Casper', + 1 => 'Laravel Framework', + ], $page2->pluck('name', 'id')->all()); + } + + public function test_it_can_use_paginated_search_with_query_callback() + { + [$page1, $page2] = $this->itCanUsePaginatedSearchWithQueryCallback(); + + $this->assertSame([ + 44 => 'Amos Larson Sr.', + 43 => 'Dana Larson Sr.', + 42 => 'Dax Larkin', + 41 => 'Gudrun Larkin', + 40 => 'Otis Larson MD', + ], $page1->pluck('name', 'id')->all()); + + $this->assertSame([ + 12 => 'Reta Larkin', + 1 => 'Laravel Framework', + ], $page2->pluck('name', 'id')->all()); + } + + protected static function scoutDriver(): string + { + return 'database'; + } +} diff --git a/tests/Integration/MeilisearchSearchableTest.php b/tests/Integration/MeilisearchSearchableTest.php new file mode 100644 index 00000000..5405b077 --- /dev/null +++ b/tests/Integration/MeilisearchSearchableTest.php @@ -0,0 +1,173 @@ +markTestSkipped(); + + return; + } + + $this->defineScoutEnvironment($app); + } + + /** + * Define database migrations. + * + * @return void + */ + protected function defineDatabaseMigrations() + { + $this->defineScoutDatabaseMigrations(); + } + + /** + * Perform any work that should take place once the database has finished refreshing. + * + * @return void + */ + protected function afterRefreshingDatabase() + { + $this->importScoutIndexFrom(User::class); + } + + public function test_it_can_use_basic_search() + { + $results = $this->itCanUseBasicSearch(); + + $this->assertSame([ + 1 => 'Laravel Framework', + 11 => 'Larry Casper', + 12 => 'Reta Larkin', + 39 => 'Linkwood Larkin', + 40 => 'Otis Larson MD', + 41 => 'Gudrun Larkin', + 42 => 'Dax Larkin', + 43 => 'Dana Larson Sr.', + 44 => 'Amos Larson Sr.', + 20 => 'Prof. Larry Prosacco DVM', + ], $results->pluck('name', 'id')->all()); + } + + public function test_it_can_use_basic_search_with_query_callback() + { + $results = $this->itCanUseBasicSearchWithQueryCallback(); + + $this->assertSame([ + 1 => 'Laravel Framework', + 12 => 'Reta Larkin', + 40 => 'Otis Larson MD', + 41 => 'Gudrun Larkin', + 42 => 'Dax Larkin', + 43 => 'Dana Larson Sr.', + 44 => 'Amos Larson Sr.', + ], $results->pluck('name', 'id')->all()); + } + + public function test_it_can_use_basic_search_to_fetch_keys() + { + $results = $this->itCanUseBasicSearchToFetchKeys(); + + $this->assertSame([ + 1, + 11, + 12, + 39, + 40, + 41, + 42, + 43, + 44, + 20, + ], $results->all()); + } + + public function test_it_can_use_basic_search_with_query_callback_to_fetch_keys() + { + $results = $this->itCanUseBasicSearchWithQueryCallbackToFetchKeys(); + + $this->assertSame([ + 1, + 11, + 12, + 39, + 40, + 41, + 42, + 43, + 44, + 20, + ], $results->all()); + } + + public function test_it_return_same_keys_with_query_callback() + { + $this->assertSame( + $this->itCanUseBasicSearchToFetchKeys()->all(), + $this->itCanUseBasicSearchWithQueryCallbackToFetchKeys()->all() + ); + } + + public function test_it_can_use_paginated_search() + { + [$page1, $page2] = $this->itCanUsePaginatedSearch(); + + $this->assertSame([ + 1 => 'Laravel Framework', + 11 => 'Larry Casper', + 12 => 'Reta Larkin', + 39 => 'Linkwood Larkin', + 40 => 'Otis Larson MD', + ], $page1->pluck('name', 'id')->all()); + + $this->assertSame([ + 41 => 'Gudrun Larkin', + 42 => 'Dax Larkin', + 43 => 'Dana Larson Sr.', + 44 => 'Amos Larson Sr.', + 20 => 'Prof. Larry Prosacco DVM', + ], $page2->pluck('name', 'id')->all()); + } + + public function test_it_can_use_paginated_search_with_query_callback() + { + [$page1, $page2] = $this->itCanUsePaginatedSearchWithQueryCallback(); + + $this->assertSame([ + 1 => 'Laravel Framework', + 12 => 'Reta Larkin', + 40 => 'Otis Larson MD', + ], $page1->pluck('name', 'id')->all()); + + $this->assertSame([ + 41 => 'Gudrun Larkin', + 42 => 'Dax Larkin', + 43 => 'Dana Larson Sr.', + 44 => 'Amos Larson Sr.', + ], $page2->pluck('name', 'id')->all()); + } + + protected static function scoutDriver(): string + { + return 'meilisearch'; + } +} diff --git a/tests/Integration/SearchableTests.php b/tests/Integration/SearchableTests.php new file mode 100644 index 00000000..9856f719 --- /dev/null +++ b/tests/Integration/SearchableTests.php @@ -0,0 +1,107 @@ +set('scout.driver', static::scoutDriver()); + } + + /** + * Define database migrations. + */ + protected function defineScoutDatabaseMigrations(): void + { + $this->loadLaravelMigrations(); + + $collect = LazyCollection::make(function () { + yield ['name' => 'Laravel Framework']; + + foreach (range(2, 10) as $key) { + yield ['name' => "Example {$key}"]; + } + + yield ['name' => 'Larry Casper', 'email_verified_at' => null]; + yield ['name' => 'Reta Larkin']; + + foreach (range(13, 19) as $key) { + yield ['name' => "Example {$key}"]; + } + + yield ['name' => 'Prof. Larry Prosacco DVM', 'email_verified_at' => null]; + + foreach (range(21, 38) as $key) { + yield ['name' => "Example {$key}", 'email_verified_at' => null]; + } + + yield ['name' => 'Linkwood Larkin', 'email_verified_at' => null]; + yield ['name' => 'Otis Larson MD']; + yield ['name' => 'Gudrun Larkin']; + yield ['name' => 'Dax Larkin']; + yield ['name' => 'Dana Larson Sr.']; + yield ['name' => 'Amos Larson Sr.']; + }); + + UserFactory::new() + ->times(44) + ->state(new Sequence(...$collect->all())) + ->create(); + } + + protected function itCanUseBasicSearch() + { + return User::search('lar')->take(10)->get(); + } + + protected function itCanUseBasicSearchWithQueryCallback() + { + return User::search('lar')->take(10)->query(function ($query) { + return $query->whereNotNull('email_verified_at'); + })->get(); + } + + protected function itCanUseBasicSearchToFetchKeys() + { + return User::search('lar')->take(10)->keys(); + } + + protected function itCanUseBasicSearchWithQueryCallbackToFetchKeys() + { + return User::search('lar')->take(10)->query(function ($query) { + return $query->whereNotNull('email_verified_at'); + })->keys(); + } + + protected function itCanUsePaginatedSearch() + { + return [ + User::search('lar')->take(10)->paginate(5, 'page', 1), + User::search('lar')->take(10)->paginate(5, 'page', 2), + ]; + } + + protected function itCanUsePaginatedSearchWithQueryCallback() + { + $queryCallback = function ($query) { + return $query->whereNotNull('email_verified_at'); + }; + + return [ + User::search('lar')->take(10)->query($queryCallback)->paginate(5, 'page', 1), + User::search('lar')->take(10)->query($queryCallback)->paginate(5, 'page', 2), + ]; + } +} diff --git a/tests/Integration/TestCase.php b/tests/Integration/TestCase.php new file mode 100644 index 00000000..718f7305 --- /dev/null +++ b/tests/Integration/TestCase.php @@ -0,0 +1,41 @@ + $model]); + } + + artisan($this, 'scout:import', ['model' => $model]); + + sleep(1); + } + + /** + * Clean up the testing environment before the next test case. + * + * @return void + */ + public static function tearDownAfterClass(): void + { + remote('scout:delete-all-indexes', [ + 'SCOUT_DRIVER' => static::scoutDriver(), + ])->mustRun(); + + parent::tearDownAfterClass(); + } + + abstract protected static function scoutDriver(): string; +}