44
55use Mockery ;
66use PHPUnit \Framework \Attributes \Test ;
7+ use Statamic \Contracts \Entries \Entry ;
78use Statamic \Events \BlueprintSaved ;
9+ use Statamic \Events \CollectionTreeEntriesMovedOrRemoved ;
10+ use Statamic \Facades \Entry as EntryFacade ;
811use Statamic \Facades \Form ;
12+ use Statamic \StaticCaching \Cacher ;
913use Statamic \StaticCaching \Invalidate ;
1014use Statamic \StaticCaching \Invalidator ;
1115use Tests \PreventSavingStacheItemsToDisk ;
@@ -26,8 +30,81 @@ public function it_invalidates_a_form_when_its_blueprint_is_saved()
2630 return $ form ->handle () === 'contact ' ;
2731 })->getMock ();
2832
29- $ invalidate = new Invalidate ($ invalidator );
33+ $ invalidate = new Invalidate ($ invalidator, Mockery:: mock (Cacher::class) );
3034
3135 $ invalidate ->invalidateByBlueprint ($ event );
3236 }
37+
38+ private function mockEntry (string $ url ): Entry
39+ {
40+ $ entry = Mockery::mock (Entry::class);
41+ $ entry ->shouldReceive ('descendants ' )->andReturn (collect ());
42+ $ entry ->shouldReceive ('isRedirect ' )->andReturn (false );
43+ $ entry ->shouldReceive ('absoluteUrl ' )->andReturn ($ url );
44+
45+ return $ entry ;
46+ }
47+
48+ #[Test]
49+ public function it_invalidates_removed_entries_when_collection_tree_is_saving ()
50+ {
51+ EntryFacade::shouldReceive ('find ' )->with ('entry-1 ' )->andReturn ($ this ->mockEntry ('http://example.com/entry-1 ' ));
52+ EntryFacade::shouldReceive ('find ' )->with ('entry-2 ' )->andReturn ($ this ->mockEntry ('http://example.com/entry-2 ' ));
53+
54+ $ event = new CollectionTreeEntriesMovedOrRemoved (removed: ['entry-1 ' , 'entry-2 ' ], moved: []);
55+
56+ $ cacher = Mockery::mock (Cacher::class);
57+ $ cacher ->shouldReceive ('invalidateUrls ' )
58+ ->with (['http://example.com/entry-1 ' , 'http://example.com/entry-2 ' ])
59+ ->once ();
60+
61+ $ invalidate = new Invalidate (Mockery::mock (Invalidator::class), $ cacher );
62+
63+ $ invalidate ->invalidateMovedOrRemovedEntries ($ event );
64+ }
65+
66+ #[Test]
67+ public function it_invalidates_entries_with_changed_ancestry_when_collection_tree_is_saving ()
68+ {
69+ EntryFacade::shouldReceive ('find ' )->with ('entry-1 ' )->andReturn ($ this ->mockEntry ('http://example.com/entry-1 ' ));
70+
71+ $ event = new CollectionTreeEntriesMovedOrRemoved (removed: [], moved: ['entry-1 ' ]);
72+
73+ $ cacher = Mockery::mock (Cacher::class);
74+ $ cacher ->shouldReceive ('invalidateUrls ' )
75+ ->with (['http://example.com/entry-1 ' ])
76+ ->once ();
77+
78+ $ invalidate = new Invalidate (Mockery::mock (Invalidator::class), $ cacher );
79+
80+ $ invalidate ->invalidateMovedOrRemovedEntries ($ event );
81+ }
82+
83+ #[Test]
84+ public function it_does_not_invalidate_entries_only_reordered_within_same_parent_when_collection_tree_is_saving ()
85+ {
86+ $ event = new CollectionTreeEntriesMovedOrRemoved (removed: [], moved: []);
87+
88+ $ cacher = Mockery::mock (Cacher::class);
89+ $ cacher ->shouldNotReceive ('invalidateUrls ' );
90+
91+ $ invalidate = new Invalidate (Mockery::mock (Invalidator::class), $ cacher );
92+
93+ $ invalidate ->invalidateMovedOrRemovedEntries ($ event );
94+ }
95+
96+ #[Test]
97+ public function it_skips_entries_that_cannot_be_found_when_collection_tree_is_saving ()
98+ {
99+ EntryFacade::shouldReceive ('find ' )->with ('missing-entry ' )->andReturn (null );
100+
101+ $ event = new CollectionTreeEntriesMovedOrRemoved (removed: ['missing-entry ' ], moved: []);
102+
103+ $ cacher = Mockery::mock (Cacher::class);
104+ $ cacher ->shouldNotReceive ('invalidateUrls ' );
105+
106+ $ invalidate = new Invalidate (Mockery::mock (Invalidator::class), $ cacher );
107+
108+ $ invalidate ->invalidateMovedOrRemovedEntries ($ event );
109+ }
33110}
0 commit comments