Are you sure you want to delete this entry?
+ +| Site | +Route | +
|---|---|
| + |
+ |
+
Are you sure you want to remove this page?
+Only the references will be removed. Entries will not be deleted.
+ ++ {{ __('messages.structures_empty') }} +
+ +| Site | -Route | -Tree | -
|---|---|---|
|
-
-
- {{ site.name }}
- |
-
- |
-
- {{ __('messages.structure_wizard_description') }} -
-{{ __('statamic::messages.collection_next_steps_configure_description') }}
{{ trans key="test::messages.hello" }}
'); - $this->makeCollection()->save(); + $this->makeCollection()->sites(['english', 'french'])->save(); tap($this->makePage('about', ['with' => ['template' => 'some_template']])->locale('english'))->save(); tap($this->makePage('le-about', ['with' => ['template' => 'some_template']])->locale('french'))->save(); @@ -377,7 +377,7 @@ private function makePage($slug, $attributes = []) private function makeCollection() { return Collection::make('pages') - ->route('{slug}') + ->routes('{slug}') ->template('default') ->entryBlueprints(['empty']); } diff --git a/tests/Routing/ResolveRedirectTest.php b/tests/Routing/ResolveRedirectTest.php new file mode 100644 index 00000000000..36e46756413 --- /dev/null +++ b/tests/Routing/ResolveRedirectTest.php @@ -0,0 +1,113 @@ +assertEquals('http://test.com', $resolver('http://test.com')); + $this->assertEquals('https://test.com', $resolver('https://test.com')); + $this->assertEquals('/test', $resolver('/test')); + $this->assertEquals('test', $resolver('test')); + $this->assertSame(404, $resolver('404')); + $this->assertSame(404, $resolver(404)); + $this->assertSame('4-oh-4', $resolver('4-oh-4')); // strings with numbers won't become ints + $this->assertNull($resolver(null)); + } + + /** @test */ + function it_cant_resolve_a_first_child_without_a_parent() + { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('Cannot resolve a page\'s child redirect without providing a page.'); + + $resolver = new ResolveRedirect; + + $this->assertEquals('/page/child', $resolver('@child')); + } + + /** @test */ + function it_cannot_resolve_a_first_child_redirect_if_the_parent_is_not_a_page() + { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('Cannot resolve a page\'s child redirect without providing a page.'); + + $resolver = new ResolveRedirect; + + $this->assertEquals('/page/child', $resolver('@child', 'not a page object')); + } + + /** @test */ + function it_resolves_first_child() + { + $resolver = new ResolveRedirect; + + $child = Mockery::mock(Page::class); + $child->shouldReceive('url')->andReturn('/parent/first-child'); + + $children = Mockery::mock(Pages::class); + $children->shouldReceive('all')->andReturn(collect([$child])); + + $parent = Mockery::mock(Page::class); + $parent->shouldReceive('pages')->andReturn($children); + + $this->assertEquals('/parent/first-child', $resolver('@child', $parent)); + } + + /** @test */ + function it_resolves_first_child_through_an_entry() + { + $resolver = new ResolveRedirect; + + $child = Mockery::mock(Page::class); + $child->shouldReceive('url')->andReturn('/parent/first-child'); + + $children = Mockery::mock(Pages::class); + $children->shouldReceive('all')->andReturn(collect([$child])); + + $parentPage = Mockery::mock(Page::class); + $parentPage->shouldReceive('pages')->andReturn($children); + + $parent = Mockery::mock(Entry::class); + $parent->shouldReceive('page')->andReturn($parentPage); + + $this->assertEquals('/parent/first-child', $resolver('@child', $parent)); + } + + /** @test */ + function a_parent_without_a_child_resolves_to_a_404() + { + $resolver = new ResolveRedirect; + + $pages = Mockery::mock(Pages::class); + $pages->shouldReceive('all')->andReturn(collect([])); + + $parent = Mockery::mock(Page::class); + $parent->shouldReceive('pages')->andReturn($pages); + + $this->assertEquals('404', $resolver('@child', $parent)); + } + + /** @test */ + function it_resolves_references_to_entries() + { + $resolver = new ResolveRedirect; + + $entry = Mockery::mock(Entry::class)->shouldReceive('url')->once()->andReturn('/the-entry')->getMock(); + Facades\Entry::shouldReceive('find')->with('123')->once()->andReturn($entry); + + $this->assertEquals('/the-entry', $resolver('entry::123')); + } +} diff --git a/tests/Routing/RoutesTest.php b/tests/Routing/RoutesTest.php index 8977791f1e0..bc590207b77 100644 --- a/tests/Routing/RoutesTest.php +++ b/tests/Routing/RoutesTest.php @@ -122,7 +122,7 @@ function it_loads_content() /** @test */ function it_loads_content_by_uri() { - $collection = Collection::make('pages')->route('/{slug}')->save(); + $collection = Collection::make('pages')->routes('/{slug}')->save(); EntryFactory::id('pages-blog')->collection($collection)->slug('blog')->data(['title' => 'Blog'])->create(); $this->viewShouldReturnRaw('layout', '{{ template_content }}'); diff --git a/tests/Stache/FeatureTest.php b/tests/Stache/FeatureTest.php index bea1a41bee0..2b8871a004e 100644 --- a/tests/Stache/FeatureTest.php +++ b/tests/Stache/FeatureTest.php @@ -20,6 +20,7 @@ use Statamic\Stache\Stores\AggregateStore; use Statamic\Stache\Stores\CollectionsStore; use Statamic\Contracts\Structures\StructureRepository; +use Statamic\Facades\Nav; class FeatureTest extends TestCase { @@ -32,7 +33,7 @@ public function setUp(): void $stache->store('taxonomies')->directory($dir . '/content/taxonomies'); $stache->store('collections')->directory($dir . '/content/collections'); $stache->store('entries')->directory($dir . '/content/collections'); - $stache->store('structures')->directory($dir . '/content/structures'); + $stache->store('navigation')->directory($dir . '/content/navigation'); $stache->store('globals')->directory($dir . '/content/globals'); $stache->store('asset-containers')->directory($dir . '/content/assets'); $stache->store('users')->directory($dir . '/users'); @@ -130,6 +131,7 @@ function it_gets_a_user() function it_gets_an_entry_by_uri() { $entry = Entry::findByUri('/numeric/two'); + $this->assertInstanceOf(\Statamic\Contracts\Entries\Entry::class, $entry); $this->assertEquals('numeric-two', $entry->id()); $this->assertEquals('Two', $entry->get('title')); @@ -140,28 +142,56 @@ function it_gets_an_entry_by_uri() function it_gets_an_entry_in_structure_by_uri() { $entry = Entry::findByUri('/about/board/directors'); + $this->assertInstanceOf(\Statamic\Structures\Page::class, $entry); $this->assertEquals('pages-directors', $entry->id()); $this->assertEquals('Directors', $entry->title()); } + /** @test */ + function it_returns_null_when_cannot_find_entry_by_uri() + { + $this->assertNull(Entry::findByUri('/unknown')); + } + /** @test */ function it_gets_structures() { - $this->assertEquals(2, Structure::all()->count()); + $this->assertEquals(3, Structure::all()->count()); } /** @test */ function it_gets_a_structure() { - $structure = Structure::find('pages'); - $this->assertEquals('pages', $structure->handle()); + $structure = Structure::find('footer'); + $this->assertEquals('footer', $structure->handle()); + // TODO: Some more assertions + } + + /** @test */ + function it_gets_navs() + { + $this->assertEquals(2, Nav::all()->count()); + } + + /** @test */ + function it_gets_a_nav() + { + $structure = Nav::find('footer'); + $this->assertEquals('footer', $structure->handle()); // TODO: Some more assertions } + /** @test */ + function it_gets_a_collection_structure() + { + $structure = Structure::find('collection::pages'); + $this->assertEquals('collection::pages', $structure->handle()); + } + /** @test */ function it_saves_structures() { - $structure = Structure::find('pages'); + $structure = Structure::find('footer'); $repo = Mockery::mock(StructureRepository::class); $repo->shouldReceive('save')->with($structure); @@ -176,7 +206,6 @@ function saving_a_collection_writes_it_to_file() Collection::make('new') ->title('New Collection') ->defaultPublishState(false) - ->orderable(true) ->dated(true) ->revisionsEnabled(true) ->cascade(['foo' => 'bar']) @@ -184,7 +213,7 @@ function saving_a_collection_writes_it_to_file() $this->assertStringEqualsFile( $path = __DIR__.'/__fixtures__/content/collections/new.yaml', - "title: 'New Collection'\norderable: true\nrevisions: true\ndate: true\ndefault_status: draft\ninject:\n foo: bar\n" + "title: 'New Collection'\nrevisions: true\ndate: true\ndefault_status: draft\ninject:\n foo: bar\n" ); @unlink($path); } diff --git a/tests/Stache/Repositories/CollectionRepositoryTest.php b/tests/Stache/Repositories/CollectionRepositoryTest.php index 9e35e26e2c4..3452f6a1f06 100644 --- a/tests/Stache/Repositories/CollectionRepositoryTest.php +++ b/tests/Stache/Repositories/CollectionRepositoryTest.php @@ -6,7 +6,7 @@ use Statamic\Stache\Stache; use Statamic\Entries\Collection; use Statamic\Stache\Stores\EntriesStore; -use Statamic\Stache\Stores\StructuresStore; +use Statamic\Stache\Stores\NavigationStore; use Statamic\Stache\Stores\CollectionsStore; use Statamic\Facades\Collection as CollectionAPI; use Statamic\Stache\Repositories\CollectionRepository; @@ -24,7 +24,7 @@ public function setUp(): void $stache->registerStores([ (new CollectionsStore($stache, app('files')))->directory($this->directory), (new EntriesStore($stache, app('files')))->directory($this->directory), - (new StructuresStore($stache, app('files')))->directory(__DIR__.'/../__fixtures__/content/structures'), + (new NavigationStore($stache, app('files')))->directory(__DIR__.'/../__fixtures__/content/navigation'), ]); $this->repo = new CollectionRepository($stache); diff --git a/tests/Stache/Repositories/EntryRepositoryTest.php b/tests/Stache/Repositories/EntryRepositoryTest.php index bd9fe72821a..f8d71e6b1da 100644 --- a/tests/Stache/Repositories/EntryRepositoryTest.php +++ b/tests/Stache/Repositories/EntryRepositoryTest.php @@ -10,7 +10,7 @@ use Statamic\Stache\Stores\EntriesStore; use Statamic\Contracts\Entries\Entry; use Statamic\Entries\EntryCollection; -use Statamic\Stache\Stores\StructuresStore; +use Statamic\Stache\Stores\NavigationStore; use Statamic\Stache\Stores\CollectionsStore; use Statamic\Stache\Repositories\EntryRepository; use Statamic\Exceptions\InvalidLocalizationException; @@ -29,7 +29,7 @@ public function setUp(): void $this->stache->registerStores([ (new CollectionsStore($this->stache, app('files')))->directory($this->directory), (new EntriesStore($this->stache, app('files')))->directory($this->directory), - (new StructuresStore($this->stache, app('files')))->directory(__DIR__.'/../__fixtures__/content/structures'), + (new NavigationStore($this->stache, app('files')))->directory(__DIR__.'/../__fixtures__/content/navigation'), ]); $this->repo = new EntryRepository($this->stache); diff --git a/tests/Stache/Repositories/NavigationRepositoryTest.php b/tests/Stache/Repositories/NavigationRepositoryTest.php new file mode 100644 index 00000000000..627f489a3e8 --- /dev/null +++ b/tests/Stache/Repositories/NavigationRepositoryTest.php @@ -0,0 +1,78 @@ +sites(['en']); + $this->directory = __DIR__.'/../__fixtures__/content/navigation'; + $stache->registerStores([ + (new CollectionsStore($stache, app('files')))->directory(__DIR__.'/../__fixtures__/content/collections'), + (new EntriesStore($stache, app('files')))->directory(__DIR__.'/../__fixtures__/content/collections'), + (new NavigationStore($stache, app('files')))->directory($this->directory) + ]); + $this->app->instance(Stache::class, $stache); + + $this->repo = new NavigationRepository($stache); + } + + /** @test */ + function it_gets_all_navs() + { + $navs = $this->repo->all(); + + $this->assertInstanceOf(Collection::class, $navs); + $this->assertCount(2, $navs); + $this->assertEveryItemIsInstanceOf(Structure::class, $navs); + + $ordered = $navs->sortBy->handle()->values(); + $this->assertEquals(['footer', 'sidebar'], $ordered->map->handle()->all()); + $this->assertEquals(['Footer', 'Sidebar'], $ordered->map->title()->all()); + } + + /** @test */ + function it_gets_a_nav_by_handle() + { + tap($this->repo->findByHandle('sidebar'), function ($nav) { + $this->assertInstanceOf(Structure::class, $nav); + $this->assertEquals('sidebar', $nav->handle()); + $this->assertEquals('Sidebar', $nav->title()); + }); + + tap($this->repo->findByHandle('footer'), function ($nav) { + $this->assertInstanceOf(Structure::class, $nav); + $this->assertEquals('footer', $nav->handle()); + $this->assertEquals('Footer', $nav->title()); + }); + + $this->assertNull($this->repo->findByHandle('unknown')); + } + + /** @test */ + function it_saves_a_nav_to_the_stache_and_to_a_file() + { + $structure = (new \Statamic\Structures\Nav)->handle('new'); + $structure->addTree($structure->makeTree('en')); + + $this->assertNull($this->repo->findByHandle('new')); + + $this->repo->save($structure); + + $this->assertNotNull($this->repo->findByHandle('new')); + $this->assertFileExists($this->directory.'/new.yaml'); + @unlink($this->directory.'/new.yaml'); + } +} diff --git a/tests/Stache/Repositories/StructureRepositoryTest.php b/tests/Stache/Repositories/StructureRepositoryTest.php deleted file mode 100644 index f7502ee51ad..00000000000 --- a/tests/Stache/Repositories/StructureRepositoryTest.php +++ /dev/null @@ -1,87 +0,0 @@ -sites(['en']); - $this->directory = __DIR__.'/../__fixtures__/content/structures'; - $stache->registerStores([ - (new CollectionsStore($stache, app('files')))->directory(__DIR__.'/../__fixtures__/content/collections'), - (new EntriesStore($stache, app('files')))->directory(__DIR__.'/../__fixtures__/content/collections'), - (new StructuresStore($stache, app('files')))->directory($this->directory) - ]); - $this->app->instance(Stache::class, $stache); - - $this->repo = new StructureRepository($stache); - } - - /** @test */ - function it_gets_all_structures() - { - $structures = $this->repo->all(); - - $this->assertInstanceOf(Collection::class, $structures); - $this->assertCount(2, $structures); - $this->assertEveryItemIsInstanceOf(Structure::class, $structures); - - $ordered = $structures->sortBy->handle()->values(); - $this->assertEquals(['footer', 'pages'], $ordered->map->handle()->all()); - $this->assertEquals(['Footer', 'Pages'], $ordered->map->title()->all()); - } - - /** @test */ - function it_gets_a_structure_by_handle() - { - tap($this->repo->findByHandle('pages'), function ($structure) { - $this->assertInstanceOf(Structure::class, $structure); - $this->assertEquals('pages', $structure->handle()); - $this->assertEquals('Pages', $structure->title()); - }); - - tap($this->repo->findByHandle('footer'), function ($structure) { - $this->assertInstanceOf(Structure::class, $structure); - $this->assertEquals('footer', $structure->handle()); - $this->assertEquals('Footer', $structure->title()); - }); - - $this->assertNull($this->repo->findByHandle('unknown')); - } - - /** @test */ - function it_saves_a_structure_to_the_stache_and_to_a_file() - { - $structure = (new \Statamic\Structures\Structure)->handle('new'); - $structure->addTree($structure->makeTree('en')); - - $this->assertNull($this->repo->findByHandle('new')); - - $this->repo->save($structure); - - $this->assertNotNull($this->repo->findByHandle('new')); - $this->assertFileExists($this->directory.'/new.yaml'); - @unlink($this->directory.'/new.yaml'); - } - - /** @test */ - function it_gets_an_entry_by_uri() - { - $entry = $this->repo->findEntryByUri('/about/board/directors'); - $this->assertEquals('Directors', $entry->title()); - $this->assertEquals('/about/board/directors', $entry->uri()); - $this->assertNull($this->repo->findEntryByUri('/unknown')); - } -} diff --git a/tests/Stache/Stores/EntriesStoreTest.php b/tests/Stache/Stores/EntriesStoreTest.php index d38c7452157..69549d7a6cf 100644 --- a/tests/Stache/Stores/EntriesStoreTest.php +++ b/tests/Stache/Stores/EntriesStoreTest.php @@ -129,4 +129,10 @@ function it_saves_to_disk() @unlink($path); $this->assertFileNotExists($path); } + + /** @test */ + function it_ignores_entries_in_a_site_subdirectory_where_the_collection_doesnt_have_that_site_enabled() + { + $this->markTestIncomplete(); + } } diff --git a/tests/Stache/Stores/StructuresStoreTest.php b/tests/Stache/Stores/NavigationStoreTest.php similarity index 84% rename from tests/Stache/Stores/StructuresStoreTest.php rename to tests/Stache/Stores/NavigationStoreTest.php index 7cc0b874126..75e43cc9ead 100644 --- a/tests/Stache/Stores/StructuresStoreTest.php +++ b/tests/Stache/Stores/NavigationStoreTest.php @@ -2,17 +2,18 @@ namespace Tests\Stache\Stores; -use Mockery; -use Statamic\Facades; -use Tests\TestCase; -use Statamic\Stache\Stache; -use Illuminate\Filesystem\Filesystem; use Facades\Statamic\Stache\Traverser; -use Statamic\Stache\Stores\StructuresStore; +use Illuminate\Filesystem\Filesystem; +use Mockery; +use Statamic\Contracts\Structures\Nav; use Statamic\Contracts\Structures\Structure; +use Statamic\Facades; use Statamic\Facades\Path; +use Statamic\Stache\Stache; +use Statamic\Stache\Stores\NavigationStore; +use Tests\TestCase; -class StructuresStoreTest extends TestCase +class NavigationStoreTest extends TestCase { function setUp(): void { @@ -21,7 +22,7 @@ function setUp(): void mkdir($this->tempDir = __DIR__.'/tmp'); $stache = (new Stache)->sites(['en']); - $this->store = (new StructuresStore($stache, app('files')))->directory($this->tempDir); + $this->store = (new NavigationStore($stache, app('files')))->directory($this->tempDir); Facades\Stache::registerStore($this->store); } @@ -63,22 +64,23 @@ function it_makes_structure_instances_from_files() $contents = <<<'EOT' title: Pages route: '{parent_uri}/{slug}' -root: pages-home tree: - - page: pages-about + entry: pages-home + - + entry: pages-about children: - - page: pages-board + entry: pages-board children: - - page: pages-directors + entry: pages-directors - - page: pages-blog # (/blog) + entry: pages-blog # (/blog) EOT; $item = $this->store->makeItemFromFile(Path::tidy($this->tempDir.'/pages.yaml'), $contents); - $this->assertInstanceOf(Structure::class, $item); + $this->assertInstanceOf(Nav::class, $item); $this->assertEquals('pages', $item->handle()); $this->assertEquals('Pages', $item->title()); // TODO: Some more assertions @@ -89,14 +91,14 @@ function it_uses_the_filename_as_the_item_key() { $this->assertEquals( 'test', - $this->store->getItemKey(Facades\Structure::make()->handle('test')) + $this->store->getItemKey(Facades\Nav::make()->handle('test')) ); } /** @test */ function it_saves_to_disk() { - $structure = Facades\Structure::make()->handle('pages'); + $structure = Facades\Nav::make()->handle('pages'); $structure->addTree($structure->makeTree('en')); $this->store->save($structure); diff --git a/tests/Stache/__fixtures__/content/collections/pages.yaml b/tests/Stache/__fixtures__/content/collections/pages.yaml index a0b02f7ed17..d8c15ccee90 100644 --- a/tests/Stache/__fixtures__/content/collections/pages.yaml +++ b/tests/Stache/__fixtures__/content/collections/pages.yaml @@ -1,3 +1,17 @@ title: Pages route: '{parent_uri}/{slug}' -structure: pages +structure: + root: true + tree: + - + entry: pages-home + - + entry: pages-about + children: + - + entry: pages-board + children: + - + entry: pages-directors + - + entry: pages-blog diff --git a/tests/Stache/__fixtures__/content/structures/footer.yaml b/tests/Stache/__fixtures__/content/navigation/footer.yaml similarity index 85% rename from tests/Stache/__fixtures__/content/structures/footer.yaml rename to tests/Stache/__fixtures__/content/navigation/footer.yaml index aed6a330991..b637a284e92 100644 --- a/tests/Stache/__fixtures__/content/structures/footer.yaml +++ b/tests/Stache/__fixtures__/content/navigation/footer.yaml @@ -1,6 +1,5 @@ title: Footer root: pages-home -route: '{slug}' tree: - entry: pages-about diff --git a/tests/Stache/__fixtures__/content/navigation/sidebar.yaml b/tests/Stache/__fixtures__/content/navigation/sidebar.yaml new file mode 100644 index 00000000000..6be10f096aa --- /dev/null +++ b/tests/Stache/__fixtures__/content/navigation/sidebar.yaml @@ -0,0 +1,6 @@ +title: Sidebar +tree: + - + entry: pages-contact + - + entry: pages-about diff --git a/tests/Stache/__fixtures__/content/structures/pages.yaml b/tests/Stache/__fixtures__/content/structures/pages.yaml deleted file mode 100644 index 7d7f8a42090..00000000000 --- a/tests/Stache/__fixtures__/content/structures/pages.yaml +++ /dev/null @@ -1,13 +0,0 @@ -title: Pages -root: pages-home -tree: - - - entry: pages-about - children: - - - entry: pages-board - children: - - - entry: pages-directors - - - entry: pages-blog diff --git a/tests/Tags/Collection/CollectionTest.php b/tests/Tags/Collection/CollectionTest.php index ba4bf1b1943..dfdc71edb20 100644 --- a/tests/Tags/Collection/CollectionTest.php +++ b/tests/Tags/Collection/CollectionTest.php @@ -2,18 +2,20 @@ namespace Tests\Tags\Collection; +use Facades\Tests\Factories\EntryFactory; +use Illuminate\Support\Carbon; +use Statamic\Exceptions\CollectionNotFoundException; use Statamic\Facades; -use Tests\TestCase; use Statamic\Facades\Antlers; +use Statamic\Facades\Blueprint; +use Statamic\Facades\Entry; +use Statamic\Structures\CollectionStructure; +use Statamic\Tags\Collection\Collection; +use Statamic\Tags\Collection\Entries; use Statamic\Tags\Context; use Statamic\Tags\Parameters; -use Illuminate\Support\Carbon; -use Statamic\Tags\Collection\Entries; -use Statamic\Tags\Collection\Collection; -use Facades\Tests\Factories\EntryFactory; use Tests\PreventSavingStacheItemsToDisk; -use Statamic\Exceptions\CollectionNotFoundException; -use Statamic\Facades\Blueprint; +use Tests\TestCase; class CollectionTest extends TestCase { @@ -35,7 +37,7 @@ function setUp(): void protected function makeEntry($collection, $slug) { - return EntryFactory::collection($collection)->slug($slug)->make(); + return EntryFactory::id($slug)->collection($collection)->slug($slug)->make(); } protected function makePosts() @@ -192,6 +194,30 @@ function it_gets_entries_from_all_collections_excluding_some_with_params() $this->assertCount(2, $this->collectionTag->index()); } + /** @test */ + function it_filters_out_redirects() + { + $this->makePosts(); + Entry::find('c')->set('redirect', 'http://example.com')->save(); + Entry::find('d')->set('redirect', 'http://example.com')->save(); + + // Redirects get filtered out by default. + $this->setTagParameters(['collection' => '*']); + $this->assertCount(7, $this->collectionTag->index()); + + // Marking as true will include them. + $this->setTagParameters(['collection' => '*', 'redirects' => true]); + $this->assertCount(9, $this->collectionTag->index()); + + // Aliased to links + $this->setTagParameters(['collection' => '*', 'links' => true]); + $this->assertCount(9, $this->collectionTag->index()); + + // Shorthand param doesn't exist to get *only* redirects. Users can do it manually with a condition. + $this->setTagParameters(['collection' => '*', 'redirect:exists' => true]); + $this->assertCount(2, $this->collectionTag->index()); + } + /** @test */ function it_counts_entries_in_a_collection() { @@ -321,8 +347,6 @@ function it_can_get_previous_and_next_entries_in_a_dated_asc_collection() /** @test */ function it_can_get_previous_and_next_entries_in_an_orderable_asc_collection() { - $this->foods->orderable(true)->save(); - $this->makeEntry($this->foods, 'a')->set('title', 'Apple')->save(); $this->makeEntry($this->foods, 'b')->set('title', 'Banana')->save(); $this->makeEntry($this->foods, 'c')->set('title', 'Carrot')->save(); @@ -333,17 +357,19 @@ function it_can_get_previous_and_next_entries_in_an_orderable_asc_collection() $this->makeEntry($this->foods, 'h')->set('title', 'Hummus')->save(); $this->makeEntry($this->foods, 'i')->set('title', 'Ice Cream')->save(); - $this->foods->setEntryPositions([ - $this->findEntryByTitle('Carrot')->id(), - $this->findEntryByTitle('Hummus')->id(), - $this->findEntryByTitle('Apple')->id(), - $this->findEntryByTitle('Ice Cream')->id(), - $this->findEntryByTitle('Banana')->id(), - $this->findEntryByTitle('Fig')->id(), - $this->findEntryByTitle('Grape')->id(), - $this->findEntryByTitle('Egg')->id(), - $this->findEntryByTitle('Danish')->id(), - ])->save(); + $structure = $this->makeStructure([ + ['entry' => 'c'], // Carrot + ['entry' => 'h'], // Hummus + ['entry' => 'a'], // Apple + ['entry' => 'i'], // Ice Cream + ['entry' => 'b'], // Banana + ['entry' => 'f'], // Fig + ['entry' => 'g'], // Grape + ['entry' => 'e'], // Egg + ['entry' => 'd'], // Danish + ], $this->foods)->maxDepth(1); + + $this->foods->structure($structure)->save(); $currentId = $this->findEntryByTitle('Banana')->id(); @@ -370,8 +396,6 @@ function it_can_get_previous_and_next_entries_in_an_orderable_asc_collection() /** @test */ function it_can_get_previous_and_next_entries_in_an_orderable_desc_collection() { - $this->foods->orderable(true)->save(); - $this->makeEntry($this->foods, 'a')->set('title', 'Apple')->save(); $this->makeEntry($this->foods, 'b')->set('title', 'Banana')->save(); $this->makeEntry($this->foods, 'c')->set('title', 'Carrot')->save(); @@ -382,17 +406,19 @@ function it_can_get_previous_and_next_entries_in_an_orderable_desc_collection() $this->makeEntry($this->foods, 'h')->set('title', 'Hummus')->save(); $this->makeEntry($this->foods, 'i')->set('title', 'Ice Cream')->save(); - $this->foods->setEntryPositions([ - $this->findEntryByTitle('Carrot')->id(), - $this->findEntryByTitle('Hummus')->id(), - $this->findEntryByTitle('Apple')->id(), - $this->findEntryByTitle('Ice Cream')->id(), - $this->findEntryByTitle('Banana')->id(), - $this->findEntryByTitle('Fig')->id(), - $this->findEntryByTitle('Grape')->id(), - $this->findEntryByTitle('Egg')->id(), - $this->findEntryByTitle('Danish')->id(), - ])->save(); + $structure = $this->makeStructure([ + ['entry' => 'c'], // Carrot + ['entry' => 'h'], // Hummus + ['entry' => 'a'], // Apple + ['entry' => 'i'], // Ice Cream + ['entry' => 'b'], // Banana + ['entry' => 'f'], // Fig + ['entry' => 'g'], // Grape + ['entry' => 'e'], // Egg + ['entry' => 'd'], // Danish + ], $this->foods)->maxDepth(1); + + $this->foods->structure($structure)->save(); $currentId = $this->findEntryByTitle('Banana')->id(); @@ -458,4 +484,15 @@ protected function runTagAndGetTitles($tagMethod) { return $this->collectionTag->{$tagMethod}()->map->get('title')->values()->all(); } + + protected function makeStructure($tree = [], $collection = null) + { + $structure = new CollectionStructure; + + if ($collection) { + $structure->collection($collection); + } + + return $structure->addTree($structure->makeTree('en')->tree($tree)); + } } diff --git a/tests/Tags/Collection/EntriesTest.php b/tests/Tags/Collection/EntriesTest.php index 46f069c0cc7..c3f39ef73db 100644 --- a/tests/Tags/Collection/EntriesTest.php +++ b/tests/Tags/Collection/EntriesTest.php @@ -10,6 +10,7 @@ use Statamic\Facades\Site; use Statamic\Facades\Taxonomy; use Statamic\Query\Scopes\Scope; +use Statamic\Structures\CollectionStructure; use Statamic\Tags\Collection\Entries; use Statamic\Tags\Context; use Statamic\Tags\Parameters; @@ -47,7 +48,7 @@ protected function getEnvironmentSetUp($app) protected function makeEntry($slug) { - return EntryFactory::slug($slug)->collection($this->collection)->make(); + return EntryFactory::id($slug)->slug($slug)->collection($this->collection)->make(); } protected function getEntries($params = []) @@ -308,6 +309,39 @@ function it_sorts_entries_randomly() $this->assertTrue($orders->unique()->count() > 1); } + /** @test */ + function it_cannot_sort_a_nested_structured_collection() + { + $this->expectException(\LogicException::class); + $this->expectExceptionMessage('Cannot sort a nested collection by order.'); + + $structure = (new CollectionStructure)->maxDepth(2); + $this->collection->structure($structure)->save(); + + $this->getEntries(['sort' => 'order|title']); + } + + /** @test */ + function it_can_sort_a_linear_structured_collection() + { + $this->makeEntry('a')->save(); + $this->makeEntry('b')->save(); + $this->makeEntry('c')->save(); + + $structure = (new CollectionStructure)->collection($this->collection)->maxDepth(1)->tap(function ($s) { + $s->addTree($s->makeTree('en')->tree([ + ['entry' => 'b'], + ['entry' => 'c'], + ['entry' => 'a'], + ])); + }); + + $this->collection->structure($structure)->save(); + + $this->assertEquals(['a', 'b', 'c'], $this->getEntries(['sort' => 'id'])->map->id()->all()); + $this->assertEquals(['b', 'c', 'a'], $this->getEntries(['sort' => 'order|title'])->map->id()->all()); + } + /** @test */ function it_filters_by_a_single_taxonomy_term() { diff --git a/tests/TestCase.php b/tests/TestCase.php index 8b1ab9f7321..f2a5f2fdf8c 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -29,7 +29,7 @@ protected function setUp(): void } if ($this->shouldPreventNavBeingBuilt) { - \Statamic\Facades\Nav::shouldReceive('build')->andReturn([]); + \Statamic\Facades\CP\Nav::shouldReceive('build')->andReturn([]); $this->addToAssertionCount(-1); // Dont want to assert this } } @@ -93,7 +93,7 @@ protected function getEnvironmentSetUp($app) $app['config']->set('statamic.stache.stores.terms.directory', __DIR__.'/__fixtures__/content/taxonomies'); $app['config']->set('statamic.stache.stores.collections.directory', __DIR__.'/__fixtures__/content/collections'); $app['config']->set('statamic.stache.stores.entries.directory', __DIR__.'/__fixtures__/content/collections'); - $app['config']->set('statamic.stache.stores.structures.directory', __DIR__.'/__fixtures__/content/structures'); + $app['config']->set('statamic.stache.stores.navigation.directory', __DIR__.'/__fixtures__/content/navigation'); $app['config']->set('statamic.stache.stores.globals.directory', __DIR__.'/__fixtures__/content/globals'); $app['config']->set('statamic.stache.stores.asset-containers.directory', __DIR__.'/__fixtures__/content/assets'); @@ -157,4 +157,12 @@ protected function isRunningWindows() { return DIRECTORY_SEPARATOR === '\\'; } + + // This method is unavailable on earlier versions of Laravel. + public function partialMock($abstract, \Closure $mock = null) + { + $mock = \Mockery::mock(...array_filter(func_get_args()))->makePartial(); + $this->app->instance($abstract, $mock); + return $mock; + } }