From e58518f51a95834f43c5d9b276dbbced57514c1c Mon Sep 17 00:00:00 2001 From: Kyrch Date: Tue, 29 Jul 2025 23:31:12 -0300 Subject: [PATCH] feat(tests): pest php (#899) --- app/Concerns/GraphQL/ResolvesArguments.php | 16 +- .../Types/Wiki/Song/PerformanceType.php | 6 +- composer.json | 6 +- composer.lock | 807 ++++++- phpstan.neon | 12 + pint.json | 3 + .../Actions/Fortify/CreateNewUserTest.php | 367 ++- .../UpdateUserProfileInformationTest.php | 421 ++-- .../List/Playlist/InsertTrackAfterTest.php | 88 +- .../List/Playlist/InsertTrackBeforeTest.php | 88 +- .../Models/List/Playlist/InsertTrackTest.php | 141 +- .../Models/List/Playlist/RemoveTrackTest.php | 146 +- .../Video/Audio/BackfillVideoAudioTest.php | 216 +- .../Dump/ReconcileDumpRepositoriesTest.php | 118 +- .../Audio/ReconcileAudioRepositoriesTest.php | 198 +- .../Video/ReconcileVideoRepositoriesTest.php | 198 +- .../ReconcileScriptRepositoriesTest.php | 146 +- .../Storage/Admin/Dump/DumpDocumentTest.php | 38 +- .../Storage/Admin/Dump/DumpWikiTest.php | 38 +- .../Storage/Admin/Dump/PruneDumpTest.php | 74 +- .../Storage/Wiki/Audio/DeleteAudioTest.php | 134 +- .../Storage/Wiki/Audio/MoveAudioTest.php | 151 +- .../Storage/Wiki/Audio/UploadAudioTest.php | 95 +- .../Storage/Wiki/Video/DeleteVideoTest.php | 134 +- .../Storage/Wiki/Video/MoveVideoTest.php | 151 +- .../Wiki/Video/Script/DeleteScriptTest.php | 110 +- .../Wiki/Video/Script/MoveScriptTest.php | 127 +- .../Wiki/Video/Script/UploadScriptTest.php | 111 +- .../Storage/Wiki/Video/UploadVideoTest.php | 270 +-- .../Storage/Admin/DumpReconcileTest.php | 81 +- .../Storage/Wiki/AudioReconcileTest.php | 117 +- .../Wiki/Video/ScriptReconcileTest.php | 83 +- .../Storage/Wiki/VideoReconcileTest.php | 125 +- .../Storage/Admin/DocumentDumpTest.php | 49 +- .../Commands/Storage/Admin/DumpPruneTest.php | 55 +- .../Commands/Storage/Admin/WikiDumpTest.php | 47 +- .../Feature/Events/Admin/AnnouncementTest.php | 74 +- tests/Feature/Events/Admin/DumpTest.php | 74 +- tests/Feature/Events/Admin/FeatureTest.php | 74 +- .../Events/Admin/FeaturedThemeTest.php | 74 +- tests/Feature/Events/Auth/UserTest.php | 104 +- tests/Feature/Events/Document/PageTest.php | 104 +- .../Events/List/ExternalProfileTest.php | 74 +- .../Events/List/Playlist/TrackTest.php | 116 +- tests/Feature/Events/List/PlaylistTest.php | 106 +- .../Events/Pivot/List/PlaylistImageTest.php | 40 +- .../Events/Pivot/Wiki/AnimeImageTest.php | 40 +- .../Events/Pivot/Wiki/AnimeResourceTest.php | 114 +- .../Events/Pivot/Wiki/AnimeSeriesTest.php | 40 +- .../Events/Pivot/Wiki/AnimeStudioTest.php | 40 +- .../Pivot/Wiki/AnimeThemeEntryVideoTest.php | 128 +- .../Events/Pivot/Wiki/ArtistImageTest.php | 40 +- .../Events/Pivot/Wiki/ArtistMemberTest.php | 114 +- .../Events/Pivot/Wiki/ArtistResourceTest.php | 114 +- .../Events/Pivot/Wiki/ArtistSongTest.php | 114 +- .../Events/Pivot/Wiki/SongResourceTest.php | 114 +- .../Events/Pivot/Wiki/StudioImageTest.php | 40 +- .../Events/Pivot/Wiki/StudioResourceTest.php | 114 +- .../Feature/Events/Wiki/Anime/SynonymTest.php | 136 +- .../Events/Wiki/Anime/Theme/EntryTest.php | 136 +- tests/Feature/Events/Wiki/Anime/ThemeTest.php | 136 +- tests/Feature/Events/Wiki/AnimeTest.php | 104 +- tests/Feature/Events/Wiki/ArtistTest.php | 104 +- tests/Feature/Events/Wiki/AudioTest.php | 104 +- .../Events/Wiki/ExternalResourceTest.php | 104 +- tests/Feature/Events/Wiki/GroupTest.php | 104 +- tests/Feature/Events/Wiki/ImageTest.php | 104 +- tests/Feature/Events/Wiki/SeriesTest.php | 104 +- tests/Feature/Events/Wiki/SongTest.php | 104 +- tests/Feature/Events/Wiki/StudioTest.php | 104 +- .../Feature/Events/Wiki/Video/ScriptTest.php | 104 +- tests/Feature/Events/Wiki/VideoTest.php | 104 +- .../GraphQL/Queries/AnimeQueryTest.php | 50 +- tests/Feature/Http/Admin/DumpTest.php | 109 +- .../Http/Admin/LatestDocumentDumpTest.php | 198 +- .../Feature/Http/Admin/LatestWikiDumpTest.php | 202 +- .../Announcement/AnnouncementDestroyTest.php | 60 +- .../Announcement/AnnouncementIndexTest.php | 343 ++- .../Announcement/AnnouncementShowTest.php | 105 +- .../Announcement/AnnouncementStoreTest.php | 80 +- .../Announcement/AnnouncementUpdateTest.php | 64 +- .../Http/Api/Admin/Dump/DumpDestroyTest.php | 60 +- .../Http/Api/Admin/Dump/DumpIndexTest.php | 343 ++- .../Http/Api/Admin/Dump/DumpShowTest.php | 105 +- .../Http/Api/Admin/Dump/DumpStoreTest.php | 80 +- .../Http/Api/Admin/Dump/DumpUpdateTest.php | 64 +- .../Api/Admin/Feature/FeatureIndexTest.php | 355 ++- .../Api/Admin/Feature/FeatureShowTest.php | 109 +- .../Api/Admin/Feature/FeatureUpdateTest.php | 76 +- .../CurrentFeaturedThemeShowTest.php | 287 +-- .../FeaturedThemeDestroyTest.php | 60 +- .../FeaturedTheme/FeaturedThemeIndexTest.php | 403 ++-- .../FeaturedTheme/FeaturedThemeShowTest.php | 177 +- .../FeaturedTheme/FeaturedThemeStoreTest.php | 167 +- .../FeaturedTheme/FeaturedThemeUpdateTest.php | 153 +- .../MyExternalProfileIndexTest.php | 99 +- .../Me/List/Playlist/MyPlaylistIndexTest.php | 99 +- .../Http/Api/Auth/User/Me/MyShowTest.php | 57 +- .../Notification/MyNotificationIndexTest.php | 95 +- .../Api/Document/Page/PageDestroyTest.php | 78 +- .../Api/Document/Page/PageForceDeleteTest.php | 60 +- .../Http/Api/Document/Page/PageIndexTest.php | 521 ++-- .../Api/Document/Page/PageRestoreTest.php | 78 +- .../Http/Api/Document/Page/PageShowTest.php | 125 +- .../Http/Api/Document/Page/PageStoreTest.php | 84 +- .../Http/Api/Document/Page/PageUpdateTest.php | 84 +- tests/Feature/Http/Api/FallbackTest.php | 25 +- .../External/Entry/ExternalEntryIndexTest.php | 627 +++-- .../External/Entry/ExternalEntryShowTest.php | 346 ++- .../External/ExternalProfileDestroyTest.php | 169 +- .../External/ExternalProfileIndexTest.php | 443 ++-- .../List/External/ExternalProfileShowTest.php | 269 +-- .../External/ExternalProfileStoreTest.php | 386 ++- .../External/ExternalProfileUpdateTest.php | 239 +- .../Playlist/PlaylistBackwardIndexTest.php | 551 ++--- .../Api/List/Playlist/PlaylistDestroyTest.php | 169 +- .../Playlist/PlaylistForwardIndexTest.php | 551 ++--- .../Api/List/Playlist/PlaylistIndexTest.php | 537 ++--- .../Api/List/Playlist/PlaylistShowTest.php | 457 ++-- .../Api/List/Playlist/PlaylistStoreTest.php | 386 ++- .../Api/List/Playlist/PlaylistUpdateTest.php | 419 ++-- .../Playlist/Track/TrackBackwardIndexTest.php | 591 +++-- .../List/Playlist/Track/TrackDestroyTest.php | 377 ++- .../Playlist/Track/TrackForwardIndexTest.php | 591 +++-- .../List/Playlist/Track/TrackIndexTest.php | 671 +++--- .../Api/List/Playlist/Track/TrackShowTest.php | 383 ++- .../List/Playlist/Track/TrackStoreTest.php | 1036 ++++---- .../List/Playlist/Track/TrackUpdateTest.php | 1131 ++++----- .../PlaylistImageDestroyTest.php | 259 +- .../PlaylistImage/PlaylistImageIndexTest.php | 679 +++--- .../PlaylistImage/PlaylistImageShowTest.php | 591 +++-- .../PlaylistImage/PlaylistImageStoreTest.php | 171 +- .../Wiki/AnimeImage/AnimeImageDestroyTest.php | 118 +- .../Wiki/AnimeImage/AnimeImageIndexTest.php | 793 +++---- .../Wiki/AnimeImage/AnimeImageShowTest.php | 437 ++-- .../Wiki/AnimeImage/AnimeImageStoreTest.php | 76 +- .../AnimeResourceDestroyTest.php | 118 +- .../AnimeResource/AnimeResourceIndexTest.php | 793 +++---- .../AnimeResource/AnimeResourceShowTest.php | 437 ++-- .../AnimeResource/AnimeResourceStoreTest.php | 82 +- .../AnimeResource/AnimeResourceUpdateTest.php | 92 +- .../AnimeSeries/AnimeSeriesDestroyTest.php | 118 +- .../Wiki/AnimeSeries/AnimeSeriesIndexTest.php | 713 +++--- .../Wiki/AnimeSeries/AnimeSeriesShowTest.php | 375 ++- .../Wiki/AnimeSeries/AnimeSeriesStoreTest.php | 76 +- .../AnimeStudio/AnimeStudioDestroyTest.php | 118 +- .../Wiki/AnimeStudio/AnimeStudioIndexTest.php | 713 +++--- .../Wiki/AnimeStudio/AnimeStudioShowTest.php | 375 ++- .../Wiki/AnimeStudio/AnimeStudioStoreTest.php | 76 +- .../AnimeThemeEntryVideoDestroyTest.php | 122 +- .../AnimeThemeEntryVideoIndexTest.php | 1275 +++++----- .../AnimeThemeEntryVideoShowTest.php | 973 ++++---- .../AnimeThemeEntryVideoStoreTest.php | 88 +- .../ArtistImage/ArtistImageDestroyTest.php | 118 +- .../Wiki/ArtistImage/ArtistImageIndexTest.php | 537 ++--- .../Wiki/ArtistImage/ArtistImageShowTest.php | 239 +- .../Wiki/ArtistImage/ArtistImageStoreTest.php | 76 +- .../ArtistMember/ArtistMemberDestroyTest.php | 98 +- .../ArtistMember/ArtistMemberIndexTest.php | 469 ++-- .../ArtistMember/ArtistMemberShowTest.php | 177 +- .../ArtistMember/ArtistMemberStoreTest.php | 72 +- .../ArtistMember/ArtistMemberUpdateTest.php | 82 +- .../ArtistResourceDestroyTest.php | 118 +- .../ArtistResourceIndexTest.php | 537 ++--- .../ArtistResource/ArtistResourceShowTest.php | 239 +- .../ArtistResourceStoreTest.php | 82 +- .../ArtistResourceUpdateTest.php | 92 +- .../Wiki/ArtistSong/ArtistSongDestroyTest.php | 118 +- .../Wiki/ArtistSong/ArtistSongIndexTest.php | 469 ++-- .../Wiki/ArtistSong/ArtistSongShowTest.php | 177 +- .../Wiki/ArtistSong/ArtistSongStoreTest.php | 82 +- .../Wiki/ArtistSong/ArtistSongUpdateTest.php | 92 +- .../SongResource/SongResourceDestroyTest.php | 118 +- .../SongResource/SongResourceIndexTest.php | 537 ++--- .../SongResource/SongResourceShowTest.php | 239 +- .../SongResource/SongResourceStoreTest.php | 82 +- .../SongResource/SongResourceUpdateTest.php | 92 +- .../StudioImage/StudioImageDestroyTest.php | 118 +- .../Wiki/StudioImage/StudioImageIndexTest.php | 537 ++--- .../Wiki/StudioImage/StudioImageShowTest.php | 239 +- .../Wiki/StudioImage/StudioImageStoreTest.php | 76 +- .../StudioResourceDestroyTest.php | 118 +- .../StudioResourceIndexTest.php | 537 ++--- .../StudioResource/StudioResourceShowTest.php | 239 +- .../StudioResourceStoreTest.php | 82 +- .../StudioResourceUpdateTest.php | 92 +- tests/Feature/Http/Api/SearchTest.php | 131 +- tests/Feature/Http/Api/ThrottleTest.php | 54 +- .../Http/Api/Wiki/Anime/AnimeDestroyTest.php | 78 +- .../Api/Wiki/Anime/AnimeForceDeleteTest.php | 60 +- .../Http/Api/Wiki/Anime/AnimeIndexTest.php | 2025 ++++++++-------- .../Http/Api/Wiki/Anime/AnimeRestoreTest.php | 78 +- .../Http/Api/Wiki/Anime/AnimeShowTest.php | 1315 +++++------ .../Http/Api/Wiki/Anime/AnimeStoreTest.php | 98 +- .../Http/Api/Wiki/Anime/AnimeUpdateTest.php | 124 +- .../Wiki/Anime/Synonym/SynonymDestroyTest.php | 84 +- .../Anime/Synonym/SynonymForceDeleteTest.php | 60 +- .../Wiki/Anime/Synonym/SynonymIndexTest.php | 949 ++++---- .../Wiki/Anime/Synonym/SynonymRestoreTest.php | 96 +- .../Wiki/Anime/Synonym/SynonymShowTest.php | 365 ++- .../Wiki/Anime/Synonym/SynonymStoreTest.php | 88 +- .../Wiki/Anime/Synonym/SynonymUpdateTest.php | 90 +- .../Anime/Theme/Entry/EntryDestroyTest.php | 96 +- .../Theme/Entry/EntryForceDeleteTest.php | 72 +- .../Wiki/Anime/Theme/Entry/EntryIndexTest.php | 1269 +++++----- .../Anime/Theme/Entry/EntryRestoreTest.php | 100 +- .../Wiki/Anime/Theme/Entry/EntryShowTest.php | 525 ++--- .../Wiki/Anime/Theme/Entry/EntryStoreTest.php | 96 +- .../Anime/Theme/Entry/EntryUpdateTest.php | 102 +- .../Api/Wiki/Anime/Theme/ThemeDestroyTest.php | 84 +- .../Wiki/Anime/Theme/ThemeForceDeleteTest.php | 60 +- .../Api/Wiki/Anime/Theme/ThemeIndexTest.php | 2097 ++++++++--------- .../Api/Wiki/Anime/Theme/ThemeRestoreTest.php | 96 +- .../Api/Wiki/Anime/Theme/ThemeShowTest.php | 1395 ++++++----- .../Api/Wiki/Anime/Theme/ThemeStoreTest.php | 96 +- .../Api/Wiki/Anime/Theme/ThemeUpdateTest.php | 122 +- .../Http/Api/Wiki/Anime/YearIndexTest.php | 33 +- .../Http/Api/Wiki/Anime/YearShowTest.php | 353 ++- .../Api/Wiki/Artist/ArtistDestroyTest.php | 78 +- .../Api/Wiki/Artist/ArtistForceDeleteTest.php | 60 +- .../Http/Api/Wiki/Artist/ArtistIndexTest.php | 1347 +++++------ .../Api/Wiki/Artist/ArtistRestoreTest.php | 78 +- .../Http/Api/Wiki/Artist/ArtistShowTest.php | 823 +++---- .../Http/Api/Wiki/Artist/ArtistStoreTest.php | 82 +- .../Http/Api/Wiki/Artist/ArtistUpdateTest.php | 84 +- .../Http/Api/Wiki/Audio/AudioDestroyTest.php | 78 +- .../Api/Wiki/Audio/AudioForceDeleteTest.php | 60 +- .../Http/Api/Wiki/Audio/AudioIndexTest.php | 731 +++--- .../Http/Api/Wiki/Audio/AudioRestoreTest.php | 78 +- .../Http/Api/Wiki/Audio/AudioShowTest.php | 173 +- .../Http/Api/Wiki/Audio/AudioStoreTest.php | 88 +- .../Http/Api/Wiki/Audio/AudioUpdateTest.php | 84 +- .../ExternalResourceDestroyTest.php | 78 +- .../ExternalResourceForceDeleteTest.php | 60 +- .../ExternalResourceIndexTest.php | 1029 ++++---- .../ExternalResourceRestoreTest.php | 78 +- .../ExternalResourceShowTest.php | 371 ++- .../ExternalResourceStoreTest.php | 88 +- .../ExternalResourceUpdateTest.php | 126 +- .../Http/Api/Wiki/Group/GroupDestroyTest.php | 78 +- .../Api/Wiki/Group/GroupForceDeleteTest.php | 60 +- .../Http/Api/Wiki/Group/GroupIndexTest.php | 1133 +++++---- .../Http/Api/Wiki/Group/GroupRestoreTest.php | 78 +- .../Http/Api/Wiki/Group/GroupShowTest.php | 513 ++-- .../Http/Api/Wiki/Group/GroupStoreTest.php | 60 +- .../Http/Api/Wiki/Group/GroupUpdateTest.php | 84 +- .../Http/Api/Wiki/Image/ImageDestroyTest.php | 78 +- .../Api/Wiki/Image/ImageForceDeleteTest.php | 60 +- .../Http/Api/Wiki/Image/ImageIndexTest.php | 1029 ++++---- .../Http/Api/Wiki/Image/ImageRestoreTest.php | 78 +- .../Http/Api/Wiki/Image/ImageShowTest.php | 371 ++- .../Http/Api/Wiki/Image/ImageStoreTest.php | 93 +- .../Http/Api/Wiki/Image/ImageUpdateTest.php | 116 +- .../Api/Wiki/Series/SeriesDestroyTest.php | 78 +- .../Api/Wiki/Series/SeriesForceDeleteTest.php | 60 +- .../Http/Api/Wiki/Series/SeriesIndexTest.php | 959 ++++---- .../Api/Wiki/Series/SeriesRestoreTest.php | 78 +- .../Http/Api/Wiki/Series/SeriesShowTest.php | 371 ++- .../Http/Api/Wiki/Series/SeriesStoreTest.php | 82 +- .../Http/Api/Wiki/Series/SeriesUpdateTest.php | 84 +- .../Http/Api/Wiki/Song/SongDestroyTest.php | 78 +- .../Api/Wiki/Song/SongForceDeleteTest.php | 60 +- .../Http/Api/Wiki/Song/SongIndexTest.php | 1135 +++++---- .../Http/Api/Wiki/Song/SongRestoreTest.php | 78 +- .../Http/Api/Wiki/Song/SongShowTest.php | 515 ++-- .../Http/Api/Wiki/Song/SongStoreTest.php | 60 +- .../Http/Api/Wiki/Song/SongUpdateTest.php | 84 +- .../Api/Wiki/Studio/StudioDestroyTest.php | 78 +- .../Api/Wiki/Studio/StudioForceDeleteTest.php | 60 +- .../Http/Api/Wiki/Studio/StudioIndexTest.php | 1111 ++++----- .../Api/Wiki/Studio/StudioRestoreTest.php | 78 +- .../Http/Api/Wiki/Studio/StudioShowTest.php | 491 ++-- .../Http/Api/Wiki/Studio/StudioStoreTest.php | 82 +- .../Http/Api/Wiki/Studio/StudioUpdateTest.php | 84 +- .../Wiki/Video/Script/ScriptDestroyTest.php | 78 +- .../Video/Script/ScriptForceDeleteTest.php | 60 +- .../Api/Wiki/Video/Script/ScriptIndexTest.php | 1273 +++++----- .../Wiki/Video/Script/ScriptRestoreTest.php | 78 +- .../Api/Wiki/Video/Script/ScriptShowTest.php | 603 +++-- .../Api/Wiki/Video/Script/ScriptStoreTest.php | 80 +- .../Wiki/Video/Script/ScriptUpdateTest.php | 84 +- .../Http/Api/Wiki/Video/VideoDestroyTest.php | 78 +- .../Api/Wiki/Video/VideoForceDeleteTest.php | 60 +- .../Http/Api/Wiki/Video/VideoIndexTest.php | 1901 +++++++-------- .../Http/Api/Wiki/Video/VideoRestoreTest.php | 78 +- .../Http/Api/Wiki/Video/VideoShowTest.php | 911 ++++--- .../Http/Api/Wiki/Video/VideoStoreTest.php | 104 +- .../Http/Api/Wiki/Video/VideoUpdateTest.php | 148 +- .../Http/Auth/EmailVerificationTest.php | 70 +- tests/Feature/Http/Wiki/Audio/AudioTest.php | 202 +- .../Http/Wiki/Video/Script/ScriptTest.php | 101 +- tests/Feature/Http/Wiki/Video/VideoTest.php | 314 +-- tests/Feature/Jobs/Admin/AnnouncementTest.php | 68 +- tests/Feature/Jobs/Admin/DumpTest.php | 68 +- tests/Feature/Jobs/Admin/FeatureTest.php | 68 +- .../Feature/Jobs/Admin/FeaturedThemeTest.php | 68 +- tests/Feature/Jobs/Auth/UserTest.php | 88 +- .../Jobs/Discord/DiscordThreadTest.php | 66 +- tests/Feature/Jobs/Document/PageTest.php | 88 +- .../Feature/Jobs/List/ExternalProfileTest.php | 68 +- .../Feature/Jobs/List/Playlist/TrackTest.php | 92 +- tests/Feature/Jobs/List/PlaylistTest.php | 68 +- .../Jobs/Pivot/List/PlaylistImageTest.php | 52 +- .../Jobs/Pivot/Wiki/AnimeImageTest.php | 52 +- .../Jobs/Pivot/Wiki/AnimeResourceTest.php | 92 +- .../Jobs/Pivot/Wiki/AnimeSeriesTest.php | 52 +- .../Jobs/Pivot/Wiki/AnimeStudioTest.php | 52 +- .../Pivot/Wiki/AnimeThemeEntryVideoTest.php | 60 +- .../Jobs/Pivot/Wiki/ArtistImageTest.php | 52 +- .../Jobs/Pivot/Wiki/ArtistMemberTest.php | 92 +- .../Jobs/Pivot/Wiki/ArtistResourceTest.php | 92 +- .../Jobs/Pivot/Wiki/ArtistSongTest.php | 92 +- .../Jobs/Pivot/Wiki/SongResourceTest.php | 92 +- .../Jobs/Pivot/Wiki/StudioImageTest.php | 52 +- .../Jobs/Pivot/Wiki/StudioResourceTest.php | 92 +- .../Jobs/SendDiscordNotificationTest.php | 148 +- tests/Feature/Jobs/Wiki/Anime/SynonymTest.php | 106 +- .../Jobs/Wiki/Anime/Theme/EntryTest.php | 110 +- tests/Feature/Jobs/Wiki/Anime/ThemeTest.php | 106 +- tests/Feature/Jobs/Wiki/AnimeTest.php | 88 +- tests/Feature/Jobs/Wiki/ArtistTest.php | 88 +- tests/Feature/Jobs/Wiki/AudioTest.php | 88 +- .../Jobs/Wiki/ExternalResourceTest.php | 88 +- tests/Feature/Jobs/Wiki/GroupTest.php | 88 +- tests/Feature/Jobs/Wiki/ImageTest.php | 88 +- tests/Feature/Jobs/Wiki/SeriesTest.php | 88 +- tests/Feature/Jobs/Wiki/SongTest.php | 88 +- tests/Feature/Jobs/Wiki/StudioTest.php | 88 +- tests/Feature/Jobs/Wiki/Video/ScriptTest.php | 88 +- tests/Feature/Jobs/Wiki/VideoTest.php | 88 +- .../Listeners/SendDiscordNotificationTest.php | 142 +- tests/Pest.php | 83 + tests/TestCase.php | 2 + tests/Unit/Actions/ActionResultTest.php | 44 +- .../Repositories/ReconcileResultsTest.php | 38 +- .../Storage/Base/DeleteResultsTest.php | 85 +- .../Actions/Storage/Base/MoveResultsTest.php | 85 +- .../Actions/Storage/Base/PruneResultsTest.php | 77 +- .../Storage/Base/UploadResultsTest.php | 77 +- tests/Unit/ArchTest.php | 106 + tests/Unit/Discord/DiscordEmbedFieldTest.php | 142 +- .../Enums/Models/Wiki/ResourceSiteTest.php | 201 +- tests/Unit/Events/AssignHashidsTest.php | 16 +- tests/Unit/Events/CascadesDeletesTest.php | 16 +- tests/Unit/Events/CascadesRestoresTest.php | 16 +- tests/Unit/Events/ManagesTrackTest.php | 16 +- .../Unit/Events/NotifiesFilamentUsersTest.php | 16 +- tests/Unit/Events/NotifiesUsersTest.php | 16 +- tests/Unit/Events/RemoveFromStorageTest.php | 16 +- tests/Unit/Events/SyncArtistSongTest.php | 16 +- .../Unit/Events/UpdatePlaylistTracksTest.php | 16 +- .../Unit/Events/UpdateRelatedIndicesTest.php | 16 +- tests/Unit/Filament/BaseResourceTestCase.php | 28 - .../Resources/Admin/AnnouncementTest.php | 117 +- .../Filament/Resources/Admin/DumpTest.php | 105 +- .../Filament/Resources/Admin/FeatureTest.php | 105 +- .../Resources/Admin/FeaturedThemeTest.php | 227 +- .../Resources/Discord/DiscordThreadTest.php | 211 +- .../Filament/Resources/Document/PageTest.php | 227 +- .../List/External/ExternalEntryTest.php | 144 +- .../Resources/List/ExternalProfileTest.php | 168 +- .../Resources/List/Playlist/TrackTest.php | 174 +- .../Filament/Resources/List/PlaylistTest.php | 168 +- .../Resources/Wiki/Anime/Theme/EntryTest.php | 255 +- .../Resources/Wiki/Anime/ThemeTest.php | 255 +- .../Filament/Resources/Wiki/AnimeTest.php | 227 +- .../Filament/Resources/Wiki/ArtistTest.php | 227 +- .../Filament/Resources/Wiki/AudioTest.php | 187 +- .../Resources/Wiki/ExternalResourceTest.php | 187 +- .../Filament/Resources/Wiki/GroupTest.php | 227 +- .../Filament/Resources/Wiki/ImageTest.php | 197 +- .../Filament/Resources/Wiki/SeriesTest.php | 227 +- .../Resources/Wiki/Song/MembershipTest.php | 271 +-- .../Resources/Wiki/Song/PerformanceTest.php | 269 +-- .../Unit/Filament/Resources/Wiki/SongTest.php | 227 +- .../Filament/Resources/Wiki/StudioTest.php | 227 +- .../Resources/Wiki/Video/ScriptTest.php | 187 +- .../Filament/Resources/Wiki/VideoTest.php | 197 +- .../Http/Api/Criteria/Field/CriteriaTest.php | 37 +- .../Http/Api/Criteria/Filter/CriteriaTest.php | 521 ++-- .../Api/Criteria/Filter/HasCriteriaTest.php | 105 +- .../Criteria/Filter/TrashedCriteriaTest.php | 21 +- .../Api/Criteria/Filter/WhereCriteriaTest.php | 79 +- .../Criteria/Filter/WhereInCriteriaTest.php | 113 +- .../Http/Api/Criteria/Paging/CriteriaTest.php | 173 +- .../Http/Api/Criteria/Sort/CriteriaTest.php | 165 +- .../Http/Api/Filter/BooleanFilterTest.php | 57 +- tests/Unit/Http/Api/Filter/DateFilterTest.php | 89 +- tests/Unit/Http/Api/Filter/EnumFilterTest.php | 69 +- tests/Unit/Http/Api/Filter/FilterTest.php | 119 +- .../Unit/Http/Api/Filter/FloatFilterTest.php | 45 +- tests/Unit/Http/Api/Filter/HasFilterTest.php | 174 +- tests/Unit/Http/Api/Filter/IntFilterTest.php | 45 +- .../Unit/Http/Api/Parser/FieldParserTest.php | 95 +- .../Unit/Http/Api/Parser/FilterParserTest.php | 195 +- .../Http/Api/Parser/IncludeParserTest.php | 141 +- .../Unit/Http/Api/Parser/PagingParserTest.php | 181 +- .../Unit/Http/Api/Parser/SearchParserTest.php | 59 +- tests/Unit/Http/Api/Parser/SortParserTest.php | 189 +- tests/Unit/Http/Api/Query/QueryTest.php | 210 +- tests/Unit/Http/Api/Scope/GlobalScopeTest.php | 51 +- .../Unit/Http/Api/Scope/RelationScopeTest.php | 67 +- tests/Unit/Http/Api/Scope/ScopeParserTest.php | 41 +- tests/Unit/Http/Api/Scope/TypeScopeTest.php | 83 +- tests/Unit/Http/Api/Sort/RandomSortTest.php | 23 +- tests/Unit/Http/Api/Sort/SortTest.php | 49 +- tests/Unit/Models/Admin/AnnouncementTest.php | 30 +- tests/Unit/Models/Admin/DumpTest.php | 30 +- tests/Unit/Models/Admin/FeatureTest.php | 61 +- tests/Unit/Models/Admin/FeaturedThemeTest.php | 112 +- tests/Unit/Models/Auth/UserTest.php | 87 +- .../Unit/Models/Discord/DiscordThreadTest.php | 59 +- tests/Unit/Models/Document/PageTest.php | 30 +- .../List/External/ExternalEntryTest.php | 114 +- .../List/External/ExternalTokenTest.php | 72 +- .../Unit/Models/List/ExternalProfileTest.php | 199 +- tests/Unit/Models/List/Playlist/TrackTest.php | 152 +- tests/Unit/Models/List/PlaylistTest.php | 249 +- .../Models/User/Report/ReportStepTest.php | 125 +- tests/Unit/Models/User/ReportTest.php | 119 +- .../Models/Wiki/Anime/AnimeSynonymTest.php | 108 +- .../Unit/Models/Wiki/Anime/AnimeThemeTest.php | 188 +- .../Wiki/Anime/Theme/AnimeThemeEntryTest.php | 134 +- tests/Unit/Models/Wiki/AnimeTest.php | 224 +- tests/Unit/Models/Wiki/ArtistTest.php | 176 +- tests/Unit/Models/Wiki/AudioTest.php | 122 +- .../Unit/Models/Wiki/ExternalResourceTest.php | 142 +- tests/Unit/Models/Wiki/GroupTest.php | 54 +- tests/Unit/Models/Wiki/ImageTest.php | 198 +- tests/Unit/Models/Wiki/SeriesTest.php | 80 +- tests/Unit/Models/Wiki/SongTest.php | 130 +- tests/Unit/Models/Wiki/StudioTest.php | 128 +- tests/Unit/Models/Wiki/Video/ScriptTest.php | 104 +- tests/Unit/Models/Wiki/VideoTest.php | 580 ++--- .../Notifications/DiscordNotificationTest.php | 34 +- tests/Unit/Pivots/List/PlaylistImageTest.php | 46 +- tests/Unit/Pivots/Wiki/AnimeImageTest.php | 46 +- tests/Unit/Pivots/Wiki/AnimeResourceTest.php | 46 +- tests/Unit/Pivots/Wiki/AnimeSeriesTest.php | 46 +- tests/Unit/Pivots/Wiki/AnimeStudioTest.php | 46 +- .../Pivots/Wiki/AnimeThemeEntryVideoTest.php | 46 +- tests/Unit/Pivots/Wiki/ArtistImageTest.php | 46 +- tests/Unit/Pivots/Wiki/ArtistMemberTest.php | 46 +- tests/Unit/Pivots/Wiki/ArtistResourceTest.php | 46 +- tests/Unit/Pivots/Wiki/ArtistSongTest.php | 46 +- tests/Unit/Pivots/Wiki/SongResourceTest.php | 46 +- tests/Unit/Pivots/Wiki/StudioImageTest.php | 46 +- tests/Unit/Pivots/Wiki/StudioResourceTest.php | 46 +- tests/Unit/Rules/Api/DelimitedTest.php | 99 +- .../Api/DistinctIgnoringDirectionTest.php | 93 +- .../Unit/Rules/Api/EnumLocalizedNameTest.php | 73 +- tests/Unit/Rules/Api/IsValidBooleanTest.php | 138 +- tests/Unit/Rules/Api/RandomSoleTest.php | 75 +- tests/Unit/Rules/ModerationTest.php | 138 +- .../Storage/StorageDirectoryExistsTest.php | 57 +- .../StorageFileDirectoryExistsTest.php | 59 +- .../Resource/AnimeResourceLinkFormatTest.php | 157 +- .../Resource/ArtistResourceLinkFormatTest.php | 157 +- .../Wiki/Resource/ResourceLinkFormatTest.php | 251 +- .../Resource/ResourceSiteMatchesLinkTest.php | 115 +- .../Resource/SongResourceLinkFormatTest.php | 157 +- .../Resource/StudioResourceLinkFormatTest.php | 157 +- .../Audio/AudioChannelLayoutStreamTest.php | 137 +- .../Audio/AudioChannelsStreamTest.php | 137 +- .../Submission/Audio/AudioCodecStreamTest.php | 137 +- .../Submission/Audio/AudioIndexStreamTest.php | 139 +- ...udioLoudnessIntegratedTargetStreamTest.php | 133 +- .../Audio/AudioLoudnessTruePeakStreamTest.php | 133 +- .../Audio/AudioSampleRateStreamTest.php | 137 +- .../AudioBitrateRestrictionFormatTest.php | 133 +- .../Format/EncoderNameFormatTest.php | 133 +- .../Format/EncoderVersionFormatTest.php | 137 +- .../Format/ExtraneousChaptersFormatTest.php | 125 +- .../Format/ExtraneousMetadataFormatTest.php | 139 +- .../Format/FormatNameFormatTest.php | 131 +- .../Format/TotalStreamsFormatTest.php | 139 +- .../VideoBitrateRestrictionFormatTest.php | 175 +- .../Rules/Wiki/Submission/SubmissionTest.php | 187 +- .../Submission/Video/VideoCodecStreamTest.php | 141 +- .../Video/VideoColorPrimariesStreamTest.php | 141 +- .../Video/VideoColorSpaceStreamTest.php | 141 +- .../Video/VideoColorTransferStreamTest.php | 141 +- .../Submission/Video/VideoIndexStreamTest.php | 137 +- .../Video/VideoPixelFormatStreamTest.php | 141 +- .../Api/Parser/FilterParserTest.php | 111 +- .../Api/Parser/PagingParserTest.php | 33 +- .../Api/Parser/SortParserTest.php | 49 +- 487 files changed, 41992 insertions(+), 54171 deletions(-) create mode 100644 tests/Pest.php create mode 100644 tests/Unit/ArchTest.php delete mode 100644 tests/Unit/Filament/BaseResourceTestCase.php diff --git a/app/Concerns/GraphQL/ResolvesArguments.php b/app/Concerns/GraphQL/ResolvesArguments.php index a9d379a0a..c17efe73e 100644 --- a/app/Concerns/GraphQL/ResolvesArguments.php +++ b/app/Concerns/GraphQL/ResolvesArguments.php @@ -54,8 +54,8 @@ trait ResolvesArguments { return collect($fields) ->filter(fn (Field $field) => $field instanceof FilterableField) - ->map(fn (FilterableField $field) => - collect($field->filterDirectives()) + ->map( + fn (FilterableField $field) => collect($field->filterDirectives()) ->map(fn (FilterDirective $directive) => $directive->argument()) ->toArray() ) @@ -106,8 +106,8 @@ trait ResolvesArguments { return collect($fields) ->filter(fn (Field $field) => $field instanceof CreatableField) - ->map(fn (Field $field) => - new Argument($field->getColumn(), $field->type()) + ->map( + fn (Field $field) => new Argument($field->getColumn(), $field->type()) ->required($field instanceof RequiredOnCreation) ) ->flatten() @@ -124,8 +124,8 @@ trait ResolvesArguments { return collect($fields) ->filter(fn (Field $field) => $field instanceof UpdatableField) - ->map(fn (Field $field) => - new Argument($field->getColumn(), $field->type()) + ->map( + fn (Field $field) => new Argument($field->getColumn(), $field->type()) ->required($field instanceof RequiredOnUpdate) ) ->flatten() @@ -142,8 +142,8 @@ trait ResolvesArguments { return collect($fields) ->filter(fn (Field $field) => $field instanceof BindableField) - ->map(fn (Field&BindableField $field) => - new Argument($field->getName(), $field->type()) + ->map( + fn (Field&BindableField $field) => new Argument($field->getName(), $field->type()) ->required($shouldRequire) ->directives([ 'bind' => [ diff --git a/app/GraphQL/Definition/Types/Wiki/Song/PerformanceType.php b/app/GraphQL/Definition/Types/Wiki/Song/PerformanceType.php index 4b11546c4..0e4ef0846 100644 --- a/app/GraphQL/Definition/Types/Wiki/Song/PerformanceType.php +++ b/app/GraphQL/Definition/Types/Wiki/Song/PerformanceType.php @@ -40,8 +40,10 @@ class PerformanceType extends EloquentType implements HasFields, HasRelations, R public function relations(): array { return [ - new BelongsToRelation(new SongType(), Performance::RELATION_SONG), - new MorphToRelation(new PerformanceArtistUnion(), Performance::RELATION_ARTIST), + new BelongsToRelation(new SongType(), Performance::RELATION_SONG) + ->notNullable(), + new MorphToRelation(new PerformanceArtistUnion(), Performance::RELATION_ARTIST) + ->notNullable(), ]; } diff --git a/composer.json b/composer.json index db6da7b1c..19519f8c0 100644 --- a/composer.json +++ b/composer.json @@ -58,12 +58,11 @@ }, "require-dev": { "barryvdh/laravel-debugbar": "^3.16.0", - "brianium/paratest": "^7.8.4", "laravel/pint": "^1.24.0", "laravel/sail": "^1.44.0", "mockery/mockery": "^1.6.12", - "nunomaduro/collision": "^8.8.2", - "phpunit/phpunit": "^11.5.27", + "pestphp/pest": "3.8.2", + "pestphp/pest-plugin-laravel": "^3.2", "predis/predis": "^2.4.0", "spatie/laravel-ignition": "^2.9.1" }, @@ -76,6 +75,7 @@ "preferred-install": "dist", "sort-packages": true, "allow-plugins": { + "pestphp/pest-plugin": true, "php-http/discovery": true } }, diff --git a/composer.lock b/composer.lock index 39684c07f..ca5ff1b38 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c103caa65639f246e64aee89ed9c823f", + "content-hash": "3fec187b8284d78cf9fbb2f595a6c296", "packages": [ { "name": "anourvalar/eloquent-serialize", @@ -6083,16 +6083,16 @@ }, { "name": "nikic/php-parser", - "version": "v5.5.0", + "version": "v5.6.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "ae59794362fe85e051a58ad36b289443f57be7a9" + "reference": "221b0d0fdf1369c71047ad1d18bb5880017bbc56" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ae59794362fe85e051a58ad36b289443f57be7a9", - "reference": "ae59794362fe85e051a58ad36b289443f57be7a9", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/221b0d0fdf1369c71047ad1d18bb5880017bbc56", + "reference": "221b0d0fdf1369c71047ad1d18bb5880017bbc56", "shasum": "" }, "require": { @@ -6135,9 +6135,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.5.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.0" }, - "time": "2025-05-31T08:24:38+00:00" + "time": "2025-07-27T20:03:57+00:00" }, { "name": "nunomaduro/termwind", @@ -12071,16 +12071,16 @@ }, { "name": "brianium/paratest", - "version": "v7.8.4", + "version": "v7.8.3", "source": { "type": "git", "url": "https://github.com/paratestphp/paratest.git", - "reference": "130a9bf0e269ee5f5b320108f794ad03e275cad4" + "reference": "a585c346ddf1bec22e51e20b5387607905604a71" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paratestphp/paratest/zipball/130a9bf0e269ee5f5b320108f794ad03e275cad4", - "reference": "130a9bf0e269ee5f5b320108f794ad03e275cad4", + "url": "https://api.github.com/repos/paratestphp/paratest/zipball/a585c346ddf1bec22e51e20b5387607905604a71", + "reference": "a585c346ddf1bec22e51e20b5387607905604a71", "shasum": "" }, "require": { @@ -12089,26 +12089,26 @@ "ext-reflection": "*", "ext-simplexml": "*", "fidry/cpu-core-counter": "^1.2.0", - "jean85/pretty-package-versions": "^2.1.1", + "jean85/pretty-package-versions": "^2.1.0", "php": "~8.2.0 || ~8.3.0 || ~8.4.0", - "phpunit/php-code-coverage": "^11.0.10", - "phpunit/php-file-iterator": "^5.1.0", - "phpunit/php-timer": "^7.0.1", - "phpunit/phpunit": "^11.5.24", - "sebastian/environment": "^7.2.1", - "symfony/console": "^6.4.22 || ^7.3.0", - "symfony/process": "^6.4.20 || ^7.3.0" + "phpunit/php-code-coverage": "^11.0.9 || ^12.0.4", + "phpunit/php-file-iterator": "^5.1.0 || ^6", + "phpunit/php-timer": "^7.0.1 || ^8", + "phpunit/phpunit": "^11.5.11 || ^12.0.6", + "sebastian/environment": "^7.2.0 || ^8", + "symfony/console": "^6.4.17 || ^7.2.1", + "symfony/process": "^6.4.19 || ^7.2.4" }, "require-dev": { "doctrine/coding-standard": "^12.0.0", "ext-pcov": "*", "ext-posix": "*", - "phpstan/phpstan": "^2.1.17", - "phpstan/phpstan-deprecation-rules": "^2.0.3", - "phpstan/phpstan-phpunit": "^2.0.6", - "phpstan/phpstan-strict-rules": "^2.0.4", - "squizlabs/php_codesniffer": "^3.13.2", - "symfony/filesystem": "^6.4.13 || ^7.3.0" + "phpstan/phpstan": "^2.1.6", + "phpstan/phpstan-deprecation-rules": "^2.0.1", + "phpstan/phpstan-phpunit": "^2.0.4", + "phpstan/phpstan-strict-rules": "^2.0.3", + "squizlabs/php_codesniffer": "^3.11.3", + "symfony/filesystem": "^6.4.13 || ^7.2.0" }, "bin": [ "bin/paratest", @@ -12148,7 +12148,7 @@ ], "support": { "issues": "https://github.com/paratestphp/paratest/issues", - "source": "https://github.com/paratestphp/paratest/tree/v7.8.4" + "source": "https://github.com/paratestphp/paratest/tree/v7.8.3" }, "funding": [ { @@ -12160,7 +12160,55 @@ "type": "paypal" } ], - "time": "2025-06-23T06:07:21+00:00" + "time": "2025-03-05T08:29:11+00:00" + }, + { + "name": "doctrine/deprecations", + "version": "1.1.5", + "source": { + "type": "git", + "url": "https://github.com/doctrine/deprecations.git", + "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38", + "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "phpunit/phpunit": "<=7.5 || >=13" + }, + "require-dev": { + "doctrine/coding-standard": "^9 || ^12 || ^13", + "phpstan/phpstan": "1.4.10 || 2.1.11", + "phpstan/phpstan-phpunit": "^1.0 || ^2", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12", + "psr/log": "^1 || ^2 || ^3" + }, + "suggest": { + "psr/log": "Allows logging deprecations via PSR-3 logger implementation" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Deprecations\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", + "homepage": "https://www.doctrine-project.org/", + "support": { + "issues": "https://github.com/doctrine/deprecations/issues", + "source": "https://github.com/doctrine/deprecations/tree/1.1.5" + }, + "time": "2025-04-07T20:06:18+00:00" }, { "name": "fidry/cpu-core-counter", @@ -12779,6 +12827,404 @@ ], "time": "2025-06-25T02:12:12+00:00" }, + { + "name": "pestphp/pest", + "version": "v3.8.2", + "source": { + "type": "git", + "url": "https://github.com/pestphp/pest.git", + "reference": "c6244a8712968dbac88eb998e7ff3b5caa556b0d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pestphp/pest/zipball/c6244a8712968dbac88eb998e7ff3b5caa556b0d", + "reference": "c6244a8712968dbac88eb998e7ff3b5caa556b0d", + "shasum": "" + }, + "require": { + "brianium/paratest": "^7.8.3", + "nunomaduro/collision": "^8.8.0", + "nunomaduro/termwind": "^2.3.0", + "pestphp/pest-plugin": "^3.0.0", + "pestphp/pest-plugin-arch": "^3.1.0", + "pestphp/pest-plugin-mutate": "^3.0.5", + "php": "^8.2.0", + "phpunit/phpunit": "^11.5.15" + }, + "conflict": { + "filp/whoops": "<2.16.0", + "phpunit/phpunit": ">11.5.15", + "sebastian/exporter": "<6.0.0", + "webmozart/assert": "<1.11.0" + }, + "require-dev": { + "pestphp/pest-dev-tools": "^3.4.0", + "pestphp/pest-plugin-type-coverage": "^3.5.0", + "symfony/process": "^7.2.5" + }, + "bin": [ + "bin/pest" + ], + "type": "library", + "extra": { + "pest": { + "plugins": [ + "Pest\\Mutate\\Plugins\\Mutate", + "Pest\\Plugins\\Configuration", + "Pest\\Plugins\\Bail", + "Pest\\Plugins\\Cache", + "Pest\\Plugins\\Coverage", + "Pest\\Plugins\\Init", + "Pest\\Plugins\\Environment", + "Pest\\Plugins\\Help", + "Pest\\Plugins\\Memory", + "Pest\\Plugins\\Only", + "Pest\\Plugins\\Printer", + "Pest\\Plugins\\ProcessIsolation", + "Pest\\Plugins\\Profile", + "Pest\\Plugins\\Retry", + "Pest\\Plugins\\Snapshot", + "Pest\\Plugins\\Verbose", + "Pest\\Plugins\\Version", + "Pest\\Plugins\\Parallel" + ] + }, + "phpstan": { + "includes": [ + "extension.neon" + ] + } + }, + "autoload": { + "files": [ + "src/Functions.php", + "src/Pest.php" + ], + "psr-4": { + "Pest\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "The elegant PHP Testing Framework.", + "keywords": [ + "framework", + "pest", + "php", + "test", + "testing", + "unit" + ], + "support": { + "issues": "https://github.com/pestphp/pest/issues", + "source": "https://github.com/pestphp/pest/tree/v3.8.2" + }, + "funding": [ + { + "url": "https://www.paypal.com/paypalme/enunomaduro", + "type": "custom" + }, + { + "url": "https://github.com/nunomaduro", + "type": "github" + } + ], + "time": "2025-04-17T10:53:02+00:00" + }, + { + "name": "pestphp/pest-plugin", + "version": "v3.0.0", + "source": { + "type": "git", + "url": "https://github.com/pestphp/pest-plugin.git", + "reference": "e79b26c65bc11c41093b10150c1341cc5cdbea83" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pestphp/pest-plugin/zipball/e79b26c65bc11c41093b10150c1341cc5cdbea83", + "reference": "e79b26c65bc11c41093b10150c1341cc5cdbea83", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^2.0.0", + "composer-runtime-api": "^2.2.2", + "php": "^8.2" + }, + "conflict": { + "pestphp/pest": "<3.0.0" + }, + "require-dev": { + "composer/composer": "^2.7.9", + "pestphp/pest": "^3.0.0", + "pestphp/pest-dev-tools": "^3.0.0" + }, + "type": "composer-plugin", + "extra": { + "class": "Pest\\Plugin\\Manager" + }, + "autoload": { + "psr-4": { + "Pest\\Plugin\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "The Pest plugin manager", + "keywords": [ + "framework", + "manager", + "pest", + "php", + "plugin", + "test", + "testing", + "unit" + ], + "support": { + "source": "https://github.com/pestphp/pest-plugin/tree/v3.0.0" + }, + "funding": [ + { + "url": "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=66BYDWAT92N6L", + "type": "custom" + }, + { + "url": "https://github.com/nunomaduro", + "type": "github" + }, + { + "url": "https://www.patreon.com/nunomaduro", + "type": "patreon" + } + ], + "time": "2024-09-08T23:21:41+00:00" + }, + { + "name": "pestphp/pest-plugin-arch", + "version": "v3.1.1", + "source": { + "type": "git", + "url": "https://github.com/pestphp/pest-plugin-arch.git", + "reference": "db7bd9cb1612b223e16618d85475c6f63b9c8daa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pestphp/pest-plugin-arch/zipball/db7bd9cb1612b223e16618d85475c6f63b9c8daa", + "reference": "db7bd9cb1612b223e16618d85475c6f63b9c8daa", + "shasum": "" + }, + "require": { + "pestphp/pest-plugin": "^3.0.0", + "php": "^8.2", + "ta-tikoma/phpunit-architecture-test": "^0.8.4" + }, + "require-dev": { + "pestphp/pest": "^3.8.1", + "pestphp/pest-dev-tools": "^3.4.0" + }, + "type": "library", + "extra": { + "pest": { + "plugins": [ + "Pest\\Arch\\Plugin" + ] + } + }, + "autoload": { + "files": [ + "src/Autoload.php" + ], + "psr-4": { + "Pest\\Arch\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "The Arch plugin for Pest PHP.", + "keywords": [ + "arch", + "architecture", + "framework", + "pest", + "php", + "plugin", + "test", + "testing", + "unit" + ], + "support": { + "source": "https://github.com/pestphp/pest-plugin-arch/tree/v3.1.1" + }, + "funding": [ + { + "url": "https://www.paypal.com/paypalme/enunomaduro", + "type": "custom" + }, + { + "url": "https://github.com/nunomaduro", + "type": "github" + } + ], + "time": "2025-04-16T22:59:48+00:00" + }, + { + "name": "pestphp/pest-plugin-laravel", + "version": "v3.2.0", + "source": { + "type": "git", + "url": "https://github.com/pestphp/pest-plugin-laravel.git", + "reference": "6801be82fd92b96e82dd72e563e5674b1ce365fc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pestphp/pest-plugin-laravel/zipball/6801be82fd92b96e82dd72e563e5674b1ce365fc", + "reference": "6801be82fd92b96e82dd72e563e5674b1ce365fc", + "shasum": "" + }, + "require": { + "laravel/framework": "^11.39.1|^12.9.2", + "pestphp/pest": "^3.8.2", + "php": "^8.2.0" + }, + "require-dev": { + "laravel/dusk": "^8.2.13|dev-develop", + "orchestra/testbench": "^9.9.0|^10.2.1", + "pestphp/pest-dev-tools": "^3.4.0" + }, + "type": "library", + "extra": { + "pest": { + "plugins": [ + "Pest\\Laravel\\Plugin" + ] + }, + "laravel": { + "providers": [ + "Pest\\Laravel\\PestServiceProvider" + ] + } + }, + "autoload": { + "files": [ + "src/Autoload.php" + ], + "psr-4": { + "Pest\\Laravel\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "The Pest Laravel Plugin", + "keywords": [ + "framework", + "laravel", + "pest", + "php", + "test", + "testing", + "unit" + ], + "support": { + "source": "https://github.com/pestphp/pest-plugin-laravel/tree/v3.2.0" + }, + "funding": [ + { + "url": "https://www.paypal.com/paypalme/enunomaduro", + "type": "custom" + }, + { + "url": "https://github.com/nunomaduro", + "type": "github" + } + ], + "time": "2025-04-21T07:40:53+00:00" + }, + { + "name": "pestphp/pest-plugin-mutate", + "version": "v3.0.5", + "source": { + "type": "git", + "url": "https://github.com/pestphp/pest-plugin-mutate.git", + "reference": "e10dbdc98c9e2f3890095b4fe2144f63a5717e08" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pestphp/pest-plugin-mutate/zipball/e10dbdc98c9e2f3890095b4fe2144f63a5717e08", + "reference": "e10dbdc98c9e2f3890095b4fe2144f63a5717e08", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.2.0", + "pestphp/pest-plugin": "^3.0.0", + "php": "^8.2", + "psr/simple-cache": "^3.0.0" + }, + "require-dev": { + "pestphp/pest": "^3.0.8", + "pestphp/pest-dev-tools": "^3.0.0", + "pestphp/pest-plugin-type-coverage": "^3.0.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Pest\\Mutate\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Sandro Gehri", + "email": "sandrogehri@gmail.com" + } + ], + "description": "Mutates your code to find untested cases", + "keywords": [ + "framework", + "mutate", + "mutation", + "pest", + "php", + "plugin", + "test", + "testing", + "unit" + ], + "support": { + "source": "https://github.com/pestphp/pest-plugin-mutate/tree/v3.0.5" + }, + "funding": [ + { + "url": "https://www.paypal.com/paypalme/enunomaduro", + "type": "custom" + }, + { + "url": "https://github.com/gehrisandro", + "type": "github" + }, + { + "url": "https://github.com/nunomaduro", + "type": "github" + } + ], + "time": "2024-09-22T07:54:40+00:00" + }, { "name": "phar-io/manifest", "version": "2.0.4", @@ -12970,6 +13416,228 @@ }, "time": "2025-07-22T14:01:30+00:00" }, + { + "name": "phpdocumentor/reflection-common", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-2.x": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", + "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" + }, + "time": "2020-06-27T09:03:43+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "5.6.2", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "92dde6a5919e34835c506ac8c523ef095a95ed62" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/92dde6a5919e34835c506ac8c523ef095a95ed62", + "reference": "92dde6a5919e34835c506ac8c523ef095a95ed62", + "shasum": "" + }, + "require": { + "doctrine/deprecations": "^1.1", + "ext-filter": "*", + "php": "^7.4 || ^8.0", + "phpdocumentor/reflection-common": "^2.2", + "phpdocumentor/type-resolver": "^1.7", + "phpstan/phpdoc-parser": "^1.7|^2.0", + "webmozart/assert": "^1.9.1" + }, + "require-dev": { + "mockery/mockery": "~1.3.5 || ~1.6.0", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-mockery": "^1.1", + "phpstan/phpstan-webmozart-assert": "^1.2", + "phpunit/phpunit": "^9.5", + "psalm/phar": "^5.26" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + }, + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.2" + }, + "time": "2025-04-13T19:20:35+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "1.10.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/679e3ce485b99e84c775d28e2e96fade9a7fb50a", + "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a", + "shasum": "" + }, + "require": { + "doctrine/deprecations": "^1.0", + "php": "^7.3 || ^8.0", + "phpdocumentor/reflection-common": "^2.0", + "phpstan/phpdoc-parser": "^1.18|^2.0" + }, + "require-dev": { + "ext-tokenizer": "*", + "phpbench/phpbench": "^1.2", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-phpunit": "^1.1", + "phpunit/phpunit": "^9.5", + "rector/rector": "^0.13.9", + "vimeo/psalm": "^4.25" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-1.x": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "support": { + "issues": "https://github.com/phpDocumentor/TypeResolver/issues", + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.10.0" + }, + "time": "2024-11-09T15:12:26+00:00" + }, + { + "name": "phpstan/phpdoc-parser", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "b9e61a61e39e02dd90944e9115241c7f7e76bfd8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/b9e61a61e39e02dd90944e9115241c7f7e76bfd8", + "reference": "b9e61a61e39e02dd90944e9115241c7f7e76bfd8", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "doctrine/annotations": "^2.0", + "nikic/php-parser": "^5.3.0", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^9.6", + "symfony/process": "^5.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPDoc parser with support for nullable, intersection and generic types", + "support": { + "issues": "https://github.com/phpstan/phpdoc-parser/issues", + "source": "https://github.com/phpstan/phpdoc-parser/tree/2.2.0" + }, + "time": "2025-07-13T07:04:09+00:00" + }, { "name": "phpunit/php-code-coverage", "version": "11.0.10", @@ -13307,16 +13975,16 @@ }, { "name": "phpunit/phpunit", - "version": "11.5.27", + "version": "11.5.15", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "446d43867314781df7e9adf79c3ec7464956fd8f" + "reference": "4b6a4ee654e5e0c5e1f17e2f83c0f4c91dee1f9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/446d43867314781df7e9adf79c3ec7464956fd8f", - "reference": "446d43867314781df7e9adf79c3ec7464956fd8f", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/4b6a4ee654e5e0c5e1f17e2f83c0f4c91dee1f9c", + "reference": "4b6a4ee654e5e0c5e1f17e2f83c0f4c91dee1f9c", "shasum": "" }, "require": { @@ -13326,11 +13994,11 @@ "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.13.3", + "myclabs/deep-copy": "^1.13.0", "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", "php": ">=8.2", - "phpunit/php-code-coverage": "^11.0.10", + "phpunit/php-code-coverage": "^11.0.9", "phpunit/php-file-iterator": "^5.1.0", "phpunit/php-invoker": "^5.0.1", "phpunit/php-text-template": "^4.0.1", @@ -13339,7 +14007,7 @@ "sebastian/code-unit": "^3.0.3", "sebastian/comparator": "^6.3.1", "sebastian/diff": "^6.0.2", - "sebastian/environment": "^7.2.1", + "sebastian/environment": "^7.2.0", "sebastian/exporter": "^6.3.0", "sebastian/global-state": "^7.0.2", "sebastian/object-enumerator": "^6.0.1", @@ -13388,7 +14056,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.27" + "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.15" }, "funding": [ { @@ -13399,20 +14067,12 @@ "url": "https://github.com/sebastianbergmann", "type": "github" }, - { - "url": "https://liberapay.com/sebastianbergmann", - "type": "liberapay" - }, - { - "url": "https://thanks.dev/u/gh/sebastianbergmann", - "type": "thanks_dev" - }, { "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", "type": "tidelift" } ], - "time": "2025-07-11T04:10:06+00:00" + "time": "2025-03-23T16:02:11+00:00" }, { "name": "predis/predis", @@ -14918,6 +15578,65 @@ ], "time": "2025-06-03T06:57:57+00:00" }, + { + "name": "ta-tikoma/phpunit-architecture-test", + "version": "0.8.5", + "source": { + "type": "git", + "url": "https://github.com/ta-tikoma/phpunit-architecture-test.git", + "reference": "cf6fb197b676ba716837c886baca842e4db29005" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ta-tikoma/phpunit-architecture-test/zipball/cf6fb197b676ba716837c886baca842e4db29005", + "reference": "cf6fb197b676ba716837c886baca842e4db29005", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.18.0 || ^5.0.0", + "php": "^8.1.0", + "phpdocumentor/reflection-docblock": "^5.3.0", + "phpunit/phpunit": "^10.5.5 || ^11.0.0 || ^12.0.0", + "symfony/finder": "^6.4.0 || ^7.0.0" + }, + "require-dev": { + "laravel/pint": "^1.13.7", + "phpstan/phpstan": "^1.10.52" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPUnit\\Architecture\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ni Shi", + "email": "futik0ma011@gmail.com" + }, + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "Methods for testing application architecture", + "keywords": [ + "architecture", + "phpunit", + "stucture", + "test", + "testing" + ], + "support": { + "issues": "https://github.com/ta-tikoma/phpunit-architecture-test/issues", + "source": "https://github.com/ta-tikoma/phpunit-architecture-test/tree/0.8.5" + }, + "time": "2025-04-20T20:23:40+00:00" + }, { "name": "theseer/tokenizer", "version": "1.2.3", diff --git a/phpstan.neon b/phpstan.neon index 5857fd01a..eaa3119d1 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -34,3 +34,15 @@ parameters: - '#Access to an undefined property App\\Models\\Wiki\\Artist::\$pivot.#' - '#Call to method assertActionMounted\(\) on an unknown class static.#' - '#Call to method assertTableActionMounted\(\) on an unknown class static.#' + - + message: '#Call to an undefined method PHPUnit\\Framework\\TestCase::.*\(\)#' + path: tests/* + - + message: '#Call to protected method expectException\(\) of class PHPUnit\\Framework\\TestCase.#' + path: tests/* + - + message: '#Call to an undefined method Pest\\PendingCalls\\TestCall::expect\(\).#' + path: tests/Unit/ArchTest.php + - + message: '#Undefined variable: \$this#' + path: tests/Pest.php diff --git a/pint.json b/pint.json index ae5f83404..5c059f140 100644 --- a/pint.json +++ b/pint.json @@ -120,6 +120,9 @@ "trailing_comma_in_multiline": true, "trim_array_spaces": true, "unary_operator_spaces": true, + "visibility_required": { + "elements": ["method", "property"] + }, "whitespace_after_comma_in_array": true } } \ No newline at end of file diff --git a/tests/Feature/Actions/Fortify/CreateNewUserTest.php b/tests/Feature/Actions/Fortify/CreateNewUserTest.php index b9e298688..75f434dce 100644 --- a/tests/Feature/Actions/Fortify/CreateNewUserTest.php +++ b/tests/Feature/Actions/Fortify/CreateNewUserTest.php @@ -2,284 +2,217 @@ declare(strict_types=1); -namespace Tests\Feature\Actions\Fortify; - use App\Actions\Fortify\CreateNewUser; use App\Constants\Config\ValidationConstants; use App\Enums\Rules\ModerationService; use App\Models\Auth\User; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Http; use Illuminate\Support\Str; use Illuminate\Validation\ValidationException; use Mockery\MockInterface; use Propaganistas\LaravelDisposableEmail\Validation\Indisposable; -use Tests\TestCase; -class CreateNewUserTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Create New User Action shall require the name, email, password & terms fields. - * - * @throws ValidationException - */ - public function testRequired(): void - { - static::expectException(ValidationException::class); +test('required', function () { + $this->expectException(ValidationException::class); - $action = new CreateNewUser(); + $action = new CreateNewUser(); - $action->create([]); - } + $action->create([]); +}); - /** - * The Create New User Action shall require usernames to be restricted to alphanumeric characters and dashes. - * - * @throws ValidationException - */ - public function testUsernameAlphaDash(): void - { - static::expectException(ValidationException::class); +test('username alpha dash', function () { + $this->expectException(ValidationException::class); - $action = new CreateNewUser(); + $action = new CreateNewUser(); - $password = Str::password(20); + $password = Str::password(20); - $action->create([ - User::ATTRIBUTE_NAME => $this->faker->password(20), - User::ATTRIBUTE_EMAIL => $this->faker->companyEmail(), - User::ATTRIBUTE_PASSWORD => $password, - 'password_confirmation' => $password, - 'terms' => 'terms', - ]); - } + $action->create([ + User::ATTRIBUTE_NAME => fake()->password(20), + User::ATTRIBUTE_EMAIL => fake()->companyEmail(), + User::ATTRIBUTE_PASSWORD => $password, + 'password_confirmation' => $password, + 'terms' => 'terms', + ]); +}); - /** - * The Create New User Action shall require usernames to be unique. - * - * @throws ValidationException - */ - public function testUsernameUnique(): void - { - static::expectException(ValidationException::class); +test('username unique', function () { + $this->expectException(ValidationException::class); - $name = $this->faker()->word(); + $name = fake()->word(); - User::factory()->createOne([ - User::ATTRIBUTE_NAME => $name, - ]); + User::factory()->createOne([ + User::ATTRIBUTE_NAME => $name, + ]); - $action = new CreateNewUser(); + $action = new CreateNewUser(); - $password = Str::password(20); + $password = Str::password(20); - $action->create([ - User::ATTRIBUTE_NAME => $name, - User::ATTRIBUTE_EMAIL => $this->faker->companyEmail(), - User::ATTRIBUTE_PASSWORD => $password, - 'password_confirmation' => $password, - 'terms' => 'terms', - ]); - } + $action->create([ + User::ATTRIBUTE_NAME => $name, + User::ATTRIBUTE_EMAIL => fake()->companyEmail(), + User::ATTRIBUTE_PASSWORD => $password, + 'password_confirmation' => $password, + 'terms' => 'terms', + ]); +}); - /** - * The Create New User Action shall create a new user. - * - * @throws ValidationException - */ - public function testCreated(): void - { - $action = new CreateNewUser(); +test('created', function () { + $action = new CreateNewUser(); - $password = Str::password(20); + $password = Str::password(20); - $action->create([ - User::ATTRIBUTE_NAME => $this->faker()->word(), - User::ATTRIBUTE_EMAIL => $this->faker->companyEmail(), - User::ATTRIBUTE_PASSWORD => $password, - 'password_confirmation' => $password, - 'terms' => 'terms', - ]); + $action->create([ + User::ATTRIBUTE_NAME => fake()->word(), + User::ATTRIBUTE_EMAIL => fake()->companyEmail(), + User::ATTRIBUTE_PASSWORD => $password, + 'password_confirmation' => $password, + 'terms' => 'terms', + ]); - static::assertDatabaseCount(User::class, 1); - } + $this->assertDatabaseCount(User::class, 1); +}); - /** - * The Create New User Action shall create a new user if the name is not flagged by OpenAI. - * - * @throws ValidationException - */ - public function testCreatedIfNotFlaggedByOpenAi(): void - { - Config::set(ValidationConstants::MODERATION_SERVICE_QUALIFIED, ModerationService::OPENAI->value); +test('created if not flagged by open ai', function () { + Config::set(ValidationConstants::MODERATION_SERVICE_QUALIFIED, ModerationService::OPENAI->value); - Http::fake([ - 'https://api.openai.com/v1/moderations' => Http::response([ - 'results' => [ - 0 => [ - 'flagged' => false, - ], + Http::fake([ + 'https://api.openai.com/v1/moderations' => Http::response([ + 'results' => [ + 0 => [ + 'flagged' => false, ], - ]), - ]); + ], + ]), + ]); - $action = new CreateNewUser(); + $action = new CreateNewUser(); - $password = Str::password(20); + $password = Str::password(20); - $action->create([ - User::ATTRIBUTE_NAME => $this->faker()->word(), - User::ATTRIBUTE_EMAIL => $this->faker->companyEmail(), - User::ATTRIBUTE_PASSWORD => $password, - 'password_confirmation' => $password, - 'terms' => 'terms', - ]); + $action->create([ + User::ATTRIBUTE_NAME => fake()->word(), + User::ATTRIBUTE_EMAIL => fake()->companyEmail(), + User::ATTRIBUTE_PASSWORD => $password, + 'password_confirmation' => $password, + 'terms' => 'terms', + ]); - static::assertDatabaseCount(User::class, 1); - } + $this->assertDatabaseCount(User::class, 1); +}); - /** - * The Create New User Action shall create a new user if the moderation service returns some error. - * - * @throws ValidationException - */ - public function testCreatedIfOpenAiFails(): void - { - Config::set(ValidationConstants::MODERATION_SERVICE_QUALIFIED, ModerationService::OPENAI->value); +test('created if open ai fails', function () { + Config::set(ValidationConstants::MODERATION_SERVICE_QUALIFIED, ModerationService::OPENAI->value); - Http::fake([ - 'https://api.openai.com/v1/moderations' => Http::response(status: 404), - ]); + Http::fake([ + 'https://api.openai.com/v1/moderations' => Http::response(status: 404), + ]); - $action = new CreateNewUser(); + $action = new CreateNewUser(); - $password = Str::password(20); + $password = Str::password(20); - $action->create([ - User::ATTRIBUTE_NAME => $this->faker()->word(), - User::ATTRIBUTE_EMAIL => $this->faker->companyEmail(), - User::ATTRIBUTE_PASSWORD => $password, - 'password_confirmation' => $password, - 'terms' => 'terms', - ]); + $action->create([ + User::ATTRIBUTE_NAME => fake()->word(), + User::ATTRIBUTE_EMAIL => fake()->companyEmail(), + User::ATTRIBUTE_PASSWORD => $password, + 'password_confirmation' => $password, + 'terms' => 'terms', + ]); - static::assertDatabaseCount(User::class, 1); - } + $this->assertDatabaseCount(User::class, 1); +}); - /** - * The Create New User Action shall prohibit users from creating usernames flagged by OpenAI. - * - * @throws ValidationException - */ - public function testValidationErrorWhenFlaggedByOpenAi(): void - { - static::expectException(ValidationException::class); +test('validation error when flagged by open ai', function () { + $this->expectException(ValidationException::class); - Config::set(ValidationConstants::MODERATION_SERVICE_QUALIFIED, ModerationService::OPENAI->value); + Config::set(ValidationConstants::MODERATION_SERVICE_QUALIFIED, ModerationService::OPENAI->value); - Http::fake([ - 'https://api.openai.com/v1/moderations' => Http::response([ - 'results' => [ - 0 => [ - 'flagged' => true, - ], + Http::fake([ + 'https://api.openai.com/v1/moderations' => Http::response([ + 'results' => [ + 0 => [ + 'flagged' => true, ], - ]), - ]); + ], + ]), + ]); - $action = new CreateNewUser(); + $action = new CreateNewUser(); - $password = Str::password(20); + $password = Str::password(20); - $action->create([ - User::ATTRIBUTE_NAME => $this->faker()->word(), - User::ATTRIBUTE_EMAIL => $this->faker->companyEmail(), - User::ATTRIBUTE_PASSWORD => $password, - 'password_confirmation' => $password, - 'terms' => 'terms', - ]); - } + $action->create([ + User::ATTRIBUTE_NAME => fake()->word(), + User::ATTRIBUTE_EMAIL => fake()->companyEmail(), + User::ATTRIBUTE_PASSWORD => $password, + 'password_confirmation' => $password, + 'terms' => 'terms', + ]); +}); - /** - * The Create New User Action shall prohibit registrations using disposable email services. - * - * @throws ValidationException - */ - public function testDisposableEmail(): void - { - static::expectException(ValidationException::class); +test('disposable email', function () { + $this->expectException(ValidationException::class); - $this->mock(Indisposable::class, function (MockInterface $mock) { - $mock->shouldReceive('validate')->once()->andReturn(false); - }); + $this->mock(Indisposable::class, function (MockInterface $mock) { + $mock->shouldReceive('validate')->once()->andReturn(false); + }); - $action = new CreateNewUser(); + $action = new CreateNewUser(); - $password = Str::password(20); + $password = Str::password(20); - $action->create([ - User::ATTRIBUTE_NAME => $this->faker()->word(), - User::ATTRIBUTE_EMAIL => $this->faker->companyEmail(), - User::ATTRIBUTE_PASSWORD => $password, - 'password_confirmation' => $password, - 'terms' => 'terms', - ]); - } + $action->create([ + User::ATTRIBUTE_NAME => fake()->word(), + User::ATTRIBUTE_EMAIL => fake()->companyEmail(), + User::ATTRIBUTE_PASSWORD => $password, + 'password_confirmation' => $password, + 'terms' => 'terms', + ]); +}); - /** - * The Create New User Action shall permit registrations using indisposable email services. - * - * @throws ValidationException - */ - public function testIndisposableEmail(): void - { - $this->mock(Indisposable::class, function (MockInterface $mock) { - $mock->shouldReceive('validate')->once()->andReturn(true); - }); +test('indisposable email', function () { + $this->mock(Indisposable::class, function (MockInterface $mock) { + $mock->shouldReceive('validate')->once()->andReturn(true); + }); - $action = new CreateNewUser(); + $action = new CreateNewUser(); - $password = Str::password(20); + $password = Str::password(20); - $action->create([ - User::ATTRIBUTE_NAME => $this->faker()->word(), - User::ATTRIBUTE_EMAIL => $this->faker->companyEmail(), - User::ATTRIBUTE_PASSWORD => $password, - 'password_confirmation' => $password, - 'terms' => 'terms', - ]); + $action->create([ + User::ATTRIBUTE_NAME => fake()->word(), + User::ATTRIBUTE_EMAIL => fake()->companyEmail(), + User::ATTRIBUTE_PASSWORD => $password, + 'password_confirmation' => $password, + 'terms' => 'terms', + ]); - static::assertDatabaseCount(User::class, 1); - } + $this->assertDatabaseCount(User::class, 1); +}); - /** - * The Create New User Action shall require emails to be unique. - * - * @throws ValidationException - */ - public function testEmailUnique(): void - { - static::expectException(ValidationException::class); +test('email unique', function () { + $this->expectException(ValidationException::class); - $email = $this->faker()->companyEmail(); + $email = fake()->companyEmail(); - User::factory()->createOne([ - User::ATTRIBUTE_EMAIL => $email, - ]); + User::factory()->createOne([ + User::ATTRIBUTE_EMAIL => $email, + ]); - $action = new CreateNewUser(); + $action = new CreateNewUser(); - $password = Str::password(20); + $password = Str::password(20); - $action->create([ - User::ATTRIBUTE_NAME => $this->faker->word(), - User::ATTRIBUTE_EMAIL => $email, - User::ATTRIBUTE_PASSWORD => $password, - 'password_confirmation' => $password, - 'terms' => 'terms', - ]); - } -} + $action->create([ + User::ATTRIBUTE_NAME => fake()->word(), + User::ATTRIBUTE_EMAIL => $email, + User::ATTRIBUTE_PASSWORD => $password, + 'password_confirmation' => $password, + 'terms' => 'terms', + ]); +}); diff --git a/tests/Feature/Actions/Fortify/UpdateUserProfileInformationTest.php b/tests/Feature/Actions/Fortify/UpdateUserProfileInformationTest.php index b2ee6fe0b..ed8436e86 100644 --- a/tests/Feature/Actions/Fortify/UpdateUserProfileInformationTest.php +++ b/tests/Feature/Actions/Fortify/UpdateUserProfileInformationTest.php @@ -2,331 +2,258 @@ declare(strict_types=1); -namespace Tests\Feature\Actions\Fortify; - use App\Actions\Fortify\UpdateUserProfileInformation; use App\Constants\Config\ValidationConstants; use App\Enums\Rules\ModerationService; use App\Models\Auth\User; use Illuminate\Auth\Notifications\VerifyEmail; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Notification; use Illuminate\Validation\ValidationException; use Mockery\MockInterface; use Propaganistas\LaravelDisposableEmail\Validation\Indisposable; -use Tests\TestCase; -class UpdateUserProfileInformationTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Update User Profile Information Action shall require the name, email, password & terms fields. - * - * @throws ValidationException - */ - public function testRequired(): void - { - static::expectException(ValidationException::class); +test('required', function () { + $this->expectException(ValidationException::class); - $user = User::factory()->createOne(); + $user = User::factory()->createOne(); - $action = new UpdateUserProfileInformation(); + $action = new UpdateUserProfileInformation(); - $action->update($user, []); - } + $action->update($user, []); +}); - /** - * The Update User Profile Information Action shall require usernames to be restricted to alphanumeric characters and dashes. - * - * @throws ValidationException - */ - public function testUsernameAlphaDash(): void - { - static::expectException(ValidationException::class); +test('username alpha dash', function () { + $this->expectException(ValidationException::class); - $user = User::factory()->createOne(); + $user = User::factory()->createOne(); - $action = new UpdateUserProfileInformation(); + $action = new UpdateUserProfileInformation(); - $action->update($user, [ - User::ATTRIBUTE_NAME => $this->faker->password(20), - ]); - } + $action->update($user, [ + User::ATTRIBUTE_NAME => fake()->password(20), + ]); +}); - /** - * The Update User Profile Information Action shall require usernames to be unique. - * - * @throws ValidationException - */ - public function testUsernameUnique(): void - { - static::expectException(ValidationException::class); +test('username unique', function () { + $this->expectException(ValidationException::class); - $name = $this->faker()->word(); + $name = fake()->word(); - User::factory()->createOne([ - User::ATTRIBUTE_NAME => $name, - ]); + User::factory()->createOne([ + User::ATTRIBUTE_NAME => $name, + ]); - $user = User::factory()->createOne(); + $user = User::factory()->createOne(); - $action = new UpdateUserProfileInformation(); + $action = new UpdateUserProfileInformation(); - $action->update($user, [ - User::ATTRIBUTE_NAME => $name, - ]); - } + $action->update($user, [ + User::ATTRIBUTE_NAME => $name, + ]); +}); - /** - * The Update User Profile Information Action shall update the user name. - * - * @throws ValidationException - */ - public function testUpdateName(): void - { - $name = $this->faker->unique()->word(); +test('update name', function () { + $name = fake()->unique()->word(); - $user = User::factory()->createOne([ - User::ATTRIBUTE_NAME => $this->faker->unique()->word(), - ]); + $user = User::factory()->createOne([ + User::ATTRIBUTE_NAME => fake()->unique()->word(), + ]); - $action = new UpdateUserProfileInformation(); + $action = new UpdateUserProfileInformation(); - $action->update($user, [ - User::ATTRIBUTE_NAME => $name, - ]); + $action->update($user, [ + User::ATTRIBUTE_NAME => $name, + ]); - static::assertDatabaseCount(User::class, 1); - static::assertDatabaseHas(User::class, [ - User::ATTRIBUTE_NAME => $name, - ]); - static::assertDatabaseMissing(User::class, [ - User::ATTRIBUTE_EMAIL_VERIFIED_AT => null, - ]); - } + $this->assertDatabaseCount(User::class, 1); + $this->assertDatabaseHas(User::class, [ + User::ATTRIBUTE_NAME => $name, + ]); + $this->assertDatabaseMissing(User::class, [ + User::ATTRIBUTE_EMAIL_VERIFIED_AT => null, + ]); +}); - /** - * The Update User Profile Information Action shall update the user email. - * - * @throws ValidationException - */ - public function testUpdateEmail(): void - { - Notification::fake(); +test('update email', function () { + Notification::fake(); - $email = $this->faker->unique()->companyEmail(); + $email = fake()->unique()->companyEmail(); - $user = User::factory()->createOne([ - User::ATTRIBUTE_EMAIL => $this->faker->unique()->companyEmail(), - ]); + $user = User::factory()->createOne([ + User::ATTRIBUTE_EMAIL => fake()->unique()->companyEmail(), + ]); - $action = new UpdateUserProfileInformation(); + $action = new UpdateUserProfileInformation(); - $action->update($user, [ - User::ATTRIBUTE_EMAIL => $email, - ]); + $action->update($user, [ + User::ATTRIBUTE_EMAIL => $email, + ]); - static::assertDatabaseCount(User::class, 1); - static::assertDatabaseHas(User::class, [ - User::ATTRIBUTE_EMAIL => $email, - User::ATTRIBUTE_EMAIL_VERIFIED_AT => null, - ]); + $this->assertDatabaseCount(User::class, 1); + $this->assertDatabaseHas(User::class, [ + User::ATTRIBUTE_EMAIL => $email, + User::ATTRIBUTE_EMAIL_VERIFIED_AT => null, + ]); - Notification::assertSentTimes(VerifyEmail::class, 1); - } + Notification::assertSentTimes(VerifyEmail::class, 1); +}); - /** - * The Update User Profile Information Action shall update the user if the name is not flagged by OpenAI. - * - * @throws ValidationException - */ - public function testCreatedIfNotFlaggedByOpenAi(): void - { - Config::set(ValidationConstants::MODERATION_SERVICE_QUALIFIED, ModerationService::OPENAI->value); +test('created if not flagged by open ai', function () { + Config::set(ValidationConstants::MODERATION_SERVICE_QUALIFIED, ModerationService::OPENAI->value); - Http::fake([ - 'https://api.openai.com/v1/moderations' => Http::response([ - 'results' => [ - 0 => [ - 'flagged' => false, - ], + Http::fake([ + 'https://api.openai.com/v1/moderations' => Http::response([ + 'results' => [ + 0 => [ + 'flagged' => false, ], - ]), - ]); + ], + ]), + ]); - $name = $this->faker->unique()->word(); + $name = fake()->unique()->word(); - $user = User::factory()->createOne([ - User::ATTRIBUTE_NAME => $this->faker->unique()->word(), - ]); + $user = User::factory()->createOne([ + User::ATTRIBUTE_NAME => fake()->unique()->word(), + ]); - $action = new UpdateUserProfileInformation(); + $action = new UpdateUserProfileInformation(); - $action->update($user, [ - User::ATTRIBUTE_NAME => $name, - ]); + $action->update($user, [ + User::ATTRIBUTE_NAME => $name, + ]); - static::assertDatabaseCount(User::class, 1); - static::assertDatabaseHas(User::class, [ - User::ATTRIBUTE_NAME => $name, - ]); - static::assertDatabaseMissing(User::class, [ - User::ATTRIBUTE_EMAIL_VERIFIED_AT => null, - ]); - } + $this->assertDatabaseCount(User::class, 1); + $this->assertDatabaseHas(User::class, [ + User::ATTRIBUTE_NAME => $name, + ]); + $this->assertDatabaseMissing(User::class, [ + User::ATTRIBUTE_EMAIL_VERIFIED_AT => null, + ]); +}); - /** - * The Update User Profile Information Action shall update the user if the moderation service returns some error. - * - * @throws ValidationException - */ - public function testCreatedIfOpenAiFails(): void - { - Config::set(ValidationConstants::MODERATION_SERVICE_QUALIFIED, ModerationService::OPENAI->value); +test('created if open ai fails', function () { + Config::set(ValidationConstants::MODERATION_SERVICE_QUALIFIED, ModerationService::OPENAI->value); - Http::fake([ - 'https://api.openai.com/v1/moderations' => Http::response(status: 404), - ]); + Http::fake([ + 'https://api.openai.com/v1/moderations' => Http::response(status: 404), + ]); - $name = $this->faker->unique()->word(); + $name = fake()->unique()->word(); - $user = User::factory()->createOne([ - User::ATTRIBUTE_NAME => $this->faker->unique()->word(), - ]); + $user = User::factory()->createOne([ + User::ATTRIBUTE_NAME => fake()->unique()->word(), + ]); - $action = new UpdateUserProfileInformation(); + $action = new UpdateUserProfileInformation(); - $action->update($user, [ - User::ATTRIBUTE_NAME => $name, - ]); + $action->update($user, [ + User::ATTRIBUTE_NAME => $name, + ]); - static::assertDatabaseCount(User::class, 1); - static::assertDatabaseHas(User::class, [ - User::ATTRIBUTE_NAME => $name, - ]); - static::assertDatabaseMissing(User::class, [ - User::ATTRIBUTE_EMAIL_VERIFIED_AT => null, - ]); - } + $this->assertDatabaseCount(User::class, 1); + $this->assertDatabaseHas(User::class, [ + User::ATTRIBUTE_NAME => $name, + ]); + $this->assertDatabaseMissing(User::class, [ + User::ATTRIBUTE_EMAIL_VERIFIED_AT => null, + ]); +}); - /** - * The Update User Profile Information Action shall prohibit users from updating usernames flagged by OpenAI. - * - * @throws ValidationException - */ - public function testValidationErrorWhenFlaggedByOpenAi(): void - { - static::expectException(ValidationException::class); +test('validation error when flagged by open ai', function () { + $this->expectException(ValidationException::class); - Config::set(ValidationConstants::MODERATION_SERVICE_QUALIFIED, ModerationService::OPENAI->value); + Config::set(ValidationConstants::MODERATION_SERVICE_QUALIFIED, ModerationService::OPENAI->value); - Http::fake([ - 'https://api.openai.com/v1/moderations' => Http::response([ - 'results' => [ - 0 => [ - 'flagged' => true, - ], + Http::fake([ + 'https://api.openai.com/v1/moderations' => Http::response([ + 'results' => [ + 0 => [ + 'flagged' => true, ], - ]), - ]); + ], + ]), + ]); - $name = $this->faker->unique()->word(); + $name = fake()->unique()->word(); - $user = User::factory()->createOne([ - User::ATTRIBUTE_NAME => $this->faker->unique()->word(), - ]); + $user = User::factory()->createOne([ + User::ATTRIBUTE_NAME => fake()->unique()->word(), + ]); - $action = new UpdateUserProfileInformation(); + $action = new UpdateUserProfileInformation(); - $action->update($user, [ - User::ATTRIBUTE_NAME => $name, - ]); - } + $action->update($user, [ + User::ATTRIBUTE_NAME => $name, + ]); +}); - /** - * The Update User Profile Information Action shall prohibit updating user emails using disposable email services. - * - * @throws ValidationException - */ - public function testDisposableEmail(): void - { - static::expectException(ValidationException::class); +test('disposable email', function () { + $this->expectException(ValidationException::class); - $this->mock(Indisposable::class, function (MockInterface $mock) { - $mock->shouldReceive('validate')->once()->andReturn(false); - }); + $this->mock(Indisposable::class, function (MockInterface $mock) { + $mock->shouldReceive('validate')->once()->andReturn(false); + }); - $email = $this->faker->unique()->companyEmail(); + $email = fake()->unique()->companyEmail(); - $user = User::factory()->createOne([ - User::ATTRIBUTE_EMAIL => $this->faker->unique()->companyEmail(), - ]); + $user = User::factory()->createOne([ + User::ATTRIBUTE_EMAIL => fake()->unique()->companyEmail(), + ]); - $action = new UpdateUserProfileInformation(); + $action = new UpdateUserProfileInformation(); - $action->update($user, [ - User::ATTRIBUTE_EMAIL => $email, - ]); - } + $action->update($user, [ + User::ATTRIBUTE_EMAIL => $email, + ]); +}); - /** - * The Update User Profile Information Action shall permit updating user emails using indisposable email services. - * - * @throws ValidationException - */ - public function testIndisposableEmail(): void - { - Notification::fake(); +test('indisposable email', function () { + Notification::fake(); - $this->mock(Indisposable::class, function (MockInterface $mock) { - $mock->shouldReceive('validate')->once()->andReturn(true); - }); + $this->mock(Indisposable::class, function (MockInterface $mock) { + $mock->shouldReceive('validate')->once()->andReturn(true); + }); - $email = $this->faker->unique()->companyEmail(); + $email = fake()->unique()->companyEmail(); - $user = User::factory()->createOne([ - User::ATTRIBUTE_EMAIL => $this->faker->unique()->companyEmail(), - ]); + $user = User::factory()->createOne([ + User::ATTRIBUTE_EMAIL => fake()->unique()->companyEmail(), + ]); - $action = new UpdateUserProfileInformation(); + $action = new UpdateUserProfileInformation(); - $action->update($user, [ - User::ATTRIBUTE_EMAIL => $email, - ]); + $action->update($user, [ + User::ATTRIBUTE_EMAIL => $email, + ]); - static::assertDatabaseCount(User::class, 1); - static::assertDatabaseHas(User::class, [ - User::ATTRIBUTE_EMAIL => $email, - User::ATTRIBUTE_EMAIL_VERIFIED_AT => null, - ]); + $this->assertDatabaseCount(User::class, 1); + $this->assertDatabaseHas(User::class, [ + User::ATTRIBUTE_EMAIL => $email, + User::ATTRIBUTE_EMAIL_VERIFIED_AT => null, + ]); - Notification::assertSentTimes(VerifyEmail::class, 1); - } + Notification::assertSentTimes(VerifyEmail::class, 1); +}); - /** - * The Update User Profile Information Action shall require emails to be unique. - * - * @throws ValidationException - */ - public function testEmailUnique(): void - { - static::expectException(ValidationException::class); +test('email unique', function () { + $this->expectException(ValidationException::class); - $email = $this->faker()->companyEmail(); + $email = fake()->companyEmail(); - User::factory()->createOne([ - User::ATTRIBUTE_EMAIL => $email, - ]); + User::factory()->createOne([ + User::ATTRIBUTE_EMAIL => $email, + ]); - $user = User::factory()->createOne(); + $user = User::factory()->createOne(); - $action = new UpdateUserProfileInformation(); + $action = new UpdateUserProfileInformation(); - $action->update($user, [ - User::ATTRIBUTE_EMAIL => $email, - ]); - } -} + $action->update($user, [ + User::ATTRIBUTE_EMAIL => $email, + ]); +}); diff --git a/tests/Feature/Actions/Models/List/Playlist/InsertTrackAfterTest.php b/tests/Feature/Actions/Models/List/Playlist/InsertTrackAfterTest.php index 680b47f09..521dd4ba0 100644 --- a/tests/Feature/Actions/Models/List/Playlist/InsertTrackAfterTest.php +++ b/tests/Feature/Actions/Models/List/Playlist/InsertTrackAfterTest.php @@ -2,79 +2,59 @@ declare(strict_types=1); -namespace Tests\Feature\Actions\Models\List\Playlist; - use App\Actions\Models\List\Playlist\InsertTrackAfterAction; use App\Models\List\Playlist; use App\Models\List\Playlist\PlaylistTrack; use App\Models\Wiki\Video; -use Exception; -use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; -class InsertTrackAfterTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Insert Track After Action shall set the track as the playlist's last track if inserting after the last track. - * - * @throws Exception - */ - public function testLastTrack(): void - { - $playlist = Playlist::factory() - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne(); +test('last track', function () { + $playlist = Playlist::factory() + ->tracks(fake()->numberBetween(2, 9)) + ->createOne(); - $last = $playlist->last; + $last = $playlist->last; - $track = PlaylistTrack::factory() - ->for($playlist) - ->for(Video::factory()) - ->createOne(); + $track = PlaylistTrack::factory() + ->for($playlist) + ->for(Video::factory()) + ->createOne(); - $action = new InsertTrackAfterAction(); + $action = new InsertTrackAfterAction(); - $action->insertAfter($playlist, $track, $last); + $action->insertAfter($playlist, $track, $last); - static::assertTrue($playlist->last()->is($track)); + $this->assertTrue($playlist->last()->is($track)); - static::assertTrue($last->next()->is($track)); + $this->assertTrue($last->next()->is($track)); - static::assertTrue($track->previous()->is($last)); - static::assertTrue($track->next()->doesntExist()); - } + $this->assertTrue($track->previous()->is($last)); + $this->assertTrue($track->next()->doesntExist()); +}); - /** - * The Insert Track After Action shall set the track as the first track's next track if inserting after it. - * - * @throws Exception - */ - public function testFirstTrack(): void - { - $playlist = Playlist::factory() - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne(); +test('first track', function () { + $playlist = Playlist::factory() + ->tracks(fake()->numberBetween(2, 9)) + ->createOne(); - $first = $playlist->first; + $first = $playlist->first; - $next = $first->next; + $next = $first->next; - $track = PlaylistTrack::factory() - ->for($playlist) - ->for(Video::factory()) - ->createOne(); + $track = PlaylistTrack::factory() + ->for($playlist) + ->for(Video::factory()) + ->createOne(); - $action = new InsertTrackAfterAction(); + $action = new InsertTrackAfterAction(); - $action->insertAfter($playlist, $track, $first); + $action->insertAfter($playlist, $track, $first); - static::assertTrue($playlist->first()->is($first)); + $this->assertTrue($playlist->first()->is($first)); - static::assertTrue($first->next()->is($track)); + $this->assertTrue($first->next()->is($track)); - static::assertTrue($track->previous()->is($first)); - static::assertTrue($track->next()->is($next)); - } -} + $this->assertTrue($track->previous()->is($first)); + $this->assertTrue($track->next()->is($next)); +}); diff --git a/tests/Feature/Actions/Models/List/Playlist/InsertTrackBeforeTest.php b/tests/Feature/Actions/Models/List/Playlist/InsertTrackBeforeTest.php index 1dba7006e..62d4194f7 100644 --- a/tests/Feature/Actions/Models/List/Playlist/InsertTrackBeforeTest.php +++ b/tests/Feature/Actions/Models/List/Playlist/InsertTrackBeforeTest.php @@ -2,79 +2,59 @@ declare(strict_types=1); -namespace Tests\Feature\Actions\Models\List\Playlist; - use App\Actions\Models\List\Playlist\InsertTrackBeforeAction; use App\Models\List\Playlist; use App\Models\List\Playlist\PlaylistTrack; use App\Models\Wiki\Video; -use Exception; -use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; -class InsertTrackBeforeTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Insert Track Before Action shall set the track as the playlist's first track if inserting before the first track. - * - * @throws Exception - */ - public function testFirstTrack(): void - { - $playlist = Playlist::factory() - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne(); +test('first track', function () { + $playlist = Playlist::factory() + ->tracks(fake()->numberBetween(2, 9)) + ->createOne(); - $first = $playlist->first; + $first = $playlist->first; - $track = PlaylistTrack::factory() - ->for($playlist) - ->for(Video::factory()) - ->createOne(); + $track = PlaylistTrack::factory() + ->for($playlist) + ->for(Video::factory()) + ->createOne(); - $action = new InsertTrackBeforeAction(); + $action = new InsertTrackBeforeAction(); - $action->insertBefore($playlist, $track, $first); + $action->insertBefore($playlist, $track, $first); - static::assertTrue($playlist->first()->is($track)); + $this->assertTrue($playlist->first()->is($track)); - static::assertTrue($first->previous()->is($track)); + $this->assertTrue($first->previous()->is($track)); - static::assertTrue($track->next()->is($first)); - static::assertTrue($track->previous()->doesntExist()); - } + $this->assertTrue($track->next()->is($first)); + $this->assertTrue($track->previous()->doesntExist()); +}); - /** - * The Insert Track Before Action shall set the track as the last track's previous track if inserting before it. - * - * @throws Exception - */ - public function testLastTrack(): void - { - $playlist = Playlist::factory() - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne(); +test('last track', function () { + $playlist = Playlist::factory() + ->tracks(fake()->numberBetween(2, 9)) + ->createOne(); - $last = $playlist->last; + $last = $playlist->last; - $previous = $last->previous; + $previous = $last->previous; - $track = PlaylistTrack::factory() - ->for($playlist) - ->for(Video::factory()) - ->createOne(); + $track = PlaylistTrack::factory() + ->for($playlist) + ->for(Video::factory()) + ->createOne(); - $action = new InsertTrackBeforeAction(); + $action = new InsertTrackBeforeAction(); - $action->insertBefore($playlist, $track, $last); + $action->insertBefore($playlist, $track, $last); - static::assertTrue($playlist->last()->is($last)); + $this->assertTrue($playlist->last()->is($last)); - static::assertTrue($last->previous()->is($track)); + $this->assertTrue($last->previous()->is($track)); - static::assertTrue($track->previous()->is($previous)); - static::assertTrue($track->next()->is($last)); - } -} + $this->assertTrue($track->previous()->is($previous)); + $this->assertTrue($track->next()->is($last)); +}); diff --git a/tests/Feature/Actions/Models/List/Playlist/InsertTrackTest.php b/tests/Feature/Actions/Models/List/Playlist/InsertTrackTest.php index f2575ece4..b8633cec0 100644 --- a/tests/Feature/Actions/Models/List/Playlist/InsertTrackTest.php +++ b/tests/Feature/Actions/Models/List/Playlist/InsertTrackTest.php @@ -2,113 +2,88 @@ declare(strict_types=1); -namespace Tests\Feature\Actions\Models\List\Playlist; - use App\Actions\Models\List\Playlist\InsertTrackAction; use App\Models\List\Playlist; use App\Models\List\Playlist\PlaylistTrack; use App\Models\Wiki\Video; -use Exception; -use Tests\TestCase; -class InsertTrackTest extends TestCase -{ - /** - * The Insert Track Action shall set the first inserted track as first and last. - * - * @throws Exception - */ - public function testFirstTrack(): void - { - $playlist = Playlist::factory()->createOne(); +test('first track', function () { + $playlist = Playlist::factory()->createOne(); - $track = PlaylistTrack::factory() - ->for($playlist) - ->for(Video::factory()) - ->createOne(); + $track = PlaylistTrack::factory() + ->for($playlist) + ->for(Video::factory()) + ->createOne(); - $action = new InsertTrackAction(); + $action = new InsertTrackAction(); - $action->insert($playlist, $track); + $action->insert($playlist, $track); - static::assertTrue($playlist->first()->is($track)); - static::assertTrue($playlist->last()->is($track)); - } + $this->assertTrue($playlist->first()->is($track)); + $this->assertTrue($playlist->last()->is($track)); +}); - /** - * The Insert Track Action shall set the second track as the first's next track and the playlist's last track. - * - * @throws Exception - */ - public function testSecondTrack(): void - { - $playlist = Playlist::factory()->createOne(); +test('second track', function () { + $playlist = Playlist::factory()->createOne(); - $first = PlaylistTrack::factory() - ->for($playlist) - ->for(Video::factory()) - ->createOne(); + $first = PlaylistTrack::factory() + ->for($playlist) + ->for(Video::factory()) + ->createOne(); - $second = PlaylistTrack::factory() - ->for($playlist) - ->for(Video::factory()) - ->createOne(); + $second = PlaylistTrack::factory() + ->for($playlist) + ->for(Video::factory()) + ->createOne(); - $action = new InsertTrackAction(); + $action = new InsertTrackAction(); - $action->insert($playlist, $first); - $action->insert($playlist, $second); + $action->insert($playlist, $first); + $action->insert($playlist, $second); - static::assertTrue($playlist->first()->is($first)); - static::assertTrue($playlist->last()->is($second)); + $this->assertTrue($playlist->first()->is($first)); + $this->assertTrue($playlist->last()->is($second)); - static::assertTrue($first->previous()->doesntExist()); - static::assertTrue($first->next()->is($second)); + $this->assertTrue($first->previous()->doesntExist()); + $this->assertTrue($first->next()->is($second)); - static::assertTrue($second->previous()->is($first)); - static::assertTrue($second->next()->doesntExist()); - } + $this->assertTrue($second->previous()->is($first)); + $this->assertTrue($second->next()->doesntExist()); +}); - /** - * The Insert Track Action shall set the third track as the second's next track and the playlist's last track. - * - * @throws Exception - */ - public function testThirdTrack(): void - { - $playlist = Playlist::factory()->createOne(); +test('third track', function () { + $playlist = Playlist::factory()->createOne(); - $first = PlaylistTrack::factory() - ->for($playlist) - ->for(Video::factory()) - ->createOne(); + $first = PlaylistTrack::factory() + ->for($playlist) + ->for(Video::factory()) + ->createOne(); - $second = PlaylistTrack::factory() - ->for($playlist) - ->for(Video::factory()) - ->createOne(); + $second = PlaylistTrack::factory() + ->for($playlist) + ->for(Video::factory()) + ->createOne(); - $third = PlaylistTrack::factory() - ->for($playlist) - ->for(Video::factory()) - ->createOne(); + $third = PlaylistTrack::factory() + ->for($playlist) + ->for(Video::factory()) + ->createOne(); - $action = new InsertTrackAction(); + $action = new InsertTrackAction(); - $action->insert($playlist, $first); - $action->insert($playlist, $second); - $action->insert($playlist, $third); + $action->insert($playlist, $first); + $action->insert($playlist, $second); + $action->insert($playlist, $third); - static::assertTrue($playlist->first()->is($first)); - static::assertTrue($playlist->last()->is($third)); + $this->assertTrue($playlist->first()->is($first)); + $this->assertTrue($playlist->last()->is($third)); - static::assertTrue($first->previous()->doesntExist()); - static::assertTrue($first->next()->is($second)); + $this->assertTrue($first->previous()->doesntExist()); + $this->assertTrue($first->next()->is($second)); - static::assertTrue($second->previous()->is($first)); - static::assertTrue($second->next()->is($third)); + $this->assertTrue($second->previous()->is($first)); + $this->assertTrue($second->next()->is($third)); - static::assertTrue($third->previous()->is($second)); - static::assertTrue($third->next()->doesntExist()); - } -} + $this->assertTrue($third->previous()->is($second)); + $this->assertTrue($third->next()->doesntExist()); +}); diff --git a/tests/Feature/Actions/Models/List/Playlist/RemoveTrackTest.php b/tests/Feature/Actions/Models/List/Playlist/RemoveTrackTest.php index a98f3d791..5f3fc5e20 100644 --- a/tests/Feature/Actions/Models/List/Playlist/RemoveTrackTest.php +++ b/tests/Feature/Actions/Models/List/Playlist/RemoveTrackTest.php @@ -2,123 +2,91 @@ declare(strict_types=1); -namespace Tests\Feature\Actions\Models\List\Playlist; - use App\Actions\Models\List\Playlist\RemoveTrackAction; use App\Models\List\Playlist; -use Exception; -use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; -class RemoveTrackTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Remove Track Action shall remove the sole track. - * - * @throws Exception - */ - public function testRemoveSole(): void - { - $playlist = Playlist::factory() - ->tracks(1) - ->createOne(); +test('remove sole', function () { + $playlist = Playlist::factory() + ->tracks(1) + ->createOne(); - $first = $playlist->first; + $first = $playlist->first; - $action = new RemoveTrackAction(); + $action = new RemoveTrackAction(); - $action->remove($playlist, $first); + $action->remove($playlist, $first); - static::assertTrue($playlist->first()->doesntExist()); - static::assertTrue($playlist->last()->doesntExist()); + $this->assertTrue($playlist->first()->doesntExist()); + $this->assertTrue($playlist->last()->doesntExist()); - static::assertTrue($first->previous()->doesntExist()); - static::assertTrue($first->next()->doesntExist()); - } + $this->assertTrue($first->previous()->doesntExist()); + $this->assertTrue($first->next()->doesntExist()); +}); - /** - * The Remove Track Action shall remove the first track and set the second track as first. - * - * @throws Exception - */ - public function testRemoveFirst(): void - { - $playlist = Playlist::factory() - ->tracks($this->faker->numberBetween(3, 9)) - ->createOne(); +test('remove first', function () { + $playlist = Playlist::factory() + ->tracks(fake()->numberBetween(3, 9)) + ->createOne(); - $first = $playlist->first; - $second = $first->next; + $first = $playlist->first; + $second = $first->next; - $action = new RemoveTrackAction(); + $action = new RemoveTrackAction(); - $action->remove($playlist, $first); + $action->remove($playlist, $first); - static::assertTrue($playlist->first()->is($second)); + $this->assertTrue($playlist->first()->is($second)); - static::assertTrue($first->previous()->doesntExist()); - static::assertTrue($first->next()->doesntExist()); + $this->assertTrue($first->previous()->doesntExist()); + $this->assertTrue($first->next()->doesntExist()); - static::assertTrue($second->previous()->doesntExist()); - } + $this->assertTrue($second->previous()->doesntExist()); +}); - /** - * The Remove Track Action shall remove the last track and set the penultimate track as last. - * - * @throws Exception - */ - public function testRemoveLast(): void - { - $playlist = Playlist::factory() - ->tracks($this->faker->numberBetween(3, 9)) - ->createOne(); +test('remove last', function () { + $playlist = Playlist::factory() + ->tracks(fake()->numberBetween(3, 9)) + ->createOne(); - $last = $playlist->last; - $previous = $last->previous; + $last = $playlist->last; + $previous = $last->previous; - $action = new RemoveTrackAction(); + $action = new RemoveTrackAction(); - $action->remove($playlist, $last); + $action->remove($playlist, $last); - static::assertTrue($playlist->last()->is($previous)); + $this->assertTrue($playlist->last()->is($previous)); - static::assertTrue($last->previous()->doesntExist()); - static::assertTrue($last->next()->doesntExist()); + $this->assertTrue($last->previous()->doesntExist()); + $this->assertTrue($last->next()->doesntExist()); - static::assertTrue($previous->next()->doesntExist()); - } + $this->assertTrue($previous->next()->doesntExist()); +}); - /** - * The Remove Track Action shall remove the second track and fill next and previous relations. - * - * @throws Exception - */ - public function testRemoveSecond(): void - { - $playlist = Playlist::factory() - ->tracks(3) - ->createOne(); +test('remove second', function () { + $playlist = Playlist::factory() + ->tracks(3) + ->createOne(); - $first = $playlist->first; - $second = $first->next; - $third = $playlist->last; + $first = $playlist->first; + $second = $first->next; + $third = $playlist->last; - $action = new RemoveTrackAction(); + $action = new RemoveTrackAction(); - $action->remove($playlist, $second); + $action->remove($playlist, $second); - static::assertTrue($playlist->first()->is($first)); - static::assertTrue($playlist->last()->is($third)); + $this->assertTrue($playlist->first()->is($first)); + $this->assertTrue($playlist->last()->is($third)); - static::assertTrue($first->previous()->doesntExist()); - static::assertTrue($first->next()->is($third)); + $this->assertTrue($first->previous()->doesntExist()); + $this->assertTrue($first->next()->is($third)); - static::assertTrue($second->previous()->doesntExist()); - static::assertTrue($second->next()->doesntExist()); + $this->assertTrue($second->previous()->doesntExist()); + $this->assertTrue($second->next()->doesntExist()); - static::assertTrue($third->previous()->is($first)); - static::assertTrue($third->next()->doesntExist()); - } -} + $this->assertTrue($third->previous()->is($first)); + $this->assertTrue($third->next()->doesntExist()); +}); diff --git a/tests/Feature/Actions/Models/Wiki/Video/Audio/BackfillVideoAudioTest.php b/tests/Feature/Actions/Models/Wiki/Video/Audio/BackfillVideoAudioTest.php index 3480858ef..e490336eb 100644 --- a/tests/Feature/Actions/Models/Wiki/Video/Audio/BackfillVideoAudioTest.php +++ b/tests/Feature/Actions/Models/Wiki/Video/Audio/BackfillVideoAudioTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Actions\Models\Wiki\Video\Audio; - use App\Actions\Models\Wiki\Video\Audio\BackfillAudioAction; use App\Constants\Config\AudioConstants; use App\Constants\Config\VideoConstants; @@ -14,165 +12,129 @@ use App\Models\Wiki\Anime\AnimeTheme; use App\Models\Wiki\Anime\Theme\AnimeThemeEntry; use App\Models\Wiki\Audio; use App\Models\Wiki\Video; -use Exception; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Str; -use Tests\TestCase; -class BackfillVideoAudioTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Backfill Audio Action shall skip the Anime if the relation already exists. - * - * @throws Exception - */ - public function testSkipped(): void - { - Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); - Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); +test('skipped', function () { + Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); + Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); - $video = Video::factory() - ->for(Audio::factory()) - ->createOne(); + $video = Video::factory() + ->for(Audio::factory()) + ->createOne(); - $action = new BackfillAudioAction($video); + $action = new BackfillAudioAction($video); - $result = $action->handle(); + $result = $action->handle(); - static::assertTrue($result->getStatus() === ActionStatus::SKIPPED); - static::assertDatabaseCount(Audio::class, 1); - static::assertEmpty(Storage::disk(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED))->allFiles()); - } + $this->assertTrue($result->getStatus() === ActionStatus::SKIPPED); + $this->assertDatabaseCount(Audio::class, 1); + $this->assertEmpty(Storage::disk(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED))->allFiles()); +}); - /** - * The Backfill Audio Action shall fail if the Video is not attached to any Entries. - * - * @throws Exception - */ - public function testFailedWhenNoEntries(): void - { - Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); - Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); +test('failed when no entries', function () { + Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); + Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); - $video = Video::factory()->createOne(); + $video = Video::factory()->createOne(); - $action = new BackfillAudioAction($video); + $action = new BackfillAudioAction($video); - $result = $action->handle(); + $result = $action->handle(); - static::assertTrue($result->hasFailed()); - static::assertDatabaseCount(Audio::class, 0); - static::assertEmpty(Storage::disk(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED))->allFiles()); - } + $this->assertTrue($result->hasFailed()); + $this->assertDatabaseCount(Audio::class, 0); + $this->assertEmpty(Storage::disk(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED))->allFiles()); +}); - /** - * The Backfill Audio Action shall pass if the Video is a source. - * - * @throws Exception - */ - public function testPassesSourceVideo(): void - { - Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); - Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); +test('passes source video', function () { + Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); + Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); - $video = Video::factory() - ->has(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->createOne([ - Video::ATTRIBUTE_PATH => $this->faker()->word().'.webm', - ]); - - Audio::factory()->createOne([ - Audio::ATTRIBUTE_PATH => Str::replace('webm', 'ogg', $video->path), + $video = Video::factory() + ->has(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->createOne([ + Video::ATTRIBUTE_PATH => fake()->word().'.webm', ]); - $action = new BackfillAudioAction($video); + Audio::factory()->createOne([ + Audio::ATTRIBUTE_PATH => Str::replace('webm', 'ogg', $video->path), + ]); - $result = $action->handle(); + $action = new BackfillAudioAction($video); - static::assertTrue($result->getStatus() === ActionStatus::PASSED); - static::assertDatabaseCount(Audio::class, 1); - static::assertTrue($video->audio()->exists()); - static::assertEmpty(Storage::disk(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED))->allFiles()); - } + $result = $action->handle(); - /** - * The Backfill Audio Action shall pass if the Video has a higher priority source. - * - * @throws Exception - */ - public function testPassesWithHigherPrioritySource(): void - { - Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); - Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); + $this->assertTrue($result->getStatus() === ActionStatus::PASSED); + $this->assertDatabaseCount(Audio::class, 1); + $this->assertTrue($video->audio()->exists()); + $this->assertEmpty(Storage::disk(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED))->allFiles()); +}); - $entry = AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory())); +test('passes with higher priority source', function () { + Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); + Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); - Video::factory() - ->hasAttached($entry, [], Video::RELATION_ANIMETHEMEENTRIES) - ->for(Audio::factory()) - ->createOne([ - Video::ATTRIBUTE_SOURCE => VideoSource::BD->value, - ]); + $entry = AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory())); - $video = Video::factory() - ->hasAttached($entry, [], Video::RELATION_ANIMETHEMEENTRIES) - ->createOne([ - Video::ATTRIBUTE_SOURCE => VideoSource::WEB->value, - ]); + Video::factory() + ->hasAttached($entry, [], Video::RELATION_ANIMETHEMEENTRIES) + ->for(Audio::factory()) + ->createOne([ + Video::ATTRIBUTE_SOURCE => VideoSource::BD->value, + ]); - $action = new BackfillAudioAction($video); + $video = Video::factory() + ->hasAttached($entry, [], Video::RELATION_ANIMETHEMEENTRIES) + ->createOne([ + Video::ATTRIBUTE_SOURCE => VideoSource::WEB->value, + ]); - $result = $action->handle(); + $action = new BackfillAudioAction($video); - static::assertTrue($result->getStatus() === ActionStatus::PASSED); - static::assertDatabaseCount(Audio::class, 1); - static::assertTrue($video->audio()->exists()); - static::assertEmpty(Storage::disk(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED))->allFiles()); - } + $result = $action->handle(); - /** - * The Backfill Audio Action shall pass if the Video has a primary version source. - * - * @throws Exception - */ - public function testPassesWithPrimaryVersionSource(): void - { - Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); - Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); + $this->assertTrue($result->getStatus() === ActionStatus::PASSED); + $this->assertDatabaseCount(Audio::class, 1); + $this->assertTrue($video->audio()->exists()); + $this->assertEmpty(Storage::disk(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED))->allFiles()); +}); - $theme = AnimeTheme::factory() - ->for(Anime::factory()) - ->createOne(); +test('passes with primary version source', function () { + Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); + Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); - $videoAttributes = Video::factory()->raw(); + $theme = AnimeTheme::factory() + ->for(Anime::factory()) + ->createOne(); - $sourceAudio = Audio::factory()->createOne(); + $videoAttributes = Video::factory()->raw(); - Video::factory() - ->has(AnimeThemeEntry::factory()->set(AnimeThemeEntry::ATTRIBUTE_VERSION, 1)->for($theme)) - ->for($sourceAudio) - ->createOne($videoAttributes); + $sourceAudio = Audio::factory()->createOne(); - Video::factory() - ->has(AnimeThemeEntry::factory()->set(AnimeThemeEntry::ATTRIBUTE_VERSION, 2)->for($theme)) - ->for(Audio::factory()) - ->createOne($videoAttributes); + Video::factory() + ->has(AnimeThemeEntry::factory()->set(AnimeThemeEntry::ATTRIBUTE_VERSION, 1)->for($theme)) + ->for($sourceAudio) + ->createOne($videoAttributes); - $video = Video::factory() - ->has(AnimeThemeEntry::factory()->set(AnimeThemeEntry::ATTRIBUTE_VERSION, 3)->for($theme)) - ->createOne($videoAttributes); + Video::factory() + ->has(AnimeThemeEntry::factory()->set(AnimeThemeEntry::ATTRIBUTE_VERSION, 2)->for($theme)) + ->for(Audio::factory()) + ->createOne($videoAttributes); - $action = new BackfillAudioAction($video); + $video = Video::factory() + ->has(AnimeThemeEntry::factory()->set(AnimeThemeEntry::ATTRIBUTE_VERSION, 3)->for($theme)) + ->createOne($videoAttributes); - $result = $action->handle(); + $action = new BackfillAudioAction($video); - static::assertTrue($result->getStatus() === ActionStatus::PASSED); - static::assertDatabaseCount(Audio::class, 2); - static::assertTrue($video->audio()->is($sourceAudio)); - static::assertEmpty(Storage::disk(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED))->allFiles()); - } -} + $result = $action->handle(); + + $this->assertTrue($result->getStatus() === ActionStatus::PASSED); + $this->assertDatabaseCount(Audio::class, 2); + $this->assertTrue($video->audio()->is($sourceAudio)); + $this->assertEmpty(Storage::disk(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED))->allFiles()); +}); diff --git a/tests/Feature/Actions/Repositories/Admin/Dump/ReconcileDumpRepositoriesTest.php b/tests/Feature/Actions/Repositories/Admin/Dump/ReconcileDumpRepositoriesTest.php index b6f971d23..bf8575faf 100644 --- a/tests/Feature/Actions/Repositories/Admin/Dump/ReconcileDumpRepositoriesTest.php +++ b/tests/Feature/Actions/Repositories/Admin/Dump/ReconcileDumpRepositoriesTest.php @@ -2,109 +2,83 @@ declare(strict_types=1); -namespace Tests\Feature\Actions\Repositories\Admin\Dump; - use App\Actions\Repositories\Admin\Dump\ReconcileDumpRepositoriesAction; use App\Constants\Config\DumpConstants; use App\Enums\Actions\ActionStatus; use App\Models\Admin\Dump; use App\Repositories\Eloquent\Admin\DumpRepository as DumpDestinationRepository; use App\Repositories\Storage\Admin\DumpRepository as DumpSourceRepository; -use Exception; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Collection; use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Storage; use Mockery\MockInterface; -use Tests\TestCase; -class ReconcileDumpRepositoriesTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * If no changes are needed, the Reconcile Dump Repository Action shall indicate no changes were made. - * - * @throws Exception - */ - public function testNoResults(): void - { - Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); +test('no results', function () { + Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); - $this->mock(DumpSourceRepository::class, function (MockInterface $mock) { - $mock->shouldReceive('get')->once()->andReturn(Collection::make()); - }); + $this->mock(DumpSourceRepository::class, function (MockInterface $mock) { + $mock->shouldReceive('get')->once()->andReturn(Collection::make()); + }); - $action = new ReconcileDumpRepositoriesAction(); + $action = new ReconcileDumpRepositoriesAction(); - $source = App::make(DumpSourceRepository::class); - $destination = App::make(DumpDestinationRepository::class); + $source = App::make(DumpSourceRepository::class); + $destination = App::make(DumpDestinationRepository::class); - $result = $action->reconcileRepositories($source, $destination); + $result = $action->reconcileRepositories($source, $destination); - static::assertTrue($result->getStatus() === ActionStatus::PASSED); - static::assertFalse($result->hasChanges()); - static::assertDatabaseCount(Dump::class, 0); - } + $this->assertTrue($result->getStatus() === ActionStatus::PASSED); + $this->assertFalse($result->hasChanges()); + $this->assertDatabaseCount(Dump::class, 0); +}); - /** - * If dumps are created, the Reconcile Dump Repository Action shall return created dumps. - * - * @throws Exception - */ - public function testCreated(): void - { - Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); +test('created', function () { + Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); - $createdDumpCount = $this->faker->numberBetween(2, 9); + $createdDumpCount = fake()->numberBetween(2, 9); - $dumps = Dump::factory()->count($createdDumpCount)->make(); + $dumps = Dump::factory()->count($createdDumpCount)->make(); - $this->mock(DumpSourceRepository::class, function (MockInterface $mock) use ($dumps) { - $mock->shouldReceive('get')->once()->andReturn($dumps); - }); + $this->mock(DumpSourceRepository::class, function (MockInterface $mock) use ($dumps) { + $mock->shouldReceive('get')->once()->andReturn($dumps); + }); - $action = new ReconcileDumpRepositoriesAction(); + $action = new ReconcileDumpRepositoriesAction(); - $source = App::make(DumpSourceRepository::class); - $destination = App::make(DumpDestinationRepository::class); + $source = App::make(DumpSourceRepository::class); + $destination = App::make(DumpDestinationRepository::class); - $result = $action->reconcileRepositories($source, $destination); + $result = $action->reconcileRepositories($source, $destination); - static::assertTrue($result->getStatus() === ActionStatus::PASSED); - static::assertTrue($result->hasChanges()); - static::assertCount($createdDumpCount, $result->getCreated()); - static::assertDatabaseCount(Dump::class, $createdDumpCount); - } + $this->assertTrue($result->getStatus() === ActionStatus::PASSED); + $this->assertTrue($result->hasChanges()); + $this->assertCount($createdDumpCount, $result->getCreated()); + $this->assertDatabaseCount(Dump::class, $createdDumpCount); +}); - /** - * If dumps are deleted, the Reconcile Dump Repository Action shall return deleted dumps. - * - * @throws Exception - */ - public function testDeleted(): void - { - Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); +test('deleted', function () { + Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); - $deletedDumpCount = $this->faker->numberBetween(2, 9); + $deletedDumpCount = fake()->numberBetween(2, 9); - Dump::factory()->count($deletedDumpCount)->create(); + Dump::factory()->count($deletedDumpCount)->create(); - $this->mock(DumpSourceRepository::class, function (MockInterface $mock) { - $mock->shouldReceive('get')->once()->andReturn(Collection::make()); - }); + $this->mock(DumpSourceRepository::class, function (MockInterface $mock) { + $mock->shouldReceive('get')->once()->andReturn(Collection::make()); + }); - $action = new ReconcileDumpRepositoriesAction(); + $action = new ReconcileDumpRepositoriesAction(); - $source = App::make(DumpSourceRepository::class); - $destination = App::make(DumpDestinationRepository::class); + $source = App::make(DumpSourceRepository::class); + $destination = App::make(DumpDestinationRepository::class); - $result = $action->reconcileRepositories($source, $destination); + $result = $action->reconcileRepositories($source, $destination); - static::assertTrue($result->getStatus() === ActionStatus::PASSED); - static::assertTrue($result->hasChanges()); - static::assertCount($deletedDumpCount, $result->getDeleted()); - static::assertEmpty(Dump::all()); - } -} + $this->assertTrue($result->getStatus() === ActionStatus::PASSED); + $this->assertTrue($result->hasChanges()); + $this->assertCount($deletedDumpCount, $result->getDeleted()); + $this->assertEmpty(Dump::all()); +}); diff --git a/tests/Feature/Actions/Repositories/Wiki/Audio/ReconcileAudioRepositoriesTest.php b/tests/Feature/Actions/Repositories/Wiki/Audio/ReconcileAudioRepositoriesTest.php index 0a61920d6..d36a44299 100644 --- a/tests/Feature/Actions/Repositories/Wiki/Audio/ReconcileAudioRepositoriesTest.php +++ b/tests/Feature/Actions/Repositories/Wiki/Audio/ReconcileAudioRepositoriesTest.php @@ -2,143 +2,111 @@ declare(strict_types=1); -namespace Tests\Feature\Actions\Repositories\Wiki\Audio; - use App\Actions\Repositories\Wiki\Audio\ReconcileAudioRepositoriesAction; use App\Enums\Actions\ActionStatus; use App\Models\Wiki\Audio; use App\Repositories\Eloquent\Wiki\AudioRepository as AudioDestinationRepository; use App\Repositories\Storage\Wiki\AudioRepository; use App\Repositories\Storage\Wiki\AudioRepository as AudioSourceRepository; -use Exception; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Collection; use Illuminate\Support\Facades\App; use Mockery\MockInterface; -use Tests\TestCase; -class ReconcileAudioRepositoriesTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * If no changes are needed, the Reconcile Audio Repository Action shall indicate no changes were made. - * - * @throws Exception - */ - public function testNoResults(): void - { - $this->mock(AudioSourceRepository::class, function (MockInterface $mock) { - $mock->shouldReceive('get')->once()->andReturn(Collection::make()); - }); +test('no results', function () { + $this->mock(AudioSourceRepository::class, function (MockInterface $mock) { + $mock->shouldReceive('get')->once()->andReturn(Collection::make()); + }); - $action = new ReconcileAudioRepositoriesAction(); + $action = new ReconcileAudioRepositoriesAction(); - $source = App::make(AudioSourceRepository::class); - $destination = App::make(AudioDestinationRepository::class); + $source = App::make(AudioSourceRepository::class); + $destination = App::make(AudioDestinationRepository::class); - $result = $action->reconcileRepositories($source, $destination); + $result = $action->reconcileRepositories($source, $destination); - static::assertTrue($result->getStatus() === ActionStatus::PASSED); - static::assertFalse($result->hasChanges()); - static::assertDatabaseCount(Audio::class, 0); + $this->assertTrue($result->getStatus() === ActionStatus::PASSED); + $this->assertFalse($result->hasChanges()); + $this->assertDatabaseCount(Audio::class, 0); +}); + +test('created', function () { + $createdAudioCount = fake()->numberBetween(2, 9); + + $audios = Audio::factory()->count($createdAudioCount)->make(); + + $this->mock(AudioSourceRepository::class, function (MockInterface $mock) use ($audios) { + $mock->shouldReceive('get')->once()->andReturn($audios); + }); + + $action = new ReconcileAudioRepositoriesAction(); + + $source = App::make(AudioSourceRepository::class); + $destination = App::make(AudioDestinationRepository::class); + + $result = $action->reconcileRepositories($source, $destination); + + $this->assertTrue($result->getStatus() === ActionStatus::PASSED); + $this->assertTrue($result->hasChanges()); + $this->assertCount($createdAudioCount, $result->getCreated()); + $this->assertDatabaseCount(Audio::class, $createdAudioCount); +}); + +test('deleted', function () { + $deletedAudioCount = fake()->numberBetween(2, 9); + + $audios = Audio::factory()->count($deletedAudioCount)->create(); + + $this->mock(AudioSourceRepository::class, function (MockInterface $mock) { + $mock->shouldReceive('get')->once()->andReturn(Collection::make()); + }); + + $action = new ReconcileAudioRepositoriesAction(); + + $source = App::make(AudioSourceRepository::class); + $destination = App::make(AudioDestinationRepository::class); + + $result = $action->reconcileRepositories($source, $destination); + + $this->assertTrue($result->getStatus() === ActionStatus::PASSED); + $this->assertTrue($result->hasChanges()); + $this->assertCount($deletedAudioCount, $result->getDeleted()); + + $this->assertDatabaseCount(Audio::class, $deletedAudioCount); + foreach ($audios as $audio) { + $this->assertSoftDeleted($audio); } +}); - /** - * If audios are created, the Reconcile Audio Repository Action shall return created audios. - * - * @throws Exception - */ - public function testCreated(): void - { - $createdAudioCount = $this->faker->numberBetween(2, 9); +test('updated', function () { + $updatedAudioCount = fake()->numberBetween(2, 9); - $audios = Audio::factory()->count($createdAudioCount)->make(); + $basenames = collect(fake()->words($updatedAudioCount)); - $this->mock(AudioSourceRepository::class, function (MockInterface $mock) use ($audios) { - $mock->shouldReceive('get')->once()->andReturn($audios); - }); + Audio::factory() + ->count($updatedAudioCount) + ->sequence(fn ($sequence) => [Audio::ATTRIBUTE_BASENAME => $basenames->get($sequence->index)]) + ->create(); - $action = new ReconcileAudioRepositoriesAction(); + $sourceAudios = Audio::factory() + ->count($updatedAudioCount) + ->sequence(fn ($sequence) => [Audio::ATTRIBUTE_BASENAME => $basenames->get($sequence->index)]) + ->make(); - $source = App::make(AudioSourceRepository::class); - $destination = App::make(AudioDestinationRepository::class); + $this->mock(AudioRepository::class, function (MockInterface $mock) use ($sourceAudios) { + $mock->shouldReceive('get')->once()->andReturn($sourceAudios); + }); - $result = $action->reconcileRepositories($source, $destination); + $action = new ReconcileAudioRepositoriesAction(); - static::assertTrue($result->getStatus() === ActionStatus::PASSED); - static::assertTrue($result->hasChanges()); - static::assertCount($createdAudioCount, $result->getCreated()); - static::assertDatabaseCount(Audio::class, $createdAudioCount); - } + $source = App::make(AudioSourceRepository::class); + $destination = App::make(AudioDestinationRepository::class); - /** - * If audios are deleted, the Reconcile Audio Repository Action shall return deleted audios. - * - * @throws Exception - */ - public function testDeleted(): void - { - $deletedAudioCount = $this->faker->numberBetween(2, 9); + $result = $action->reconcileRepositories($source, $destination); - $audios = Audio::factory()->count($deletedAudioCount)->create(); - - $this->mock(AudioSourceRepository::class, function (MockInterface $mock) { - $mock->shouldReceive('get')->once()->andReturn(Collection::make()); - }); - - $action = new ReconcileAudioRepositoriesAction(); - - $source = App::make(AudioSourceRepository::class); - $destination = App::make(AudioDestinationRepository::class); - - $result = $action->reconcileRepositories($source, $destination); - - static::assertTrue($result->getStatus() === ActionStatus::PASSED); - static::assertTrue($result->hasChanges()); - static::assertCount($deletedAudioCount, $result->getDeleted()); - - static::assertDatabaseCount(Audio::class, $deletedAudioCount); - foreach ($audios as $audio) { - static::assertSoftDeleted($audio); - } - } - - /** - * If audios are updated, the Reconcile Audio Repository Action shall return updated audios. - * - * @throws Exception - */ - public function testUpdated(): void - { - $updatedAudioCount = $this->faker->numberBetween(2, 9); - - $basenames = collect($this->faker->words($updatedAudioCount)); - - Audio::factory() - ->count($updatedAudioCount) - ->sequence(fn ($sequence) => [Audio::ATTRIBUTE_BASENAME => $basenames->get($sequence->index)]) - ->create(); - - $sourceAudios = Audio::factory() - ->count($updatedAudioCount) - ->sequence(fn ($sequence) => [Audio::ATTRIBUTE_BASENAME => $basenames->get($sequence->index)]) - ->make(); - - $this->mock(AudioRepository::class, function (MockInterface $mock) use ($sourceAudios) { - $mock->shouldReceive('get')->once()->andReturn($sourceAudios); - }); - - $action = new ReconcileAudioRepositoriesAction(); - - $source = App::make(AudioSourceRepository::class); - $destination = App::make(AudioDestinationRepository::class); - - $result = $action->reconcileRepositories($source, $destination); - - static::assertTrue($result->getStatus() === ActionStatus::PASSED); - static::assertTrue($result->hasChanges()); - static::assertCount($updatedAudioCount, $result->getUpdated()); - static::assertDatabaseCount(Audio::class, $updatedAudioCount); - } -} + $this->assertTrue($result->getStatus() === ActionStatus::PASSED); + $this->assertTrue($result->hasChanges()); + $this->assertCount($updatedAudioCount, $result->getUpdated()); + $this->assertDatabaseCount(Audio::class, $updatedAudioCount); +}); diff --git a/tests/Feature/Actions/Repositories/Wiki/Video/ReconcileVideoRepositoriesTest.php b/tests/Feature/Actions/Repositories/Wiki/Video/ReconcileVideoRepositoriesTest.php index 7c504efd0..990b3a6dd 100644 --- a/tests/Feature/Actions/Repositories/Wiki/Video/ReconcileVideoRepositoriesTest.php +++ b/tests/Feature/Actions/Repositories/Wiki/Video/ReconcileVideoRepositoriesTest.php @@ -2,143 +2,111 @@ declare(strict_types=1); -namespace Tests\Feature\Actions\Repositories\Wiki\Video; - use App\Actions\Repositories\Wiki\Video\ReconcileVideoRepositoriesAction; use App\Enums\Actions\ActionStatus; use App\Models\Wiki\Video; use App\Repositories\Eloquent\Wiki\VideoRepository as VideoDestinationRepository; use App\Repositories\Storage\Wiki\VideoRepository; use App\Repositories\Storage\Wiki\VideoRepository as VideoSourceRepository; -use Exception; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Collection; use Illuminate\Support\Facades\App; use Mockery\MockInterface; -use Tests\TestCase; -class ReconcileVideoRepositoriesTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * If no changes are needed, the Reconcile Video Repository Action shall indicate no changes were made. - * - * @throws Exception - */ - public function testNoResults(): void - { - $this->mock(VideoSourceRepository::class, function (MockInterface $mock) { - $mock->shouldReceive('get')->once()->andReturn(Collection::make()); - }); +test('no results', function () { + $this->mock(VideoSourceRepository::class, function (MockInterface $mock) { + $mock->shouldReceive('get')->once()->andReturn(Collection::make()); + }); - $action = new ReconcileVideoRepositoriesAction(); + $action = new ReconcileVideoRepositoriesAction(); - $source = App::make(VideoSourceRepository::class); - $destination = App::make(VideoDestinationRepository::class); + $source = App::make(VideoSourceRepository::class); + $destination = App::make(VideoDestinationRepository::class); - $result = $action->reconcileRepositories($source, $destination); + $result = $action->reconcileRepositories($source, $destination); - static::assertTrue($result->getStatus() === ActionStatus::PASSED); - static::assertFalse($result->hasChanges()); - static::assertDatabaseCount(Video::class, 0); + $this->assertTrue($result->getStatus() === ActionStatus::PASSED); + $this->assertFalse($result->hasChanges()); + $this->assertDatabaseCount(Video::class, 0); +}); + +test('created', function () { + $createdVideoCount = fake()->numberBetween(2, 9); + + $videos = Video::factory()->count($createdVideoCount)->make(); + + $this->mock(VideoSourceRepository::class, function (MockInterface $mock) use ($videos) { + $mock->shouldReceive('get')->once()->andReturn($videos); + }); + + $action = new ReconcileVideoRepositoriesAction(); + + $source = App::make(VideoSourceRepository::class); + $destination = App::make(VideoDestinationRepository::class); + + $result = $action->reconcileRepositories($source, $destination); + + $this->assertTrue($result->getStatus() === ActionStatus::PASSED); + $this->assertTrue($result->hasChanges()); + $this->assertCount($createdVideoCount, $result->getCreated()); + $this->assertDatabaseCount(Video::class, $createdVideoCount); +}); + +test('deleted', function () { + $deletedVideoCount = fake()->numberBetween(2, 9); + + $videos = Video::factory()->count($deletedVideoCount)->create(); + + $this->mock(VideoSourceRepository::class, function (MockInterface $mock) { + $mock->shouldReceive('get')->once()->andReturn(Collection::make()); + }); + + $action = new ReconcileVideoRepositoriesAction(); + + $source = App::make(VideoSourceRepository::class); + $destination = App::make(VideoDestinationRepository::class); + + $result = $action->reconcileRepositories($source, $destination); + + $this->assertTrue($result->getStatus() === ActionStatus::PASSED); + $this->assertTrue($result->hasChanges()); + $this->assertCount($deletedVideoCount, $result->getDeleted()); + + $this->assertDatabaseCount(Video::class, $deletedVideoCount); + foreach ($videos as $video) { + $this->assertSoftDeleted($video); } +}); - /** - * If videos are created, the Reconcile Video Repository Action shall return created videos. - * - * @throws Exception - */ - public function testCreated(): void - { - $createdVideoCount = $this->faker->numberBetween(2, 9); +test('updated', function () { + $updatedVideoCount = fake()->numberBetween(2, 9); - $videos = Video::factory()->count($createdVideoCount)->make(); + $basenames = collect(fake()->words($updatedVideoCount)); - $this->mock(VideoSourceRepository::class, function (MockInterface $mock) use ($videos) { - $mock->shouldReceive('get')->once()->andReturn($videos); - }); + Video::factory() + ->count($updatedVideoCount) + ->sequence(fn ($sequence) => [Video::ATTRIBUTE_BASENAME => $basenames->get($sequence->index)]) + ->create(); - $action = new ReconcileVideoRepositoriesAction(); + $sourceVideos = Video::factory() + ->count($updatedVideoCount) + ->sequence(fn ($sequence) => [Video::ATTRIBUTE_BASENAME => $basenames->get($sequence->index)]) + ->make(); - $source = App::make(VideoSourceRepository::class); - $destination = App::make(VideoDestinationRepository::class); + $this->mock(VideoRepository::class, function (MockInterface $mock) use ($sourceVideos) { + $mock->shouldReceive('get')->once()->andReturn($sourceVideos); + }); - $result = $action->reconcileRepositories($source, $destination); + $action = new ReconcileVideoRepositoriesAction(); - static::assertTrue($result->getStatus() === ActionStatus::PASSED); - static::assertTrue($result->hasChanges()); - static::assertCount($createdVideoCount, $result->getCreated()); - static::assertDatabaseCount(Video::class, $createdVideoCount); - } + $source = App::make(VideoSourceRepository::class); + $destination = App::make(VideoDestinationRepository::class); - /** - * If videos are deleted, the Reconcile Video Repository Action shall return deleted videos. - * - * @throws Exception - */ - public function testDeleted(): void - { - $deletedVideoCount = $this->faker->numberBetween(2, 9); + $result = $action->reconcileRepositories($source, $destination); - $videos = Video::factory()->count($deletedVideoCount)->create(); - - $this->mock(VideoSourceRepository::class, function (MockInterface $mock) { - $mock->shouldReceive('get')->once()->andReturn(Collection::make()); - }); - - $action = new ReconcileVideoRepositoriesAction(); - - $source = App::make(VideoSourceRepository::class); - $destination = App::make(VideoDestinationRepository::class); - - $result = $action->reconcileRepositories($source, $destination); - - static::assertTrue($result->getStatus() === ActionStatus::PASSED); - static::assertTrue($result->hasChanges()); - static::assertCount($deletedVideoCount, $result->getDeleted()); - - static::assertDatabaseCount(Video::class, $deletedVideoCount); - foreach ($videos as $video) { - static::assertSoftDeleted($video); - } - } - - /** - * If videos are updated, the Reconcile Video Repository Action shall return updated videos. - * - * @throws Exception - */ - public function testUpdated(): void - { - $updatedVideoCount = $this->faker->numberBetween(2, 9); - - $basenames = collect($this->faker->words($updatedVideoCount)); - - Video::factory() - ->count($updatedVideoCount) - ->sequence(fn ($sequence) => [Video::ATTRIBUTE_BASENAME => $basenames->get($sequence->index)]) - ->create(); - - $sourceVideos = Video::factory() - ->count($updatedVideoCount) - ->sequence(fn ($sequence) => [Video::ATTRIBUTE_BASENAME => $basenames->get($sequence->index)]) - ->make(); - - $this->mock(VideoRepository::class, function (MockInterface $mock) use ($sourceVideos) { - $mock->shouldReceive('get')->once()->andReturn($sourceVideos); - }); - - $action = new ReconcileVideoRepositoriesAction(); - - $source = App::make(VideoSourceRepository::class); - $destination = App::make(VideoDestinationRepository::class); - - $result = $action->reconcileRepositories($source, $destination); - - static::assertTrue($result->getStatus() === ActionStatus::PASSED); - static::assertTrue($result->hasChanges()); - static::assertCount($updatedVideoCount, $result->getUpdated()); - static::assertDatabaseCount(Video::class, $updatedVideoCount); - } -} + $this->assertTrue($result->getStatus() === ActionStatus::PASSED); + $this->assertTrue($result->hasChanges()); + $this->assertCount($updatedVideoCount, $result->getUpdated()); + $this->assertDatabaseCount(Video::class, $updatedVideoCount); +}); diff --git a/tests/Feature/Actions/Repositories/Wiki/Video/Script/ReconcileScriptRepositoriesTest.php b/tests/Feature/Actions/Repositories/Wiki/Video/Script/ReconcileScriptRepositoriesTest.php index f538ba098..b7fee67b8 100644 --- a/tests/Feature/Actions/Repositories/Wiki/Video/Script/ReconcileScriptRepositoriesTest.php +++ b/tests/Feature/Actions/Repositories/Wiki/Video/Script/ReconcileScriptRepositoriesTest.php @@ -2,104 +2,78 @@ declare(strict_types=1); -namespace Tests\Feature\Actions\Repositories\Wiki\Video\Script; - use App\Actions\Repositories\Wiki\Video\Script\ReconcileScriptRepositoriesAction; use App\Enums\Actions\ActionStatus; use App\Models\Wiki\Video\VideoScript; use App\Repositories\Eloquent\Wiki\Video\ScriptRepository as ScriptDestinationRepository; use App\Repositories\Storage\Wiki\Video\ScriptRepository as ScriptSourceRepository; -use Exception; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Collection; use Illuminate\Support\Facades\App; use Mockery\MockInterface; -use Tests\TestCase; -class ReconcileScriptRepositoriesTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * If no changes are needed, the Reconcile Script Repository Action shall indicate no changes were made. - * - * @throws Exception - */ - public function testNoResults(): void - { - $this->mock(ScriptSourceRepository::class, function (MockInterface $mock) { - $mock->shouldReceive('get')->once()->andReturn(Collection::make()); - }); +test('no results', function () { + $this->mock(ScriptSourceRepository::class, function (MockInterface $mock) { + $mock->shouldReceive('get')->once()->andReturn(Collection::make()); + }); - $action = new ReconcileScriptRepositoriesAction(); + $action = new ReconcileScriptRepositoriesAction(); - $source = App::make(ScriptSourceRepository::class); - $destination = App::make(ScriptDestinationRepository::class); + $source = App::make(ScriptSourceRepository::class); + $destination = App::make(ScriptDestinationRepository::class); - $result = $action->reconcileRepositories($source, $destination); + $result = $action->reconcileRepositories($source, $destination); - static::assertTrue($result->getStatus() === ActionStatus::PASSED); - static::assertFalse($result->hasChanges()); - static::assertDatabaseCount(VideoScript::class, 0); + $this->assertTrue($result->getStatus() === ActionStatus::PASSED); + $this->assertFalse($result->hasChanges()); + $this->assertDatabaseCount(VideoScript::class, 0); +}); + +test('created', function () { + $createdScriptCount = fake()->numberBetween(2, 9); + + $scripts = VideoScript::factory()->count($createdScriptCount)->make(); + + $this->mock(ScriptSourceRepository::class, function (MockInterface $mock) use ($scripts) { + $mock->shouldReceive('get')->once()->andReturn($scripts); + }); + + $action = new ReconcileScriptRepositoriesAction(); + + $source = App::make(ScriptSourceRepository::class); + $destination = App::make(ScriptDestinationRepository::class); + + $result = $action->reconcileRepositories($source, $destination); + + $this->assertTrue($result->getStatus() === ActionStatus::PASSED); + $this->assertTrue($result->hasChanges()); + $this->assertCount($createdScriptCount, $result->getCreated()); + $this->assertDatabaseCount(VideoScript::class, $createdScriptCount); +}); + +test('deleted', function () { + $deletedScriptCount = fake()->numberBetween(2, 9); + + $scripts = VideoScript::factory()->count($deletedScriptCount)->create(); + + $this->mock(ScriptSourceRepository::class, function (MockInterface $mock) { + $mock->shouldReceive('get')->once()->andReturn(Collection::make()); + }); + + $action = new ReconcileScriptRepositoriesAction(); + + $source = App::make(ScriptSourceRepository::class); + $destination = App::make(ScriptDestinationRepository::class); + + $result = $action->reconcileRepositories($source, $destination); + + $this->assertTrue($result->getStatus() === ActionStatus::PASSED); + $this->assertTrue($result->hasChanges()); + $this->assertCount($deletedScriptCount, $result->getDeleted()); + + $this->assertDatabaseCount(VideoScript::class, $deletedScriptCount); + foreach ($scripts as $script) { + $this->assertSoftDeleted($script); } - - /** - * If video scripts are created, the Reconcile Script Repository Action shall return created video scripts. - * - * @throws Exception - */ - public function testCreated(): void - { - $createdScriptCount = $this->faker->numberBetween(2, 9); - - $scripts = VideoScript::factory()->count($createdScriptCount)->make(); - - $this->mock(ScriptSourceRepository::class, function (MockInterface $mock) use ($scripts) { - $mock->shouldReceive('get')->once()->andReturn($scripts); - }); - - $action = new ReconcileScriptRepositoriesAction(); - - $source = App::make(ScriptSourceRepository::class); - $destination = App::make(ScriptDestinationRepository::class); - - $result = $action->reconcileRepositories($source, $destination); - - static::assertTrue($result->getStatus() === ActionStatus::PASSED); - static::assertTrue($result->hasChanges()); - static::assertCount($createdScriptCount, $result->getCreated()); - static::assertDatabaseCount(VideoScript::class, $createdScriptCount); - } - - /** - * If video scripts are deleted, the Reconcile Script Repository Action shall return deleted video scripts. - * - * @throws Exception - */ - public function testDeleted(): void - { - $deletedScriptCount = $this->faker->numberBetween(2, 9); - - $scripts = VideoScript::factory()->count($deletedScriptCount)->create(); - - $this->mock(ScriptSourceRepository::class, function (MockInterface $mock) { - $mock->shouldReceive('get')->once()->andReturn(Collection::make()); - }); - - $action = new ReconcileScriptRepositoriesAction(); - - $source = App::make(ScriptSourceRepository::class); - $destination = App::make(ScriptDestinationRepository::class); - - $result = $action->reconcileRepositories($source, $destination); - - static::assertTrue($result->getStatus() === ActionStatus::PASSED); - static::assertTrue($result->hasChanges()); - static::assertCount($deletedScriptCount, $result->getDeleted()); - - static::assertDatabaseCount(VideoScript::class, $deletedScriptCount); - foreach ($scripts as $script) { - static::assertSoftDeleted($script); - } - } -} +}); diff --git a/tests/Feature/Actions/Storage/Admin/Dump/DumpDocumentTest.php b/tests/Feature/Actions/Storage/Admin/Dump/DumpDocumentTest.php index 5ead02a30..d20c916ee 100644 --- a/tests/Feature/Actions/Storage/Admin/Dump/DumpDocumentTest.php +++ b/tests/Feature/Actions/Storage/Admin/Dump/DumpDocumentTest.php @@ -2,42 +2,28 @@ declare(strict_types=1); -namespace Tests\Feature\Actions\Storage\Admin\Dump; - use App\Actions\Storage\Admin\Dump\DumpDocumentAction; use App\Constants\Config\DumpConstants; use App\Enums\Actions\ActionStatus; use App\Models\Admin\Dump; -use Exception; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Date; use Illuminate\Support\Facades\Storage; -use Tests\TestCase; -class DumpDocumentTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Database Dump Command shall output "Database dump '{dumpFile}' has been created". - * - * @throws Exception - */ - public function testDataBaseDumpOutput(): void - { - $local = Storage::fake('local'); - $fs = Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); +test('database dump output', function () { + $local = Storage::fake('local'); + $fs = Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); - Date::setTestNow($this->faker->iso8601()); + Date::setTestNow(fake()->iso8601()); - $action = new DumpDocumentAction(); + $action = new DumpDocumentAction(); - $result = $action->handle(); + $result = $action->handle(); - static::assertTrue($result->getStatus() === ActionStatus::PASSED); - static::assertEmpty($local->allFiles()); - static::assertCount(1, $fs->allFiles()); - static::assertDatabaseCount(Dump::class, 1); - } -} + $this->assertTrue($result->getStatus() === ActionStatus::PASSED); + $this->assertEmpty($local->allFiles()); + $this->assertCount(1, $fs->allFiles()); + $this->assertDatabaseCount(Dump::class, 1); +}); diff --git a/tests/Feature/Actions/Storage/Admin/Dump/DumpWikiTest.php b/tests/Feature/Actions/Storage/Admin/Dump/DumpWikiTest.php index d9b93cd46..5f66de10d 100644 --- a/tests/Feature/Actions/Storage/Admin/Dump/DumpWikiTest.php +++ b/tests/Feature/Actions/Storage/Admin/Dump/DumpWikiTest.php @@ -2,42 +2,28 @@ declare(strict_types=1); -namespace Tests\Feature\Actions\Storage\Admin\Dump; - use App\Actions\Storage\Admin\Dump\DumpWikiAction; use App\Constants\Config\DumpConstants; use App\Enums\Actions\ActionStatus; use App\Models\Admin\Dump; -use Exception; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Date; use Illuminate\Support\Facades\Storage; -use Tests\TestCase; -class DumpWikiTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Database Dump Command shall output "Database dump '{dumpFile}' has been created". - * - * @throws Exception - */ - public function testDataBaseDumpOutput(): void - { - $local = Storage::fake('local'); - $fs = Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); +test('database dump output', function () { + $local = Storage::fake('local'); + $fs = Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); - Date::setTestNow($this->faker->iso8601()); + Date::setTestNow(fake()->iso8601()); - $action = new DumpWikiAction(); + $action = new DumpWikiAction(); - $result = $action->handle(); + $result = $action->handle(); - static::assertTrue($result->getStatus() === ActionStatus::PASSED); - static::assertEmpty($local->allFiles()); - static::assertCount(1, $fs->allFiles()); - static::assertDatabaseCount(Dump::class, 1); - } -} + $this->assertTrue($result->getStatus() === ActionStatus::PASSED); + $this->assertEmpty($local->allFiles()); + $this->assertCount(1, $fs->allFiles()); + $this->assertDatabaseCount(Dump::class, 1); +}); diff --git a/tests/Feature/Actions/Storage/Admin/Dump/PruneDumpTest.php b/tests/Feature/Actions/Storage/Admin/Dump/PruneDumpTest.php index ccf78ce79..11bf64e3d 100644 --- a/tests/Feature/Actions/Storage/Admin/Dump/PruneDumpTest.php +++ b/tests/Feature/Actions/Storage/Admin/Dump/PruneDumpTest.php @@ -2,76 +2,56 @@ declare(strict_types=1); -namespace Tests\Feature\Actions\Storage\Admin\Dump; - use App\Actions\Storage\Admin\Dump\DumpWikiAction; use App\Actions\Storage\Admin\Dump\PruneDumpAction; use App\Constants\Config\DumpConstants; use App\Enums\Actions\ActionStatus; use App\Models\Admin\Dump; -use Exception; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Date; use Illuminate\Support\Facades\Storage; -use Tests\TestCase; -class PruneDumpTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * If no changes are needed, the Prune Dumps Action shall fail. - * - * @throws Exception - */ - public function testNoResults(): void - { - $fs = Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); +test('no results', function () { + $fs = Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); - $action = new PruneDumpAction($this->faker->numberBetween(2, 9)); + $action = new PruneDumpAction(fake()->numberBetween(2, 9)); - $pruneResults = $action->handle(); + $pruneResults = $action->handle(); - $result = $pruneResults->toActionResult(); + $result = $pruneResults->toActionResult(); - static::assertEmpty($fs->allFiles()); - static::assertTrue($result->hasFailed()); - static::assertDatabaseCount(Dump::class, 0); - } + $this->assertEmpty($fs->allFiles()); + $this->assertTrue($result->hasFailed()); + $this->assertDatabaseCount(Dump::class, 0); +}); - /** - * The Prune Dumps Action shall prune dumps before the specified date by hours from the present time. - * - * @throws Exception - */ - public function testPruned(): void - { - $fs = Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); +test('pruned', function () { + $fs = Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); - $prunedCount = $this->faker->randomDigitNotNull(); + $prunedCount = fake()->randomDigitNotNull(); - Collection::times($prunedCount, function () { - Date::setTestNow($this->faker->iso8601()); + Collection::times($prunedCount, function () { + Date::setTestNow(fake()->iso8601()); - $action = new DumpWikiAction(); + $action = new DumpWikiAction(); - $action->handle(); - }); + $action->handle(); + }); - Date::setTestNow(); + Date::setTestNow(); - $action = new PruneDumpAction(-1); + $action = new PruneDumpAction(-1); - $pruneResults = $action->handle(); + $pruneResults = $action->handle(); - $action->then($pruneResults); + $action->then($pruneResults); - $result = $pruneResults->toActionResult(); + $result = $pruneResults->toActionResult(); - static::assertEmpty($fs->allFiles()); - static::assertTrue($result->getStatus() === ActionStatus::PASSED); - static::assertEmpty(Dump::all()); - } -} + $this->assertEmpty($fs->allFiles()); + $this->assertTrue($result->getStatus() === ActionStatus::PASSED); + $this->assertEmpty(Dump::all()); +}); diff --git a/tests/Feature/Actions/Storage/Wiki/Audio/DeleteAudioTest.php b/tests/Feature/Actions/Storage/Wiki/Audio/DeleteAudioTest.php index 0a16a8ee2..6f5492ce2 100644 --- a/tests/Feature/Actions/Storage/Wiki/Audio/DeleteAudioTest.php +++ b/tests/Feature/Actions/Storage/Wiki/Audio/DeleteAudioTest.php @@ -2,119 +2,93 @@ declare(strict_types=1); -namespace Tests\Feature\Actions\Storage\Wiki\Audio; - use App\Actions\Storage\Wiki\Audio\DeleteAudioAction; use App\Constants\Config\AudioConstants; use App\Enums\Actions\ActionStatus; use App\Models\Wiki\Audio; -use Exception; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Http\Testing\File; use Illuminate\Http\Testing\MimeType; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\File as FileFacade; use Illuminate\Support\Facades\Storage; -use Tests\TestCase; -class DeleteAudioTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Delete Audio Action shall fail if there are no deletions. - */ - public function testDefault(): void - { - Config::set(AudioConstants::DISKS_QUALIFIED, []); - Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); +test('default', function () { + Config::set(AudioConstants::DISKS_QUALIFIED, []); + Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); - $audio = Audio::factory()->createOne(); + $audio = Audio::factory()->createOne(); - $action = new DeleteAudioAction($audio); + $action = new DeleteAudioAction($audio); - $storageResults = $action->handle(); + $storageResults = $action->handle(); - $result = $storageResults->toActionResult(); + $result = $storageResults->toActionResult(); - static::assertTrue($result->hasFailed()); - } + $this->assertTrue($result->hasFailed()); +}); - /** - * The Delete Audio Action shall pass if there are deletions. - */ - public function testPassed(): void - { - Config::set(AudioConstants::DISKS_QUALIFIED, [Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)]); - Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); +test('passed', function () { + Config::set(AudioConstants::DISKS_QUALIFIED, [Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)]); + Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); - $file = File::fake()->create($this->faker->word().'.ogg', $this->faker->randomDigitNotNull()); + $file = File::fake()->create(fake()->word().'.ogg', fake()->randomDigitNotNull()); - $audio = Audio::factory()->createOne([ - Audio::ATTRIBUTE_BASENAME => FileFacade::basename($file->path()), - Audio::ATTRIBUTE_FILENAME => FileFacade::name($file->path()), - Audio::ATTRIBUTE_MIMETYPE => MimeType::from($file->path()), - Audio::ATTRIBUTE_PATH => $file->path(), - ]); + $audio = Audio::factory()->createOne([ + Audio::ATTRIBUTE_BASENAME => FileFacade::basename($file->path()), + Audio::ATTRIBUTE_FILENAME => FileFacade::name($file->path()), + Audio::ATTRIBUTE_MIMETYPE => MimeType::from($file->path()), + Audio::ATTRIBUTE_PATH => $file->path(), + ]); - $action = new DeleteAudioAction($audio); + $action = new DeleteAudioAction($audio); - $storageResults = $action->handle(); + $storageResults = $action->handle(); - $result = $storageResults->toActionResult(); + $result = $storageResults->toActionResult(); - static::assertTrue($result->getStatus() === ActionStatus::PASSED); - } + $this->assertTrue($result->getStatus() === ActionStatus::PASSED); +}); - /** - * The Delete Audio Action shall delete the file from the configured disks. - */ - public function testDeletedFromDisk(): void - { - Config::set(AudioConstants::DISKS_QUALIFIED, [Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)]); - Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); +test('deleted from disk', function () { + Config::set(AudioConstants::DISKS_QUALIFIED, [Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)]); + Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); - $file = File::fake()->create($this->faker->word().'.ogg', $this->faker->randomDigitNotNull()); + $file = File::fake()->create(fake()->word().'.ogg', fake()->randomDigitNotNull()); - $audio = Audio::factory()->createOne([ - Audio::ATTRIBUTE_BASENAME => FileFacade::basename($file->path()), - Audio::ATTRIBUTE_FILENAME => FileFacade::name($file->path()), - Audio::ATTRIBUTE_MIMETYPE => MimeType::from($file->path()), - Audio::ATTRIBUTE_PATH => $file->path(), - ]); + $audio = Audio::factory()->createOne([ + Audio::ATTRIBUTE_BASENAME => FileFacade::basename($file->path()), + Audio::ATTRIBUTE_FILENAME => FileFacade::name($file->path()), + Audio::ATTRIBUTE_MIMETYPE => MimeType::from($file->path()), + Audio::ATTRIBUTE_PATH => $file->path(), + ]); - $action = new DeleteAudioAction($audio); + $action = new DeleteAudioAction($audio); - $action->handle(); + $action->handle(); - static::assertEmpty(Storage::disk(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED))->allFiles()); - } + $this->assertEmpty(Storage::disk(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED))->allFiles()); +}); - /** - * The Delete Audio Action shall delete the audio. - * - * @throws Exception - */ - public function testAudioDeleted(): void - { - Config::set(AudioConstants::DISKS_QUALIFIED, [Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)]); - Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); +test('audio deleted', function () { + Config::set(AudioConstants::DISKS_QUALIFIED, [Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)]); + Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); - $file = File::fake()->create($this->faker->word().'.ogg', $this->faker->randomDigitNotNull()); + $file = File::fake()->create(fake()->word().'.ogg', fake()->randomDigitNotNull()); - $audio = Audio::factory()->createOne([ - Audio::ATTRIBUTE_BASENAME => FileFacade::basename($file->path()), - Audio::ATTRIBUTE_FILENAME => FileFacade::name($file->path()), - Audio::ATTRIBUTE_MIMETYPE => MimeType::from($file->path()), - Audio::ATTRIBUTE_PATH => $file->path(), - ]); + $audio = Audio::factory()->createOne([ + Audio::ATTRIBUTE_BASENAME => FileFacade::basename($file->path()), + Audio::ATTRIBUTE_FILENAME => FileFacade::name($file->path()), + Audio::ATTRIBUTE_MIMETYPE => MimeType::from($file->path()), + Audio::ATTRIBUTE_PATH => $file->path(), + ]); - $action = new DeleteAudioAction($audio); + $action = new DeleteAudioAction($audio); - $result = $action->handle(); + $result = $action->handle(); - $action->then($result); + $action->then($result); - static::assertSoftDeleted($audio); - } -} + $this->assertSoftDeleted($audio); +}); diff --git a/tests/Feature/Actions/Storage/Wiki/Audio/MoveAudioTest.php b/tests/Feature/Actions/Storage/Wiki/Audio/MoveAudioTest.php index 7d0288442..f0ffc1342 100644 --- a/tests/Feature/Actions/Storage/Wiki/Audio/MoveAudioTest.php +++ b/tests/Feature/Actions/Storage/Wiki/Audio/MoveAudioTest.php @@ -2,133 +2,110 @@ declare(strict_types=1); -namespace Tests\Feature\Actions\Storage\Wiki\Audio; - use App\Actions\Storage\Wiki\Audio\MoveAudioAction; use App\Constants\Config\AudioConstants; use App\Enums\Actions\ActionStatus; use App\Models\Wiki\Audio; use Illuminate\Filesystem\FilesystemAdapter; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Http\Testing\File; use Illuminate\Http\Testing\MimeType; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\File as FileFacade; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Str; -use Tests\TestCase; -class MoveAudioTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Move Audio Action shall fail if there are no moves. - */ - public function testDefault(): void - { - Config::set(AudioConstants::DISKS_QUALIFIED, []); - Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); +test('default', function () { + Config::set(AudioConstants::DISKS_QUALIFIED, []); + Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); - $audio = Audio::factory()->createOne(); + $audio = Audio::factory()->createOne(); - $action = new MoveAudioAction($audio, $this->faker->word()); + $action = new MoveAudioAction($audio, fake()->word()); - $storageResults = $action->handle(); + $storageResults = $action->handle(); - $result = $storageResults->toActionResult(); + $result = $storageResults->toActionResult(); - static::assertTrue($result->hasFailed()); - } + $this->assertTrue($result->hasFailed()); +}); - /** - * The Move Audio Action shall pass if there are moves. - */ - public function testPassed(): void - { - /** @var FilesystemAdapter $fs */ - $fs = Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); - Config::set(AudioConstants::DISKS_QUALIFIED, [Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)]); +test('passed', function () { + /** @var FilesystemAdapter $fs */ + $fs = Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); + Config::set(AudioConstants::DISKS_QUALIFIED, [Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)]); - $file = File::fake()->create($this->faker->word().'.ogg', $this->faker->randomDigitNotNull()); + $file = File::fake()->create(fake()->word().'.ogg', fake()->randomDigitNotNull()); - $directory = $this->faker->unique()->word(); + $directory = fake()->unique()->word(); - $audio = Audio::factory()->createOne([ - Audio::ATTRIBUTE_BASENAME => FileFacade::basename($file->path()), - Audio::ATTRIBUTE_FILENAME => FileFacade::name($file->path()), - Audio::ATTRIBUTE_MIMETYPE => MimeType::from($file->path()), - Audio::ATTRIBUTE_PATH => $fs->putFileAs($directory, $file, $file->getClientOriginalName()), - ]); + $audio = Audio::factory()->createOne([ + Audio::ATTRIBUTE_BASENAME => FileFacade::basename($file->path()), + Audio::ATTRIBUTE_FILENAME => FileFacade::name($file->path()), + Audio::ATTRIBUTE_MIMETYPE => MimeType::from($file->path()), + Audio::ATTRIBUTE_PATH => $fs->putFileAs($directory, $file, $file->getClientOriginalName()), + ]); - $action = new MoveAudioAction($audio, Str::replace($directory, $this->faker->unique()->word(), $audio->path)); + $action = new MoveAudioAction($audio, Str::replace($directory, fake()->unique()->word(), $audio->path)); - $storageResults = $action->handle(); + $storageResults = $action->handle(); - $result = $storageResults->toActionResult(); + $result = $storageResults->toActionResult(); - static::assertTrue($result->getStatus() === ActionStatus::PASSED); - } + $this->assertTrue($result->getStatus() === ActionStatus::PASSED); +}); - /** - * The Move Audio Action shall move the file in the configured disks. - */ - public function testMovedInDisk(): void - { - /** @var FilesystemAdapter $fs */ - $fs = Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); - Config::set(AudioConstants::DISKS_QUALIFIED, [Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)]); +test('moved in disk', function () { + /** @var FilesystemAdapter $fs */ + $fs = Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); + Config::set(AudioConstants::DISKS_QUALIFIED, [Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)]); - $file = File::fake()->create($this->faker->word().'.ogg', $this->faker->randomDigitNotNull()); + $file = File::fake()->create(fake()->word().'.ogg', fake()->randomDigitNotNull()); - $directory = $this->faker->unique()->word(); + $directory = fake()->unique()->word(); - $audio = Audio::factory()->createOne([ - Audio::ATTRIBUTE_BASENAME => FileFacade::basename($file->path()), - Audio::ATTRIBUTE_FILENAME => FileFacade::name($file->path()), - Audio::ATTRIBUTE_MIMETYPE => MimeType::from($file->path()), - Audio::ATTRIBUTE_PATH => $fs->putFileAs($directory, $file, $file->getClientOriginalName()), - ]); + $audio = Audio::factory()->createOne([ + Audio::ATTRIBUTE_BASENAME => FileFacade::basename($file->path()), + Audio::ATTRIBUTE_FILENAME => FileFacade::name($file->path()), + Audio::ATTRIBUTE_MIMETYPE => MimeType::from($file->path()), + Audio::ATTRIBUTE_PATH => $fs->putFileAs($directory, $file, $file->getClientOriginalName()), + ]); - $from = $audio->path(); - $to = Str::replace($directory, $this->faker->unique()->word(), $audio->path); + $from = $audio->path(); + $to = Str::replace($directory, fake()->unique()->word(), $audio->path); - $action = new MoveAudioAction($audio, $to); + $action = new MoveAudioAction($audio, $to); - $action->handle(); + $action->handle(); - $fs->assertMissing($from); - $fs->assertExists($to); - } + $fs->assertMissing($from); + $fs->assertExists($to); +}); - /** - * The Move Audio Action shall move the audio. - */ - public function testAudioUpdated(): void - { - /** @var FilesystemAdapter $fs */ - $fs = Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); - Config::set(AudioConstants::DISKS_QUALIFIED, [Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)]); +test('audio updated', function () { + /** @var FilesystemAdapter $fs */ + $fs = Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); + Config::set(AudioConstants::DISKS_QUALIFIED, [Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)]); - $file = File::fake()->create($this->faker->word().'.ogg', $this->faker->randomDigitNotNull()); + $file = File::fake()->create(fake()->word().'.ogg', fake()->randomDigitNotNull()); - $directory = $this->faker->unique()->word(); + $directory = fake()->unique()->word(); - $audio = Audio::factory()->createOne([ - Audio::ATTRIBUTE_BASENAME => FileFacade::basename($file->path()), - Audio::ATTRIBUTE_FILENAME => FileFacade::name($file->path()), - Audio::ATTRIBUTE_MIMETYPE => MimeType::from($file->path()), - Audio::ATTRIBUTE_PATH => $fs->putFileAs($directory, $file, $file->getClientOriginalName()), - ]); + $audio = Audio::factory()->createOne([ + Audio::ATTRIBUTE_BASENAME => FileFacade::basename($file->path()), + Audio::ATTRIBUTE_FILENAME => FileFacade::name($file->path()), + Audio::ATTRIBUTE_MIMETYPE => MimeType::from($file->path()), + Audio::ATTRIBUTE_PATH => $fs->putFileAs($directory, $file, $file->getClientOriginalName()), + ]); - $to = Str::replace($directory, $this->faker->unique()->word(), $audio->path); + $to = Str::replace($directory, fake()->unique()->word(), $audio->path); - $action = new MoveAudioAction($audio, $to); + $action = new MoveAudioAction($audio, $to); - $result = $action->handle(); + $result = $action->handle(); - $action->then($result); + $action->then($result); - static::assertDatabaseHas(Audio::class, [Audio::ATTRIBUTE_PATH => $to]); - } -} + $this->assertDatabaseHas(Audio::class, [Audio::ATTRIBUTE_PATH => $to]); +}); diff --git a/tests/Feature/Actions/Storage/Wiki/Audio/UploadAudioTest.php b/tests/Feature/Actions/Storage/Wiki/Audio/UploadAudioTest.php index 4da2ab344..c9f4dfad0 100644 --- a/tests/Feature/Actions/Storage/Wiki/Audio/UploadAudioTest.php +++ b/tests/Feature/Actions/Storage/Wiki/Audio/UploadAudioTest.php @@ -2,93 +2,70 @@ declare(strict_types=1); -namespace Tests\Feature\Actions\Storage\Wiki\Audio; - use App\Actions\Storage\Wiki\Audio\UploadAudioAction; use App\Constants\Config\AudioConstants; use App\Enums\Actions\ActionStatus; use App\Models\Wiki\Audio; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Http\Testing\File; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Storage; -use Tests\TestCase; -class UploadAudioTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Upload Audio Action shall fail if there are no uploads. - */ - public function testDefault(): void - { - Config::set(AudioConstants::DISKS_QUALIFIED, []); - Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); +test('default', function () { + Config::set(AudioConstants::DISKS_QUALIFIED, []); + Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); - $file = File::fake()->create($this->faker->word().'.ogg', $this->faker->randomDigitNotNull()); + $file = File::fake()->create(fake()->word().'.ogg', fake()->randomDigitNotNull()); - $action = new UploadAudioAction($file, $this->faker->word()); + $action = new UploadAudioAction($file, fake()->word()); - $storageResults = $action->handle(); + $storageResults = $action->handle(); - $result = $storageResults->toActionResult(); + $result = $storageResults->toActionResult(); - static::assertTrue($result->hasFailed()); - } + $this->assertTrue($result->hasFailed()); +}); - /** - * The Upload Audio Action shall pass if given a valid file. - */ - public function testPassed(): void - { - Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); - Config::set(AudioConstants::DISKS_QUALIFIED, [Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)]); +test('passed', function () { + Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); + Config::set(AudioConstants::DISKS_QUALIFIED, [Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)]); - $file = File::fake()->create($this->faker->word().'.ogg', $this->faker->randomDigitNotNull()); + $file = File::fake()->create(fake()->word().'.ogg', fake()->randomDigitNotNull()); - $action = new UploadAudioAction($file, $this->faker->word()); + $action = new UploadAudioAction($file, fake()->word()); - $storageResults = $action->handle(); + $storageResults = $action->handle(); - $result = $storageResults->toActionResult(); + $result = $storageResults->toActionResult(); - static::assertTrue($result->getStatus() === ActionStatus::PASSED); - } + $this->assertTrue($result->getStatus() === ActionStatus::PASSED); +}); - /** - * The Upload Audio Action shall upload the file to the configured disk. - */ - public function testUploadedToDisk(): void - { - Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); - Config::set(AudioConstants::DISKS_QUALIFIED, [Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)]); +test('uploaded to disk', function () { + Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); + Config::set(AudioConstants::DISKS_QUALIFIED, [Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)]); - $file = File::fake()->create($this->faker->word().'.ogg', $this->faker->randomDigitNotNull()); + $file = File::fake()->create(fake()->word().'.ogg', fake()->randomDigitNotNull()); - $action = new UploadAudioAction($file, $this->faker->word()); + $action = new UploadAudioAction($file, fake()->word()); - $action->handle(); + $action->handle(); - static::assertCount(1, Storage::disk(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED))->allFiles()); - } + $this->assertCount(1, Storage::disk(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED))->allFiles()); +}); - /** - * The Upload Audio Action shall upload the file to the configured disk. - */ - public function testCreatedAudio(): void - { - Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); - Config::set(AudioConstants::DISKS_QUALIFIED, [Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)]); +test('created audio', function () { + Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); + Config::set(AudioConstants::DISKS_QUALIFIED, [Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)]); - $file = File::fake()->create($this->faker->word().'.ogg', $this->faker->randomDigitNotNull()); + $file = File::fake()->create(fake()->word().'.ogg', fake()->randomDigitNotNull()); - $action = new UploadAudioAction($file, $this->faker->word()); + $action = new UploadAudioAction($file, fake()->word()); - $result = $action->handle(); + $result = $action->handle(); - $action->then($result); + $action->then($result); - static::assertDatabaseCount(Audio::class, 1); - } -} + $this->assertDatabaseCount(Audio::class, 1); +}); diff --git a/tests/Feature/Actions/Storage/Wiki/Video/DeleteVideoTest.php b/tests/Feature/Actions/Storage/Wiki/Video/DeleteVideoTest.php index ab8e9b951..480ece38a 100644 --- a/tests/Feature/Actions/Storage/Wiki/Video/DeleteVideoTest.php +++ b/tests/Feature/Actions/Storage/Wiki/Video/DeleteVideoTest.php @@ -2,119 +2,93 @@ declare(strict_types=1); -namespace Tests\Feature\Actions\Storage\Wiki\Video; - use App\Actions\Storage\Wiki\Video\DeleteVideoAction; use App\Constants\Config\VideoConstants; use App\Enums\Actions\ActionStatus; use App\Models\Wiki\Video; -use Exception; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Http\Testing\File; use Illuminate\Http\Testing\MimeType; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\File as FileFacade; use Illuminate\Support\Facades\Storage; -use Tests\TestCase; -class DeleteVideoTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Delete Video Action shall fail if there are no deletions. - */ - public function testDefault(): void - { - Config::set(VideoConstants::DISKS_QUALIFIED, []); - Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); +test('default', function () { + Config::set(VideoConstants::DISKS_QUALIFIED, []); + Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); - $video = Video::factory()->createOne(); + $video = Video::factory()->createOne(); - $action = new DeleteVideoAction($video); + $action = new DeleteVideoAction($video); - $storageResults = $action->handle(); + $storageResults = $action->handle(); - $result = $storageResults->toActionResult(); + $result = $storageResults->toActionResult(); - static::assertTrue($result->hasFailed()); - } + $this->assertTrue($result->hasFailed()); +}); - /** - * The Delete Video Action shall pass if there are deletions. - */ - public function testPassed(): void - { - Config::set(VideoConstants::DISKS_QUALIFIED, [Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)]); - Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); +test('passed', function () { + Config::set(VideoConstants::DISKS_QUALIFIED, [Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)]); + Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); - $file = File::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); + $file = File::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - $video = Video::factory()->createOne([ - Video::ATTRIBUTE_BASENAME => FileFacade::basename($file->path()), - Video::ATTRIBUTE_FILENAME => FileFacade::name($file->path()), - Video::ATTRIBUTE_MIMETYPE => MimeType::from($file->path()), - Video::ATTRIBUTE_PATH => $file->path(), - ]); + $video = Video::factory()->createOne([ + Video::ATTRIBUTE_BASENAME => FileFacade::basename($file->path()), + Video::ATTRIBUTE_FILENAME => FileFacade::name($file->path()), + Video::ATTRIBUTE_MIMETYPE => MimeType::from($file->path()), + Video::ATTRIBUTE_PATH => $file->path(), + ]); - $action = new DeleteVideoAction($video); + $action = new DeleteVideoAction($video); - $storageResults = $action->handle(); + $storageResults = $action->handle(); - $result = $storageResults->toActionResult(); + $result = $storageResults->toActionResult(); - static::assertTrue($result->getStatus() === ActionStatus::PASSED); - } + $this->assertTrue($result->getStatus() === ActionStatus::PASSED); +}); - /** - * The Delete Video Action shall delete the file from the configured disks. - */ - public function testDeletedFromDisk(): void - { - Config::set(VideoConstants::DISKS_QUALIFIED, [Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)]); - Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); +test('deleted from disk', function () { + Config::set(VideoConstants::DISKS_QUALIFIED, [Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)]); + Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); - $file = File::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); + $file = File::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - $video = Video::factory()->createOne([ - Video::ATTRIBUTE_BASENAME => FileFacade::basename($file->path()), - Video::ATTRIBUTE_FILENAME => FileFacade::name($file->path()), - Video::ATTRIBUTE_MIMETYPE => MimeType::from($file->path()), - Video::ATTRIBUTE_PATH => $file->path(), - ]); + $video = Video::factory()->createOne([ + Video::ATTRIBUTE_BASENAME => FileFacade::basename($file->path()), + Video::ATTRIBUTE_FILENAME => FileFacade::name($file->path()), + Video::ATTRIBUTE_MIMETYPE => MimeType::from($file->path()), + Video::ATTRIBUTE_PATH => $file->path(), + ]); - $action = new DeleteVideoAction($video); + $action = new DeleteVideoAction($video); - $action->handle(); + $action->handle(); - static::assertEmpty(Storage::disk(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED))->allFiles()); - } + $this->assertEmpty(Storage::disk(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED))->allFiles()); +}); - /** - * The Delete Video Action shall delete the video. - * - * @throws Exception - */ - public function testVideoDeleted(): void - { - Config::set(VideoConstants::DISKS_QUALIFIED, [Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)]); - Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); +test('video deleted', function () { + Config::set(VideoConstants::DISKS_QUALIFIED, [Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)]); + Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); - $file = File::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); + $file = File::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - $video = Video::factory()->createOne([ - Video::ATTRIBUTE_BASENAME => FileFacade::basename($file->path()), - Video::ATTRIBUTE_FILENAME => FileFacade::name($file->path()), - Video::ATTRIBUTE_MIMETYPE => MimeType::from($file->path()), - Video::ATTRIBUTE_PATH => $file->path(), - ]); + $video = Video::factory()->createOne([ + Video::ATTRIBUTE_BASENAME => FileFacade::basename($file->path()), + Video::ATTRIBUTE_FILENAME => FileFacade::name($file->path()), + Video::ATTRIBUTE_MIMETYPE => MimeType::from($file->path()), + Video::ATTRIBUTE_PATH => $file->path(), + ]); - $action = new DeleteVideoAction($video); + $action = new DeleteVideoAction($video); - $result = $action->handle(); + $result = $action->handle(); - $action->then($result); + $action->then($result); - static::assertSoftDeleted($video); - } -} + $this->assertSoftDeleted($video); +}); diff --git a/tests/Feature/Actions/Storage/Wiki/Video/MoveVideoTest.php b/tests/Feature/Actions/Storage/Wiki/Video/MoveVideoTest.php index bd024cb7f..cce8974d7 100644 --- a/tests/Feature/Actions/Storage/Wiki/Video/MoveVideoTest.php +++ b/tests/Feature/Actions/Storage/Wiki/Video/MoveVideoTest.php @@ -2,133 +2,110 @@ declare(strict_types=1); -namespace Tests\Feature\Actions\Storage\Wiki\Video; - use App\Actions\Storage\Wiki\Video\MoveVideoAction; use App\Constants\Config\VideoConstants; use App\Enums\Actions\ActionStatus; use App\Models\Wiki\Video; use Illuminate\Filesystem\FilesystemAdapter; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Http\Testing\File; use Illuminate\Http\Testing\MimeType; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\File as FileFacade; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Str; -use Tests\TestCase; -class MoveVideoTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Move Video Action shall fail if there are no moves. - */ - public function testDefault(): void - { - Config::set(VideoConstants::DISKS_QUALIFIED, []); - Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); +test('default', function () { + Config::set(VideoConstants::DISKS_QUALIFIED, []); + Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); - $video = Video::factory()->createOne(); + $video = Video::factory()->createOne(); - $action = new MoveVideoAction($video, $this->faker->word()); + $action = new MoveVideoAction($video, fake()->word()); - $storageResults = $action->handle(); + $storageResults = $action->handle(); - $result = $storageResults->toActionResult(); + $result = $storageResults->toActionResult(); - static::assertTrue($result->hasFailed()); - } + $this->assertTrue($result->hasFailed()); +}); - /** - * The Move Video Action shall pass if there are moves. - */ - public function testPassed(): void - { - /** @var FilesystemAdapter $fs */ - $fs = Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); - Config::set(VideoConstants::DISKS_QUALIFIED, [Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)]); +test('passed', function () { + /** @var FilesystemAdapter $fs */ + $fs = Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); + Config::set(VideoConstants::DISKS_QUALIFIED, [Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)]); - $file = File::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); + $file = File::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - $directory = $this->faker->unique()->word(); + $directory = fake()->unique()->word(); - $video = Video::factory()->createOne([ - Video::ATTRIBUTE_BASENAME => FileFacade::basename($file->path()), - Video::ATTRIBUTE_FILENAME => FileFacade::name($file->path()), - Video::ATTRIBUTE_MIMETYPE => MimeType::from($file->path()), - Video::ATTRIBUTE_PATH => $fs->putFileAs($directory, $file, $file->getClientOriginalName()), - ]); + $video = Video::factory()->createOne([ + Video::ATTRIBUTE_BASENAME => FileFacade::basename($file->path()), + Video::ATTRIBUTE_FILENAME => FileFacade::name($file->path()), + Video::ATTRIBUTE_MIMETYPE => MimeType::from($file->path()), + Video::ATTRIBUTE_PATH => $fs->putFileAs($directory, $file, $file->getClientOriginalName()), + ]); - $action = new MoveVideoAction($video, Str::replace($directory, $this->faker->unique()->word(), $video->path)); + $action = new MoveVideoAction($video, Str::replace($directory, fake()->unique()->word(), $video->path)); - $storageResults = $action->handle(); + $storageResults = $action->handle(); - $result = $storageResults->toActionResult(); + $result = $storageResults->toActionResult(); - static::assertTrue($result->getStatus() === ActionStatus::PASSED); - } + $this->assertTrue($result->getStatus() === ActionStatus::PASSED); +}); - /** - * The Move Video Action shall move the file in the configured disks. - */ - public function testMovedInDisk(): void - { - /** @var FilesystemAdapter $fs */ - $fs = Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); - Config::set(VideoConstants::DISKS_QUALIFIED, [Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)]); +test('moved in disk', function () { + /** @var FilesystemAdapter $fs */ + $fs = Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); + Config::set(VideoConstants::DISKS_QUALIFIED, [Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)]); - $file = File::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); + $file = File::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - $directory = $this->faker->unique()->word(); + $directory = fake()->unique()->word(); - $video = Video::factory()->createOne([ - Video::ATTRIBUTE_BASENAME => FileFacade::basename($file->path()), - Video::ATTRIBUTE_FILENAME => FileFacade::name($file->path()), - Video::ATTRIBUTE_MIMETYPE => MimeType::from($file->path()), - Video::ATTRIBUTE_PATH => $fs->putFileAs($directory, $file, $file->getClientOriginalName()), - ]); + $video = Video::factory()->createOne([ + Video::ATTRIBUTE_BASENAME => FileFacade::basename($file->path()), + Video::ATTRIBUTE_FILENAME => FileFacade::name($file->path()), + Video::ATTRIBUTE_MIMETYPE => MimeType::from($file->path()), + Video::ATTRIBUTE_PATH => $fs->putFileAs($directory, $file, $file->getClientOriginalName()), + ]); - $from = $video->path(); - $to = Str::replace($directory, $this->faker->unique()->word(), $video->path); + $from = $video->path(); + $to = Str::replace($directory, fake()->unique()->word(), $video->path); - $action = new MoveVideoAction($video, $to); + $action = new MoveVideoAction($video, $to); - $action->handle(); + $action->handle(); - $fs->assertMissing($from); - $fs->assertExists($to); - } + $fs->assertMissing($from); + $fs->assertExists($to); +}); - /** - * The Move Video Action shall move the video. - */ - public function testVideoUpdated(): void - { - /** @var FilesystemAdapter $fs */ - $fs = Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); - Config::set(VideoConstants::DISKS_QUALIFIED, [Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)]); +test('video updated', function () { + /** @var FilesystemAdapter $fs */ + $fs = Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); + Config::set(VideoConstants::DISKS_QUALIFIED, [Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)]); - $file = File::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); + $file = File::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - $directory = $this->faker->unique()->word(); + $directory = fake()->unique()->word(); - $video = Video::factory()->createOne([ - Video::ATTRIBUTE_BASENAME => FileFacade::basename($file->path()), - Video::ATTRIBUTE_FILENAME => FileFacade::name($file->path()), - Video::ATTRIBUTE_MIMETYPE => MimeType::from($file->path()), - Video::ATTRIBUTE_PATH => $fs->putFileAs($directory, $file, $file->getClientOriginalName()), - ]); + $video = Video::factory()->createOne([ + Video::ATTRIBUTE_BASENAME => FileFacade::basename($file->path()), + Video::ATTRIBUTE_FILENAME => FileFacade::name($file->path()), + Video::ATTRIBUTE_MIMETYPE => MimeType::from($file->path()), + Video::ATTRIBUTE_PATH => $fs->putFileAs($directory, $file, $file->getClientOriginalName()), + ]); - $to = Str::replace($directory, $this->faker->unique()->word(), $video->path); + $to = Str::replace($directory, fake()->unique()->word(), $video->path); - $action = new MoveVideoAction($video, $to); + $action = new MoveVideoAction($video, $to); - $result = $action->handle(); + $result = $action->handle(); - $action->then($result); + $action->then($result); - static::assertDatabaseHas(Video::class, [Video::ATTRIBUTE_PATH => $to]); - } -} + $this->assertDatabaseHas(Video::class, [Video::ATTRIBUTE_PATH => $to]); +}); diff --git a/tests/Feature/Actions/Storage/Wiki/Video/Script/DeleteScriptTest.php b/tests/Feature/Actions/Storage/Wiki/Video/Script/DeleteScriptTest.php index 84b957937..ceba70787 100644 --- a/tests/Feature/Actions/Storage/Wiki/Video/Script/DeleteScriptTest.php +++ b/tests/Feature/Actions/Storage/Wiki/Video/Script/DeleteScriptTest.php @@ -2,105 +2,79 @@ declare(strict_types=1); -namespace Tests\Feature\Actions\Storage\Wiki\Video\Script; - use App\Actions\Storage\Wiki\Video\Script\DeleteScriptAction; use App\Constants\Config\VideoConstants; use App\Enums\Actions\ActionStatus; use App\Models\Wiki\Video\VideoScript; -use Exception; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Http\Testing\File; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Storage; -use Tests\TestCase; -class DeleteScriptTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Delete Script Action shall fail if there are no deletions. - */ - public function testDefault(): void - { - Config::set(VideoConstants::SCRIPT_DISK_QUALIFIED, []); - Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); +test('default', function () { + Config::set(VideoConstants::SCRIPT_DISK_QUALIFIED, []); + Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); - $script = VideoScript::factory()->createOne(); + $script = VideoScript::factory()->createOne(); - $action = new DeleteScriptAction($script); + $action = new DeleteScriptAction($script); - $storageResults = $action->handle(); + $storageResults = $action->handle(); - $result = $storageResults->toActionResult(); + $result = $storageResults->toActionResult(); - static::assertTrue($result->hasFailed()); - } + $this->assertTrue($result->hasFailed()); +}); - /** - * The Delete Script Action shall pass if there are deletions. - */ - public function testPassed(): void - { - Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); +test('passed', function () { + Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); - $file = File::fake()->create($this->faker->word().'.txt', $this->faker->randomDigitNotNull()); + $file = File::fake()->create(fake()->word().'.txt', fake()->randomDigitNotNull()); - $script = VideoScript::factory()->createOne([ - VideoScript::ATTRIBUTE_PATH => $file->path(), - ]); + $script = VideoScript::factory()->createOne([ + VideoScript::ATTRIBUTE_PATH => $file->path(), + ]); - $action = new DeleteScriptAction($script); + $action = new DeleteScriptAction($script); - $storageResults = $action->handle(); + $storageResults = $action->handle(); - $result = $storageResults->toActionResult(); + $result = $storageResults->toActionResult(); - static::assertTrue($result->getStatus() === ActionStatus::PASSED); - } + $this->assertTrue($result->getStatus() === ActionStatus::PASSED); +}); - /** - * The Delete Script Action shall delete the file from the configured disks. - */ - public function testDeletedFromDisk(): void - { - $fs = Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); +test('deleted from disk', function () { + $fs = Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); - $file = File::fake()->create($this->faker->word().'.txt', $this->faker->randomDigitNotNull()); + $file = File::fake()->create(fake()->word().'.txt', fake()->randomDigitNotNull()); - $script = VideoScript::factory()->createOne([ - VideoScript::ATTRIBUTE_PATH => $file->path(), - ]); + $script = VideoScript::factory()->createOne([ + VideoScript::ATTRIBUTE_PATH => $file->path(), + ]); - $action = new DeleteScriptAction($script); + $action = new DeleteScriptAction($script); - $action->handle(); + $action->handle(); - static::assertEmpty($fs->allFiles()); - } + $this->assertEmpty($fs->allFiles()); +}); - /** - * The Delete Video Action shall delete the script. - * - * @throws Exception - */ - public function testVideoDeleted(): void - { - Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); +test('video deleted', function () { + Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); - $file = File::fake()->create($this->faker->word().'.txt', $this->faker->randomDigitNotNull()); + $file = File::fake()->create(fake()->word().'.txt', fake()->randomDigitNotNull()); - $script = VideoScript::factory()->createOne([ - VideoScript::ATTRIBUTE_PATH => $file->path(), - ]); + $script = VideoScript::factory()->createOne([ + VideoScript::ATTRIBUTE_PATH => $file->path(), + ]); - $action = new DeleteScriptAction($script); + $action = new DeleteScriptAction($script); - $result = $action->handle(); + $result = $action->handle(); - $action->then($result); + $action->then($result); - static::assertSoftDeleted($script); - } -} + $this->assertSoftDeleted($script); +}); diff --git a/tests/Feature/Actions/Storage/Wiki/Video/Script/MoveScriptTest.php b/tests/Feature/Actions/Storage/Wiki/Video/Script/MoveScriptTest.php index 92e7c6eca..b892a04e2 100644 --- a/tests/Feature/Actions/Storage/Wiki/Video/Script/MoveScriptTest.php +++ b/tests/Feature/Actions/Storage/Wiki/Video/Script/MoveScriptTest.php @@ -2,119 +2,96 @@ declare(strict_types=1); -namespace Tests\Feature\Actions\Storage\Wiki\Video\Script; - use App\Actions\Storage\Wiki\Video\Script\MoveScriptAction; use App\Constants\Config\VideoConstants; use App\Enums\Actions\ActionStatus; use App\Models\Wiki\Video\VideoScript; use Illuminate\Filesystem\FilesystemAdapter; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Http\Testing\File; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Str; -use Tests\TestCase; -class MoveScriptTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Move Script Action shall fail if there are no moves. - */ - public function testDefault(): void - { - Config::set(VideoConstants::SCRIPT_DISK_QUALIFIED, []); - Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); +test('default', function () { + Config::set(VideoConstants::SCRIPT_DISK_QUALIFIED, []); + Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); - $script = VideoScript::factory()->createOne(); + $script = VideoScript::factory()->createOne(); - $action = new MoveScriptAction($script, $this->faker->word()); + $action = new MoveScriptAction($script, fake()->word()); - $storageResults = $action->handle(); + $storageResults = $action->handle(); - $result = $storageResults->toActionResult(); + $result = $storageResults->toActionResult(); - static::assertTrue($result->hasFailed()); - } + $this->assertTrue($result->hasFailed()); +}); - /** - * The Move Script Action shall pass if there are moves. - */ - public function testPassed(): void - { - /** @var FilesystemAdapter $fs */ - $fs = Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); +test('passed', function () { + /** @var FilesystemAdapter $fs */ + $fs = Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); - $file = File::fake()->create($this->faker->word().'.txt', $this->faker->randomDigitNotNull()); + $file = File::fake()->create(fake()->word().'.txt', fake()->randomDigitNotNull()); - $directory = $this->faker->unique()->word(); + $directory = fake()->unique()->word(); - $script = VideoScript::factory()->createOne([ - VideoScript::ATTRIBUTE_PATH => $fs->putFileAs($directory, $file, $file->getClientOriginalName()), - ]); + $script = VideoScript::factory()->createOne([ + VideoScript::ATTRIBUTE_PATH => $fs->putFileAs($directory, $file, $file->getClientOriginalName()), + ]); - $action = new MoveScriptAction($script, Str::replace($directory, $this->faker->unique()->word(), $script->path)); + $action = new MoveScriptAction($script, Str::replace($directory, fake()->unique()->word(), $script->path)); - $storageResults = $action->handle(); + $storageResults = $action->handle(); - $result = $storageResults->toActionResult(); + $result = $storageResults->toActionResult(); - static::assertTrue($result->getStatus() === ActionStatus::PASSED); - } + $this->assertTrue($result->getStatus() === ActionStatus::PASSED); +}); - /** - * The Move Script Action shall move the file in the configured disks. - */ - public function testMovedInDisk(): void - { - /** @var FilesystemAdapter $fs */ - $fs = Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); +test('moved in disk', function () { + /** @var FilesystemAdapter $fs */ + $fs = Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); - $file = File::fake()->create($this->faker->word().'.txt', $this->faker->randomDigitNotNull()); + $file = File::fake()->create(fake()->word().'.txt', fake()->randomDigitNotNull()); - $directory = $this->faker->unique()->word(); + $directory = fake()->unique()->word(); - $script = VideoScript::factory()->createOne([ - VideoScript::ATTRIBUTE_PATH => $fs->putFileAs($directory, $file, $file->getClientOriginalName()), - ]); + $script = VideoScript::factory()->createOne([ + VideoScript::ATTRIBUTE_PATH => $fs->putFileAs($directory, $file, $file->getClientOriginalName()), + ]); - $from = $script->path; - $to = Str::replace($directory, $this->faker->unique()->word(), $script->path); + $from = $script->path; + $to = Str::replace($directory, fake()->unique()->word(), $script->path); - $action = new MoveScriptAction($script, $to); + $action = new MoveScriptAction($script, $to); - $action->handle(); + $action->handle(); - $fs->assertMissing($from); - $fs->assertExists($to); - } + $fs->assertMissing($from); + $fs->assertExists($to); +}); - /** - * The Move Script Action shall move the script. - */ - public function testScriptUpdated(): void - { - /** @var FilesystemAdapter $fs */ - $fs = Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); +test('script updated', function () { + /** @var FilesystemAdapter $fs */ + $fs = Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); - $file = File::fake()->create($this->faker->word().'.txt', $this->faker->randomDigitNotNull()); + $file = File::fake()->create(fake()->word().'.txt', fake()->randomDigitNotNull()); - $directory = $this->faker->unique()->word(); + $directory = fake()->unique()->word(); - $script = VideoScript::factory()->createOne([ - VideoScript::ATTRIBUTE_PATH => $fs->putFileAs($directory, $file, $file->getClientOriginalName()), - ]); + $script = VideoScript::factory()->createOne([ + VideoScript::ATTRIBUTE_PATH => $fs->putFileAs($directory, $file, $file->getClientOriginalName()), + ]); - $to = Str::replace($directory, $this->faker->unique()->word(), $script->path); + $to = Str::replace($directory, fake()->unique()->word(), $script->path); - $action = new MoveScriptAction($script, $to); + $action = new MoveScriptAction($script, $to); - $result = $action->handle(); + $result = $action->handle(); - $action->then($result); + $action->then($result); - static::assertDatabaseHas(VideoScript::class, [VideoScript::ATTRIBUTE_PATH => $to]); - } -} + $this->assertDatabaseHas(VideoScript::class, [VideoScript::ATTRIBUTE_PATH => $to]); +}); diff --git a/tests/Feature/Actions/Storage/Wiki/Video/Script/UploadScriptTest.php b/tests/Feature/Actions/Storage/Wiki/Video/Script/UploadScriptTest.php index afed16acd..2251f9410 100644 --- a/tests/Feature/Actions/Storage/Wiki/Video/Script/UploadScriptTest.php +++ b/tests/Feature/Actions/Storage/Wiki/Video/Script/UploadScriptTest.php @@ -2,111 +2,84 @@ declare(strict_types=1); -namespace Tests\Feature\Actions\Storage\Wiki\Video\Script; - use App\Actions\Storage\Wiki\Video\Script\UploadScriptAction; use App\Constants\Config\VideoConstants; use App\Enums\Actions\ActionStatus; use App\Models\Wiki\Video; use App\Models\Wiki\Video\VideoScript; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Http\Testing\File; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Storage; -use Tests\TestCase; -class UploadScriptTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Upload Script Action shall fail if there are no uploads. - */ - public function testDefault(): void - { - Config::set(VideoConstants::SCRIPT_DISK_QUALIFIED, []); - Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); +test('default', function () { + Config::set(VideoConstants::SCRIPT_DISK_QUALIFIED, []); + Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); - $file = File::fake()->create($this->faker->word().'.txt', $this->faker->randomDigitNotNull()); + $file = File::fake()->create(fake()->word().'.txt', fake()->randomDigitNotNull()); - $action = new UploadScriptAction($file, $this->faker->word()); + $action = new UploadScriptAction($file, fake()->word()); - $storageResults = $action->handle(); + $storageResults = $action->handle(); - $result = $storageResults->toActionResult(); + $result = $storageResults->toActionResult(); - static::assertTrue($result->hasFailed()); - } + $this->assertTrue($result->hasFailed()); +}); - /** - * The Upload Script Action shall pass if given a valid file. - */ - public function testPassed(): void - { - Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); +test('passed', function () { + Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); - $file = File::fake()->create($this->faker->word().'.txt', $this->faker->randomDigitNotNull()); + $file = File::fake()->create(fake()->word().'.txt', fake()->randomDigitNotNull()); - $action = new UploadScriptAction($file, $this->faker->word()); + $action = new UploadScriptAction($file, fake()->word()); - $storageResults = $action->handle(); + $storageResults = $action->handle(); - $result = $storageResults->toActionResult(); + $result = $storageResults->toActionResult(); - static::assertTrue($result->getStatus() === ActionStatus::PASSED); - } + $this->assertTrue($result->getStatus() === ActionStatus::PASSED); +}); - /** - * The Upload Script Action shall upload the file to the configured disk. - */ - public function testUploadedToDisk(): void - { - $fs = Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); +test('uploaded to disk', function () { + $fs = Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); - $file = File::fake()->create($this->faker->word().'.txt', $this->faker->randomDigitNotNull()); + $file = File::fake()->create(fake()->word().'.txt', fake()->randomDigitNotNull()); - $action = new UploadScriptAction($file, $this->faker->word()); + $action = new UploadScriptAction($file, fake()->word()); - $action->handle(); + $action->handle(); - static::assertCount(1, $fs->allFiles()); - } + $this->assertCount(1, $fs->allFiles()); +}); - /** - * The Upload Video Action shall upload the file to the configured disk. - */ - public function testCreatedVideo(): void - { - Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); +test('created video', function () { + Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); - $file = File::fake()->create($this->faker->word().'.txt', $this->faker->randomDigitNotNull()); + $file = File::fake()->create(fake()->word().'.txt', fake()->randomDigitNotNull()); - $action = new UploadScriptAction($file, $this->faker->word()); + $action = new UploadScriptAction($file, fake()->word()); - $result = $action->handle(); + $result = $action->handle(); - $action->then($result); + $action->then($result); - static::assertDatabaseCount(VideoScript::class, 1); - } + $this->assertDatabaseCount(VideoScript::class, 1); +}); - /** - * The Upload Script Action shall attach the provided video. - */ - public function testAttachesVideo(): void - { - Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); +test('attaches video', function () { + Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); - $file = File::fake()->create($this->faker->word().'.txt', $this->faker->randomDigitNotNull()); + $file = File::fake()->create(fake()->word().'.txt', fake()->randomDigitNotNull()); - $video = Video::factory()->createOne(); + $video = Video::factory()->createOne(); - $action = new UploadScriptAction($file, $this->faker->word(), $video); + $action = new UploadScriptAction($file, fake()->word(), $video); - $result = $action->handle(); + $result = $action->handle(); - $action->then($result); + $action->then($result); - static::assertTrue($video->videoscript()->exists()); - } -} + $this->assertTrue($video->videoscript()->exists()); +}); diff --git a/tests/Feature/Actions/Storage/Wiki/Video/UploadVideoTest.php b/tests/Feature/Actions/Storage/Wiki/Video/UploadVideoTest.php index 58ed03ede..182cc9171 100644 --- a/tests/Feature/Actions/Storage/Wiki/Video/UploadVideoTest.php +++ b/tests/Feature/Actions/Storage/Wiki/Video/UploadVideoTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Actions\Storage\Wiki\Video; - use App\Actions\Storage\Wiki\UploadedFileAction; use App\Actions\Storage\Wiki\Video\UploadVideoAction; use App\Constants\Config\VideoConstants; @@ -16,218 +14,176 @@ use App\Models\Wiki\Anime\Theme\AnimeThemeEntry; use App\Models\Wiki\Video; use App\Models\Wiki\Video\VideoScript; use App\Pivots\Wiki\AnimeThemeEntryVideo; -use Exception; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Http\Testing\File; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Process; use Illuminate\Support\Facades\Storage; -use Tests\TestCase; -class UploadVideoTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Upload Video Action shall fail if there are no uploads. - */ - public function testDefault(): void - { - Config::set(VideoConstants::DISKS_QUALIFIED, []); - Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); +test('default', function () { + Config::set(VideoConstants::DISKS_QUALIFIED, []); + Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); - $file = File::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); + $file = File::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - $action = new UploadVideoAction($file, $this->faker->word()); + $action = new UploadVideoAction($file, fake()->word()); - $storageResults = $action->handle(); + $storageResults = $action->handle(); - $result = $storageResults->toActionResult(); + $result = $storageResults->toActionResult(); - static::assertTrue($result->hasFailed()); - } + $this->assertTrue($result->hasFailed()); +}); - /** - * The Upload Video Action shall pass if given a valid file. - */ - public function testPassed(): void - { - Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); - Config::set(VideoConstants::DISKS_QUALIFIED, [Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)]); +test('passed', function () { + Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); + Config::set(VideoConstants::DISKS_QUALIFIED, [Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)]); - $file = File::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); + $file = File::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - $action = new UploadVideoAction($file, $this->faker->word()); + $action = new UploadVideoAction($file, fake()->word()); - $storageResults = $action->handle(); + $storageResults = $action->handle(); - $result = $storageResults->toActionResult(); + $result = $storageResults->toActionResult(); - static::assertTrue($result->getStatus() === ActionStatus::PASSED); - } + $this->assertTrue($result->getStatus() === ActionStatus::PASSED); +}); - /** - * The Upload Video Action shall upload the file to the configured disk. - */ - public function testUploadedToDisk(): void - { - Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); - Config::set(VideoConstants::DISKS_QUALIFIED, [Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)]); +test('uploaded to disk', function () { + Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); + Config::set(VideoConstants::DISKS_QUALIFIED, [Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)]); - $file = File::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); + $file = File::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - $action = new UploadVideoAction($file, $this->faker->word()); + $action = new UploadVideoAction($file, fake()->word()); - $action->handle(); + $action->handle(); - static::assertCount(1, Storage::disk(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED))->allFiles()); - } + $this->assertCount(1, Storage::disk(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED))->allFiles()); +}); - /** - * The Upload Video Action shall upload the file to the configured disk. - * - * @throws Exception - */ - public function testCreatedVideo(): void - { - Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); - Config::set(VideoConstants::DISKS_QUALIFIED, [Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)]); +test('created video', function () { + Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); + Config::set(VideoConstants::DISKS_QUALIFIED, [Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)]); - $file = File::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); + $file = File::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'streams' => [ - 0 => [ - 'height' => $this->faker->randomNumber(), - ], + Process::fake([ + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'streams' => [ + 0 => [ + 'height' => fake()->randomNumber(), ], - ])), - ]); + ], + ])), + ]); - $action = new UploadVideoAction($file, $this->faker->word()); + $action = new UploadVideoAction($file, fake()->word()); - $result = $action->handle(); + $result = $action->handle(); - $action->then($result); + $action->then($result); - static::assertDatabaseCount(Video::class, 1); - } + $this->assertDatabaseCount(Video::class, 1); +}); - /** - * The Upload Video Action shall set additional video attributes. - * - * @throws Exception - */ - public function testSetsAttributes(): void - { - Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); - Config::set(VideoConstants::DISKS_QUALIFIED, [Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)]); +test('sets attributes', function () { + Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); + Config::set(VideoConstants::DISKS_QUALIFIED, [Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)]); - $file = File::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); + $file = File::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'streams' => [ - 0 => [ - 'height' => $this->faker->randomNumber(), - ], + Process::fake([ + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'streams' => [ + 0 => [ + 'height' => fake()->randomNumber(), ], - ])), - ]); + ], + ])), + ]); - $overlap = Arr::random(VideoOverlap::cases()); - $source = Arr::random(VideoSource::cases()); + $overlap = Arr::random(VideoOverlap::cases()); + $source = Arr::random(VideoSource::cases()); - $attributes = [ - Video::ATTRIBUTE_NC => $this->faker->boolean(), - Video::ATTRIBUTE_SUBBED => $this->faker->boolean(), - Video::ATTRIBUTE_LYRICS => $this->faker->boolean(), - Video::ATTRIBUTE_UNCEN => $this->faker->boolean(), - Video::ATTRIBUTE_OVERLAP => $overlap->value, - Video::ATTRIBUTE_SOURCE => $source->value, - ]; + $attributes = [ + Video::ATTRIBUTE_NC => fake()->boolean(), + Video::ATTRIBUTE_SUBBED => fake()->boolean(), + Video::ATTRIBUTE_LYRICS => fake()->boolean(), + Video::ATTRIBUTE_UNCEN => fake()->boolean(), + Video::ATTRIBUTE_OVERLAP => $overlap->value, + Video::ATTRIBUTE_SOURCE => $source->value, + ]; - $action = new UploadVideoAction($file, $this->faker->word(), $attributes); + $action = new UploadVideoAction($file, fake()->word(), $attributes); - $result = $action->handle(); + $result = $action->handle(); - $action->then($result); + $action->then($result); - static::assertDatabaseHas(Video::class, $attributes); - } + $this->assertDatabaseHas(Video::class, $attributes); +}); - /** - * The Upload Video Action shall attach the provided entry. - * - * @throws Exception - */ - public function testAttachesEntry(): void - { - Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); - Config::set(VideoConstants::DISKS_QUALIFIED, [Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)]); +test('attaches entry', function () { + Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); + Config::set(VideoConstants::DISKS_QUALIFIED, [Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)]); - $file = File::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); + $file = File::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'streams' => [ - 0 => [ - 'height' => $this->faker->randomNumber(), - ], + Process::fake([ + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'streams' => [ + 0 => [ + 'height' => fake()->randomNumber(), ], - ])), - ]); + ], + ])), + ]); - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - $action = new UploadVideoAction(file: $file, path: $this->faker->word(), entry: $entry); + $action = new UploadVideoAction(file: $file, path: fake()->word(), entry: $entry); - $result = $action->handle(); + $result = $action->handle(); - $action->then($result); + $action->then($result); - static::assertDatabaseCount(AnimeThemeEntryVideo::class, 1); - } + $this->assertDatabaseCount(AnimeThemeEntryVideo::class, 1); +}); - /** - * The Upload Video Action shall attach the provided script. - * - * @throws Exception - */ - public function testAssociatesScript(): void - { - Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); - Config::set(VideoConstants::DISKS_QUALIFIED, [Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)]); - Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); +test('associates script', function () { + Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); + Config::set(VideoConstants::DISKS_QUALIFIED, [Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)]); + Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); - $file = File::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); - $script = File::fake()->create($this->faker->word().'.txt', $this->faker->randomDigitNotNull()); + $file = File::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); + $script = File::fake()->create(fake()->word().'.txt', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'streams' => [ - 0 => [ - 'height' => $this->faker->randomNumber(), - ], + Process::fake([ + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'streams' => [ + 0 => [ + 'height' => fake()->randomNumber(), ], - ])), - ]); + ], + ])), + ]); - $action = new UploadVideoAction(file: $file, path: $this->faker->word(), script: $script); + $action = new UploadVideoAction(file: $file, path: fake()->word(), script: $script); - $result = $action->handle(); + $result = $action->handle(); - $action->then($result); + $action->then($result); - /** @var Video $video */ - $video = Video::query()->first(); + /** @var Video $video */ + $video = Video::query()->first(); - static::assertNotNull($video); + $this->assertNotNull($video); - static::assertDatabaseHas(VideoScript::class, [VideoScript::ATTRIBUTE_VIDEO => $video->video_id]); - } -} + $this->assertDatabaseHas(VideoScript::class, [VideoScript::ATTRIBUTE_VIDEO => $video->video_id]); +}); diff --git a/tests/Feature/Console/Commands/Repositories/Storage/Admin/DumpReconcileTest.php b/tests/Feature/Console/Commands/Repositories/Storage/Admin/DumpReconcileTest.php index 2398a8867..cd59045a2 100644 --- a/tests/Feature/Console/Commands/Repositories/Storage/Admin/DumpReconcileTest.php +++ b/tests/Feature/Console/Commands/Repositories/Storage/Admin/DumpReconcileTest.php @@ -2,74 +2,55 @@ declare(strict_types=1); -namespace Tests\Feature\Console\Commands\Repositories\Storage\Admin; - use App\Console\Commands\Repositories\Storage\Admin\DumpReconcileCommand; use App\Constants\Config\DumpConstants; use App\Models\Admin\Dump; use App\Repositories\Storage\Admin\DumpRepository; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Storage; use Mockery\MockInterface; -use Tests\TestCase; -class DumpReconcileTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * If no changes are needed, the Reconcile Dump Command shall output 'No Dumps created or deleted or updated'. - */ - public function testNoResults(): void - { - $this->mock(DumpRepository::class, function (MockInterface $mock) { - $mock->shouldReceive('get')->once()->andReturn(Collection::make()); - }); +test('no results', function () { + $this->mock(DumpRepository::class, function (MockInterface $mock) { + $mock->shouldReceive('get')->once()->andReturn(Collection::make()); + }); - $this->artisan(DumpReconcileCommand::class) - ->assertSuccessful() - ->expectsOutput('No Dumps created or deleted or updated'); - } + $this->artisan(DumpReconcileCommand::class) + ->assertSuccessful() + ->expectsOutput('No Dumps created or deleted or updated'); +}); - /** - * If dumps are created, the Reconcile Dump Command shall output '{Created Count} Dumps created, 0 Dumps deleted, 0 Dumps updated'. - */ - public function testCreated(): void - { - Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); +test('created', function () { + Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); - $createdDumpCount = $this->faker->numberBetween(2, 9); + $createdDumpCount = fake()->numberBetween(2, 9); - $dumps = Dump::factory()->count($createdDumpCount)->make(); + $dumps = Dump::factory()->count($createdDumpCount)->make(); - $this->mock(DumpRepository::class, function (MockInterface $mock) use ($dumps) { - $mock->shouldReceive('get')->once()->andReturn($dumps); - }); + $this->mock(DumpRepository::class, function (MockInterface $mock) use ($dumps) { + $mock->shouldReceive('get')->once()->andReturn($dumps); + }); - $this->artisan(DumpReconcileCommand::class) - ->assertSuccessful() - ->expectsOutput("$createdDumpCount Dumps created, 0 Dumps deleted, 0 Dumps updated"); - } + $this->artisan(DumpReconcileCommand::class) + ->assertSuccessful() + ->expectsOutput("$createdDumpCount Dumps created, 0 Dumps deleted, 0 Dumps updated"); +}); - /** - * If dumps are deleted, the Reconcile Dump Command shall output '0 Dumps created, {Deleted Count} Dumps deleted, 0 Dumps updated'. - */ - public function testDeleted(): void - { - Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); +test('deleted', function () { + Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); - $deletedDumpCount = $this->faker->numberBetween(2, 9); + $deletedDumpCount = fake()->numberBetween(2, 9); - Dump::factory()->count($deletedDumpCount)->create(); + Dump::factory()->count($deletedDumpCount)->create(); - $this->mock(DumpRepository::class, function (MockInterface $mock) { - $mock->shouldReceive('get')->once()->andReturn(Collection::make()); - }); + $this->mock(DumpRepository::class, function (MockInterface $mock) { + $mock->shouldReceive('get')->once()->andReturn(Collection::make()); + }); - $this->artisan(DumpReconcileCommand::class) - ->assertSuccessful() - ->expectsOutput("0 Dumps created, $deletedDumpCount Dumps deleted, 0 Dumps updated"); - } -} + $this->artisan(DumpReconcileCommand::class) + ->assertSuccessful() + ->expectsOutput("0 Dumps created, $deletedDumpCount Dumps deleted, 0 Dumps updated"); +}); diff --git a/tests/Feature/Console/Commands/Repositories/Storage/Wiki/AudioReconcileTest.php b/tests/Feature/Console/Commands/Repositories/Storage/Wiki/AudioReconcileTest.php index 92afc7260..faddb33b7 100644 --- a/tests/Feature/Console/Commands/Repositories/Storage/Wiki/AudioReconcileTest.php +++ b/tests/Feature/Console/Commands/Repositories/Storage/Wiki/AudioReconcileTest.php @@ -2,95 +2,72 @@ declare(strict_types=1); -namespace Tests\Feature\Console\Commands\Repositories\Storage\Wiki; - use App\Console\Commands\Repositories\Storage\Wiki\AudioReconcileCommand; use App\Models\Wiki\Audio; use App\Repositories\Storage\Wiki\AudioRepository; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Collection; use Mockery\MockInterface; -use Tests\TestCase; -class AudioReconcileTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * If no changes are needed, the Reconcile Audio Command shall output 'No Audio created or deleted or updated'. - */ - public function testNoResults(): void - { - $this->mock(AudioRepository::class, function (MockInterface $mock) { - $mock->shouldReceive('get')->once()->andReturn(Collection::make()); - }); +test('no results', function () { + $this->mock(AudioRepository::class, function (MockInterface $mock) { + $mock->shouldReceive('get')->once()->andReturn(Collection::make()); + }); - $this->artisan(AudioReconcileCommand::class) - ->assertSuccessful() - ->expectsOutput('No Audio created or deleted or updated'); - } + $this->artisan(AudioReconcileCommand::class) + ->assertSuccessful() + ->expectsOutput('No Audio created or deleted or updated'); +}); - /** - * If audios are created, the Reconcile Audio Command shall output '{Created Count} Audio created, 0 Audio deleted, 0 Audio updated'. - */ - public function testCreated(): void - { - $createdAudioCount = $this->faker->numberBetween(2, 9); +test('created', function () { + $createdAudioCount = fake()->numberBetween(2, 9); - $audios = Audio::factory()->count($createdAudioCount)->make(); + $audios = Audio::factory()->count($createdAudioCount)->make(); - $this->mock(AudioRepository::class, function (MockInterface $mock) use ($audios) { - $mock->shouldReceive('get')->once()->andReturn($audios); - }); + $this->mock(AudioRepository::class, function (MockInterface $mock) use ($audios) { + $mock->shouldReceive('get')->once()->andReturn($audios); + }); - $this->artisan(AudioReconcileCommand::class) - ->assertSuccessful() - ->expectsOutput("$createdAudioCount Audio created, 0 Audio deleted, 0 Audio updated"); - } + $this->artisan(AudioReconcileCommand::class) + ->assertSuccessful() + ->expectsOutput("$createdAudioCount Audio created, 0 Audio deleted, 0 Audio updated"); +}); - /** - * If audios are deleted, the Reconcile Audio Command shall output '0 Audio created, {Deleted Count} Audio deleted, 0 Audio updated'. - */ - public function testDeleted(): void - { - $deletedAudioCount = $this->faker->numberBetween(2, 9); +test('deleted', function () { + $deletedAudioCount = fake()->numberBetween(2, 9); - Audio::factory()->count($deletedAudioCount)->create(); + Audio::factory()->count($deletedAudioCount)->create(); - $this->mock(AudioRepository::class, function (MockInterface $mock) { - $mock->shouldReceive('get')->once()->andReturn(Collection::make()); - }); + $this->mock(AudioRepository::class, function (MockInterface $mock) { + $mock->shouldReceive('get')->once()->andReturn(Collection::make()); + }); - $this->artisan(AudioReconcileCommand::class) - ->assertSuccessful() - ->expectsOutput("0 Audio created, $deletedAudioCount Audio deleted, 0 Audio updated"); - } + $this->artisan(AudioReconcileCommand::class) + ->assertSuccessful() + ->expectsOutput("0 Audio created, $deletedAudioCount Audio deleted, 0 Audio updated"); +}); - /** - * If audios are updated, the Reconcile Audio Command shall output '0 Audio created, 0 Audio deleted, {Updated Count} Audio updated'. - */ - public function testUpdated(): void - { - $updatedAudioCount = $this->faker->numberBetween(2, 9); +test('updated', function () { + $updatedAudioCount = fake()->numberBetween(2, 9); - $basenames = collect($this->faker->words($updatedAudioCount)); + $basenames = collect(fake()->words($updatedAudioCount)); - Audio::factory() - ->count($updatedAudioCount) - ->sequence(fn ($sequence) => [Audio::ATTRIBUTE_BASENAME => $basenames->get($sequence->index)]) - ->create(); + Audio::factory() + ->count($updatedAudioCount) + ->sequence(fn ($sequence) => [Audio::ATTRIBUTE_BASENAME => $basenames->get($sequence->index)]) + ->create(); - $sourceAudios = Audio::factory() - ->count($updatedAudioCount) - ->sequence(fn ($sequence) => [Audio::ATTRIBUTE_BASENAME => $basenames->get($sequence->index)]) - ->create(); + $sourceAudios = Audio::factory() + ->count($updatedAudioCount) + ->sequence(fn ($sequence) => [Audio::ATTRIBUTE_BASENAME => $basenames->get($sequence->index)]) + ->create(); - $this->mock(AudioRepository::class, function (MockInterface $mock) use ($sourceAudios) { - $mock->shouldReceive('get')->once()->andReturn($sourceAudios); - }); + $this->mock(AudioRepository::class, function (MockInterface $mock) use ($sourceAudios) { + $mock->shouldReceive('get')->once()->andReturn($sourceAudios); + }); - $this->artisan(AudioReconcileCommand::class) - ->assertSuccessful() - ->expectsOutput("0 Audio created, 0 Audio deleted, $updatedAudioCount Audio updated"); - } -} + $this->artisan(AudioReconcileCommand::class) + ->assertSuccessful() + ->expectsOutput("0 Audio created, 0 Audio deleted, $updatedAudioCount Audio updated"); +}); diff --git a/tests/Feature/Console/Commands/Repositories/Storage/Wiki/Video/ScriptReconcileTest.php b/tests/Feature/Console/Commands/Repositories/Storage/Wiki/Video/ScriptReconcileTest.php index 993f7852c..ec71cdf12 100644 --- a/tests/Feature/Console/Commands/Repositories/Storage/Wiki/Video/ScriptReconcileTest.php +++ b/tests/Feature/Console/Commands/Repositories/Storage/Wiki/Video/ScriptReconcileTest.php @@ -2,76 +2,57 @@ declare(strict_types=1); -namespace Tests\Feature\Console\Commands\Repositories\Storage\Wiki\Video; - use App\Console\Commands\Repositories\Storage\Wiki\Video\ScriptReconcileCommand; use App\Constants\Config\VideoConstants; use App\Models\Wiki\Video\VideoScript; use App\Repositories\Storage\Wiki\Video\ScriptRepository; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Storage; use Mockery\MockInterface; -use Tests\TestCase; -class ScriptReconcileTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * If no changes are needed, the Reconcile Script Command shall output 'No Video Scripts created or deleted or updated'. - */ - public function testNoResults(): void - { - Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); +test('no results', function () { + Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); - $this->mock(ScriptRepository::class, function (MockInterface $mock) { - $mock->shouldReceive('get')->once()->andReturn(Collection::make()); - }); + $this->mock(ScriptRepository::class, function (MockInterface $mock) { + $mock->shouldReceive('get')->once()->andReturn(Collection::make()); + }); - $this->artisan(ScriptReconcileCommand::class) - ->assertSuccessful() - ->expectsOutput('No Video Scripts created or deleted or updated'); - } + $this->artisan(ScriptReconcileCommand::class) + ->assertSuccessful() + ->expectsOutput('No Video Scripts created or deleted or updated'); +}); - /** - * If scripts are created, the Reconcile Script Command shall output '{Created Count} Video Scripts created, 0 Video Scripts deleted, 0 Video Scripts updated'. - */ - public function testCreated(): void - { - Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); +test('created', function () { + Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); - $createdScriptCount = $this->faker->numberBetween(2, 9); + $createdScriptCount = fake()->numberBetween(2, 9); - $scripts = VideoScript::factory()->count($createdScriptCount)->make(); + $scripts = VideoScript::factory()->count($createdScriptCount)->make(); - $this->mock(ScriptRepository::class, function (MockInterface $mock) use ($scripts) { - $mock->shouldReceive('get')->once()->andReturn($scripts); - }); + $this->mock(ScriptRepository::class, function (MockInterface $mock) use ($scripts) { + $mock->shouldReceive('get')->once()->andReturn($scripts); + }); - $this->artisan(ScriptReconcileCommand::class) - ->assertSuccessful() - ->expectsOutput("$createdScriptCount Video Scripts created, 0 Video Scripts deleted, 0 Video Scripts updated"); - } + $this->artisan(ScriptReconcileCommand::class) + ->assertSuccessful() + ->expectsOutput("$createdScriptCount Video Scripts created, 0 Video Scripts deleted, 0 Video Scripts updated"); +}); - /** - * If scripts are deleted, the Reconcile Script Command shall output '0 Video Scripts created, {Deleted Count} Video Scripts deleted, 0 Video Scripts updated'. - */ - public function testDeleted(): void - { - Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); +test('deleted', function () { + Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); - $deletedScriptCount = $this->faker->numberBetween(2, 9); + $deletedScriptCount = fake()->numberBetween(2, 9); - VideoScript::factory()->count($deletedScriptCount)->create(); + VideoScript::factory()->count($deletedScriptCount)->create(); - $this->mock(ScriptRepository::class, function (MockInterface $mock) { - $mock->shouldReceive('get')->once()->andReturn(Collection::make()); - }); + $this->mock(ScriptRepository::class, function (MockInterface $mock) { + $mock->shouldReceive('get')->once()->andReturn(Collection::make()); + }); - $this->artisan(ScriptReconcileCommand::class) - ->assertSuccessful() - ->expectsOutput("0 Video Scripts created, $deletedScriptCount Video Scripts deleted, 0 Video Scripts updated"); - } -} + $this->artisan(ScriptReconcileCommand::class) + ->assertSuccessful() + ->expectsOutput("0 Video Scripts created, $deletedScriptCount Video Scripts deleted, 0 Video Scripts updated"); +}); diff --git a/tests/Feature/Console/Commands/Repositories/Storage/Wiki/VideoReconcileTest.php b/tests/Feature/Console/Commands/Repositories/Storage/Wiki/VideoReconcileTest.php index 0720e386f..5dcb79a1b 100644 --- a/tests/Feature/Console/Commands/Repositories/Storage/Wiki/VideoReconcileTest.php +++ b/tests/Feature/Console/Commands/Repositories/Storage/Wiki/VideoReconcileTest.php @@ -2,106 +2,83 @@ declare(strict_types=1); -namespace Tests\Feature\Console\Commands\Repositories\Storage\Wiki; - use App\Console\Commands\Repositories\Storage\Wiki\VideoReconcileCommand; use App\Constants\Config\VideoConstants; use App\Models\Wiki\Video; use App\Repositories\Storage\Wiki\VideoRepository; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Storage; use Mockery\MockInterface; -use Tests\TestCase; -class VideoReconcileTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * If no changes are needed, the Reconcile Video Command shall output 'No Videos created or deleted or updated'. - */ - public function testNoResults(): void - { - Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); +test('no results', function () { + Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); - $this->mock(VideoRepository::class, function (MockInterface $mock) { - $mock->shouldReceive('get')->once()->andReturn(Collection::make()); - }); + $this->mock(VideoRepository::class, function (MockInterface $mock) { + $mock->shouldReceive('get')->once()->andReturn(Collection::make()); + }); - $this->artisan(VideoReconcileCommand::class) - ->assertSuccessful() - ->expectsOutput('No Videos created or deleted or updated'); - } + $this->artisan(VideoReconcileCommand::class) + ->assertSuccessful() + ->expectsOutput('No Videos created or deleted or updated'); +}); - /** - * If videos are created, the Reconcile Video Command shall output '{Created Count} Videos created, 0 Videos deleted, 0 Videos updated'. - */ - public function testCreated(): void - { - Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); +test('created', function () { + Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); - $createdVideoCount = $this->faker->numberBetween(2, 9); + $createdVideoCount = fake()->numberBetween(2, 9); - $videos = Video::factory()->count($createdVideoCount)->make(); + $videos = Video::factory()->count($createdVideoCount)->make(); - $this->mock(VideoRepository::class, function (MockInterface $mock) use ($videos) { - $mock->shouldReceive('get')->once()->andReturn($videos); - }); + $this->mock(VideoRepository::class, function (MockInterface $mock) use ($videos) { + $mock->shouldReceive('get')->once()->andReturn($videos); + }); - $this->artisan(VideoReconcileCommand::class) - ->assertSuccessful() - ->expectsOutput("$createdVideoCount Videos created, 0 Videos deleted, 0 Videos updated"); - } + $this->artisan(VideoReconcileCommand::class) + ->assertSuccessful() + ->expectsOutput("$createdVideoCount Videos created, 0 Videos deleted, 0 Videos updated"); +}); - /** - * If videos are deleted, the Reconcile Video Command shall output '0 Videos created, {Deleted Count} Videos deleted, 0 Videos updated'. - */ - public function testDeleted(): void - { - Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); +test('deleted', function () { + Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); - $deletedVideoCount = $this->faker->numberBetween(2, 9); + $deletedVideoCount = fake()->numberBetween(2, 9); - Video::factory()->count($deletedVideoCount)->create(); + Video::factory()->count($deletedVideoCount)->create(); - $this->mock(VideoRepository::class, function (MockInterface $mock) { - $mock->shouldReceive('get')->once()->andReturn(Collection::make()); - }); + $this->mock(VideoRepository::class, function (MockInterface $mock) { + $mock->shouldReceive('get')->once()->andReturn(Collection::make()); + }); - $this->artisan(VideoReconcileCommand::class) - ->assertSuccessful() - ->expectsOutput("0 Videos created, $deletedVideoCount Videos deleted, 0 Videos updated"); - } + $this->artisan(VideoReconcileCommand::class) + ->assertSuccessful() + ->expectsOutput("0 Videos created, $deletedVideoCount Videos deleted, 0 Videos updated"); +}); - /** - * If videos are updated, the Reconcile Video Command shall output '0 Videos created, 0 Videos deleted, {Updated Count} Videos updated'. - */ - public function testUpdated(): void - { - Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); +test('updated', function () { + Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); - $updatedVideoCount = $this->faker->numberBetween(2, 9); + $updatedVideoCount = fake()->numberBetween(2, 9); - $basenames = collect($this->faker->words($updatedVideoCount)); + $basenames = collect(fake()->words($updatedVideoCount)); - Video::factory() - ->count($updatedVideoCount) - ->sequence(fn ($sequence) => [Video::ATTRIBUTE_BASENAME => $basenames->get($sequence->index)]) - ->create(); + Video::factory() + ->count($updatedVideoCount) + ->sequence(fn ($sequence) => [Video::ATTRIBUTE_BASENAME => $basenames->get($sequence->index)]) + ->create(); - $sourceVideos = Video::factory() - ->count($updatedVideoCount) - ->sequence(fn ($sequence) => [Video::ATTRIBUTE_BASENAME => $basenames->get($sequence->index)]) - ->create(); + $sourceVideos = Video::factory() + ->count($updatedVideoCount) + ->sequence(fn ($sequence) => [Video::ATTRIBUTE_BASENAME => $basenames->get($sequence->index)]) + ->create(); - $this->mock(VideoRepository::class, function (MockInterface $mock) use ($sourceVideos) { - $mock->shouldReceive('get')->once()->andReturn($sourceVideos); - }); + $this->mock(VideoRepository::class, function (MockInterface $mock) use ($sourceVideos) { + $mock->shouldReceive('get')->once()->andReturn($sourceVideos); + }); - $this->artisan(VideoReconcileCommand::class) - ->assertSuccessful() - ->expectsOutput("0 Videos created, 0 Videos deleted, $updatedVideoCount Videos updated"); - } -} + $this->artisan(VideoReconcileCommand::class) + ->assertSuccessful() + ->expectsOutput("0 Videos created, 0 Videos deleted, $updatedVideoCount Videos updated"); +}); diff --git a/tests/Feature/Console/Commands/Storage/Admin/DocumentDumpTest.php b/tests/Feature/Console/Commands/Storage/Admin/DocumentDumpTest.php index 3d7fd9355..6a4a464b4 100644 --- a/tests/Feature/Console/Commands/Storage/Admin/DocumentDumpTest.php +++ b/tests/Feature/Console/Commands/Storage/Admin/DocumentDumpTest.php @@ -2,48 +2,33 @@ declare(strict_types=1); -namespace Tests\Feature\Console\Commands\Storage\Admin; - use App\Console\Commands\Storage\Admin\DocumentDumpCommand; use App\Constants\Config\DumpConstants; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Date; use Illuminate\Support\Facades\Storage; -use Tests\TestCase; -class DocumentDumpTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Database Dump Command shall output "Database dump '{dumpFile}' has been created". - */ - public function testDataBaseDumpOutput(): void - { - Storage::fake('local'); - Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); +test('database dump output', function () { + Storage::fake('local'); + Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); - Date::setTestNow($this->faker->iso8601()); + Date::setTestNow(fake()->iso8601()); - $this->artisan(DocumentDumpCommand::class) - ->assertSuccessful() - ->expectsOutputToContain('has been created'); - } + $this->artisan(DocumentDumpCommand::class) + ->assertSuccessful() + ->expectsOutputToContain('has been created'); +}); - /** - * The Database Dump Command shall produce a file in the /path/to/project/storage/db-dumps directory. - */ - public function testDataBaseDumpFile(): void - { - $local = Storage::fake('local'); - $fs = Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); +test('database dump file', function () { + $local = Storage::fake('local'); + $fs = Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); - Date::setTestNow($this->faker->iso8601()); + Date::setTestNow(fake()->iso8601()); - $this->artisan(DocumentDumpCommand::class)->run(); + $this->artisan(DocumentDumpCommand::class)->run(); - static::assertEmpty($local->allFiles()); - static::assertCount(1, $fs->allFiles()); - } -} + $this->assertEmpty($local->allFiles()); + $this->assertCount(1, $fs->allFiles()); +}); diff --git a/tests/Feature/Console/Commands/Storage/Admin/DumpPruneTest.php b/tests/Feature/Console/Commands/Storage/Admin/DumpPruneTest.php index c41fb0622..18cc3eb28 100644 --- a/tests/Feature/Console/Commands/Storage/Admin/DumpPruneTest.php +++ b/tests/Feature/Console/Commands/Storage/Admin/DumpPruneTest.php @@ -2,55 +2,40 @@ declare(strict_types=1); -namespace Tests\Feature\Console\Commands\Storage\Admin; - use App\Actions\Storage\Admin\Dump\DumpWikiAction; use App\Console\Commands\Storage\Admin\DumpPruneCommand; use App\Constants\Config\DumpConstants; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Date; use Illuminate\Support\Facades\Storage; -use Tests\TestCase; -class DumpPruneTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * If no changes are needed, the Prune Database Dumps Command shall output 'No database dumps deleted'. - */ - public function testNoResults(): void - { - Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); +test('no results', function () { + Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); - $this->artisan(DumpPruneCommand::class, ['--hours' => 0]) - ->assertFailed() - ->expectsOutput('No prunings were attempted.'); - } + $this->artisan(DumpPruneCommand::class, ['--hours' => 0]) + ->assertFailed() + ->expectsOutput('No prunings were attempted.'); +}); - /** - * If dumps are deleted, the Prune Database Dumps Command shall output '{Deleted Count} database dumps deleted'. - */ - public function testDeleted(): void - { - Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); +test('deleted', function () { + Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); - $prunedCount = $this->faker->randomDigitNotNull(); + $prunedCount = fake()->randomDigitNotNull(); - Collection::times($prunedCount, function () { - Date::setTestNow($this->faker->iso8601()); + Collection::times($prunedCount, function () { + Date::setTestNow(fake()->iso8601()); - $action = new DumpWikiAction(); + $action = new DumpWikiAction(); - $action->handle(); - }); + $action->handle(); + }); - Date::setTestNow(); + Date::setTestNow(); - $this->artisan(DumpPruneCommand::class, ['--hours' => -1]) - ->assertSuccessful() - ->expectsOutputToContain('Pruned'); - } -} + $this->artisan(DumpPruneCommand::class, ['--hours' => -1]) + ->assertSuccessful() + ->expectsOutputToContain('Pruned'); +}); diff --git a/tests/Feature/Console/Commands/Storage/Admin/WikiDumpTest.php b/tests/Feature/Console/Commands/Storage/Admin/WikiDumpTest.php index 6e7546752..d090afea7 100644 --- a/tests/Feature/Console/Commands/Storage/Admin/WikiDumpTest.php +++ b/tests/Feature/Console/Commands/Storage/Admin/WikiDumpTest.php @@ -2,47 +2,32 @@ declare(strict_types=1); -namespace Tests\Feature\Console\Commands\Storage\Admin; - use App\Console\Commands\Storage\Admin\WikiDumpCommand; use App\Constants\Config\DumpConstants; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Date; use Illuminate\Support\Facades\Storage; -use Tests\TestCase; -class WikiDumpTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Database Dump Command shall output "Database dump '{dumpFile}' has been created". - */ - public function testDataBaseDumpOutput(): void - { - Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); +test('database dump output', function () { + Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); - Date::setTestNow($this->faker->iso8601()); + Date::setTestNow(fake()->iso8601()); - $this->artisan(WikiDumpCommand::class) - ->assertSuccessful() - ->expectsOutputToContain('has been created'); - } + $this->artisan(WikiDumpCommand::class) + ->assertSuccessful() + ->expectsOutputToContain('has been created'); +}); - /** - * The Database Dump Command shall produce a file in the /path/to/project/storage/db-dumps directory. - */ - public function testDataBaseDumpFile(): void - { - $local = Storage::fake('local'); - $fs = Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); +test('database dump file', function () { + $local = Storage::fake('local'); + $fs = Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); - Date::setTestNow($this->faker->iso8601()); + Date::setTestNow(fake()->iso8601()); - $this->artisan(WikiDumpCommand::class)->run(); + $this->artisan(WikiDumpCommand::class)->run(); - static::assertEmpty($local->allFiles()); - static::assertCount(1, $fs->allFiles()); - } -} + $this->assertEmpty($local->allFiles()); + $this->assertCount(1, $fs->allFiles()); +}); diff --git a/tests/Feature/Events/Admin/AnnouncementTest.php b/tests/Feature/Events/Admin/AnnouncementTest.php index 1dc89ecfe..4ccdf988c 100644 --- a/tests/Feature/Events/Admin/AnnouncementTest.php +++ b/tests/Feature/Events/Admin/AnnouncementTest.php @@ -2,69 +2,47 @@ declare(strict_types=1); -namespace Tests\Feature\Events\Admin; - use App\Events\Admin\Announcement\AnnouncementCreated; use App\Events\Admin\Announcement\AnnouncementDeleted; use App\Events\Admin\Announcement\AnnouncementUpdated; use App\Models\Admin\Announcement; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class AnnouncementTest extends TestCase -{ - /** - * When an Announcement is created, an AnnouncementCreated event shall be dispatched. - */ - public function testAnnouncementCreatedEventDispatched(): void - { - Announcement::factory()->create(); +test('announcement created event dispatched', function () { + Announcement::factory()->create(); - Event::assertDispatched(AnnouncementCreated::class); - } + Event::assertDispatched(AnnouncementCreated::class); +}); - /** - * When an Announcement is deleted, an AnnouncementDeleted event shall be dispatched. - */ - public function testAnnouncementDeletedEventDispatched(): void - { - $announcement = Announcement::factory()->create(); +test('announcement deleted event dispatched', function () { + $announcement = Announcement::factory()->create(); - $announcement->delete(); + $announcement->delete(); - Event::assertDispatched(AnnouncementDeleted::class); - } + Event::assertDispatched(AnnouncementDeleted::class); +}); - /** - * When an Announcement is updated, an AnnouncementUpdated event shall be dispatched. - */ - public function testAnnouncementUpdatedEventDispatched(): void - { - $announcement = Announcement::factory()->createOne(); - $changes = Announcement::factory()->makeOne(); +test('announcement updated event dispatched', function () { + $announcement = Announcement::factory()->createOne(); + $changes = Announcement::factory()->makeOne(); - $announcement->fill($changes->getAttributes()); - $announcement->save(); + $announcement->fill($changes->getAttributes()); + $announcement->save(); - Event::assertDispatched(AnnouncementUpdated::class); - } + Event::assertDispatched(AnnouncementUpdated::class); +}); - /** - * The AnnouncementUpdated event shall contain embed fields. - */ - public function testAnnouncementUpdatedEventEmbedFields(): void - { - $announcement = Announcement::factory()->createOne(); - $changes = Announcement::factory()->makeOne(); +test('announcement updated event embed fields', function () { + $announcement = Announcement::factory()->createOne(); + $changes = Announcement::factory()->makeOne(); - $announcement->fill($changes->getAttributes()); - $announcement->save(); + $announcement->fill($changes->getAttributes()); + $announcement->save(); - Event::assertDispatched(AnnouncementUpdated::class, function (AnnouncementUpdated $event) { - $message = $event->getDiscordMessage(); + Event::assertDispatched(AnnouncementUpdated::class, function (AnnouncementUpdated $event) { + $message = $event->getDiscordMessage(); - return ! empty(Arr::get($message->embed, 'fields')); - }); - } -} + return ! empty(Arr::get($message->embed, 'fields')); + }); +}); diff --git a/tests/Feature/Events/Admin/DumpTest.php b/tests/Feature/Events/Admin/DumpTest.php index 4bef6e263..3595411fa 100644 --- a/tests/Feature/Events/Admin/DumpTest.php +++ b/tests/Feature/Events/Admin/DumpTest.php @@ -2,69 +2,47 @@ declare(strict_types=1); -namespace Tests\Feature\Events\Admin; - use App\Events\Admin\Dump\DumpCreated; use App\Events\Admin\Dump\DumpDeleted; use App\Events\Admin\Dump\DumpUpdated; use App\Models\Admin\Dump; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class DumpTest extends TestCase -{ - /** - * When a Dump is created, a DumpCreated event shall be dispatched. - */ - public function testDumpCreatedEventDispatched(): void - { - Dump::factory()->create(); +test('dump created event dispatched', function () { + Dump::factory()->create(); - Event::assertDispatched(DumpCreated::class); - } + Event::assertDispatched(DumpCreated::class); +}); - /** - * When a Dump is deleted, a DumpDeleted event shall be dispatched. - */ - public function testDumpDeletedEventDispatched(): void - { - $dump = Dump::factory()->create(); +test('dump deleted event dispatched', function () { + $dump = Dump::factory()->create(); - $dump->delete(); + $dump->delete(); - Event::assertDispatched(DumpDeleted::class); - } + Event::assertDispatched(DumpDeleted::class); +}); - /** - * When a Dump is updated, a DumpUpdated event shall be dispatched. - */ - public function testDumpUpdatedEventDispatched(): void - { - $dump = Dump::factory()->createOne(); - $changes = Dump::factory()->makeOne(); +test('dump updated event dispatched', function () { + $dump = Dump::factory()->createOne(); + $changes = Dump::factory()->makeOne(); - $dump->fill($changes->getAttributes()); - $dump->save(); + $dump->fill($changes->getAttributes()); + $dump->save(); - Event::assertDispatched(DumpUpdated::class); - } + Event::assertDispatched(DumpUpdated::class); +}); - /** - * The DumpUpdated event shall contain embed fields. - */ - public function testDumpUpdatedEventEmbedFields(): void - { - $dump = Dump::factory()->createOne(); - $changes = Dump::factory()->makeOne(); +test('dump updated event embed fields', function () { + $dump = Dump::factory()->createOne(); + $changes = Dump::factory()->makeOne(); - $dump->fill($changes->getAttributes()); - $dump->save(); + $dump->fill($changes->getAttributes()); + $dump->save(); - Event::assertDispatched(DumpUpdated::class, function (DumpUpdated $event) { - $message = $event->getDiscordMessage(); + Event::assertDispatched(DumpUpdated::class, function (DumpUpdated $event) { + $message = $event->getDiscordMessage(); - return ! empty(Arr::get($message->embed, 'fields')); - }); - } -} + return ! empty(Arr::get($message->embed, 'fields')); + }); +}); diff --git a/tests/Feature/Events/Admin/FeatureTest.php b/tests/Feature/Events/Admin/FeatureTest.php index 93ed1d98c..780699aa5 100644 --- a/tests/Feature/Events/Admin/FeatureTest.php +++ b/tests/Feature/Events/Admin/FeatureTest.php @@ -2,69 +2,47 @@ declare(strict_types=1); -namespace Tests\Feature\Events\Admin; - use App\Events\Admin\Feature\FeatureCreated; use App\Events\Admin\Feature\FeatureDeleted; use App\Events\Admin\Feature\FeatureUpdated; use App\Models\Admin\Feature; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class FeatureTest extends TestCase -{ - /** - * When a Feature is created, a FeatureCreated event shall be dispatched. - */ - public function testFeatureCreatedEventDispatched(): void - { - Feature::factory()->create(); +test('feature created event dispatched', function () { + Feature::factory()->create(); - Event::assertDispatched(FeatureCreated::class); - } + Event::assertDispatched(FeatureCreated::class); +}); - /** - * When a Feature is deleted, a FeatureDeleted event shall be dispatched. - */ - public function testFeatureDeletedEventDispatched(): void - { - $feature = Feature::factory()->create(); +test('feature deleted event dispatched', function () { + $feature = Feature::factory()->create(); - $feature->delete(); + $feature->delete(); - Event::assertDispatched(FeatureDeleted::class); - } + Event::assertDispatched(FeatureDeleted::class); +}); - /** - * When a Feature is updated, a FeatureUpdated event shall be dispatched. - */ - public function testFeatureUpdatedEventDispatched(): void - { - $feature = Feature::factory()->createOne(); +test('feature updated event dispatched', function () { + $feature = Feature::factory()->createOne(); - $feature->update([ - Feature::ATTRIBUTE_VALUE => ! $feature->value, - ]); + $feature->update([ + Feature::ATTRIBUTE_VALUE => ! $feature->value, + ]); - Event::assertDispatched(FeatureUpdated::class); - } + Event::assertDispatched(FeatureUpdated::class); +}); - /** - * The FeatureUpdated event shall contain embed fields. - */ - public function testFeatureUpdatedEventEmbedFields(): void - { - $feature = Feature::factory()->createOne(); +test('feature updated event embed fields', function () { + $feature = Feature::factory()->createOne(); - $feature->update([ - Feature::ATTRIBUTE_VALUE => ! $feature->value, - ]); + $feature->update([ + Feature::ATTRIBUTE_VALUE => ! $feature->value, + ]); - Event::assertDispatched(FeatureUpdated::class, function (FeatureUpdated $event) { - $message = $event->getDiscordMessage(); + Event::assertDispatched(FeatureUpdated::class, function (FeatureUpdated $event) { + $message = $event->getDiscordMessage(); - return ! empty(Arr::get($message->embed, 'fields')); - }); - } -} + return ! empty(Arr::get($message->embed, 'fields')); + }); +}); diff --git a/tests/Feature/Events/Admin/FeaturedThemeTest.php b/tests/Feature/Events/Admin/FeaturedThemeTest.php index 4cbf7a60a..726a700b3 100644 --- a/tests/Feature/Events/Admin/FeaturedThemeTest.php +++ b/tests/Feature/Events/Admin/FeaturedThemeTest.php @@ -2,69 +2,47 @@ declare(strict_types=1); -namespace Tests\Feature\Events\Admin; - use App\Events\Admin\FeaturedTheme\FeaturedThemeCreated; use App\Events\Admin\FeaturedTheme\FeaturedThemeDeleted; use App\Events\Admin\FeaturedTheme\FeaturedThemeUpdated; use App\Models\Admin\FeaturedTheme; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class FeaturedThemeTest extends TestCase -{ - /** - * When a Featured Theme is created, a FeaturedThemeCreated event shall be dispatched. - */ - public function testFeaturedThemeCreatedEventDispatched(): void - { - FeaturedTheme::factory()->create(); +test('featured theme created event dispatched', function () { + FeaturedTheme::factory()->create(); - Event::assertDispatched(FeaturedThemeCreated::class); - } + Event::assertDispatched(FeaturedThemeCreated::class); +}); - /** - * When a Featured Theme is deleted, a FeaturedThemeDeleted event shall be dispatched. - */ - public function testFeaturedThemeDeletedEventDispatched(): void - { - $featuredTheme = FeaturedTheme::factory()->create(); +test('featured theme deleted event dispatched', function () { + $featuredTheme = FeaturedTheme::factory()->create(); - $featuredTheme->delete(); + $featuredTheme->delete(); - Event::assertDispatched(FeaturedThemeDeleted::class); - } + Event::assertDispatched(FeaturedThemeDeleted::class); +}); - /** - * When a Featured Theme is updated, a FeaturedThemeUpdated event shall be dispatched. - */ - public function testFeaturedThemeUpdatedEventDispatched(): void - { - $featuredTheme = FeaturedTheme::factory()->createOne(); - $changes = FeaturedTheme::factory()->makeOne(); +test('featured theme updated event dispatched', function () { + $featuredTheme = FeaturedTheme::factory()->createOne(); + $changes = FeaturedTheme::factory()->makeOne(); - $featuredTheme->fill($changes->getAttributes()); - $featuredTheme->save(); + $featuredTheme->fill($changes->getAttributes()); + $featuredTheme->save(); - Event::assertDispatched(FeaturedThemeUpdated::class); - } + Event::assertDispatched(FeaturedThemeUpdated::class); +}); - /** - * The FeaturedThemeUpdated event shall contain embed fields. - */ - public function testFeaturedThemeUpdatedEventEmbedFields(): void - { - $featuredTheme = FeaturedTheme::factory()->createOne(); - $changes = FeaturedTheme::factory()->makeOne(); +test('featured theme updated event embed fields', function () { + $featuredTheme = FeaturedTheme::factory()->createOne(); + $changes = FeaturedTheme::factory()->makeOne(); - $featuredTheme->fill($changes->getAttributes()); - $featuredTheme->save(); + $featuredTheme->fill($changes->getAttributes()); + $featuredTheme->save(); - Event::assertDispatched(FeaturedThemeUpdated::class, function (FeaturedThemeUpdated $event) { - $message = $event->getDiscordMessage(); + Event::assertDispatched(FeaturedThemeUpdated::class, function (FeaturedThemeUpdated $event) { + $message = $event->getDiscordMessage(); - return ! empty(Arr::get($message->embed, 'fields')); - }); - } -} + return ! empty(Arr::get($message->embed, 'fields')); + }); +}); diff --git a/tests/Feature/Events/Auth/UserTest.php b/tests/Feature/Events/Auth/UserTest.php index b3dd2bb34..cf0bb3b66 100644 --- a/tests/Feature/Events/Auth/UserTest.php +++ b/tests/Feature/Events/Auth/UserTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Events\Auth; - use App\Events\Auth\User\UserCreated; use App\Events\Auth\User\UserDeleted; use App\Events\Auth\User\UserRestored; @@ -11,87 +9,57 @@ use App\Events\Auth\User\UserUpdated; use App\Models\Auth\User; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class UserTest extends TestCase -{ - /** - * When a User is created, a UserCreated event shall be dispatched. - */ - public function testUserCreatedEventDispatched(): void - { - User::factory()->createOne(); +test('user created event dispatched', function () { + User::factory()->createOne(); - Event::assertDispatched(UserCreated::class); - } + Event::assertDispatched(UserCreated::class); +}); - /** - * When a User is deleted, a UserDeleted event shall be dispatched. - */ - public function testUserDeletedEventDispatched(): void - { - $user = User::factory()->createOne(); +test('user deleted event dispatched', function () { + $user = User::factory()->createOne(); - $user->delete(); + $user->delete(); - Event::assertDispatched(UserDeleted::class); - } + Event::assertDispatched(UserDeleted::class); +}); - /** - * When a User is restored, a UserRestored event shall be dispatched. - */ - public function testUserRestoredEventDispatched(): void - { - $user = User::factory()->createOne(); +test('user restored event dispatched', function () { + $user = User::factory()->createOne(); - $user->restore(); + $user->restore(); - Event::assertDispatched(UserRestored::class); - } + Event::assertDispatched(UserRestored::class); +}); - /** - * When a User is restored, a UserUpdated event shall not be dispatched. - * Note: This is a customization that overrides default framework behavior. - * An updated event is fired on restore. - */ - public function testUserRestoresQuietly(): void - { - $user = User::factory()->createOne(); +test('user restores quietly', function () { + $user = User::factory()->createOne(); - $user->restore(); + $user->restore(); - Event::assertNotDispatched(UserUpdated::class); - } + Event::assertNotDispatched(UserUpdated::class); +}); - /** - * When a User is updated, a UserUpdated event shall be dispatched. - */ - public function testUserUpdatedEventDispatched(): void - { - $user = User::factory()->createOne(); - $changes = User::factory()->makeOne(); +test('user updated event dispatched', function () { + $user = User::factory()->createOne(); + $changes = User::factory()->makeOne(); - $user->fill($changes->getAttributes()); - $user->save(); + $user->fill($changes->getAttributes()); + $user->save(); - Event::assertDispatched(UserUpdated::class); - } + Event::assertDispatched(UserUpdated::class); +}); - /** - * The UserUpdated event shall contain embed fields. - */ - public function testUserUpdatedEventEmbedFields(): void - { - $user = User::factory()->createOne(); - $changes = User::factory()->makeOne(); +test('user updated event embed fields', function () { + $user = User::factory()->createOne(); + $changes = User::factory()->makeOne(); - $user->fill($changes->getAttributes()); - $user->save(); + $user->fill($changes->getAttributes()); + $user->save(); - Event::assertDispatched(UserUpdated::class, function (UserUpdated $event) { - $message = $event->getDiscordMessage(); + Event::assertDispatched(UserUpdated::class, function (UserUpdated $event) { + $message = $event->getDiscordMessage(); - return ! empty(Arr::get($message->embed, 'fields')); - }); - } -} + return ! empty(Arr::get($message->embed, 'fields')); + }); +}); diff --git a/tests/Feature/Events/Document/PageTest.php b/tests/Feature/Events/Document/PageTest.php index b2d188df7..cd415b7a3 100644 --- a/tests/Feature/Events/Document/PageTest.php +++ b/tests/Feature/Events/Document/PageTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Events\Document; - use App\Events\Document\Page\PageCreated; use App\Events\Document\Page\PageDeleted; use App\Events\Document\Page\PageRestored; @@ -11,87 +9,57 @@ use App\Events\Document\Page\PageUpdated; use App\Models\Document\Page; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class PageTest extends TestCase -{ - /** - * When a Page is created, an PageCreated event shall be dispatched. - */ - public function testPageCreatedEventDispatched(): void - { - Page::factory()->createOne(); +test('page created event dispatched', function () { + Page::factory()->createOne(); - Event::assertDispatched(PageCreated::class); - } + Event::assertDispatched(PageCreated::class); +}); - /** - * When a Page is deleted, an PageDeleted event shall be dispatched. - */ - public function testPageDeletedEventDispatched(): void - { - $page = Page::factory()->createOne(); +test('page deleted event dispatched', function () { + $page = Page::factory()->createOne(); - $page->delete(); + $page->delete(); - Event::assertDispatched(PageDeleted::class); - } + Event::assertDispatched(PageDeleted::class); +}); - /** - * When a Page is restored, an PageRestored event shall be dispatched. - */ - public function testPageRestoredEventDispatched(): void - { - $page = Page::factory()->createOne(); +test('page restored event dispatched', function () { + $page = Page::factory()->createOne(); - $page->restore(); + $page->restore(); - Event::assertDispatched(PageRestored::class); - } + Event::assertDispatched(PageRestored::class); +}); - /** - * When a Page is restored, a PageUpdated event shall not be dispatched. - * Note: This is a customization that overrides default framework behavior. - * An updated event is fired on restore. - */ - public function testPageRestoresQuietly(): void - { - $page = Page::factory()->createOne(); +test('page restores quietly', function () { + $page = Page::factory()->createOne(); - $page->restore(); + $page->restore(); - Event::assertNotDispatched(PageUpdated::class); - } + Event::assertNotDispatched(PageUpdated::class); +}); - /** - * When a Page is updated, an PageUpdated event shall be dispatched. - */ - public function testPageUpdatedEventDispatched(): void - { - $page = Page::factory()->createOne(); - $changes = Page::factory()->makeOne(); +test('page updated event dispatched', function () { + $page = Page::factory()->createOne(); + $changes = Page::factory()->makeOne(); - $page->fill($changes->getAttributes()); - $page->save(); + $page->fill($changes->getAttributes()); + $page->save(); - Event::assertDispatched(PageUpdated::class); - } + Event::assertDispatched(PageUpdated::class); +}); - /** - * The PageUpdated event shall contain embed fields. - */ - public function testPageUpdatedEventEmbedFields(): void - { - $page = Page::factory()->createOne(); - $changes = Page::factory()->makeOne(); +test('page updated event embed fields', function () { + $page = Page::factory()->createOne(); + $changes = Page::factory()->makeOne(); - $page->fill($changes->getAttributes()); - $page->save(); + $page->fill($changes->getAttributes()); + $page->save(); - Event::assertDispatched(PageUpdated::class, function (PageUpdated $event) { - $message = $event->getDiscordMessage(); + Event::assertDispatched(PageUpdated::class, function (PageUpdated $event) { + $message = $event->getDiscordMessage(); - return ! empty(Arr::get($message->embed, 'fields')); - }); - } -} + return ! empty(Arr::get($message->embed, 'fields')); + }); +}); diff --git a/tests/Feature/Events/List/ExternalProfileTest.php b/tests/Feature/Events/List/ExternalProfileTest.php index dcf8b0251..d41df6b48 100644 --- a/tests/Feature/Events/List/ExternalProfileTest.php +++ b/tests/Feature/Events/List/ExternalProfileTest.php @@ -2,69 +2,47 @@ declare(strict_types=1); -namespace Tests\Feature\Events\List; - use App\Events\List\ExternalProfile\ExternalProfileCreated; use App\Events\List\ExternalProfile\ExternalProfileDeleted; use App\Events\List\ExternalProfile\ExternalProfileUpdated; use App\Models\List\ExternalProfile; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class ExternalProfileTest extends TestCase -{ - /** - * When a profile is created, a ExternalProfileCreated event shall be dispatched. - */ - public function testExternalProfileCreatedEventDispatched(): void - { - ExternalProfile::factory()->createOne(); +test('external profile created event dispatched', function () { + ExternalProfile::factory()->createOne(); - Event::assertDispatched(ExternalProfileCreated::class); - } + Event::assertDispatched(ExternalProfileCreated::class); +}); - /** - * When a profile is deleted, a ExternalProfileDeleted event shall be dispatched. - */ - public function testExternalProfileDeletedEventDispatched(): void - { - $profile = ExternalProfile::factory()->createOne(); +test('external profile deleted event dispatched', function () { + $profile = ExternalProfile::factory()->createOne(); - $profile->delete(); + $profile->delete(); - Event::assertDispatched(ExternalProfileDeleted::class); - } + Event::assertDispatched(ExternalProfileDeleted::class); +}); - /** - * When a profile is updated, a ExternalProfileUpdated event shall be dispatched. - */ - public function testExternalProfileUpdatedEventDispatched(): void - { - $profile = ExternalProfile::factory()->createOne(); - $changes = ExternalProfile::factory()->makeOne(); +test('external profile updated event dispatched', function () { + $profile = ExternalProfile::factory()->createOne(); + $changes = ExternalProfile::factory()->makeOne(); - $profile->fill($changes->getAttributes()); - $profile->save(); + $profile->fill($changes->getAttributes()); + $profile->save(); - Event::assertDispatched(ExternalProfileUpdated::class); - } + Event::assertDispatched(ExternalProfileUpdated::class); +}); - /** - * The ExternalProfileUpdated event shall contain embed fields. - */ - public function testExternalProfileUpdatedEventEmbedFields(): void - { - $profile = ExternalProfile::factory()->createOne(); - $changes = ExternalProfile::factory()->makeOne(); +test('external profile updated event embed fields', function () { + $profile = ExternalProfile::factory()->createOne(); + $changes = ExternalProfile::factory()->makeOne(); - $profile->fill($changes->getAttributes()); - $profile->save(); + $profile->fill($changes->getAttributes()); + $profile->save(); - Event::assertDispatched(ExternalProfileUpdated::class, function (ExternalProfileUpdated $event) { - $message = $event->getDiscordMessage(); + Event::assertDispatched(ExternalProfileUpdated::class, function (ExternalProfileUpdated $event) { + $message = $event->getDiscordMessage(); - return ! empty(Arr::get($message->embed, 'fields')); - }); - } -} + return ! empty(Arr::get($message->embed, 'fields')); + }); +}); diff --git a/tests/Feature/Events/List/Playlist/TrackTest.php b/tests/Feature/Events/List/Playlist/TrackTest.php index d5848824d..a2f92f86f 100644 --- a/tests/Feature/Events/List/Playlist/TrackTest.php +++ b/tests/Feature/Events/List/Playlist/TrackTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Events\List\Playlist; - use App\Contracts\Models\HasHashids; use App\Events\List\Playlist\Track\TrackCreated; use App\Events\List\Playlist\Track\TrackDeleted; @@ -12,89 +10,65 @@ use App\Models\List\Playlist; use App\Models\List\Playlist\PlaylistTrack; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class TrackTest extends TestCase -{ - /** - * When a Playlist Track is created, a TrackCreated event shall be dispatched. - */ - public function testTrackCreatedEventDispatched(): void - { - PlaylistTrack::factory() - ->for(Playlist::factory()) - ->createOne(); +test('track created event dispatched', function () { + PlaylistTrack::factory() + ->for(Playlist::factory()) + ->createOne(); - Event::assertDispatched(TrackCreated::class); - } + Event::assertDispatched(TrackCreated::class); +}); - /** - * When a Playlist Track is deleted, a TrackDeleted event shall be dispatched. - */ - public function testTrackDeletedEventDispatched(): void - { - $track = PlaylistTrack::factory() - ->for(Playlist::factory()) - ->createOne(); +test('track deleted event dispatched', function () { + $track = PlaylistTrack::factory() + ->for(Playlist::factory()) + ->createOne(); - $track->delete(); + $track->delete(); - Event::assertDispatched(TrackDeleted::class); - } + Event::assertDispatched(TrackDeleted::class); +}); - /** - * When a Track is updated, a TrackUpdated event shall be dispatched. - */ - public function testTrackUpdatedEventDispatched(): void - { - $track = PlaylistTrack::factory() - ->for(Playlist::factory()) - ->createOne(); +test('track updated event dispatched', function () { + $track = PlaylistTrack::factory() + ->for(Playlist::factory()) + ->createOne(); - $changes = PlaylistTrack::factory() - ->for(Playlist::factory()) - ->makeOne(); + $changes = PlaylistTrack::factory() + ->for(Playlist::factory()) + ->makeOne(); - $track->fill($changes->getAttributes()); - $track->save(); + $track->fill($changes->getAttributes()); + $track->save(); - Event::assertDispatched(TrackUpdated::class); - } + Event::assertDispatched(TrackUpdated::class); +}); - /** - * The TrackUpdated event shall contain embed fields. - */ - public function testPlaylistUpdatedEventEmbedFields(): void - { - $track = PlaylistTrack::factory() - ->for(Playlist::factory()) - ->createOne(); +test('playlist updated event embed fields', function () { + $track = PlaylistTrack::factory() + ->for(Playlist::factory()) + ->createOne(); - $changes = PlaylistTrack::factory() - ->for(Playlist::factory()) - ->makeOne(); + $changes = PlaylistTrack::factory() + ->for(Playlist::factory()) + ->makeOne(); - $track->fill($changes->getAttributes()); - $track->save(); + $track->fill($changes->getAttributes()); + $track->save(); - Event::assertDispatched(TrackUpdated::class, function (TrackUpdated $event) { - $message = $event->getDiscordMessage(); + Event::assertDispatched(TrackUpdated::class, function (TrackUpdated $event) { + $message = $event->getDiscordMessage(); - return ! empty(Arr::get($message->embed, 'fields')); - }); - } + return ! empty(Arr::get($message->embed, 'fields')); + }); +}); - /** - * The Track Created event shall assign hashids to the track. - */ - public function testPlaylistCreatedAssignsHashids(): void - { - Event::fakeExcept(TrackCreated::class); +test('playlist created assigns hashids', function () { + Event::fakeExcept(TrackCreated::class); - PlaylistTrack::factory() - ->for(Playlist::factory()) - ->createOne(); + PlaylistTrack::factory() + ->for(Playlist::factory()) + ->createOne(); - static::assertDatabaseMissing(PlaylistTrack::class, [HasHashids::ATTRIBUTE_HASHID => null]); - } -} + $this->assertDatabaseMissing(PlaylistTrack::class, [HasHashids::ATTRIBUTE_HASHID => null]); +}); diff --git a/tests/Feature/Events/List/PlaylistTest.php b/tests/Feature/Events/List/PlaylistTest.php index e3dc3db24..4aa15aab2 100644 --- a/tests/Feature/Events/List/PlaylistTest.php +++ b/tests/Feature/Events/List/PlaylistTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Events\List; - use App\Contracts\Models\HasHashids; use App\Events\List\Playlist\PlaylistCreated; use App\Events\List\Playlist\PlaylistDeleted; @@ -12,87 +10,59 @@ use App\Models\Auth\User; use App\Models\List\Playlist; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class PlaylistTest extends TestCase -{ - /** - * When a Playlist is created, a PlaylistCreated event shall be dispatched. - */ - public function testPlaylistCreatedEventDispatched(): void - { - Playlist::factory()->createOne(); +test('playlist created event dispatched', function () { + Playlist::factory()->createOne(); - Event::assertDispatched(PlaylistCreated::class); - } + Event::assertDispatched(PlaylistCreated::class); +}); - /** - * When a Playlist is deleted, a PlaylistDeleted event shall be dispatched. - */ - public function testPlaylistDeletedEventDispatched(): void - { - $playlist = Playlist::factory()->createOne(); +test('playlist deleted event dispatched', function () { + $playlist = Playlist::factory()->createOne(); - $playlist->delete(); + $playlist->delete(); - Event::assertDispatched(PlaylistDeleted::class); - } + Event::assertDispatched(PlaylistDeleted::class); +}); - /** - * When a Playlist is updated, a PlaylistUpdated event shall be dispatched. - */ - public function testPlaylistUpdatedEventDispatched(): void - { - $playlist = Playlist::factory()->createOne(); - $changes = Playlist::factory()->makeOne(); +test('playlist updated event dispatched', function () { + $playlist = Playlist::factory()->createOne(); + $changes = Playlist::factory()->makeOne(); - $playlist->fill($changes->getAttributes()); - $playlist->save(); + $playlist->fill($changes->getAttributes()); + $playlist->save(); - Event::assertDispatched(PlaylistUpdated::class); - } + Event::assertDispatched(PlaylistUpdated::class); +}); - /** - * The PlaylistUpdated event shall contain embed fields. - */ - public function testPlaylistUpdatedEventEmbedFields(): void - { - $playlist = Playlist::factory()->createOne(); - $changes = Playlist::factory()->makeOne(); +test('playlist updated event embed fields', function () { + $playlist = Playlist::factory()->createOne(); + $changes = Playlist::factory()->makeOne(); - $playlist->fill($changes->getAttributes()); - $playlist->save(); + $playlist->fill($changes->getAttributes()); + $playlist->save(); - Event::assertDispatched(PlaylistUpdated::class, function (PlaylistUpdated $event) { - $message = $event->getDiscordMessage(); + Event::assertDispatched(PlaylistUpdated::class, function (PlaylistUpdated $event) { + $message = $event->getDiscordMessage(); - return ! empty(Arr::get($message->embed, 'fields')); - }); - } + return ! empty(Arr::get($message->embed, 'fields')); + }); +}); - /** - * The Playlist Created event shall assign hashids to the playlist without an owner. - */ - public function testPlaylistCreatedAssignsNullableUserHashids(): void - { - Event::fakeExcept(PlaylistCreated::class); +test('playlist created assigns nullable user hashids', function () { + Event::fakeExcept(PlaylistCreated::class); - Playlist::factory()->createOne(); + Playlist::factory()->createOne(); - static::assertDatabaseMissing(Playlist::class, [HasHashids::ATTRIBUTE_HASHID => null]); - } + $this->assertDatabaseMissing(Playlist::class, [HasHashids::ATTRIBUTE_HASHID => null]); +}); - /** - * The Playlist Created event shall assign hashids to the playlist with an owner. - */ - public function testPlaylistCreatedAssignsNonNullUserHashids(): void - { - Event::fakeExcept(PlaylistCreated::class); +test('playlist created assigns non null user hashids', function () { + Event::fakeExcept(PlaylistCreated::class); - Playlist::factory() - ->for(User::factory()) - ->createOne(); + Playlist::factory() + ->for(User::factory()) + ->createOne(); - static::assertDatabaseMissing(Playlist::class, [HasHashids::ATTRIBUTE_HASHID => null]); - } -} + $this->assertDatabaseMissing(Playlist::class, [HasHashids::ATTRIBUTE_HASHID => null]); +}); diff --git a/tests/Feature/Events/Pivot/List/PlaylistImageTest.php b/tests/Feature/Events/Pivot/List/PlaylistImageTest.php index 7b1dc0ff2..fda2e0290 100644 --- a/tests/Feature/Events/Pivot/List/PlaylistImageTest.php +++ b/tests/Feature/Events/Pivot/List/PlaylistImageTest.php @@ -2,41 +2,27 @@ declare(strict_types=1); -namespace Tests\Feature\Events\Pivot\List; - use App\Events\Pivot\List\PlaylistImage\PlaylistImageCreated; use App\Events\Pivot\List\PlaylistImage\PlaylistImageDeleted; use App\Models\List\Playlist; use App\Models\Wiki\Image; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class PlaylistImageTest extends TestCase -{ - /** - * When a Playlist is attached to an Image or vice versa, a PlaylistImageCreated event shall be dispatched. - */ - public function testPlaylistImageCreatedEventDispatched(): void - { - $playlist = Playlist::factory()->createOne(); - $image = Image::factory()->createOne(); +test('playlist image created event dispatched', function () { + $playlist = Playlist::factory()->createOne(); + $image = Image::factory()->createOne(); - $playlist->images()->attach($image); + $playlist->images()->attach($image); - Event::assertDispatched(PlaylistImageCreated::class); - } + Event::assertDispatched(PlaylistImageCreated::class); +}); - /** - * When a Playlist is detached from an Image or vice versa, a PlaylistImageDeleted event shall be dispatched. - */ - public function testPlaylistImageDeletedEventDispatched(): void - { - $playlist = Playlist::factory()->createOne(); - $image = Image::factory()->createOne(); +test('playlist image deleted event dispatched', function () { + $playlist = Playlist::factory()->createOne(); + $image = Image::factory()->createOne(); - $playlist->images()->attach($image); - $playlist->images()->detach($image); + $playlist->images()->attach($image); + $playlist->images()->detach($image); - Event::assertDispatched(PlaylistImageDeleted::class); - } -} + Event::assertDispatched(PlaylistImageDeleted::class); +}); diff --git a/tests/Feature/Events/Pivot/Wiki/AnimeImageTest.php b/tests/Feature/Events/Pivot/Wiki/AnimeImageTest.php index d9d80dc71..43055469d 100644 --- a/tests/Feature/Events/Pivot/Wiki/AnimeImageTest.php +++ b/tests/Feature/Events/Pivot/Wiki/AnimeImageTest.php @@ -2,41 +2,27 @@ declare(strict_types=1); -namespace Tests\Feature\Events\Pivot\Wiki; - use App\Events\Pivot\Wiki\AnimeImage\AnimeImageCreated; use App\Events\Pivot\Wiki\AnimeImage\AnimeImageDeleted; use App\Models\Wiki\Anime; use App\Models\Wiki\Image; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class AnimeImageTest extends TestCase -{ - /** - * When an Anime is attached to an Image or vice versa, an AnimeImageCreated event shall be dispatched. - */ - public function testAnimeImageCreatedEventDispatched(): void - { - $anime = Anime::factory()->createOne(); - $image = Image::factory()->createOne(); +test('anime image created event dispatched', function () { + $anime = Anime::factory()->createOne(); + $image = Image::factory()->createOne(); - $anime->images()->attach($image); + $anime->images()->attach($image); - Event::assertDispatched(AnimeImageCreated::class); - } + Event::assertDispatched(AnimeImageCreated::class); +}); - /** - * When an Anime is detached from an Image or vice versa, an AnimeImageDeleted event shall be dispatched. - */ - public function testAnimeImageDeletedEventDispatched(): void - { - $anime = Anime::factory()->createOne(); - $image = Image::factory()->createOne(); +test('anime image deleted event dispatched', function () { + $anime = Anime::factory()->createOne(); + $image = Image::factory()->createOne(); - $anime->images()->attach($image); - $anime->images()->detach($image); + $anime->images()->attach($image); + $anime->images()->detach($image); - Event::assertDispatched(AnimeImageDeleted::class); - } -} + Event::assertDispatched(AnimeImageDeleted::class); +}); diff --git a/tests/Feature/Events/Pivot/Wiki/AnimeResourceTest.php b/tests/Feature/Events/Pivot/Wiki/AnimeResourceTest.php index a25714d59..d555f5f4a 100644 --- a/tests/Feature/Events/Pivot/Wiki/AnimeResourceTest.php +++ b/tests/Feature/Events/Pivot/Wiki/AnimeResourceTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Events\Pivot\Wiki; - use App\Events\Pivot\Wiki\AnimeResource\AnimeResourceCreated; use App\Events\Pivot\Wiki\AnimeResource\AnimeResourceDeleted; use App\Events\Pivot\Wiki\AnimeResource\AnimeResourceUpdated; @@ -12,86 +10,66 @@ use App\Models\Wiki\ExternalResource; use App\Pivots\Wiki\AnimeResource; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class AnimeResourceTest extends TestCase -{ - /** - * When an Anime is attached to a Resource or vice versa, an AnimeResourceCreated event shall be dispatched. - */ - public function testAnimeResourceCreatedEventDispatched(): void - { - $anime = Anime::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); +test('anime resource created event dispatched', function () { + $anime = Anime::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - $anime->resources()->attach($resource); + $anime->resources()->attach($resource); - Event::assertDispatched(AnimeResourceCreated::class); - } + Event::assertDispatched(AnimeResourceCreated::class); +}); - /** - * When an Anime is detached from a Resource or vice versa, an AnimeResourceDeleted event shall be dispatched. - */ - public function testAnimeResourceDeletedEventDispatched(): void - { - $anime = Anime::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); +test('anime resource deleted event dispatched', function () { + $anime = Anime::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - $anime->resources()->attach($resource); - $anime->resources()->detach($resource); + $anime->resources()->attach($resource); + $anime->resources()->detach($resource); - Event::assertDispatched(AnimeResourceDeleted::class); - } + Event::assertDispatched(AnimeResourceDeleted::class); +}); - /** - * When an Anime Resource pivot is updated, an AnimeResourceUpdated event shall be dispatched. - */ - public function testAnimeResourceUpdatedEventDispatched(): void - { - $anime = Anime::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); +test('anime resource updated event dispatched', function () { + $anime = Anime::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - $animeResource = AnimeResource::factory() - ->for($anime, 'anime') - ->for($resource, 'resource') - ->createOne(); + $animeResource = AnimeResource::factory() + ->for($anime, 'anime') + ->for($resource, 'resource') + ->createOne(); - $changes = AnimeResource::factory() - ->for($anime, 'anime') - ->for($resource, 'resource') - ->makeOne(); + $changes = AnimeResource::factory() + ->for($anime, 'anime') + ->for($resource, 'resource') + ->makeOne(); - $animeResource->fill($changes->getAttributes()); - $animeResource->save(); + $animeResource->fill($changes->getAttributes()); + $animeResource->save(); - Event::assertDispatched(AnimeResourceUpdated::class); - } + Event::assertDispatched(AnimeResourceUpdated::class); +}); - /** - * The AnimeResourceUpdated event shall contain embed fields. - */ - public function testAnimeResourceUpdatedEventEmbedFields(): void - { - $anime = Anime::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); +test('anime resource updated event embed fields', function () { + $anime = Anime::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - $animeResource = AnimeResource::factory() - ->for($anime, 'anime') - ->for($resource, 'resource') - ->createOne(); + $animeResource = AnimeResource::factory() + ->for($anime, 'anime') + ->for($resource, 'resource') + ->createOne(); - $changes = AnimeResource::factory() - ->for($anime, 'anime') - ->for($resource, 'resource') - ->makeOne(); + $changes = AnimeResource::factory() + ->for($anime, 'anime') + ->for($resource, 'resource') + ->makeOne(); - $animeResource->fill($changes->getAttributes()); - $animeResource->save(); + $animeResource->fill($changes->getAttributes()); + $animeResource->save(); - Event::assertDispatched(AnimeResourceUpdated::class, function (AnimeResourceUpdated $event) { - $message = $event->getDiscordMessage(); + Event::assertDispatched(AnimeResourceUpdated::class, function (AnimeResourceUpdated $event) { + $message = $event->getDiscordMessage(); - return ! empty(Arr::get($message->embed, 'fields')); - }); - } -} + return ! empty(Arr::get($message->embed, 'fields')); + }); +}); diff --git a/tests/Feature/Events/Pivot/Wiki/AnimeSeriesTest.php b/tests/Feature/Events/Pivot/Wiki/AnimeSeriesTest.php index cc5c37c72..6847db271 100644 --- a/tests/Feature/Events/Pivot/Wiki/AnimeSeriesTest.php +++ b/tests/Feature/Events/Pivot/Wiki/AnimeSeriesTest.php @@ -2,41 +2,27 @@ declare(strict_types=1); -namespace Tests\Feature\Events\Pivot\Wiki; - use App\Events\Pivot\Wiki\AnimeSeries\AnimeSeriesCreated; use App\Events\Pivot\Wiki\AnimeSeries\AnimeSeriesDeleted; use App\Models\Wiki\Anime; use App\Models\Wiki\Series; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class AnimeSeriesTest extends TestCase -{ - /** - * When an Anime is attached to a Series or vice versa, an AnimeSeriesCreated event shall be dispatched. - */ - public function testAnimeSeriesCreatedEventDispatched(): void - { - $anime = Anime::factory()->createOne(); - $series = Series::factory()->createOne(); +test('anime series created event dispatched', function () { + $anime = Anime::factory()->createOne(); + $series = Series::factory()->createOne(); - $anime->series()->attach($series); + $anime->series()->attach($series); - Event::assertDispatched(AnimeSeriesCreated::class); - } + Event::assertDispatched(AnimeSeriesCreated::class); +}); - /** - * When an Anime is detached from a Series or vice versa, an AnimeSeriesDeleted event shall be dispatched. - */ - public function testAnimeSeriesDeletedEventDispatched(): void - { - $anime = Anime::factory()->createOne(); - $series = Series::factory()->createOne(); +test('anime series deleted event dispatched', function () { + $anime = Anime::factory()->createOne(); + $series = Series::factory()->createOne(); - $anime->series()->attach($series); - $anime->series()->detach($series); + $anime->series()->attach($series); + $anime->series()->detach($series); - Event::assertDispatched(AnimeSeriesDeleted::class); - } -} + Event::assertDispatched(AnimeSeriesDeleted::class); +}); diff --git a/tests/Feature/Events/Pivot/Wiki/AnimeStudioTest.php b/tests/Feature/Events/Pivot/Wiki/AnimeStudioTest.php index baaceee6f..4a291475d 100644 --- a/tests/Feature/Events/Pivot/Wiki/AnimeStudioTest.php +++ b/tests/Feature/Events/Pivot/Wiki/AnimeStudioTest.php @@ -2,41 +2,27 @@ declare(strict_types=1); -namespace Tests\Feature\Events\Pivot\Wiki; - use App\Events\Pivot\Wiki\AnimeStudio\AnimeStudioCreated; use App\Events\Pivot\Wiki\AnimeStudio\AnimeStudioDeleted; use App\Models\Wiki\Anime; use App\Models\Wiki\Studio; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class AnimeStudioTest extends TestCase -{ - /** - * When an Anime is attached to a Studio or vice versa, an AnimeStudioCreated event shall be dispatched. - */ - public function testAnimeStudioCreatedEventDispatched(): void - { - $anime = Anime::factory()->createOne(); - $studio = Studio::factory()->createOne(); +test('anime studio created event dispatched', function () { + $anime = Anime::factory()->createOne(); + $studio = Studio::factory()->createOne(); - $anime->studios()->attach($studio); + $anime->studios()->attach($studio); - Event::assertDispatched(AnimeStudioCreated::class); - } + Event::assertDispatched(AnimeStudioCreated::class); +}); - /** - * When an Anime is detached from a Studio or vice versa, an AnimeStudioDeleted event shall be dispatched. - */ - public function testAnimeStudioDeletedEventDispatched(): void - { - $anime = Anime::factory()->createOne(); - $studio = Studio::factory()->createOne(); +test('anime studio deleted event dispatched', function () { + $anime = Anime::factory()->createOne(); + $studio = Studio::factory()->createOne(); - $anime->studios()->attach($studio); - $anime->studios()->detach($studio); + $anime->studios()->attach($studio); + $anime->studios()->detach($studio); - Event::assertDispatched(AnimeStudioDeleted::class); - } -} + Event::assertDispatched(AnimeStudioDeleted::class); +}); diff --git a/tests/Feature/Events/Pivot/Wiki/AnimeThemeEntryVideoTest.php b/tests/Feature/Events/Pivot/Wiki/AnimeThemeEntryVideoTest.php index 0ed12b1e9..219465326 100644 --- a/tests/Feature/Events/Pivot/Wiki/AnimeThemeEntryVideoTest.php +++ b/tests/Feature/Events/Pivot/Wiki/AnimeThemeEntryVideoTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Events\Pivot\Wiki; - use App\Events\Pivot\Wiki\AnimeThemeEntryVideo\AnimeThemeEntryVideoCreated; use App\Events\Pivot\Wiki\AnimeThemeEntryVideo\AnimeThemeEntryVideoDeleted; use App\Models\List\Playlist; @@ -13,95 +11,75 @@ use App\Models\Wiki\Anime\AnimeTheme; use App\Models\Wiki\Anime\Theme\AnimeThemeEntry; use App\Models\Wiki\Video; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class AnimeThemeEntryVideoTest extends TestCase -{ - /** - * When a Video is attached to an AnimeThemeEntry or vice versa, an AnimeThemeEntryVideoTest event shall be dispatched. - */ - public function testAnimeThemeEntryVideoCreatedEventDispatched(): void - { - $video = Video::factory()->createOne(); - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); +test('anime theme entry video created event dispatched', function () { + $video = Video::factory()->createOne(); + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - $video->animethemeentries()->attach($entry); + $video->animethemeentries()->attach($entry); - Event::assertDispatched(AnimeThemeEntryVideoCreated::class); - } + Event::assertDispatched(AnimeThemeEntryVideoCreated::class); +}); - /** - * When a Video is detached from an AnimeThemeEntry or vice versa, an AnimeThemeEntryVideoDeleted event shall be dispatched. - */ - public function testAnimeThemeEntryVideoDeletedEventDispatched(): void - { - $video = Video::factory()->createOne(); - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); +test('anime theme entry video deleted event dispatched', function () { + $video = Video::factory()->createOne(); + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - $video->animethemeentries()->attach($entry); - $video->animethemeentries()->detach($entry); + $video->animethemeentries()->attach($entry); + $video->animethemeentries()->detach($entry); - Event::assertDispatched(AnimeThemeEntryVideoDeleted::class); - } + Event::assertDispatched(AnimeThemeEntryVideoDeleted::class); +}); - /** - * When a Video is attached to an AnimeThemeEntry, the playlist tracks should be updated. - */ - public function testAnimeThemeEntryVideoCreatedEventUpdatePlaylistTracks(): void - { - $video = Video::factory()->createOne(); - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); +test('anime theme entry video created event update playlist tracks', function () { + $video = Video::factory()->createOne(); + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - $video->animethemeentries()->attach($entry); + $video->animethemeentries()->attach($entry); - $track = PlaylistTrack::factory() - ->for(Playlist::factory()) - ->for($video) - ->createOne(); + $track = PlaylistTrack::factory() + ->for(Playlist::factory()) + ->for($video) + ->createOne(); - Event::assertDispatched(AnimeThemeEntryVideoCreated::class, function (AnimeThemeEntryVideoCreated $event) use ($entry, $track) { - $event->updatePlaylistTracks(); + Event::assertDispatched(AnimeThemeEntryVideoCreated::class, function (AnimeThemeEntryVideoCreated $event) use ($entry, $track) { + $event->updatePlaylistTracks(); - return $track->refresh()->animethemeentry()->is($entry); - }); - } + return $track->refresh()->animethemeentry()->is($entry); + }); +}); - /** - * When a Video is detached from an AnimeThemeEntry, the playlist tracks should be updated. - */ - public function testAnimeThemeEntryVideoDeletedEventUpdatePlaylistTracks(): void - { - $video = Video::factory()->createOne(); +test('anime theme entry video deleted event update playlist tracks', function () { + $video = Video::factory()->createOne(); - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - $secondEntry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); + $secondEntry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - $video->animethemeentries()->attach($entry); + $video->animethemeentries()->attach($entry); - $track = PlaylistTrack::factory() - ->for(Playlist::factory()) - ->for($video) - ->for($entry) - ->createOne(); + $track = PlaylistTrack::factory() + ->for(Playlist::factory()) + ->for($video) + ->for($entry) + ->createOne(); - $video->animethemeentries()->attach($secondEntry); - $video->animethemeentries()->detach($entry); + $video->animethemeentries()->attach($secondEntry); + $video->animethemeentries()->detach($entry); - Event::assertDispatched(AnimeThemeEntryVideoDeleted::class, function (AnimeThemeEntryVideoDeleted $event) use ($secondEntry, $track) { - $event->updatePlaylistTracks(); + Event::assertDispatched(AnimeThemeEntryVideoDeleted::class, function (AnimeThemeEntryVideoDeleted $event) use ($secondEntry, $track) { + $event->updatePlaylistTracks(); - return $track->refresh()->animethemeentry()->is($secondEntry); - }); - } -} + return $track->refresh()->animethemeentry()->is($secondEntry); + }); +}); diff --git a/tests/Feature/Events/Pivot/Wiki/ArtistImageTest.php b/tests/Feature/Events/Pivot/Wiki/ArtistImageTest.php index 3e8a4ba17..ac48865c8 100644 --- a/tests/Feature/Events/Pivot/Wiki/ArtistImageTest.php +++ b/tests/Feature/Events/Pivot/Wiki/ArtistImageTest.php @@ -2,41 +2,27 @@ declare(strict_types=1); -namespace Tests\Feature\Events\Pivot\Wiki; - use App\Events\Pivot\Wiki\ArtistImage\ArtistImageCreated; use App\Events\Pivot\Wiki\ArtistImage\ArtistImageDeleted; use App\Models\Wiki\Artist; use App\Models\Wiki\Image; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class ArtistImageTest extends TestCase -{ - /** - * When an Artist is attached to an Image or vice versa, an ArtistImageCreated event shall be dispatched. - */ - public function testArtistImageCreatedEventDispatched(): void - { - $artist = Artist::factory()->createOne(); - $image = Image::factory()->createOne(); +test('artist image created event dispatched', function () { + $artist = Artist::factory()->createOne(); + $image = Image::factory()->createOne(); - $artist->images()->attach($image); + $artist->images()->attach($image); - Event::assertDispatched(ArtistImageCreated::class); - } + Event::assertDispatched(ArtistImageCreated::class); +}); - /** - * When an Artist is detached from an Image or vice versa, an ArtistImageDeleted event shall be dispatched. - */ - public function testArtistImageDeletedEventDispatched(): void - { - $artist = Artist::factory()->createOne(); - $image = Image::factory()->createOne(); +test('artist image deleted event dispatched', function () { + $artist = Artist::factory()->createOne(); + $image = Image::factory()->createOne(); - $artist->images()->attach($image); - $artist->images()->detach($image); + $artist->images()->attach($image); + $artist->images()->detach($image); - Event::assertDispatched(ArtistImageDeleted::class); - } -} + Event::assertDispatched(ArtistImageDeleted::class); +}); diff --git a/tests/Feature/Events/Pivot/Wiki/ArtistMemberTest.php b/tests/Feature/Events/Pivot/Wiki/ArtistMemberTest.php index 6484eb5fd..a2d79586a 100644 --- a/tests/Feature/Events/Pivot/Wiki/ArtistMemberTest.php +++ b/tests/Feature/Events/Pivot/Wiki/ArtistMemberTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Events\Pivot\Wiki; - use App\Events\Pivot\Wiki\ArtistMember\ArtistMemberCreated; use App\Events\Pivot\Wiki\ArtistMember\ArtistMemberDeleted; use App\Events\Pivot\Wiki\ArtistMember\ArtistMemberUpdated; @@ -11,86 +9,66 @@ use App\Models\Wiki\Artist; use App\Pivots\Wiki\ArtistMember; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class ArtistMemberTest extends TestCase -{ - /** - * When an Artist is attached to a Member or vice versa, an ArtistMemberCreated event shall be dispatched. - */ - public function testArtistMemberCreatedEventDispatched(): void - { - $artist = Artist::factory()->createOne(); - $member = Artist::factory()->createOne(); +test('artist member created event dispatched', function () { + $artist = Artist::factory()->createOne(); + $member = Artist::factory()->createOne(); - $artist->members()->attach($member); + $artist->members()->attach($member); - Event::assertDispatched(ArtistMemberCreated::class); - } + Event::assertDispatched(ArtistMemberCreated::class); +}); - /** - * When an Artist is detached from a Member or vice versa, an ArtistMemberDeleted event shall be dispatched. - */ - public function testArtistMemberDeletedEventDispatched(): void - { - $artist = Artist::factory()->createOne(); - $member = Artist::factory()->createOne(); +test('artist member deleted event dispatched', function () { + $artist = Artist::factory()->createOne(); + $member = Artist::factory()->createOne(); - $artist->members()->attach($member); - $artist->members()->detach($member); + $artist->members()->attach($member); + $artist->members()->detach($member); - Event::assertDispatched(ArtistMemberDeleted::class); - } + Event::assertDispatched(ArtistMemberDeleted::class); +}); - /** - * When an Artist Member pivot is updated, an ArtistMemberUpdated event shall be dispatched. - */ - public function testArtistMemberUpdatedEventDispatched(): void - { - $artist = Artist::factory()->createOne(); - $member = Artist::factory()->createOne(); +test('artist member updated event dispatched', function () { + $artist = Artist::factory()->createOne(); + $member = Artist::factory()->createOne(); - $artistMember = ArtistMember::factory() - ->for($artist, 'artist') - ->for($member, 'member') - ->createOne(); + $artistMember = ArtistMember::factory() + ->for($artist, 'artist') + ->for($member, 'member') + ->createOne(); - $changes = ArtistMember::factory() - ->for($artist, 'artist') - ->for($member, 'member') - ->makeOne(); + $changes = ArtistMember::factory() + ->for($artist, 'artist') + ->for($member, 'member') + ->makeOne(); - $artistMember->fill($changes->getAttributes()); - $artistMember->save(); + $artistMember->fill($changes->getAttributes()); + $artistMember->save(); - Event::assertDispatched(ArtistMemberUpdated::class); - } + Event::assertDispatched(ArtistMemberUpdated::class); +}); - /** - * The ArtistMemberUpdated event shall contain embed fields. - */ - public function testArtistMemberUpdatedEventEmbedFields(): void - { - $artist = Artist::factory()->createOne(); - $member = Artist::factory()->createOne(); +test('artist member updated event embed fields', function () { + $artist = Artist::factory()->createOne(); + $member = Artist::factory()->createOne(); - $artistMember = ArtistMember::factory() - ->for($artist, 'artist') - ->for($member, 'member') - ->createOne(); + $artistMember = ArtistMember::factory() + ->for($artist, 'artist') + ->for($member, 'member') + ->createOne(); - $changes = ArtistMember::factory() - ->for($artist, 'artist') - ->for($member, 'member') - ->makeOne(); + $changes = ArtistMember::factory() + ->for($artist, 'artist') + ->for($member, 'member') + ->makeOne(); - $artistMember->fill($changes->getAttributes()); - $artistMember->save(); + $artistMember->fill($changes->getAttributes()); + $artistMember->save(); - Event::assertDispatched(ArtistMemberUpdated::class, function (ArtistMemberUpdated $event) { - $message = $event->getDiscordMessage(); + Event::assertDispatched(ArtistMemberUpdated::class, function (ArtistMemberUpdated $event) { + $message = $event->getDiscordMessage(); - return ! empty(Arr::get($message->embed, 'fields')); - }); - } -} + return ! empty(Arr::get($message->embed, 'fields')); + }); +}); diff --git a/tests/Feature/Events/Pivot/Wiki/ArtistResourceTest.php b/tests/Feature/Events/Pivot/Wiki/ArtistResourceTest.php index b28fee684..aae38658a 100644 --- a/tests/Feature/Events/Pivot/Wiki/ArtistResourceTest.php +++ b/tests/Feature/Events/Pivot/Wiki/ArtistResourceTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Events\Pivot\Wiki; - use App\Events\Pivot\Wiki\ArtistResource\ArtistResourceCreated; use App\Events\Pivot\Wiki\ArtistResource\ArtistResourceDeleted; use App\Events\Pivot\Wiki\ArtistResource\ArtistResourceUpdated; @@ -12,86 +10,66 @@ use App\Models\Wiki\ExternalResource; use App\Pivots\Wiki\ArtistResource; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class ArtistResourceTest extends TestCase -{ - /** - * When an Artist is attached to a Resource or vice versa, an ArtistResourceCreated event shall be dispatched. - */ - public function testArtistResourceCreatedEventDispatched(): void - { - $artist = Artist::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); +test('artist resource created event dispatched', function () { + $artist = Artist::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - $artist->resources()->attach($resource); + $artist->resources()->attach($resource); - Event::assertDispatched(ArtistResourceCreated::class); - } + Event::assertDispatched(ArtistResourceCreated::class); +}); - /** - * When an Artist is detached from a Resource or vice versa, an ArtistResourceDeleted event shall be dispatched. - */ - public function testArtistResourceDeletedEventDispatched(): void - { - $artist = Artist::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); +test('artist resource deleted event dispatched', function () { + $artist = Artist::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - $artist->resources()->attach($resource); - $artist->resources()->detach($resource); + $artist->resources()->attach($resource); + $artist->resources()->detach($resource); - Event::assertDispatched(ArtistResourceDeleted::class); - } + Event::assertDispatched(ArtistResourceDeleted::class); +}); - /** - * When an Artist Resource pivot is updated, an ArtistResourceUpdated event shall be dispatched. - */ - public function testArtistResourceUpdatedEventDispatched(): void - { - $artist = Artist::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); +test('artist resource updated event dispatched', function () { + $artist = Artist::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - $artistResource = ArtistResource::factory() - ->for($artist, 'artist') - ->for($resource, 'resource') - ->createOne(); + $artistResource = ArtistResource::factory() + ->for($artist, 'artist') + ->for($resource, 'resource') + ->createOne(); - $changes = ArtistResource::factory() - ->for($artist, 'artist') - ->for($resource, 'resource') - ->makeOne(); + $changes = ArtistResource::factory() + ->for($artist, 'artist') + ->for($resource, 'resource') + ->makeOne(); - $artistResource->fill($changes->getAttributes()); - $artistResource->save(); + $artistResource->fill($changes->getAttributes()); + $artistResource->save(); - Event::assertDispatched(ArtistResourceUpdated::class); - } + Event::assertDispatched(ArtistResourceUpdated::class); +}); - /** - * The ArtistResourceUpdated event shall contain embed fields. - */ - public function testArtistResourceUpdatedEventEmbedFields(): void - { - $artist = Artist::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); +test('artist resource updated event embed fields', function () { + $artist = Artist::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - $artistResource = ArtistResource::factory() - ->for($artist, 'artist') - ->for($resource, 'resource') - ->createOne(); + $artistResource = ArtistResource::factory() + ->for($artist, 'artist') + ->for($resource, 'resource') + ->createOne(); - $changes = ArtistResource::factory() - ->for($artist, 'artist') - ->for($resource, 'resource') - ->makeOne(); + $changes = ArtistResource::factory() + ->for($artist, 'artist') + ->for($resource, 'resource') + ->makeOne(); - $artistResource->fill($changes->getAttributes()); - $artistResource->save(); + $artistResource->fill($changes->getAttributes()); + $artistResource->save(); - Event::assertDispatched(ArtistResourceUpdated::class, function (ArtistResourceUpdated $event) { - $message = $event->getDiscordMessage(); + Event::assertDispatched(ArtistResourceUpdated::class, function (ArtistResourceUpdated $event) { + $message = $event->getDiscordMessage(); - return ! empty(Arr::get($message->embed, 'fields')); - }); - } -} + return ! empty(Arr::get($message->embed, 'fields')); + }); +}); diff --git a/tests/Feature/Events/Pivot/Wiki/ArtistSongTest.php b/tests/Feature/Events/Pivot/Wiki/ArtistSongTest.php index 207835ae4..41fbd9920 100644 --- a/tests/Feature/Events/Pivot/Wiki/ArtistSongTest.php +++ b/tests/Feature/Events/Pivot/Wiki/ArtistSongTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Events\Pivot\Wiki; - use App\Events\Pivot\Wiki\ArtistSong\ArtistSongCreated; use App\Events\Pivot\Wiki\ArtistSong\ArtistSongDeleted; use App\Events\Pivot\Wiki\ArtistSong\ArtistSongUpdated; @@ -12,86 +10,66 @@ use App\Models\Wiki\Song; use App\Pivots\Wiki\ArtistSong; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class ArtistSongTest extends TestCase -{ - /** - * When an Artist is attached to a Song or vice versa, an ArtistSongCreated event shall be dispatched. - */ - public function testArtistSongCreatedEventDispatched(): void - { - $artist = Artist::factory()->createOne(); - $song = Song::factory()->createOne(); +test('artist song created event dispatched', function () { + $artist = Artist::factory()->createOne(); + $song = Song::factory()->createOne(); - $artist->songs()->attach($song); + $artist->songs()->attach($song); - Event::assertDispatched(ArtistSongCreated::class); - } + Event::assertDispatched(ArtistSongCreated::class); +}); - /** - * When an Artist is detached from a Song or vice versa, an ArtistSongDeleted event shall be dispatched. - */ - public function testArtistSongDeletedEventDispatched(): void - { - $artist = Artist::factory()->createOne(); - $song = Song::factory()->createOne(); +test('artist song deleted event dispatched', function () { + $artist = Artist::factory()->createOne(); + $song = Song::factory()->createOne(); - $artist->songs()->attach($song); - $artist->songs()->detach($song); + $artist->songs()->attach($song); + $artist->songs()->detach($song); - Event::assertDispatched(ArtistSongDeleted::class); - } + Event::assertDispatched(ArtistSongDeleted::class); +}); - /** - * When an Artist Song pivot is updated, an ArtistSongUpdated event shall be dispatched. - */ - public function testArtistSongUpdatedEventDispatched(): void - { - $artist = Artist::factory()->createOne(); - $song = Song::factory()->createOne(); +test('artist song updated event dispatched', function () { + $artist = Artist::factory()->createOne(); + $song = Song::factory()->createOne(); - $artistSong = ArtistSong::factory() - ->for($artist, 'artist') - ->for($song, 'song') - ->createOne(); + $artistSong = ArtistSong::factory() + ->for($artist, 'artist') + ->for($song, 'song') + ->createOne(); - $changes = ArtistSong::factory() - ->for($artist, 'artist') - ->for($song, 'song') - ->makeOne(); + $changes = ArtistSong::factory() + ->for($artist, 'artist') + ->for($song, 'song') + ->makeOne(); - $artistSong->fill($changes->getAttributes()); - $artistSong->save(); + $artistSong->fill($changes->getAttributes()); + $artistSong->save(); - Event::assertDispatched(ArtistSongUpdated::class); - } + Event::assertDispatched(ArtistSongUpdated::class); +}); - /** - * The ArtistSongUpdated event shall contain embed fields. - */ - public function testArtistSongUpdatedEventEmbedFields(): void - { - $artist = Artist::factory()->createOne(); - $song = Song::factory()->createOne(); +test('artist song updated event embed fields', function () { + $artist = Artist::factory()->createOne(); + $song = Song::factory()->createOne(); - $artistSong = ArtistSong::factory() - ->for($artist, 'artist') - ->for($song, 'song') - ->createOne(); + $artistSong = ArtistSong::factory() + ->for($artist, 'artist') + ->for($song, 'song') + ->createOne(); - $changes = ArtistSong::factory() - ->for($artist, 'artist') - ->for($song, 'song') - ->makeOne(); + $changes = ArtistSong::factory() + ->for($artist, 'artist') + ->for($song, 'song') + ->makeOne(); - $artistSong->fill($changes->getAttributes()); - $artistSong->save(); + $artistSong->fill($changes->getAttributes()); + $artistSong->save(); - Event::assertDispatched(ArtistSongUpdated::class, function (ArtistSongUpdated $event) { - $message = $event->getDiscordMessage(); + Event::assertDispatched(ArtistSongUpdated::class, function (ArtistSongUpdated $event) { + $message = $event->getDiscordMessage(); - return ! empty(Arr::get($message->embed, 'fields')); - }); - } -} + return ! empty(Arr::get($message->embed, 'fields')); + }); +}); diff --git a/tests/Feature/Events/Pivot/Wiki/SongResourceTest.php b/tests/Feature/Events/Pivot/Wiki/SongResourceTest.php index c592bd954..c720b89da 100644 --- a/tests/Feature/Events/Pivot/Wiki/SongResourceTest.php +++ b/tests/Feature/Events/Pivot/Wiki/SongResourceTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Events\Pivot\Wiki; - use App\Events\Pivot\Wiki\SongResource\SongResourceCreated; use App\Events\Pivot\Wiki\SongResource\SongResourceDeleted; use App\Events\Pivot\Wiki\SongResource\SongResourceUpdated; @@ -12,86 +10,66 @@ use App\Models\Wiki\Song; use App\Pivots\Wiki\SongResource; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class SongResourceTest extends TestCase -{ - /** - * When an Song is attached to a Resource or vice versa, an SongResourceCreated event shall be dispatched. - */ - public function testSongResourceCreatedEventDispatched(): void - { - $song = Song::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); +test('song resource created event dispatched', function () { + $song = Song::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - $song->resources()->attach($resource); + $song->resources()->attach($resource); - Event::assertDispatched(SongResourceCreated::class); - } + Event::assertDispatched(SongResourceCreated::class); +}); - /** - * When an Song is detached from a Resource or vice versa, an SongResourceDeleted event shall be dispatched. - */ - public function testSongResourceDeletedEventDispatched(): void - { - $song = Song::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); +test('song resource deleted event dispatched', function () { + $song = Song::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - $song->resources()->attach($resource); - $song->resources()->detach($resource); + $song->resources()->attach($resource); + $song->resources()->detach($resource); - Event::assertDispatched(SongResourceDeleted::class); - } + Event::assertDispatched(SongResourceDeleted::class); +}); - /** - * When an Song Resource pivot is updated, an SongResourceUpdated event shall be dispatched. - */ - public function testSongResourceUpdatedEventDispatched(): void - { - $song = Song::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); +test('song resource updated event dispatched', function () { + $song = Song::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - $songResource = SongResource::factory() - ->for($song, 'song') - ->for($resource, 'resource') - ->createOne(); + $songResource = SongResource::factory() + ->for($song, 'song') + ->for($resource, 'resource') + ->createOne(); - $changes = SongResource::factory() - ->for($song, 'song') - ->for($resource, 'resource') - ->makeOne(); + $changes = SongResource::factory() + ->for($song, 'song') + ->for($resource, 'resource') + ->makeOne(); - $songResource->fill($changes->getAttributes()); - $songResource->save(); + $songResource->fill($changes->getAttributes()); + $songResource->save(); - Event::assertDispatched(SongResourceUpdated::class); - } + Event::assertDispatched(SongResourceUpdated::class); +}); - /** - * The SongResourceUpdated event shall contain embed fields. - */ - public function testSongResourceUpdatedEventEmbedFields(): void - { - $song = Song::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); +test('song resource updated event embed fields', function () { + $song = Song::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - $songResource = SongResource::factory() - ->for($song, 'song') - ->for($resource, 'resource') - ->createOne(); + $songResource = SongResource::factory() + ->for($song, 'song') + ->for($resource, 'resource') + ->createOne(); - $changes = SongResource::factory() - ->for($song, 'song') - ->for($resource, 'resource') - ->makeOne(); + $changes = SongResource::factory() + ->for($song, 'song') + ->for($resource, 'resource') + ->makeOne(); - $songResource->fill($changes->getAttributes()); - $songResource->save(); + $songResource->fill($changes->getAttributes()); + $songResource->save(); - Event::assertDispatched(SongResourceUpdated::class, function (SongResourceUpdated $event) { - $message = $event->getDiscordMessage(); + Event::assertDispatched(SongResourceUpdated::class, function (SongResourceUpdated $event) { + $message = $event->getDiscordMessage(); - return ! empty(Arr::get($message->embed, 'fields')); - }); - } -} + return ! empty(Arr::get($message->embed, 'fields')); + }); +}); diff --git a/tests/Feature/Events/Pivot/Wiki/StudioImageTest.php b/tests/Feature/Events/Pivot/Wiki/StudioImageTest.php index ff6da8762..e2fa69be9 100644 --- a/tests/Feature/Events/Pivot/Wiki/StudioImageTest.php +++ b/tests/Feature/Events/Pivot/Wiki/StudioImageTest.php @@ -2,41 +2,27 @@ declare(strict_types=1); -namespace Tests\Feature\Events\Pivot\Wiki; - use App\Events\Pivot\Wiki\StudioImage\StudioImageCreated; use App\Events\Pivot\Wiki\StudioImage\StudioImageDeleted; use App\Models\Wiki\Image; use App\Models\Wiki\Studio; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class StudioImageTest extends TestCase -{ - /** - * When a Studio is attached to an Image or vice versa, a StudioImageCreated event shall be dispatched. - */ - public function testStudioImageCreatedEventDispatched(): void - { - $studio = Studio::factory()->createOne(); - $image = Image::factory()->createOne(); +test('studio image created event dispatched', function () { + $studio = Studio::factory()->createOne(); + $image = Image::factory()->createOne(); - $studio->images()->attach($image); + $studio->images()->attach($image); - Event::assertDispatched(StudioImageCreated::class); - } + Event::assertDispatched(StudioImageCreated::class); +}); - /** - * When a Studio is detached from an Image or vice versa, a StudioImageDeleted event shall be dispatched. - */ - public function testStudioImageDeletedEventDispatched(): void - { - $studio = Studio::factory()->createOne(); - $image = Image::factory()->createOne(); +test('studio image deleted event dispatched', function () { + $studio = Studio::factory()->createOne(); + $image = Image::factory()->createOne(); - $studio->images()->attach($image); - $studio->images()->detach($image); + $studio->images()->attach($image); + $studio->images()->detach($image); - Event::assertDispatched(StudioImageDeleted::class); - } -} + Event::assertDispatched(StudioImageDeleted::class); +}); diff --git a/tests/Feature/Events/Pivot/Wiki/StudioResourceTest.php b/tests/Feature/Events/Pivot/Wiki/StudioResourceTest.php index af43b4bc1..212cf93d9 100644 --- a/tests/Feature/Events/Pivot/Wiki/StudioResourceTest.php +++ b/tests/Feature/Events/Pivot/Wiki/StudioResourceTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Events\Pivot\Wiki; - use App\Events\Pivot\Wiki\StudioResource\StudioResourceCreated; use App\Events\Pivot\Wiki\StudioResource\StudioResourceDeleted; use App\Events\Pivot\Wiki\StudioResource\StudioResourceUpdated; @@ -12,86 +10,66 @@ use App\Models\Wiki\Studio; use App\Pivots\Wiki\StudioResource; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class StudioResourceTest extends TestCase -{ - /** - * When a Studio is attached to a Resource or vice versa, a StudioResourceCreated event shall be dispatched. - */ - public function testStudioResourceCreatedEventDispatched(): void - { - $studio = Studio::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); +test('studio resource created event dispatched', function () { + $studio = Studio::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - $studio->resources()->attach($resource); + $studio->resources()->attach($resource); - Event::assertDispatched(StudioResourceCreated::class); - } + Event::assertDispatched(StudioResourceCreated::class); +}); - /** - * When a Studio is detached to a Resource or vice versa, a StudioResourceDeleted event shall be dispatched. - */ - public function testStudioResourceDeletedEventDispatched(): void - { - $studio = Studio::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); +test('studio resource deleted event dispatched', function () { + $studio = Studio::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - $studio->resources()->attach($resource); - $studio->resources()->detach($resource); + $studio->resources()->attach($resource); + $studio->resources()->detach($resource); - Event::assertDispatched(StudioResourceDeleted::class); - } + Event::assertDispatched(StudioResourceDeleted::class); +}); - /** - * When a Studio Resource pivot is updated, a StudioResourceUpdated event shall be dispatched. - */ - public function testStudioResourceUpdatedEventDispatched(): void - { - $studio = Studio::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); +test('studio resource updated event dispatched', function () { + $studio = Studio::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - $studioResource = StudioResource::factory() - ->for($studio, 'studio') - ->for($resource, 'resource') - ->createOne(); + $studioResource = StudioResource::factory() + ->for($studio, 'studio') + ->for($resource, 'resource') + ->createOne(); - $changes = StudioResource::factory() - ->for($studio, 'studio') - ->for($resource, 'resource') - ->makeOne(); + $changes = StudioResource::factory() + ->for($studio, 'studio') + ->for($resource, 'resource') + ->makeOne(); - $studioResource->fill($changes->getAttributes()); - $studioResource->save(); + $studioResource->fill($changes->getAttributes()); + $studioResource->save(); - Event::assertDispatched(StudioResourceUpdated::class); - } + Event::assertDispatched(StudioResourceUpdated::class); +}); - /** - * The StudioResourceUpdated event shall contain embed fields. - */ - public function testStudioResourceUpdatedEventEmbedFields(): void - { - $studio = Studio::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); +test('studio resource updated event embed fields', function () { + $studio = Studio::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - $studioResource = StudioResource::factory() - ->for($studio, 'studio') - ->for($resource, 'resource') - ->createOne(); + $studioResource = StudioResource::factory() + ->for($studio, 'studio') + ->for($resource, 'resource') + ->createOne(); - $changes = StudioResource::factory() - ->for($studio, 'studio') - ->for($resource, 'resource') - ->makeOne(); + $changes = StudioResource::factory() + ->for($studio, 'studio') + ->for($resource, 'resource') + ->makeOne(); - $studioResource->fill($changes->getAttributes()); - $studioResource->save(); + $studioResource->fill($changes->getAttributes()); + $studioResource->save(); - Event::assertDispatched(StudioResourceUpdated::class, function (StudioResourceUpdated $event) { - $message = $event->getDiscordMessage(); + Event::assertDispatched(StudioResourceUpdated::class, function (StudioResourceUpdated $event) { + $message = $event->getDiscordMessage(); - return ! empty(Arr::get($message->embed, 'fields')); - }); - } -} + return ! empty(Arr::get($message->embed, 'fields')); + }); +}); diff --git a/tests/Feature/Events/Wiki/Anime/SynonymTest.php b/tests/Feature/Events/Wiki/Anime/SynonymTest.php index c60006b6a..e171b46d7 100644 --- a/tests/Feature/Events/Wiki/Anime/SynonymTest.php +++ b/tests/Feature/Events/Wiki/Anime/SynonymTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Events\Wiki\Anime; - use App\Events\Wiki\Anime\Synonym\SynonymCreated; use App\Events\Wiki\Anime\Synonym\SynonymDeleted; use App\Events\Wiki\Anime\Synonym\SynonymRestored; @@ -12,105 +10,75 @@ use App\Models\Wiki\Anime; use App\Models\Wiki\Anime\AnimeSynonym; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class SynonymTest extends TestCase -{ - /** - * When a Synonym is created, a SynonymCreated event shall be dispatched. - */ - public function testSynonymCreatedEventDispatched(): void - { - AnimeSynonym::factory() - ->for(Anime::factory()) - ->createOne(); +test('synonym created event dispatched', function () { + AnimeSynonym::factory() + ->for(Anime::factory()) + ->createOne(); - Event::assertDispatched(SynonymCreated::class); - } + Event::assertDispatched(SynonymCreated::class); +}); - /** - * When a Synonym is deleted, a SynonymDeleted event shall be dispatched. - */ - public function testSynonymDeletedEventDispatched(): void - { - $synonym = AnimeSynonym::factory() - ->for(Anime::factory()) - ->createOne(); +test('synonym deleted event dispatched', function () { + $synonym = AnimeSynonym::factory() + ->for(Anime::factory()) + ->createOne(); - $synonym->delete(); + $synonym->delete(); - Event::assertDispatched(SynonymDeleted::class); - } + Event::assertDispatched(SynonymDeleted::class); +}); - /** - * When a Synonym is restored, a SynonymRestored event shall be dispatched. - */ - public function testSynonymRestoredEventDispatched(): void - { - $synonym = AnimeSynonym::factory() - ->for(Anime::factory()) - ->createOne(); +test('synonym restored event dispatched', function () { + $synonym = AnimeSynonym::factory() + ->for(Anime::factory()) + ->createOne(); - $synonym->restore(); + $synonym->restore(); - Event::assertDispatched(SynonymRestored::class); - } + Event::assertDispatched(SynonymRestored::class); +}); - /** - * When a Synonym is restored, a SynonymUpdated event shall not be dispatched. - * Note: This is a customization that overrides default framework behavior. - * An updated event is fired on restore. - */ - public function testSynonymRestoresQuietly(): void - { - $synonym = AnimeSynonym::factory() - ->for(Anime::factory()) - ->createOne(); +test('synonym restores quietly', function () { + $synonym = AnimeSynonym::factory() + ->for(Anime::factory()) + ->createOne(); - $synonym->restore(); + $synonym->restore(); - Event::assertNotDispatched(SynonymUpdated::class); - } + Event::assertNotDispatched(SynonymUpdated::class); +}); - /** - * When a Synonym is updated, a SynonymUpdated event shall be dispatched. - */ - public function testSynonymUpdatedEventDispatched(): void - { - $synonym = AnimeSynonym::factory() - ->for(Anime::factory()) - ->createOne(); +test('synonym updated event dispatched', function () { + $synonym = AnimeSynonym::factory() + ->for(Anime::factory()) + ->createOne(); - $changes = AnimeSynonym::factory() - ->for(Anime::factory()) - ->makeOne(); + $changes = AnimeSynonym::factory() + ->for(Anime::factory()) + ->makeOne(); - $synonym->fill($changes->getAttributes()); - $synonym->save(); + $synonym->fill($changes->getAttributes()); + $synonym->save(); - Event::assertDispatched(SynonymUpdated::class); - } + Event::assertDispatched(SynonymUpdated::class); +}); - /** - * The SynonymUpdated event shall contain embed fields. - */ - public function testSynonymUpdatedEventEmbedFields(): void - { - $synonym = AnimeSynonym::factory() - ->for(Anime::factory()) - ->createOne(); +test('synonym updated event embed fields', function () { + $synonym = AnimeSynonym::factory() + ->for(Anime::factory()) + ->createOne(); - $changes = AnimeSynonym::factory() - ->for(Anime::factory()) - ->makeOne(); + $changes = AnimeSynonym::factory() + ->for(Anime::factory()) + ->makeOne(); - $synonym->fill($changes->getAttributes()); - $synonym->save(); + $synonym->fill($changes->getAttributes()); + $synonym->save(); - Event::assertDispatched(SynonymUpdated::class, function (SynonymUpdated $event) { - $message = $event->getDiscordMessage(); + Event::assertDispatched(SynonymUpdated::class, function (SynonymUpdated $event) { + $message = $event->getDiscordMessage(); - return ! empty(Arr::get($message->embed, 'fields')); - }); - } -} + return ! empty(Arr::get($message->embed, 'fields')); + }); +}); diff --git a/tests/Feature/Events/Wiki/Anime/Theme/EntryTest.php b/tests/Feature/Events/Wiki/Anime/Theme/EntryTest.php index 1467ebc2b..454d66fb3 100644 --- a/tests/Feature/Events/Wiki/Anime/Theme/EntryTest.php +++ b/tests/Feature/Events/Wiki/Anime/Theme/EntryTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Events\Wiki\Anime\Theme; - use App\Events\Wiki\Anime\Theme\Entry\EntryCreated; use App\Events\Wiki\Anime\Theme\Entry\EntryDeleted; use App\Events\Wiki\Anime\Theme\Entry\EntryRestored; @@ -13,105 +11,75 @@ use App\Models\Wiki\Anime\AnimeTheme; use App\Models\Wiki\Anime\Theme\AnimeThemeEntry; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class EntryTest extends TestCase -{ - /** - * When an Entry is created, an EntryCreated event shall be dispatched. - */ - public function testEntryCreatedEventDispatched(): void - { - AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); +test('entry created event dispatched', function () { + AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - Event::assertDispatched(EntryCreated::class); - } + Event::assertDispatched(EntryCreated::class); +}); - /** - * When an Entry is deleted, an EntryDeleted event shall be dispatched. - */ - public function testEntryDeletedEventDispatched(): void - { - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); +test('entry deleted event dispatched', function () { + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - $entry->delete(); + $entry->delete(); - Event::assertDispatched(EntryDeleted::class); - } + Event::assertDispatched(EntryDeleted::class); +}); - /** - * When an Entry is restored, an EntryRestored event shall be dispatched. - */ - public function testEntryRestoredEventDispatched(): void - { - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); +test('entry restored event dispatched', function () { + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - $entry->restore(); + $entry->restore(); - Event::assertDispatched(EntryRestored::class); - } + Event::assertDispatched(EntryRestored::class); +}); - /** - * When an Entry is restored, an EntryUpdated event shall not be dispatched. - * Note: This is a customization that overrides default framework behavior. - * An updated event is fired on restore. - */ - public function testEntryRestoresQuietly(): void - { - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); +test('entry restores quietly', function () { + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - $entry->restore(); + $entry->restore(); - Event::assertNotDispatched(EntryUpdated::class); - } + Event::assertNotDispatched(EntryUpdated::class); +}); - /** - * When an Entry is updated, an EntryUpdated event shall be dispatched. - */ - public function testEntryUpdatedEventDispatched(): void - { - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); +test('entry updated event dispatched', function () { + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - $changes = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->makeOne(); + $changes = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->makeOne(); - $entry->fill($changes->getAttributes()); - $entry->save(); + $entry->fill($changes->getAttributes()); + $entry->save(); - Event::assertDispatched(EntryUpdated::class); - } + Event::assertDispatched(EntryUpdated::class); +}); - /** - * The EntryUpdated event shall contain embed fields. - */ - public function testEntryUpdatedEventEmbedFields(): void - { - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); +test('entry updated event embed fields', function () { + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - $changes = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->makeOne(); + $changes = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->makeOne(); - $entry->fill($changes->getAttributes()); - $entry->save(); + $entry->fill($changes->getAttributes()); + $entry->save(); - Event::assertDispatched(EntryUpdated::class, function (EntryUpdated $event) { - $message = $event->getDiscordMessage(); + Event::assertDispatched(EntryUpdated::class, function (EntryUpdated $event) { + $message = $event->getDiscordMessage(); - return ! empty(Arr::get($message->embed, 'fields')); - }); - } -} + return ! empty(Arr::get($message->embed, 'fields')); + }); +}); diff --git a/tests/Feature/Events/Wiki/Anime/ThemeTest.php b/tests/Feature/Events/Wiki/Anime/ThemeTest.php index 1a470f78b..98f172c2b 100644 --- a/tests/Feature/Events/Wiki/Anime/ThemeTest.php +++ b/tests/Feature/Events/Wiki/Anime/ThemeTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Events\Wiki\Anime; - use App\Events\Wiki\Anime\Theme\ThemeCreated; use App\Events\Wiki\Anime\Theme\ThemeDeleted; use App\Events\Wiki\Anime\Theme\ThemeRestored; @@ -12,105 +10,75 @@ use App\Models\Wiki\Anime; use App\Models\Wiki\Anime\AnimeTheme; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class ThemeTest extends TestCase -{ - /** - * When a Theme is created, a ThemeCreated event shall be dispatched. - */ - public function testThemeCreatedEventDispatched(): void - { - AnimeTheme::factory() - ->for(Anime::factory()) - ->createOne(); +test('theme created event dispatched', function () { + AnimeTheme::factory() + ->for(Anime::factory()) + ->createOne(); - Event::assertDispatched(ThemeCreated::class); - } + Event::assertDispatched(ThemeCreated::class); +}); - /** - * When a Theme is deleted, a ThemeDeleted event shall be dispatched. - */ - public function testThemeDeletedEventDispatched(): void - { - $theme = AnimeTheme::factory() - ->for(Anime::factory()) - ->createOne(); +test('theme deleted event dispatched', function () { + $theme = AnimeTheme::factory() + ->for(Anime::factory()) + ->createOne(); - $theme->delete(); + $theme->delete(); - Event::assertDispatched(ThemeDeleted::class); - } + Event::assertDispatched(ThemeDeleted::class); +}); - /** - * When a Theme is restored, a ThemeRestored event shall be dispatched. - */ - public function testThemeRestoredEventDispatched(): void - { - $theme = AnimeTheme::factory() - ->for(Anime::factory()) - ->createOne(); +test('theme restored event dispatched', function () { + $theme = AnimeTheme::factory() + ->for(Anime::factory()) + ->createOne(); - $theme->restore(); + $theme->restore(); - Event::assertDispatched(ThemeRestored::class); - } + Event::assertDispatched(ThemeRestored::class); +}); - /** - * When a Theme is restored, a ThemeUpdated event shall not be dispatched. - * Note: This is a customization that overrides default framework behavior. - * An updated event is fired on restore. - */ - public function testThemeRestoresQuietly(): void - { - $theme = AnimeTheme::factory() - ->for(Anime::factory()) - ->createOne(); +test('theme restores quietly', function () { + $theme = AnimeTheme::factory() + ->for(Anime::factory()) + ->createOne(); - $theme->restore(); + $theme->restore(); - Event::assertNotDispatched(ThemeUpdated::class); - } + Event::assertNotDispatched(ThemeUpdated::class); +}); - /** - * When a Theme is updated, a ThemeUpdated event shall be dispatched. - */ - public function testThemeUpdatedEventDispatched(): void - { - $theme = AnimeTheme::factory() - ->for(Anime::factory()) - ->createOne(); +test('theme updated event dispatched', function () { + $theme = AnimeTheme::factory() + ->for(Anime::factory()) + ->createOne(); - $changes = AnimeTheme::factory() - ->for(Anime::factory()) - ->makeOne(); + $changes = AnimeTheme::factory() + ->for(Anime::factory()) + ->makeOne(); - $theme->fill($changes->getAttributes()); - $theme->save(); + $theme->fill($changes->getAttributes()); + $theme->save(); - Event::assertDispatched(ThemeUpdated::class); - } + Event::assertDispatched(ThemeUpdated::class); +}); - /** - * The ThemeUpdated event shall contain embed fields. - */ - public function testThemeUpdatedEventEmbedFields(): void - { - $theme = AnimeTheme::factory() - ->for(Anime::factory()) - ->createOne(); +test('theme updated event embed fields', function () { + $theme = AnimeTheme::factory() + ->for(Anime::factory()) + ->createOne(); - $changes = AnimeTheme::factory() - ->for(Anime::factory()) - ->makeOne(); + $changes = AnimeTheme::factory() + ->for(Anime::factory()) + ->makeOne(); - $theme->fill($changes->getAttributes()); - $theme->save(); + $theme->fill($changes->getAttributes()); + $theme->save(); - Event::assertDispatched(ThemeUpdated::class, function (ThemeUpdated $event) { - $message = $event->getDiscordMessage(); + Event::assertDispatched(ThemeUpdated::class, function (ThemeUpdated $event) { + $message = $event->getDiscordMessage(); - return ! empty(Arr::get($message->embed, 'fields')); - }); - } -} + return ! empty(Arr::get($message->embed, 'fields')); + }); +}); diff --git a/tests/Feature/Events/Wiki/AnimeTest.php b/tests/Feature/Events/Wiki/AnimeTest.php index 45ddb354f..3670a7b11 100644 --- a/tests/Feature/Events/Wiki/AnimeTest.php +++ b/tests/Feature/Events/Wiki/AnimeTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Events\Wiki; - use App\Events\Wiki\Anime\AnimeCreated; use App\Events\Wiki\Anime\AnimeDeleted; use App\Events\Wiki\Anime\AnimeRestored; @@ -11,87 +9,57 @@ use App\Events\Wiki\Anime\AnimeUpdated; use App\Models\Wiki\Anime; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class AnimeTest extends TestCase -{ - /** - * When an Anime is created, an AnimeCreated event shall be dispatched. - */ - public function testAnimeCreatedEventDispatched(): void - { - Anime::factory()->createOne(); +test('anime created event dispatched', function () { + Anime::factory()->createOne(); - Event::assertDispatched(AnimeCreated::class); - } + Event::assertDispatched(AnimeCreated::class); +}); - /** - * When an Anime is deleted, an AnimeDeleted event shall be dispatched. - */ - public function testAnimeDeletedEventDispatched(): void - { - $anime = Anime::factory()->createOne(); +test('anime deleted event dispatched', function () { + $anime = Anime::factory()->createOne(); - $anime->delete(); + $anime->delete(); - Event::assertDispatched(AnimeDeleted::class); - } + Event::assertDispatched(AnimeDeleted::class); +}); - /** - * When an Anime is restored, an AnimeRestored event shall be dispatched. - */ - public function testAnimeRestoredEventDispatched(): void - { - $anime = Anime::factory()->createOne(); +test('anime restored event dispatched', function () { + $anime = Anime::factory()->createOne(); - $anime->restore(); + $anime->restore(); - Event::assertDispatched(AnimeRestored::class); - } + Event::assertDispatched(AnimeRestored::class); +}); - /** - * When an Anime is restored, an AnimeUpdated event shall not be dispatched. - * Note: This is a customization that overrides default framework behavior. - * An updated event is fired on restore. - */ - public function testAnimeRestoresQuietly(): void - { - $anime = Anime::factory()->createOne(); +test('anime restores quietly', function () { + $anime = Anime::factory()->createOne(); - $anime->restore(); + $anime->restore(); - Event::assertNotDispatched(AnimeUpdated::class); - } + Event::assertNotDispatched(AnimeUpdated::class); +}); - /** - * When an Anime is updated, an AnimeUpdated event shall be dispatched. - */ - public function testAnimeUpdatedEventDispatched(): void - { - $anime = Anime::factory()->createOne(); - $changes = Anime::factory()->makeOne(); +test('anime updated event dispatched', function () { + $anime = Anime::factory()->createOne(); + $changes = Anime::factory()->makeOne(); - $anime->fill($changes->getAttributes()); - $anime->save(); + $anime->fill($changes->getAttributes()); + $anime->save(); - Event::assertDispatched(AnimeUpdated::class); - } + Event::assertDispatched(AnimeUpdated::class); +}); - /** - * The AnimeUpdated event shall contain embed fields. - */ - public function testAnimeUpdatedEventEmbedFields(): void - { - $anime = Anime::factory()->createOne(); - $changes = Anime::factory()->makeOne(); +test('anime updated event embed fields', function () { + $anime = Anime::factory()->createOne(); + $changes = Anime::factory()->makeOne(); - $anime->fill($changes->getAttributes()); - $anime->save(); + $anime->fill($changes->getAttributes()); + $anime->save(); - Event::assertDispatched(AnimeUpdated::class, function (AnimeUpdated $event) { - $message = $event->getDiscordMessage(); + Event::assertDispatched(AnimeUpdated::class, function (AnimeUpdated $event) { + $message = $event->getDiscordMessage(); - return ! empty(Arr::get($message->embed, 'fields')); - }); - } -} + return ! empty(Arr::get($message->embed, 'fields')); + }); +}); diff --git a/tests/Feature/Events/Wiki/ArtistTest.php b/tests/Feature/Events/Wiki/ArtistTest.php index a5c80235d..440e26264 100644 --- a/tests/Feature/Events/Wiki/ArtistTest.php +++ b/tests/Feature/Events/Wiki/ArtistTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Events\Wiki; - use App\Events\Wiki\Artist\ArtistCreated; use App\Events\Wiki\Artist\ArtistDeleted; use App\Events\Wiki\Artist\ArtistRestored; @@ -11,87 +9,57 @@ use App\Events\Wiki\Artist\ArtistUpdated; use App\Models\Wiki\Artist; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class ArtistTest extends TestCase -{ - /** - * When an Artist is created, an ArtistCreated event shall be dispatched. - */ - public function testArtistCreatedEventDispatched(): void - { - Artist::factory()->createOne(); +test('artist created event dispatched', function () { + Artist::factory()->createOne(); - Event::assertDispatched(ArtistCreated::class); - } + Event::assertDispatched(ArtistCreated::class); +}); - /** - * When an Artist is deleted, an ArtistDeleted event shall be dispatched. - */ - public function testArtistDeletedEventDispatched(): void - { - $artist = Artist::factory()->createOne(); +test('artist deleted event dispatched', function () { + $artist = Artist::factory()->createOne(); - $artist->delete(); + $artist->delete(); - Event::assertDispatched(ArtistDeleted::class); - } + Event::assertDispatched(ArtistDeleted::class); +}); - /** - * When an Artist is restored, an ArtistRestored event shall be dispatched. - */ - public function testArtistRestoredEventDispatched(): void - { - $artist = Artist::factory()->createOne(); +test('artist restored event dispatched', function () { + $artist = Artist::factory()->createOne(); - $artist->restore(); + $artist->restore(); - Event::assertDispatched(ArtistRestored::class); - } + Event::assertDispatched(ArtistRestored::class); +}); - /** - * When an Artist is restored, an ArtistUpdated event shall not be dispatched. - * Note: This is a customization that overrides default framework behavior. - * An updated event is fired on restore. - */ - public function testArtistRestoresQuietly(): void - { - $artist = Artist::factory()->createOne(); +test('artist restores quietly', function () { + $artist = Artist::factory()->createOne(); - $artist->restore(); + $artist->restore(); - Event::assertNotDispatched(ArtistUpdated::class); - } + Event::assertNotDispatched(ArtistUpdated::class); +}); - /** - * When an Artist is updated, an ArtistUpdated event shall be dispatched. - */ - public function testArtistUpdatedEventDispatched(): void - { - $artist = Artist::factory()->createOne(); - $changes = Artist::factory()->makeOne(); +test('artist updated event dispatched', function () { + $artist = Artist::factory()->createOne(); + $changes = Artist::factory()->makeOne(); - $artist->fill($changes->getAttributes()); - $artist->save(); + $artist->fill($changes->getAttributes()); + $artist->save(); - Event::assertDispatched(ArtistUpdated::class); - } + Event::assertDispatched(ArtistUpdated::class); +}); - /** - * The ArtistUpdated event shall contain embed fields. - */ - public function testArtistUpdatedEventEmbedFields(): void - { - $artist = Artist::factory()->createOne(); - $changes = Artist::factory()->makeOne(); +test('artist updated event embed fields', function () { + $artist = Artist::factory()->createOne(); + $changes = Artist::factory()->makeOne(); - $artist->fill($changes->getAttributes()); - $artist->save(); + $artist->fill($changes->getAttributes()); + $artist->save(); - Event::assertDispatched(ArtistUpdated::class, function (ArtistUpdated $event) { - $message = $event->getDiscordMessage(); + Event::assertDispatched(ArtistUpdated::class, function (ArtistUpdated $event) { + $message = $event->getDiscordMessage(); - return ! empty(Arr::get($message->embed, 'fields')); - }); - } -} + return ! empty(Arr::get($message->embed, 'fields')); + }); +}); diff --git a/tests/Feature/Events/Wiki/AudioTest.php b/tests/Feature/Events/Wiki/AudioTest.php index 55853b22d..39f689430 100644 --- a/tests/Feature/Events/Wiki/AudioTest.php +++ b/tests/Feature/Events/Wiki/AudioTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Events\Wiki; - use App\Events\Wiki\Audio\AudioCreated; use App\Events\Wiki\Audio\AudioDeleted; use App\Events\Wiki\Audio\AudioRestored; @@ -11,87 +9,57 @@ use App\Events\Wiki\Audio\AudioUpdated; use App\Models\Wiki\Audio; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class AudioTest extends TestCase -{ - /** - * When an Audio is created, an AudioCreated event shall be dispatched. - */ - public function testAudioCreatedEventDispatched(): void - { - Audio::factory()->createOne(); +test('audio created event dispatched', function () { + Audio::factory()->createOne(); - Event::assertDispatched(AudioCreated::class); - } + Event::assertDispatched(AudioCreated::class); +}); - /** - * When an Audio is deleted, an AudioDeleted event shall be dispatched. - */ - public function testAudioDeletedEventDispatched(): void - { - $audio = Audio::factory()->createOne(); +test('audio deleted event dispatched', function () { + $audio = Audio::factory()->createOne(); - $audio->delete(); + $audio->delete(); - Event::assertDispatched(AudioDeleted::class); - } + Event::assertDispatched(AudioDeleted::class); +}); - /** - * When an Audio is restored, an AudioRestored event shall be dispatched. - */ - public function testAudioRestoredEventDispatched(): void - { - $audio = Audio::factory()->createOne(); +test('audio restored event dispatched', function () { + $audio = Audio::factory()->createOne(); - $audio->restore(); + $audio->restore(); - Event::assertDispatched(AudioRestored::class); - } + Event::assertDispatched(AudioRestored::class); +}); - /** - * When an Audio is restored, an AudioUpdated event shall not be dispatched. - * Note: This is a customization that overrides default framework behavior. - * An updated event is fired on restore. - */ - public function testAudioRestoresQuietly(): void - { - $audio = Audio::factory()->createOne(); +test('audio restores quietly', function () { + $audio = Audio::factory()->createOne(); - $audio->restore(); + $audio->restore(); - Event::assertNotDispatched(AudioUpdated::class); - } + Event::assertNotDispatched(AudioUpdated::class); +}); - /** - * When an Audio is updated, an AudioUpdated event shall be dispatched. - */ - public function testAudioUpdatedEventDispatched(): void - { - $audio = Audio::factory()->createOne(); - $changes = Audio::factory()->makeOne(); +test('audio updated event dispatched', function () { + $audio = Audio::factory()->createOne(); + $changes = Audio::factory()->makeOne(); - $audio->fill($changes->getAttributes()); - $audio->save(); + $audio->fill($changes->getAttributes()); + $audio->save(); - Event::assertDispatched(AudioUpdated::class); - } + Event::assertDispatched(AudioUpdated::class); +}); - /** - * The AudioUpdated event shall contain embed fields. - */ - public function testAudioUpdatedEventEmbedFields(): void - { - $audio = Audio::factory()->createOne(); - $changes = Audio::factory()->makeOne(); +test('audio updated event embed fields', function () { + $audio = Audio::factory()->createOne(); + $changes = Audio::factory()->makeOne(); - $audio->fill($changes->getAttributes()); - $audio->save(); + $audio->fill($changes->getAttributes()); + $audio->save(); - Event::assertDispatched(AudioUpdated::class, function (AudioUpdated $event) { - $message = $event->getDiscordMessage(); + Event::assertDispatched(AudioUpdated::class, function (AudioUpdated $event) { + $message = $event->getDiscordMessage(); - return ! empty(Arr::get($message->embed, 'fields')); - }); - } -} + return ! empty(Arr::get($message->embed, 'fields')); + }); +}); diff --git a/tests/Feature/Events/Wiki/ExternalResourceTest.php b/tests/Feature/Events/Wiki/ExternalResourceTest.php index 3c062a864..bb03c7c18 100644 --- a/tests/Feature/Events/Wiki/ExternalResourceTest.php +++ b/tests/Feature/Events/Wiki/ExternalResourceTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Events\Wiki; - use App\Events\Wiki\ExternalResource\ExternalResourceCreated; use App\Events\Wiki\ExternalResource\ExternalResourceDeleted; use App\Events\Wiki\ExternalResource\ExternalResourceRestored; @@ -11,87 +9,57 @@ use App\Events\Wiki\ExternalResource\ExternalResourceUpdated; use App\Models\Wiki\ExternalResource; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class ExternalResourceTest extends TestCase -{ - /** - * When a Resource is created, an ExternalResourceCreated event shall be dispatched. - */ - public function testExternalResourceCreatedEventDispatched(): void - { - ExternalResource::factory()->createOne(); +test('external resource created event dispatched', function () { + ExternalResource::factory()->createOne(); - Event::assertDispatched(ExternalResourceCreated::class); - } + Event::assertDispatched(ExternalResourceCreated::class); +}); - /** - * When a Resource is deleted, an ExternalResourceDeleted event shall be dispatched. - */ - public function testExternalResourceDeletedEventDispatched(): void - { - $resource = ExternalResource::factory()->createOne(); +test('external resource deleted event dispatched', function () { + $resource = ExternalResource::factory()->createOne(); - $resource->delete(); + $resource->delete(); - Event::assertDispatched(ExternalResourceDeleted::class); - } + Event::assertDispatched(ExternalResourceDeleted::class); +}); - /** - * When a Resource is restored, an ExternalResourceRestored event shall be dispatched. - */ - public function testExternalResourceRestoredEventDispatched(): void - { - $resource = ExternalResource::factory()->createOne(); +test('external resource restored event dispatched', function () { + $resource = ExternalResource::factory()->createOne(); - $resource->restore(); + $resource->restore(); - Event::assertDispatched(ExternalResourceRestored::class); - } + Event::assertDispatched(ExternalResourceRestored::class); +}); - /** - * When a Resource is restored, an ExternalResourceUpdated event shall not be dispatched. - * Note: This is a customization that overrides default framework behavior. - * An updated event is fired on restore. - */ - public function testExternalResourceRestoresQuietly(): void - { - $resource = ExternalResource::factory()->createOne(); +test('external resource restores quietly', function () { + $resource = ExternalResource::factory()->createOne(); - $resource->restore(); + $resource->restore(); - Event::assertNotDispatched(ExternalResourceUpdated::class); - } + Event::assertNotDispatched(ExternalResourceUpdated::class); +}); - /** - * When an ExternalResource is updated, an ExternalResourceUpdated event shall be dispatched. - */ - public function testExternalResourceUpdatedEventDispatched(): void - { - $resource = ExternalResource::factory()->createOne(); - $changes = ExternalResource::factory()->makeOne(); +test('external resource updated event dispatched', function () { + $resource = ExternalResource::factory()->createOne(); + $changes = ExternalResource::factory()->makeOne(); - $resource->fill($changes->getAttributes()); - $resource->save(); + $resource->fill($changes->getAttributes()); + $resource->save(); - Event::assertDispatched(ExternalResourceUpdated::class); - } + Event::assertDispatched(ExternalResourceUpdated::class); +}); - /** - * The ExternalResourceUpdated event shall contain embed fields. - */ - public function testExternalResourceUpdatedEventEmbedFields(): void - { - $resource = ExternalResource::factory()->createOne(); - $changes = ExternalResource::factory()->makeOne(); +test('external resource updated event embed fields', function () { + $resource = ExternalResource::factory()->createOne(); + $changes = ExternalResource::factory()->makeOne(); - $resource->fill($changes->getAttributes()); - $resource->save(); + $resource->fill($changes->getAttributes()); + $resource->save(); - Event::assertDispatched(ExternalResourceUpdated::class, function (ExternalResourceUpdated $event) { - $message = $event->getDiscordMessage(); + Event::assertDispatched(ExternalResourceUpdated::class, function (ExternalResourceUpdated $event) { + $message = $event->getDiscordMessage(); - return ! empty(Arr::get($message->embed, 'fields')); - }); - } -} + return ! empty(Arr::get($message->embed, 'fields')); + }); +}); diff --git a/tests/Feature/Events/Wiki/GroupTest.php b/tests/Feature/Events/Wiki/GroupTest.php index 864109b74..22fad2bf8 100644 --- a/tests/Feature/Events/Wiki/GroupTest.php +++ b/tests/Feature/Events/Wiki/GroupTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Events\Wiki; - use App\Events\Wiki\Group\GroupCreated; use App\Events\Wiki\Group\GroupDeleted; use App\Events\Wiki\Group\GroupRestored; @@ -11,87 +9,57 @@ use App\Events\Wiki\Group\GroupUpdated; use App\Models\Wiki\Group; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class GroupTest extends TestCase -{ - /** - * When a Group is created, a GroupCreated event shall be dispatched. - */ - public function testGroupCreatedEventDispatched(): void - { - Group::factory()->createOne(); +test('group created event dispatched', function () { + Group::factory()->createOne(); - Event::assertDispatched(GroupCreated::class); - } + Event::assertDispatched(GroupCreated::class); +}); - /** - * When a Group is deleted, a GroupDeleted event shall be dispatched. - */ - public function testGroupDeletedEventDispatched(): void - { - $group = Group::factory()->createOne(); +test('group deleted event dispatched', function () { + $group = Group::factory()->createOne(); - $group->delete(); + $group->delete(); - Event::assertDispatched(GroupDeleted::class); - } + Event::assertDispatched(GroupDeleted::class); +}); - /** - * When a Group is restored, a GroupRestored event shall be dispatched. - */ - public function testGroupRestoredEventDispatched(): void - { - $group = Group::factory()->createOne(); +test('group restored event dispatched', function () { + $group = Group::factory()->createOne(); - $group->restore(); + $group->restore(); - Event::assertDispatched(GroupRestored::class); - } + Event::assertDispatched(GroupRestored::class); +}); - /** - * When a Group is restored, a GroupUpdated event shall not be dispatched. - * Note: This is a customization that overrides default framework behavior. - * An updated event is fired on restore. - */ - public function testGroupRestoresQuietly(): void - { - $group = Group::factory()->createOne(); +test('group restores quietly', function () { + $group = Group::factory()->createOne(); - $group->restore(); + $group->restore(); - Event::assertNotDispatched(GroupUpdated::class); - } + Event::assertNotDispatched(GroupUpdated::class); +}); - /** - * When a Group is updated, a GroupUpdated event shall be dispatched. - */ - public function testGroupUpdatedEventDispatched(): void - { - $group = Group::factory()->createOne(); - $changes = Group::factory()->makeOne(); +test('group updated event dispatched', function () { + $group = Group::factory()->createOne(); + $changes = Group::factory()->makeOne(); - $group->fill($changes->getAttributes()); - $group->save(); + $group->fill($changes->getAttributes()); + $group->save(); - Event::assertDispatched(GroupUpdated::class); - } + Event::assertDispatched(GroupUpdated::class); +}); - /** - * The GroupUpdated event shall contain embed fields. - */ - public function testGroupUpdatedEventEmbedFields(): void - { - $group = Group::factory()->createOne(); - $changes = Group::factory()->makeOne(); +test('group updated event embed fields', function () { + $group = Group::factory()->createOne(); + $changes = Group::factory()->makeOne(); - $group->fill($changes->getAttributes()); - $group->save(); + $group->fill($changes->getAttributes()); + $group->save(); - Event::assertDispatched(GroupUpdated::class, function (GroupUpdated $event) { - $message = $event->getDiscordMessage(); + Event::assertDispatched(GroupUpdated::class, function (GroupUpdated $event) { + $message = $event->getDiscordMessage(); - return ! empty(Arr::get($message->embed, 'fields')); - }); - } -} + return ! empty(Arr::get($message->embed, 'fields')); + }); +}); diff --git a/tests/Feature/Events/Wiki/ImageTest.php b/tests/Feature/Events/Wiki/ImageTest.php index f024a3f6a..e826291b9 100644 --- a/tests/Feature/Events/Wiki/ImageTest.php +++ b/tests/Feature/Events/Wiki/ImageTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Events\Wiki; - use App\Events\Wiki\Image\ImageCreated; use App\Events\Wiki\Image\ImageDeleted; use App\Events\Wiki\Image\ImageRestored; @@ -11,87 +9,57 @@ use App\Events\Wiki\Image\ImageUpdated; use App\Models\Wiki\Image; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class ImageTest extends TestCase -{ - /** - * When an Image is created, an ImageCreated event shall be dispatched. - */ - public function testImageCreatedEventDispatched(): void - { - Image::factory()->createOne(); +test('image created event dispatched', function () { + Image::factory()->createOne(); - Event::assertDispatched(ImageCreated::class); - } + Event::assertDispatched(ImageCreated::class); +}); - /** - * When an Image is deleted, an ImageDeleted event shall be dispatched. - */ - public function testImageDeletedEventDispatched(): void - { - $image = Image::factory()->createOne(); +test('image deleted event dispatched', function () { + $image = Image::factory()->createOne(); - $image->delete(); + $image->delete(); - Event::assertDispatched(ImageDeleted::class); - } + Event::assertDispatched(ImageDeleted::class); +}); - /** - * When an Image is restored, an ImageRestored event shall be dispatched. - */ - public function testImageRestoredEventDispatched(): void - { - $image = Image::factory()->createOne(); +test('image restored event dispatched', function () { + $image = Image::factory()->createOne(); - $image->restore(); + $image->restore(); - Event::assertDispatched(ImageRestored::class); - } + Event::assertDispatched(ImageRestored::class); +}); - /** - * When an Image is restored, an ImageUpdated event shall not be dispatched. - * Note: This is a customization that overrides default framework behavior. - * An updated event is fired on restore. - */ - public function testImageRestoresQuietly(): void - { - $image = Image::factory()->createOne(); +test('image restores quietly', function () { + $image = Image::factory()->createOne(); - $image->restore(); + $image->restore(); - Event::assertNotDispatched(ImageUpdated::class); - } + Event::assertNotDispatched(ImageUpdated::class); +}); - /** - * When an Image is updated, an ImageUpdated event shall be dispatched. - */ - public function testImageUpdatedEventDispatched(): void - { - $image = Image::factory()->createOne(); - $changes = Image::factory()->makeOne(); +test('image updated event dispatched', function () { + $image = Image::factory()->createOne(); + $changes = Image::factory()->makeOne(); - $image->fill($changes->getAttributes()); - $image->save(); + $image->fill($changes->getAttributes()); + $image->save(); - Event::assertDispatched(ImageUpdated::class); - } + Event::assertDispatched(ImageUpdated::class); +}); - /** - * The ImageUpdated event shall contain embed fields. - */ - public function testImageUpdatedEventEmbedFields(): void - { - $image = Image::factory()->createOne(); - $changes = Image::factory()->makeOne(); +test('image updated event embed fields', function () { + $image = Image::factory()->createOne(); + $changes = Image::factory()->makeOne(); - $image->fill($changes->getAttributes()); - $image->save(); + $image->fill($changes->getAttributes()); + $image->save(); - Event::assertDispatched(ImageUpdated::class, function (ImageUpdated $event) { - $message = $event->getDiscordMessage(); + Event::assertDispatched(ImageUpdated::class, function (ImageUpdated $event) { + $message = $event->getDiscordMessage(); - return ! empty(Arr::get($message->embed, 'fields')); - }); - } -} + return ! empty(Arr::get($message->embed, 'fields')); + }); +}); diff --git a/tests/Feature/Events/Wiki/SeriesTest.php b/tests/Feature/Events/Wiki/SeriesTest.php index 67e23512c..736b786d4 100644 --- a/tests/Feature/Events/Wiki/SeriesTest.php +++ b/tests/Feature/Events/Wiki/SeriesTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Events\Wiki; - use App\Events\Wiki\Series\SeriesCreated; use App\Events\Wiki\Series\SeriesDeleted; use App\Events\Wiki\Series\SeriesRestored; @@ -11,87 +9,57 @@ use App\Events\Wiki\Series\SeriesUpdated; use App\Models\Wiki\Series; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class SeriesTest extends TestCase -{ - /** - * When a Series is created, a SeriesCreated event shall be dispatched. - */ - public function testSeriesCreatedEventDispatched(): void - { - Series::factory()->createOne(); +test('series created event dispatched', function () { + Series::factory()->createOne(); - Event::assertDispatched(SeriesCreated::class); - } + Event::assertDispatched(SeriesCreated::class); +}); - /** - * When a Series is deleted, a SeriesDeleted event shall be dispatched. - */ - public function testSeriesDeletedEventDispatched(): void - { - $series = Series::factory()->createOne(); +test('series deleted event dispatched', function () { + $series = Series::factory()->createOne(); - $series->delete(); + $series->delete(); - Event::assertDispatched(SeriesDeleted::class); - } + Event::assertDispatched(SeriesDeleted::class); +}); - /** - * When a Series is restored, a SeriesRestored event shall be dispatched. - */ - public function testSeriesRestoredEventDispatched(): void - { - $series = Series::factory()->createOne(); +test('series restored event dispatched', function () { + $series = Series::factory()->createOne(); - $series->restore(); + $series->restore(); - Event::assertDispatched(SeriesRestored::class); - } + Event::assertDispatched(SeriesRestored::class); +}); - /** - * When a Series is restored, a SeriesUpdated event shall not be dispatched. - * Note: This is a customization that overrides default framework behavior. - * An updated event is fired on restore. - */ - public function testSeriesRestoresQuietly(): void - { - $series = Series::factory()->createOne(); +test('series restores quietly', function () { + $series = Series::factory()->createOne(); - $series->restore(); + $series->restore(); - Event::assertNotDispatched(SeriesUpdated::class); - } + Event::assertNotDispatched(SeriesUpdated::class); +}); - /** - * When a Series is updated, a SeriesUpdated event shall be dispatched. - */ - public function testSeriesUpdatedEventDispatched(): void - { - $series = Series::factory()->createOne(); - $changes = Series::factory()->makeOne(); +test('series updated event dispatched', function () { + $series = Series::factory()->createOne(); + $changes = Series::factory()->makeOne(); - $series->fill($changes->getAttributes()); - $series->save(); + $series->fill($changes->getAttributes()); + $series->save(); - Event::assertDispatched(SeriesUpdated::class); - } + Event::assertDispatched(SeriesUpdated::class); +}); - /** - * The SeriesUpdated event shall contain embed fields. - */ - public function testSeriesUpdatedEventEmbedFields(): void - { - $series = Series::factory()->createOne(); - $changes = Series::factory()->makeOne(); +test('series updated event embed fields', function () { + $series = Series::factory()->createOne(); + $changes = Series::factory()->makeOne(); - $series->fill($changes->getAttributes()); - $series->save(); + $series->fill($changes->getAttributes()); + $series->save(); - Event::assertDispatched(SeriesUpdated::class, function (SeriesUpdated $event) { - $message = $event->getDiscordMessage(); + Event::assertDispatched(SeriesUpdated::class, function (SeriesUpdated $event) { + $message = $event->getDiscordMessage(); - return ! empty(Arr::get($message->embed, 'fields')); - }); - } -} + return ! empty(Arr::get($message->embed, 'fields')); + }); +}); diff --git a/tests/Feature/Events/Wiki/SongTest.php b/tests/Feature/Events/Wiki/SongTest.php index 6cef01e96..b097ceef7 100644 --- a/tests/Feature/Events/Wiki/SongTest.php +++ b/tests/Feature/Events/Wiki/SongTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Events\Wiki; - use App\Events\Wiki\Song\SongCreated; use App\Events\Wiki\Song\SongDeleted; use App\Events\Wiki\Song\SongRestored; @@ -11,87 +9,57 @@ use App\Events\Wiki\Song\SongUpdated; use App\Models\Wiki\Song; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class SongTest extends TestCase -{ - /** - * When a Song is created, a SongCreated event shall be dispatched. - */ - public function testSongCreatedEventDispatched(): void - { - Song::factory()->createOne(); +test('song created event dispatched', function () { + Song::factory()->createOne(); - Event::assertDispatched(SongCreated::class); - } + Event::assertDispatched(SongCreated::class); +}); - /** - * When a Song is deleted, a SongDeleted event shall be dispatched. - */ - public function testSongDeletedEventDispatched(): void - { - $song = Song::factory()->createOne(); +test('song deleted event dispatched', function () { + $song = Song::factory()->createOne(); - $song->delete(); + $song->delete(); - Event::assertDispatched(SongDeleted::class); - } + Event::assertDispatched(SongDeleted::class); +}); - /** - * When a Song is restored, a SongRestored event shall be dispatched. - */ - public function testSongRestoredEventDispatched(): void - { - $song = Song::factory()->createOne(); +test('song restored event dispatched', function () { + $song = Song::factory()->createOne(); - $song->restore(); + $song->restore(); - Event::assertDispatched(SongRestored::class); - } + Event::assertDispatched(SongRestored::class); +}); - /** - * When a Song is restored, a SongUpdated event shall not be dispatched. - * Note: This is a customization that overrides default framework behavior. - * An updated event is fired on restore. - */ - public function testSongRestoresQuietly(): void - { - $song = Song::factory()->createOne(); +test('song restores quietly', function () { + $song = Song::factory()->createOne(); - $song->restore(); + $song->restore(); - Event::assertNotDispatched(SongUpdated::class); - } + Event::assertNotDispatched(SongUpdated::class); +}); - /** - * When a Song is updated, a SongUpdated event shall be dispatched. - */ - public function testSongUpdatedEventDispatched(): void - { - $song = Song::factory()->createOne(); - $changes = Song::factory()->makeOne(); +test('song updated event dispatched', function () { + $song = Song::factory()->createOne(); + $changes = Song::factory()->makeOne(); - $song->fill($changes->getAttributes()); - $song->save(); + $song->fill($changes->getAttributes()); + $song->save(); - Event::assertDispatched(SongUpdated::class); - } + Event::assertDispatched(SongUpdated::class); +}); - /** - * The SongUpdated event shall contain embed fields. - */ - public function testSongUpdatedEventEmbedFields(): void - { - $song = Song::factory()->createOne(); - $changes = Song::factory()->makeOne(); +test('song updated event embed fields', function () { + $song = Song::factory()->createOne(); + $changes = Song::factory()->makeOne(); - $song->fill($changes->getAttributes()); - $song->save(); + $song->fill($changes->getAttributes()); + $song->save(); - Event::assertDispatched(SongUpdated::class, function (SongUpdated $event) { - $message = $event->getDiscordMessage(); + Event::assertDispatched(SongUpdated::class, function (SongUpdated $event) { + $message = $event->getDiscordMessage(); - return ! empty(Arr::get($message->embed, 'fields')); - }); - } -} + return ! empty(Arr::get($message->embed, 'fields')); + }); +}); diff --git a/tests/Feature/Events/Wiki/StudioTest.php b/tests/Feature/Events/Wiki/StudioTest.php index 86d788d3a..6ed0b8299 100644 --- a/tests/Feature/Events/Wiki/StudioTest.php +++ b/tests/Feature/Events/Wiki/StudioTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Events\Wiki; - use App\Events\Wiki\Studio\StudioCreated; use App\Events\Wiki\Studio\StudioDeleted; use App\Events\Wiki\Studio\StudioRestored; @@ -11,87 +9,57 @@ use App\Events\Wiki\Studio\StudioUpdated; use App\Models\Wiki\Studio; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class StudioTest extends TestCase -{ - /** - * When a Studio is created, a StudioCreated event shall be dispatched. - */ - public function testStudioCreatedEventDispatched(): void - { - Studio::factory()->createOne(); +test('studio created event dispatched', function () { + Studio::factory()->createOne(); - Event::assertDispatched(StudioCreated::class); - } + Event::assertDispatched(StudioCreated::class); +}); - /** - * When a Studio is deleted, a StudioDeleted event shall be dispatched. - */ - public function testStudioDeletedEventDispatched(): void - { - $studio = Studio::factory()->createOne(); +test('studio deleted event dispatched', function () { + $studio = Studio::factory()->createOne(); - $studio->delete(); + $studio->delete(); - Event::assertDispatched(StudioDeleted::class); - } + Event::assertDispatched(StudioDeleted::class); +}); - /** - * When a Studio is restored, a StudioRestored event shall be dispatched. - */ - public function testStudioRestoredEventDispatched(): void - { - $studio = Studio::factory()->createOne(); +test('studio restored event dispatched', function () { + $studio = Studio::factory()->createOne(); - $studio->restore(); + $studio->restore(); - Event::assertDispatched(StudioRestored::class); - } + Event::assertDispatched(StudioRestored::class); +}); - /** - * When a Studio is restored, a StudioUpdated event shall not be dispatched. - * Note: This is a customization that overrides default framework behavior. - * An updated event is fired on restore. - */ - public function testStudioRestoresQuietly(): void - { - $studio = Studio::factory()->createOne(); +test('studio restores quietly', function () { + $studio = Studio::factory()->createOne(); - $studio->restore(); + $studio->restore(); - Event::assertNotDispatched(StudioUpdated::class); - } + Event::assertNotDispatched(StudioUpdated::class); +}); - /** - * When a Studio is updated, a StudioUpdated event shall be dispatched. - */ - public function testStudioUpdatedEventDispatched(): void - { - $studio = Studio::factory()->createOne(); - $changes = Studio::factory()->makeOne(); +test('studio updated event dispatched', function () { + $studio = Studio::factory()->createOne(); + $changes = Studio::factory()->makeOne(); - $studio->fill($changes->getAttributes()); - $studio->save(); + $studio->fill($changes->getAttributes()); + $studio->save(); - Event::assertDispatched(StudioUpdated::class); - } + Event::assertDispatched(StudioUpdated::class); +}); - /** - * The StudioUpdated event shall contain embed fields. - */ - public function testStudioUpdatedEventEmbedFields(): void - { - $studio = Studio::factory()->createOne(); - $changes = Studio::factory()->makeOne(); +test('studio updated event embed fields', function () { + $studio = Studio::factory()->createOne(); + $changes = Studio::factory()->makeOne(); - $studio->fill($changes->getAttributes()); - $studio->save(); + $studio->fill($changes->getAttributes()); + $studio->save(); - Event::assertDispatched(StudioUpdated::class, function (StudioUpdated $event) { - $message = $event->getDiscordMessage(); + Event::assertDispatched(StudioUpdated::class, function (StudioUpdated $event) { + $message = $event->getDiscordMessage(); - return ! empty(Arr::get($message->embed, 'fields')); - }); - } -} + return ! empty(Arr::get($message->embed, 'fields')); + }); +}); diff --git a/tests/Feature/Events/Wiki/Video/ScriptTest.php b/tests/Feature/Events/Wiki/Video/ScriptTest.php index 9e2fdb97a..cdb706ccf 100644 --- a/tests/Feature/Events/Wiki/Video/ScriptTest.php +++ b/tests/Feature/Events/Wiki/Video/ScriptTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Events\Wiki\Video; - use App\Events\Wiki\Video\Script\VideoScriptCreated; use App\Events\Wiki\Video\Script\VideoScriptDeleted; use App\Events\Wiki\Video\Script\VideoScriptRestored; @@ -11,87 +9,57 @@ use App\Events\Wiki\Video\Script\VideoScriptUpdated; use App\Models\Wiki\Video\VideoScript; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class ScriptTest extends TestCase -{ - /** - * When a Script is created, a VideoScriptCreated event shall be dispatched. - */ - public function testVideoScriptCreatedEventDispatched(): void - { - VideoScript::factory()->createOne(); +test('video script created event dispatched', function () { + VideoScript::factory()->createOne(); - Event::assertDispatched(VideoScriptCreated::class); - } + Event::assertDispatched(VideoScriptCreated::class); +}); - /** - * When a Script is deleted, a VideoScriptDeleted event shall be dispatched. - */ - public function testVideoScriptDeletedEventDispatched(): void - { - $script = VideoScript::factory()->createOne(); +test('video script deleted event dispatched', function () { + $script = VideoScript::factory()->createOne(); - $script->delete(); + $script->delete(); - Event::assertDispatched(VideoScriptDeleted::class); - } + Event::assertDispatched(VideoScriptDeleted::class); +}); - /** - * When a Script is restored, a VideoScriptRestored event shall be dispatched. - */ - public function testVideoScriptRestoredEventDispatched(): void - { - $script = VideoScript::factory()->createOne(); +test('video script restored event dispatched', function () { + $script = VideoScript::factory()->createOne(); - $script->restore(); + $script->restore(); - Event::assertDispatched(VideoScriptRestored::class); - } + Event::assertDispatched(VideoScriptRestored::class); +}); - /** - * When a Script is restored, a VideoScriptUpdated event shall not be dispatched. - * Note: This is a customization that overrides default framework behavior. - * An updated event is fired on restore. - */ - public function testVideoScriptRestoresQuietly(): void - { - $script = VideoScript::factory()->createOne(); +test('video script restores quietly', function () { + $script = VideoScript::factory()->createOne(); - $script->restore(); + $script->restore(); - Event::assertNotDispatched(VideoScriptUpdated::class); - } + Event::assertNotDispatched(VideoScriptUpdated::class); +}); - /** - * When a Script is updated, a VideoScriptUpdated event shall be dispatched. - */ - public function testVideoScriptUpdatedEventDispatched(): void - { - $script = VideoScript::factory()->createOne(); - $changes = VideoScript::factory()->makeOne(); +test('video script updated event dispatched', function () { + $script = VideoScript::factory()->createOne(); + $changes = VideoScript::factory()->makeOne(); - $script->fill($changes->getAttributes()); - $script->save(); + $script->fill($changes->getAttributes()); + $script->save(); - Event::assertDispatched(VideoScriptUpdated::class); - } + Event::assertDispatched(VideoScriptUpdated::class); +}); - /** - * The VideoScriptUpdated event shall contain embed fields. - */ - public function testVideoScriptUpdatedEventEmbedFields(): void - { - $script = VideoScript::factory()->createOne(); - $changes = VideoScript::factory()->makeOne(); +test('video script updated event embed fields', function () { + $script = VideoScript::factory()->createOne(); + $changes = VideoScript::factory()->makeOne(); - $script->fill($changes->getAttributes()); - $script->save(); + $script->fill($changes->getAttributes()); + $script->save(); - Event::assertDispatched(VideoScriptUpdated::class, function (VideoScriptUpdated $event) { - $message = $event->getDiscordMessage(); + Event::assertDispatched(VideoScriptUpdated::class, function (VideoScriptUpdated $event) { + $message = $event->getDiscordMessage(); - return ! empty(Arr::get($message->embed, 'fields')); - }); - } -} + return ! empty(Arr::get($message->embed, 'fields')); + }); +}); diff --git a/tests/Feature/Events/Wiki/VideoTest.php b/tests/Feature/Events/Wiki/VideoTest.php index 331414ac7..dafdbf16b 100644 --- a/tests/Feature/Events/Wiki/VideoTest.php +++ b/tests/Feature/Events/Wiki/VideoTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Events\Wiki; - use App\Events\Wiki\Video\VideoCreated; use App\Events\Wiki\Video\VideoDeleted; use App\Events\Wiki\Video\VideoRestored; @@ -11,87 +9,57 @@ use App\Events\Wiki\Video\VideoUpdated; use App\Models\Wiki\Video; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class VideoTest extends TestCase -{ - /** - * When a Video is created, a VideoCreated event shall be dispatched. - */ - public function testVideoCreatedEventDispatched(): void - { - Video::factory()->createOne(); +test('video created event dispatched', function () { + Video::factory()->createOne(); - Event::assertDispatched(VideoCreated::class); - } + Event::assertDispatched(VideoCreated::class); +}); - /** - * When a Video is deleted, a VideoDeleted event shall be dispatched. - */ - public function testVideoDeletedEventDispatched(): void - { - $video = Video::factory()->createOne(); +test('video deleted event dispatched', function () { + $video = Video::factory()->createOne(); - $video->delete(); + $video->delete(); - Event::assertDispatched(VideoDeleted::class); - } + Event::assertDispatched(VideoDeleted::class); +}); - /** - * When a Video is restored, a VideoRestored event shall be dispatched. - */ - public function testVideoRestoredEventDispatched(): void - { - $video = Video::factory()->createOne(); +test('video restored event dispatched', function () { + $video = Video::factory()->createOne(); - $video->restore(); + $video->restore(); - Event::assertDispatched(VideoRestored::class); - } + Event::assertDispatched(VideoRestored::class); +}); - /** - * When a Video is restored, a VideoUpdated event shall not be dispatched. - * Note: This is a customization that overrides default framework behavior. - * An updated event is fired on restore. - */ - public function testVideoRestoresQuietly(): void - { - $video = Video::factory()->createOne(); +test('video restores quietly', function () { + $video = Video::factory()->createOne(); - $video->restore(); + $video->restore(); - Event::assertNotDispatched(VideoUpdated::class); - } + Event::assertNotDispatched(VideoUpdated::class); +}); - /** - * When a Video is updated, a VideoUpdated event shall be dispatched. - */ - public function testVideoUpdatedEventDispatched(): void - { - $video = Video::factory()->createOne(); - $changes = Video::factory()->makeOne(); +test('video updated event dispatched', function () { + $video = Video::factory()->createOne(); + $changes = Video::factory()->makeOne(); - $video->fill($changes->getAttributes()); - $video->save(); + $video->fill($changes->getAttributes()); + $video->save(); - Event::assertDispatched(VideoUpdated::class); - } + Event::assertDispatched(VideoUpdated::class); +}); - /** - * The VideoUpdated event shall contain embed fields. - */ - public function testVideoUpdatedEventEmbedFields(): void - { - $video = Video::factory()->createOne(); - $changes = Video::factory()->makeOne(); +test('video updated event embed fields', function () { + $video = Video::factory()->createOne(); + $changes = Video::factory()->makeOne(); - $video->fill($changes->getAttributes()); - $video->save(); + $video->fill($changes->getAttributes()); + $video->save(); - Event::assertDispatched(VideoUpdated::class, function (VideoUpdated $event) { - $message = $event->getDiscordMessage(); + Event::assertDispatched(VideoUpdated::class, function (VideoUpdated $event) { + $message = $event->getDiscordMessage(); - return ! empty(Arr::get($message->embed, 'fields')); - }); - } -} + return ! empty(Arr::get($message->embed, 'fields')); + }); +}); diff --git a/tests/Feature/GraphQL/Queries/AnimeQueryTest.php b/tests/Feature/GraphQL/Queries/AnimeQueryTest.php index 620b80374..c561965f8 100644 --- a/tests/Feature/GraphQL/Queries/AnimeQueryTest.php +++ b/tests/Feature/GraphQL/Queries/AnimeQueryTest.php @@ -2,42 +2,32 @@ declare(strict_types=1); -namespace Tests\Feature\GraphQL\Queries; - use App\Models\Wiki\Anime; -use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; -class AnimeQueryTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The animeyears Query shall return a list of years. - */ - public function testAnimeYearsQuery(): void - { - static::markTestSkipped('TODO'); - /** @phpstan-ignore-next-line */ - $years = Anime::factory() - ->count($this->faker->randomDigitNotNull()) - ->create() - ->map(fn (Anime $anime) => $anime->getAttribute(Anime::ATTRIBUTE_YEAR)) - ->sortBy(fn (int $year) => $year) - ->unique() - ->values() - ->toArray(); +test('anime years query', function () { + $this->markTestSkipped('TODO'); - $response = $this->graphQL(' + /** @phpstan-ignore-next-line */ + $years = Anime::factory() + ->count(fake()->randomDigitNotNull()) + ->create() + ->map(fn (Anime $anime) => $anime->getAttribute(Anime::ATTRIBUTE_YEAR)) + ->sortBy(fn (int $year) => $year) + ->unique() + ->values() + ->toArray(); + + $response = $this->graphQL(' { animeyears } '); - $response->assertJson([ - 'data' => [ - 'animeyears' => $years, - ], - ]); - } -} + $response->assertJson([ + 'data' => [ + 'animeyears' => $years, + ], + ]); +}); diff --git a/tests/Feature/Http/Admin/DumpTest.php b/tests/Feature/Http/Admin/DumpTest.php index 464e75787..1ef1d1f00 100644 --- a/tests/Feature/Http/Admin/DumpTest.php +++ b/tests/Feature/Http/Admin/DumpTest.php @@ -2,100 +2,77 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Admin; - use App\Constants\Config\DumpConstants; use App\Enums\Auth\SpecialPermission; use App\Features\AllowDumpDownloading; use App\Models\Admin\Dump; use App\Models\Auth\User; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Http\Testing\File; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Storage; use Laravel\Pennant\Feature; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class DumpTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * If dump downloading is disabled through the Allow Dump Downloading feature, - * the user shall receive a forbidden exception. - */ - public function testDumpDownloadingNotAllowedForbidden(): void - { - Feature::deactivate(AllowDumpDownloading::class); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $dump = Dump::factory()->createOne(); +test('dump downloading not allowed forbidden', function () { + Feature::deactivate(AllowDumpDownloading::class); - $response = $this->get(route('dump.show', ['dump' => $dump])); + $dump = Dump::factory()->createOne(); - $response->assertForbidden(); - } + $response = get(route('dump.show', ['dump' => $dump])); - /** - * Unsafe dumps shall be forbidden. - */ - public function testDumpDownloadingForbiddenForUnsafeDumps(): void - { - Feature::activate(AllowDumpDownloading::class); + $response->assertForbidden(); +}); - $dump = Dump::factory() - ->unsafe() - ->createOne(); +test('dump downloading forbidden for unsafe dumps', function () { + Feature::activate(AllowDumpDownloading::class); - $response = $this->get(route('dump.show', ['dump' => $dump])); + $dump = Dump::factory() + ->unsafe() + ->createOne(); - $response->assertForbidden(); - } + $response = get(route('dump.show', ['dump' => $dump])); - /** - * Users with the bypass feature flag permission shall be permitted to download dumps - * even if the Allow Dump Downloading feature is disabled. - */ - public function testVideoStreamingPermittedForBypass(): void - { - Feature::activate(AllowDumpDownloading::class, $this->faker->boolean()); + $response->assertForbidden(); +}); - $fs = Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); - $filename = Dump::factory()->makeOne()->path.'.sql'; - $file = File::fake()->create($filename); - $fsFile = $fs->putFileAs('', $file, $filename); +test('video streaming permitted for bypass', function () { + Feature::activate(AllowDumpDownloading::class, fake()->boolean()); - $dump = Dump::factory()->createOne([ - Dump::ATTRIBUTE_PATH => $fsFile, - ]); + $fs = Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); + $filename = Dump::factory()->makeOne()->path.'.sql'; + $file = File::fake()->create($filename); + $fsFile = $fs->putFileAs('', $file, $filename); - $user = User::factory()->withPermissions(SpecialPermission::BYPASS_FEATURE_FLAGS->value)->createOne(); + $dump = Dump::factory()->createOne([ + Dump::ATTRIBUTE_PATH => $fsFile, + ]); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(SpecialPermission::BYPASS_FEATURE_FLAGS->value)->createOne(); - $response = $this->get(route('dump.show', ['dump' => $dump])); + Sanctum::actingAs($user); - $response->assertDownload($dump->path); - } + $response = get(route('dump.show', ['dump' => $dump])); - /** - * If dump downloading is enabled, the dump is downloaded from storage through the response. - */ - public function testDownloadedThroughResponse(): void - { - Feature::activate(AllowDumpDownloading::class); + $response->assertDownload($dump->path); +}); - $fs = Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); - $filename = Dump::factory()->makeOne()->path.'.sql'; - $file = File::fake()->create($filename); - $fsFile = $fs->putFileAs('', $file, $filename); +test('downloaded through response', function () { + Feature::activate(AllowDumpDownloading::class); - $dump = Dump::factory()->createOne([ - Dump::ATTRIBUTE_PATH => $fsFile, - ]); + $fs = Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); + $filename = Dump::factory()->makeOne()->path.'.sql'; + $file = File::fake()->create($filename); + $fsFile = $fs->putFileAs('', $file, $filename); - $response = $this->get(route('dump.show', ['dump' => $dump])); + $dump = Dump::factory()->createOne([ + Dump::ATTRIBUTE_PATH => $fsFile, + ]); - $response->assertDownload($dump->path); - } -} + $response = get(route('dump.show', ['dump' => $dump])); + + $response->assertDownload($dump->path); +}); diff --git a/tests/Feature/Http/Admin/LatestDocumentDumpTest.php b/tests/Feature/Http/Admin/LatestDocumentDumpTest.php index 7816939fa..d10ca6464 100644 --- a/tests/Feature/Http/Admin/LatestDocumentDumpTest.php +++ b/tests/Feature/Http/Admin/LatestDocumentDumpTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Admin; - use App\Actions\Storage\Admin\Dump\DumpDocumentAction; use App\Actions\Storage\Admin\Dump\DumpWikiAction; use App\Constants\Config\DumpConstants; @@ -11,8 +9,6 @@ use App\Enums\Auth\SpecialPermission; use App\Features\AllowDumpDownloading; use App\Models\Admin\Dump; use App\Models\Auth\User; -use Exception; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Http\Testing\File; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Config; @@ -20,150 +16,124 @@ use Illuminate\Support\Facades\Storage; use Illuminate\Support\Str; use Laravel\Pennant\Feature; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class LatestDocumentDumpTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * If dump downloading is disabled through the Allow Dump Downloading feature, - * the user shall receive a forbidden exception. - * - * @throws Exception - */ - public function testDumpDownloadingNotAllowedForbidden(): void - { - Storage::fake('local'); - Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); +uses(Illuminate\Foundation\Testing\WithFaker::class); - Feature::deactivate(AllowDumpDownloading::class); +test('dump downloading not allowed forbidden', function () { + Storage::fake('local'); + Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); + Feature::deactivate(AllowDumpDownloading::class); + + $action = new DumpWikiAction(); + + $action->handle(); + + $response = get(route('dump.latest.document.show')); + + $response->assertForbidden(); +}); + +test('video streaming permitted for bypass', function () { + Storage::fake('local'); + $fs = Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); + + Feature::activate(AllowDumpDownloading::class, fake()->boolean()); + + Collection::times(fake()->randomDigitNotNull(), function () { $action = new DumpWikiAction(); $action->handle(); + }); - $response = $this->get(route('dump.latest.document.show')); + Collection::times(fake()->randomDigitNotNull(), function () { + $action = new DumpDocumentAction(); - $response->assertForbidden(); - } + $action->handle(); + }); - /** - * Users with the bypass feature flag permission shall be permitted to download the latest document dump - * even if the Allow Dump Downloading feature is disabled. - */ - public function testVideoStreamingPermittedForBypass(): void - { - Storage::fake('local'); - $fs = Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); + $path = Str::of(DumpDocumentAction::FILENAME_PREFIX) + ->append(fake()->word()) + ->append('.sql') + ->__toString(); - Feature::activate(AllowDumpDownloading::class, $this->faker->boolean()); + $file = File::fake()->create($path); + $fsFile = $fs->putFileAs('', $file, $path); - Collection::times($this->faker->randomDigitNotNull(), function () { - $action = new DumpWikiAction(); + $dump = Dump::factory()->createOne([ + Dump::ATTRIBUTE_PATH => $fsFile, + ]); - $action->handle(); - }); + $user = User::factory()->withPermissions(SpecialPermission::BYPASS_FEATURE_FLAGS->value)->createOne(); - Collection::times($this->faker->randomDigitNotNull(), function () { - $action = new DumpDocumentAction(); + Sanctum::actingAs($user); - $action->handle(); - }); + $response = get(route('dump.latest.document.show')); - $path = Str::of(DumpDocumentAction::FILENAME_PREFIX) - ->append($this->faker->word()) - ->append('.sql') - ->__toString(); + $response->assertDownload($dump->path); +}); - $file = File::fake()->create($path); - $fsFile = $fs->putFileAs('', $file, $path); +test('not found if no document dumps', function () { + Storage::fake('local'); + Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); - $dump = Dump::factory()->createOne([ - Dump::ATTRIBUTE_PATH => $fsFile, - ]); + Feature::activate(AllowDumpDownloading::class); - $user = User::factory()->withPermissions(SpecialPermission::BYPASS_FEATURE_FLAGS->value)->createOne(); + $response = get(route('dump.latest.document.show')); - Sanctum::actingAs($user); + $response->assertNotFound(); +}); - $response = $this->get(route('dump.latest.document.show')); +test('not found if wiki dumps exist', function () { + Storage::fake('local'); + Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); - $response->assertDownload($dump->path); - } + Feature::activate(AllowDumpDownloading::class); - /** - * If no dumps exist, the user shall receive a not found error. - */ - public function testNotFoundIfNoDocumentDumps(): void - { - Storage::fake('local'); - Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); + Collection::times(fake()->randomDigitNotNull(), function () { + $action = new DumpWikiAction(); - Feature::activate(AllowDumpDownloading::class); + $action->handle(); + }); - $response = $this->get(route('dump.latest.document.show')); + $response = get(route('dump.latest.document.show')); - $response->assertNotFound(); - } + $response->assertNotFound(); +}); - /** - * If no document dumps exist, the user shall receive a not found error. - */ - public function testNotFoundIfWikiDumpsExist(): void - { - Storage::fake('local'); - Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); +test('latest document dump downloaded', function () { + Storage::fake('local'); + $fs = Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); - Feature::activate(AllowDumpDownloading::class); + Feature::activate(AllowDumpDownloading::class); - Collection::times($this->faker->randomDigitNotNull(), function () { - $action = new DumpWikiAction(); + Collection::times(fake()->randomDigitNotNull(), function () { + $action = new DumpWikiAction(); - $action->handle(); - }); + $action->handle(); + }); - $response = $this->get(route('dump.latest.document.show')); + Collection::times(fake()->randomDigitNotNull(), function () { + $action = new DumpDocumentAction(); - $response->assertNotFound(); - } + $action->handle(); + }); - /** - * If document dumps exist, the latest document dump is downloaded from storage through the response. - */ - public function testLatestDocumentDumpDownloaded(): void - { - Storage::fake('local'); - $fs = Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); + $path = Str::of(DumpDocumentAction::FILENAME_PREFIX) + ->append(fake()->word()) + ->append('.sql') + ->__toString(); - Feature::activate(AllowDumpDownloading::class); + $file = File::fake()->create($path); + $fsFile = $fs->putFileAs('', $file, $path); - Collection::times($this->faker->randomDigitNotNull(), function () { - $action = new DumpWikiAction(); + $dump = Dump::factory()->createOne([ + Dump::ATTRIBUTE_PATH => $fsFile, + ]); - $action->handle(); - }); + $response = get(route('dump.latest.document.show')); - Collection::times($this->faker->randomDigitNotNull(), function () { - $action = new DumpDocumentAction(); - - $action->handle(); - }); - - $path = Str::of(DumpDocumentAction::FILENAME_PREFIX) - ->append($this->faker->word()) - ->append('.sql') - ->__toString(); - - $file = File::fake()->create($path); - $fsFile = $fs->putFileAs('', $file, $path); - - $dump = Dump::factory()->createOne([ - Dump::ATTRIBUTE_PATH => $fsFile, - ]); - - $response = $this->get(route('dump.latest.document.show')); - - $response->assertDownload($dump->path); - } -} + $response->assertDownload($dump->path); +}); diff --git a/tests/Feature/Http/Admin/LatestWikiDumpTest.php b/tests/Feature/Http/Admin/LatestWikiDumpTest.php index 843327151..58401fa07 100644 --- a/tests/Feature/Http/Admin/LatestWikiDumpTest.php +++ b/tests/Feature/Http/Admin/LatestWikiDumpTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Admin; - use App\Actions\Storage\Admin\Dump\DumpDocumentAction; use App\Actions\Storage\Admin\Dump\DumpWikiAction; use App\Constants\Config\DumpConstants; @@ -11,8 +9,6 @@ use App\Enums\Auth\SpecialPermission; use App\Features\AllowDumpDownloading; use App\Models\Admin\Dump; use App\Models\Auth\User; -use Exception; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Http\Testing\File; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Config; @@ -20,150 +16,124 @@ use Illuminate\Support\Facades\Storage; use Illuminate\Support\Str; use Laravel\Pennant\Feature; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class LatestWikiDumpTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * If dump downloading is disabled through the Allow Dump Downloading feature, - * the user shall receive a forbidden exception. - * - * @throws Exception - */ - public function testDumpDownloadingNotAllowedForbidden(): void - { - Storage::fake('local'); - Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); +uses(Illuminate\Foundation\Testing\WithFaker::class); - Feature::deactivate(AllowDumpDownloading::class); +test('dump downloading not allowed forbidden', function () { + Storage::fake('local'); + Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); + Feature::deactivate(AllowDumpDownloading::class); + + $action = new DumpWikiAction(); + + $action->handle(); + + $response = get(route('dump.latest.wiki.show')); + + $response->assertForbidden(); +}); + +test('video streaming permitted for bypass', function () { + Storage::fake('local'); + $fs = Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); + + Feature::activate(AllowDumpDownloading::class, fake()->boolean()); + + Collection::times(fake()->randomDigitNotNull(), function () { + $action = new DumpDocumentAction(); + + $action->handle(); + }); + + Collection::times(fake()->randomDigitNotNull(), function () { $action = new DumpWikiAction(); $action->handle(); + }); - $response = $this->get(route('dump.latest.wiki.show')); + $path = Str::of(DumpWikiAction::FILENAME_PREFIX) + ->append(fake()->word()) + ->append('.sql') + ->__toString(); - $response->assertForbidden(); - } + $file = File::fake()->create($path); + $fsFile = $fs->putFileAs('', $file, $path); - /** - * Users with the bypass feature flag permission shall be permitted to download the latest wiki dump - * even if the Allow Dump Downloading feature is disabled. - */ - public function testVideoStreamingPermittedForBypass(): void - { - Storage::fake('local'); - $fs = Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); + $dump = Dump::factory()->createOne([ + Dump::ATTRIBUTE_PATH => $fsFile, + ]); - Feature::activate(AllowDumpDownloading::class, $this->faker->boolean()); + $user = User::factory()->withPermissions(SpecialPermission::BYPASS_FEATURE_FLAGS->value)->createOne(); - Collection::times($this->faker->randomDigitNotNull(), function () { - $action = new DumpDocumentAction(); + Sanctum::actingAs($user); - $action->handle(); - }); + $response = get(route('dump.latest.wiki.show')); - Collection::times($this->faker->randomDigitNotNull(), function () { - $action = new DumpWikiAction(); + $response->assertDownload($dump->path); +}); - $action->handle(); - }); +test('not found if no wiki dumps', function () { + Storage::fake('local'); + Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); - $path = Str::of(DumpWikiAction::FILENAME_PREFIX) - ->append($this->faker->word()) - ->append('.sql') - ->__toString(); + Feature::activate(AllowDumpDownloading::class); - $file = File::fake()->create($path); - $fsFile = $fs->putFileAs('', $file, $path); + $response = get(route('dump.latest.wiki.show')); - $dump = Dump::factory()->createOne([ - Dump::ATTRIBUTE_PATH => $fsFile, - ]); + $response->assertNotFound(); +}); - $user = User::factory()->withPermissions(SpecialPermission::BYPASS_FEATURE_FLAGS->value)->createOne(); +test('not found if document dumps exist', function () { + Storage::fake('local'); + Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); - Sanctum::actingAs($user); + Feature::activate(AllowDumpDownloading::class); - $response = $this->get(route('dump.latest.wiki.show')); + Collection::times(fake()->randomDigitNotNull(), function () { + $action = new DumpDocumentAction(); - $response->assertDownload($dump->path); - } + $action->handle(); + }); - /** - * If no dumps exist, the user shall receive a not found error. - */ - public function testNotFoundIfNoWikiDumps(): void - { - Storage::fake('local'); - Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); + $response = get(route('dump.latest.wiki.show')); - Feature::activate(AllowDumpDownloading::class); + $response->assertNotFound(); +}); - $response = $this->get(route('dump.latest.wiki.show')); +test('latest wiki dump downloaded', function () { + Storage::fake('local'); + $fs = Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); - $response->assertNotFound(); - } + Feature::activate(AllowDumpDownloading::class); - /** - * If no wiki dumps exist, the user shall receive a not found error. - */ - public function testNotFoundIfDocumentDumpsExist(): void - { - Storage::fake('local'); - Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); + Collection::times(fake()->randomDigitNotNull(), function () { + $action = new DumpDocumentAction(); - Feature::activate(AllowDumpDownloading::class); + $action->handle(); + }); - Collection::times($this->faker->randomDigitNotNull(), function () { - $action = new DumpDocumentAction(); + Collection::times(fake()->randomDigitNotNull(), function () { + $action = new DumpWikiAction(); - $action->handle(); - }); + $action->handle(); + }); - $response = $this->get(route('dump.latest.wiki.show')); + $path = Str::of(DumpWikiAction::FILENAME_PREFIX) + ->append(fake()->word()) + ->append('.sql') + ->__toString(); - $response->assertNotFound(); - } + $file = File::fake()->create($path); + $fsFile = $fs->putFileAs('', $file, $path); - /** - * If wiki dumps exist, the latest wiki dump is downloaded from storage through the response. - */ - public function testLatestWikiDumpDownloaded(): void - { - Storage::fake('local'); - $fs = Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED)); + $dump = Dump::factory()->createOne([ + Dump::ATTRIBUTE_PATH => $fsFile, + ]); - Feature::activate(AllowDumpDownloading::class); + $response = get(route('dump.latest.wiki.show')); - Collection::times($this->faker->randomDigitNotNull(), function () { - $action = new DumpDocumentAction(); - - $action->handle(); - }); - - Collection::times($this->faker->randomDigitNotNull(), function () { - $action = new DumpWikiAction(); - - $action->handle(); - }); - - $path = Str::of(DumpWikiAction::FILENAME_PREFIX) - ->append($this->faker->word()) - ->append('.sql') - ->__toString(); - - $file = File::fake()->create($path); - $fsFile = $fs->putFileAs('', $file, $path); - - $dump = Dump::factory()->createOne([ - Dump::ATTRIBUTE_PATH => $fsFile, - ]); - - $response = $this->get(route('dump.latest.wiki.show')); - - $response->assertDownload($dump->path); - } -} + $response->assertDownload($dump->path); +}); diff --git a/tests/Feature/Http/Api/Admin/Announcement/AnnouncementDestroyTest.php b/tests/Feature/Http/Api/Admin/Announcement/AnnouncementDestroyTest.php index 2c39d741d..3af68ed8b 100644 --- a/tests/Feature/Http/Api/Admin/Announcement/AnnouncementDestroyTest.php +++ b/tests/Feature/Http/Api/Admin/Announcement/AnnouncementDestroyTest.php @@ -2,58 +2,42 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Admin\Announcement; - use App\Enums\Auth\CrudPermission; use App\Models\Admin\Announcement; use App\Models\Auth\User; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class AnnouncementDestroyTest extends TestCase -{ - /** - * The Announcement Destroy Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $announcement = Announcement::factory()->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.announcement.destroy', ['announcement' => $announcement])); +test('protected', function () { + $announcement = Announcement::factory()->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.announcement.destroy', ['announcement' => $announcement])); - /** - * The Announcement Destroy Endpoint shall forbid users without the delete announcement permission. - */ - public function testForbidden(): void - { - $announcement = Announcement::factory()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $announcement = Announcement::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.announcement.destroy', ['announcement' => $announcement])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.announcement.destroy', ['announcement' => $announcement])); - /** - * The Announcement Destroy Endpoint shall delete the announcement. - */ - public function testDeleted(): void - { - $announcement = Announcement::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Announcement::class))->createOne(); +test('deleted', function () { + $announcement = Announcement::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Announcement::class))->createOne(); - $response = $this->delete(route('api.announcement.destroy', ['announcement' => $announcement])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertModelMissing($announcement); - } -} + $response = delete(route('api.announcement.destroy', ['announcement' => $announcement])); + + $response->assertOk(); + $this->assertModelMissing($announcement); +}); diff --git a/tests/Feature/Http/Api/Admin/Announcement/AnnouncementIndexTest.php b/tests/Feature/Http/Api/Admin/Announcement/AnnouncementIndexTest.php index b2fedd9fe..728e0b37d 100644 --- a/tests/Feature/Http/Api/Admin/Announcement/AnnouncementIndexTest.php +++ b/tests/Feature/Http/Api/Admin/Announcement/AnnouncementIndexTest.php @@ -2,9 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Admin\Announcement; - -use App\Concerns\Actions\Http\Api\SortsModels; use App\Contracts\Http\Api\Field\SortableField; use App\Enums\Http\Api\Sort\Direction; use App\Http\Api\Criteria\Paging\Criteria; @@ -21,230 +18,200 @@ use App\Http\Resources\Admin\Collection\AnnouncementCollection; use App\Http\Resources\Admin\Resource\AnnouncementResource; use App\Models\Admin\Announcement; use App\Models\BaseModel; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; -use Tests\TestCase; -class AnnouncementIndexTest extends TestCase -{ - use SortsModels; - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the Announcement Index Endpoint shall return a collection of Announcement Resources. - */ - public function testDefault(): void - { - $announcements = Announcement::factory()->count($this->faker->randomDigitNotNull())->create(); +uses(App\Concerns\Actions\Http\Api\SortsModels::class); - $response = $this->get(route('api.announcement.index')); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response->assertJson( - json_decode( - json_encode( - new AnnouncementCollection($announcements, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } +test('default', function () { + $announcements = Announcement::factory()->count(fake()->randomDigitNotNull())->create(); - /** - * The Announcement Index Endpoint shall return a collection of public Announcement Resources. - */ - public function testPrivate(): void - { - Announcement::factory() - ->private() - ->count($this->faker->randomDigitNotNull()) - ->create(); + $response = get(route('api.announcement.index')); - $announcements = Announcement::factory() - ->count($this->faker->randomDigitNotNull()) - ->create(); + $response->assertJson( + json_decode( + json_encode( + new AnnouncementCollection($announcements, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $response = $this->get(route('api.announcement.index')); +test('private', function () { + Announcement::factory() + ->private() + ->count(fake()->randomDigitNotNull()) + ->create(); - $response->assertJson( - json_decode( - json_encode( - new AnnouncementCollection($announcements, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $announcements = Announcement::factory() + ->count(fake()->randomDigitNotNull()) + ->create(); - /** - * The Announcement Index Endpoint shall be paginated. - */ - public function testPaginated(): void - { - Announcement::factory()->count($this->faker->randomDigitNotNull())->create(); + $response = get(route('api.announcement.index')); - $response = $this->get(route('api.announcement.index')); + $response->assertJson( + json_decode( + json_encode( + new AnnouncementCollection($announcements, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $response->assertJsonStructure([ - AnnouncementCollection::$wrap, - 'links', - 'meta', - ]); - } +test('paginated', function () { + Announcement::factory()->count(fake()->randomDigitNotNull())->create(); - /** - * The Announcement Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new AnnouncementSchema(); + $response = get(route('api.announcement.index')); - $fields = collect($schema->fields()); + $response->assertJsonStructure([ + AnnouncementCollection::$wrap, + 'links', + 'meta', + ]); +}); - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); +test('sparse fieldsets', function () { + $schema = new AnnouncementSchema(); - $parameters = [ - FieldParser::param() => [ - AnnouncementResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; + $fields = collect($schema->fields()); - $announcements = Announcement::factory()->count($this->faker->randomDigitNotNull())->create(); + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); - $response = $this->get(route('api.announcement.index', $parameters)); + $parameters = [ + FieldParser::param() => [ + AnnouncementResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; - $response->assertJson( - json_decode( - json_encode( - new AnnouncementCollection($announcements, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $announcements = Announcement::factory()->count(fake()->randomDigitNotNull())->create(); - /** - * The Announcement Index Endpoint shall support sorting resources. - */ - public function testSorts(): void - { - $schema = new AnnouncementSchema(); + $response = get(route('api.announcement.index', $parameters)); - /** @var Sort $sort */ - $sort = collect($schema->fields()) - ->filter(fn (Field $field) => $field instanceof SortableField) - ->map(fn (SortableField $field) => $field->getSort()) - ->random(); + $response->assertJson( + json_decode( + json_encode( + new AnnouncementCollection($announcements, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - SortParser::param() => $sort->format(Arr::random(Direction::cases())), - ]; +test('sorts', function () { + $schema = new AnnouncementSchema(); - $query = new Query($parameters); + /** @var Sort $sort */ + $sort = collect($schema->fields()) + ->filter(fn (Field $field) => $field instanceof SortableField) + ->map(fn (SortableField $field) => $field->getSort()) + ->random(); - Announcement::factory()->count($this->faker->randomDigitNotNull())->create(); + $parameters = [ + SortParser::param() => $sort->format(Arr::random(Direction::cases())), + ]; - $response = $this->get(route('api.announcement.index', $parameters)); + $query = new Query($parameters); - $announcements = $this->sort(Announcement::query(), $query, $schema)->get(); + Announcement::factory()->count(fake()->randomDigitNotNull())->create(); - $response->assertJson( - json_decode( - json_encode( - new AnnouncementCollection($announcements, $query) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.announcement.index', $parameters)); - /** - * The Announcement Index Endpoint shall support filtering by created_at. - */ - public function testCreatedAtFilter(): void - { - $createdFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); + $announcements = $this->sort(Announcement::query(), $query, $schema)->get(); - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; + $response->assertJson( + json_decode( + json_encode( + new AnnouncementCollection($announcements, $query) + ->response() + ->getData() + ), + true + ) + ); +}); - Carbon::withTestNow($createdFilter, function () { - Announcement::factory()->count($this->faker->randomDigitNotNull())->create(); - }); +test('created at filter', function () { + $createdFilter = fake()->date(); + $excludedDate = fake()->date(); - Carbon::withTestNow($excludedDate, function () { - Announcement::factory()->count($this->faker->randomDigitNotNull())->create(); - }); + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; - $announcement = Announcement::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); + Carbon::withTestNow($createdFilter, function () { + Announcement::factory()->count(fake()->randomDigitNotNull())->create(); + }); - $response = $this->get(route('api.announcement.index', $parameters)); + Carbon::withTestNow($excludedDate, function () { + Announcement::factory()->count(fake()->randomDigitNotNull())->create(); + }); - $response->assertJson( - json_decode( - json_encode( - new AnnouncementCollection($announcement, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $announcement = Announcement::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - /** - * The Announcement Index Endpoint shall support filtering by updated_at. - */ - public function testUpdatedAtFilter(): void - { - $updatedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); + $response = get(route('api.announcement.index', $parameters)); - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; + $response->assertJson( + json_decode( + json_encode( + new AnnouncementCollection($announcement, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - Carbon::withTestNow($updatedFilter, function () { - Announcement::factory()->count($this->faker->randomDigitNotNull())->create(); - }); +test('updated at filter', function () { + $updatedFilter = fake()->date(); + $excludedDate = fake()->date(); - Carbon::withTestNow($excludedDate, function () { - Announcement::factory()->count($this->faker->randomDigitNotNull())->create(); - }); + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; - $announcement = Announcement::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); + Carbon::withTestNow($updatedFilter, function () { + Announcement::factory()->count(fake()->randomDigitNotNull())->create(); + }); - $response = $this->get(route('api.announcement.index', $parameters)); + Carbon::withTestNow($excludedDate, function () { + Announcement::factory()->count(fake()->randomDigitNotNull())->create(); + }); - $response->assertJson( - json_decode( - json_encode( - new AnnouncementCollection($announcement, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $announcement = Announcement::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); + + $response = get(route('api.announcement.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnnouncementCollection($announcement, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Admin/Announcement/AnnouncementShowTest.php b/tests/Feature/Http/Api/Admin/Announcement/AnnouncementShowTest.php index 0b381161a..fde8c7e69 100644 --- a/tests/Feature/Http/Api/Admin/Announcement/AnnouncementShowTest.php +++ b/tests/Feature/Http/Api/Admin/Announcement/AnnouncementShowTest.php @@ -2,84 +2,67 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Admin\Announcement; - use App\Http\Api\Field\Field; use App\Http\Api\Parser\FieldParser; use App\Http\Api\Query\Query; use App\Http\Api\Schema\Admin\AnnouncementSchema; use App\Http\Resources\Admin\Resource\AnnouncementResource; use App\Models\Admin\Announcement; -use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; -class AnnouncementShowTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the Announcement Show Endpoint shall return an Announcement Resource. - */ - public function testDefault(): void - { - $announcement = Announcement::factory()->create(); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response = $this->get(route('api.announcement.show', ['announcement' => $announcement])); +test('default', function () { + $announcement = Announcement::factory()->create(); - $response->assertJson( - json_decode( - json_encode( - new AnnouncementResource($announcement, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.announcement.show', ['announcement' => $announcement])); - /** - * The Announcement Show Endpoint shall forbid access to a private announcement. - */ - public function testCannotViewPrivate(): void - { - $announcement = Announcement::factory()->private()->create(); + $response->assertJson( + json_decode( + json_encode( + new AnnouncementResource($announcement, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $response = $this->get(route('api.announcement.show', ['announcement' => $announcement])); +test('cannot view private', function () { + $announcement = Announcement::factory()->private()->create(); - $response->assertForbidden(); - } + $response = get(route('api.announcement.show', ['announcement' => $announcement])); - /** - * The Announcement Show Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new AnnouncementSchema(); + $response->assertForbidden(); +}); - $fields = collect($schema->fields()); +test('sparse fieldsets', function () { + $schema = new AnnouncementSchema(); - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); + $fields = collect($schema->fields()); - $parameters = [ - FieldParser::param() => [ - AnnouncementResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); - $announcement = Announcement::factory()->create(); + $parameters = [ + FieldParser::param() => [ + AnnouncementResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; - $response = $this->get(route('api.announcement.show', ['announcement' => $announcement] + $parameters)); + $announcement = Announcement::factory()->create(); - $response->assertJson( - json_decode( - json_encode( - new AnnouncementResource($announcement, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response = get(route('api.announcement.show', ['announcement' => $announcement] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnnouncementResource($announcement, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Admin/Announcement/AnnouncementStoreTest.php b/tests/Feature/Http/Api/Admin/Announcement/AnnouncementStoreTest.php index 1896d701c..d3afd6cf8 100644 --- a/tests/Feature/Http/Api/Admin/Announcement/AnnouncementStoreTest.php +++ b/tests/Feature/Http/Api/Admin/Announcement/AnnouncementStoreTest.php @@ -2,74 +2,54 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Admin\Announcement; - use App\Enums\Auth\CrudPermission; use App\Models\Admin\Announcement; use App\Models\Auth\User; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class AnnouncementStoreTest extends TestCase -{ - /** - * The Announcement Store Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $announcement = Announcement::factory()->makeOne(); +use function Pest\Laravel\post; - $response = $this->post(route('api.announcement.store', $announcement->toArray())); +test('protected', function () { + $announcement = Announcement::factory()->makeOne(); - $response->assertUnauthorized(); - } + $response = post(route('api.announcement.store', $announcement->toArray())); - /** - * The Announcement Store Endpoint shall forbid users without the create announcement permission. - */ - public function testForbidden(): void - { - $announcement = Announcement::factory()->makeOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $announcement = Announcement::factory()->makeOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->post(route('api.announcement.store', $announcement->toArray())); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.announcement.store', $announcement->toArray())); - /** - * The Announcement Store Endpoint shall require the content field. - */ - public function testRequiredFields(): void - { - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Announcement::class))->createOne(); + $response->assertForbidden(); +}); - Sanctum::actingAs($user); +test('required fields', function () { + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Announcement::class))->createOne(); - $response = $this->post(route('api.announcement.store')); + Sanctum::actingAs($user); - $response->assertJsonValidationErrors([ - Announcement::ATTRIBUTE_CONTENT, - ]); - } + $response = post(route('api.announcement.store')); - /** - * The Announcement Store Endpoint shall create an announcement. - */ - public function testCreate(): void - { - $parameters = Announcement::factory()->raw(); + $response->assertJsonValidationErrors([ + Announcement::ATTRIBUTE_CONTENT, + ]); +}); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Announcement::class))->createOne(); +test('create', function () { + $parameters = Announcement::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Announcement::class))->createOne(); - $response = $this->post(route('api.announcement.store', $parameters)); + Sanctum::actingAs($user); - $response->assertCreated(); - static::assertDatabaseCount(Announcement::class, 1); - } -} + $response = post(route('api.announcement.store', $parameters)); + + $response->assertCreated(); + $this->assertDatabaseCount(Announcement::class, 1); +}); diff --git a/tests/Feature/Http/Api/Admin/Announcement/AnnouncementUpdateTest.php b/tests/Feature/Http/Api/Admin/Announcement/AnnouncementUpdateTest.php index b6c5d7aef..d05008565 100644 --- a/tests/Feature/Http/Api/Admin/Announcement/AnnouncementUpdateTest.php +++ b/tests/Feature/Http/Api/Admin/Announcement/AnnouncementUpdateTest.php @@ -2,63 +2,47 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Admin\Announcement; - use App\Enums\Auth\CrudPermission; use App\Models\Admin\Announcement; use App\Models\Auth\User; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class AnnouncementUpdateTest extends TestCase -{ - /** - * The Announcement Update Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $announcement = Announcement::factory()->createOne(); +use function Pest\Laravel\put; - $parameters = Announcement::factory()->raw(); +test('protected', function () { + $announcement = Announcement::factory()->createOne(); - $response = $this->put(route('api.announcement.update', ['announcement' => $announcement] + $parameters)); + $parameters = Announcement::factory()->raw(); - $response->assertUnauthorized(); - } + $response = put(route('api.announcement.update', ['announcement' => $announcement] + $parameters)); - /** - * The Announcement Update Endpoint shall forbid users without the update announcement permission. - */ - public function testForbidden(): void - { - $announcement = Announcement::factory()->createOne(); + $response->assertUnauthorized(); +}); - $parameters = Announcement::factory()->raw(); +test('forbidden', function () { + $announcement = Announcement::factory()->createOne(); - $user = User::factory()->createOne(); + $parameters = Announcement::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->put(route('api.announcement.update', ['announcement' => $announcement] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.announcement.update', ['announcement' => $announcement] + $parameters)); - /** - * The Announcement Update Endpoint shall update an announcement. - */ - public function testUpdate(): void - { - $announcement = Announcement::factory()->createOne(); + $response->assertForbidden(); +}); - $parameters = Announcement::factory()->raw(); +test('update', function () { + $announcement = Announcement::factory()->createOne(); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Announcement::class))->createOne(); + $parameters = Announcement::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Announcement::class))->createOne(); - $response = $this->put(route('api.announcement.update', ['announcement' => $announcement] + $parameters)); + Sanctum::actingAs($user); - $response->assertOk(); - } -} + $response = put(route('api.announcement.update', ['announcement' => $announcement] + $parameters)); + + $response->assertOk(); +}); diff --git a/tests/Feature/Http/Api/Admin/Dump/DumpDestroyTest.php b/tests/Feature/Http/Api/Admin/Dump/DumpDestroyTest.php index 54e03dfce..09f6d860e 100644 --- a/tests/Feature/Http/Api/Admin/Dump/DumpDestroyTest.php +++ b/tests/Feature/Http/Api/Admin/Dump/DumpDestroyTest.php @@ -2,58 +2,42 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Admin\Dump; - use App\Enums\Auth\CrudPermission; use App\Models\Admin\Dump; use App\Models\Auth\User; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class DumpDestroyTest extends TestCase -{ - /** - * The Dump Destroy Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $dump = Dump::factory()->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.dump.destroy', ['dump' => $dump])); +test('protected', function () { + $dump = Dump::factory()->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.dump.destroy', ['dump' => $dump])); - /** - * The Dump Destroy Endpoint shall forbid users without the delete dump permission. - */ - public function testForbidden(): void - { - $dump = Dump::factory()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $dump = Dump::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.dump.destroy', ['dump' => $dump])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.dump.destroy', ['dump' => $dump])); - /** - * The Dump Destroy Endpoint shall delete the dump. - */ - public function testDeleted(): void - { - $dump = Dump::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Dump::class))->createOne(); +test('deleted', function () { + $dump = Dump::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Dump::class))->createOne(); - $response = $this->delete(route('api.dump.destroy', ['dump' => $dump])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertModelMissing($dump); - } -} + $response = delete(route('api.dump.destroy', ['dump' => $dump])); + + $response->assertOk(); + $this->assertModelMissing($dump); +}); diff --git a/tests/Feature/Http/Api/Admin/Dump/DumpIndexTest.php b/tests/Feature/Http/Api/Admin/Dump/DumpIndexTest.php index 3a208fedd..749d4cc88 100644 --- a/tests/Feature/Http/Api/Admin/Dump/DumpIndexTest.php +++ b/tests/Feature/Http/Api/Admin/Dump/DumpIndexTest.php @@ -2,9 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Admin\Dump; - -use App\Concerns\Actions\Http\Api\SortsModels; use App\Contracts\Http\Api\Field\SortableField; use App\Enums\Http\Api\Sort\Direction; use App\Http\Api\Criteria\Paging\Criteria; @@ -21,230 +18,200 @@ use App\Http\Resources\Admin\Collection\DumpCollection; use App\Http\Resources\Admin\Resource\DumpResource; use App\Models\Admin\Dump; use App\Models\BaseModel; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; -use Tests\TestCase; -class DumpIndexTest extends TestCase -{ - use SortsModels; - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the Dump Index Endpoint shall return a collection of Dump Resources. - */ - public function testDefault(): void - { - $dumps = Dump::factory()->count($this->faker->randomDigitNotNull())->create(); +uses(App\Concerns\Actions\Http\Api\SortsModels::class); - $response = $this->get(route('api.dump.index')); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response->assertJson( - json_decode( - json_encode( - new DumpCollection($dumps, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } +test('default', function () { + $dumps = Dump::factory()->count(fake()->randomDigitNotNull())->create(); - /** - * The Dump Index Endpoint shall return a collection of safe Dump Resources. - */ - public function testUnsafe(): void - { - Dump::factory() - ->unsafe() - ->count($this->faker->randomDigitNotNull()) - ->create(); + $response = get(route('api.dump.index')); - $dumps = Dump::factory() - ->count($this->faker->randomDigitNotNull()) - ->create(); + $response->assertJson( + json_decode( + json_encode( + new DumpCollection($dumps, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $response = $this->get(route('api.dump.index')); +test('unsafe', function () { + Dump::factory() + ->unsafe() + ->count(fake()->randomDigitNotNull()) + ->create(); - $response->assertJson( - json_decode( - json_encode( - new DumpCollection($dumps, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $dumps = Dump::factory() + ->count(fake()->randomDigitNotNull()) + ->create(); - /** - * The Dump Index Endpoint shall be paginated. - */ - public function testPaginated(): void - { - Dump::factory()->count($this->faker->randomDigitNotNull())->create(); + $response = get(route('api.dump.index')); - $response = $this->get(route('api.dump.index')); + $response->assertJson( + json_decode( + json_encode( + new DumpCollection($dumps, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $response->assertJsonStructure([ - DumpCollection::$wrap, - 'links', - 'meta', - ]); - } +test('paginated', function () { + Dump::factory()->count(fake()->randomDigitNotNull())->create(); - /** - * The Dump Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new DumpSchema(); + $response = get(route('api.dump.index')); - $fields = collect($schema->fields()); + $response->assertJsonStructure([ + DumpCollection::$wrap, + 'links', + 'meta', + ]); +}); - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); +test('sparse fieldsets', function () { + $schema = new DumpSchema(); - $parameters = [ - FieldParser::param() => [ - DumpResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; + $fields = collect($schema->fields()); - $dumps = Dump::factory()->count($this->faker->randomDigitNotNull())->create(); + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); - $response = $this->get(route('api.dump.index', $parameters)); + $parameters = [ + FieldParser::param() => [ + DumpResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; - $response->assertJson( - json_decode( - json_encode( - new DumpCollection($dumps, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $dumps = Dump::factory()->count(fake()->randomDigitNotNull())->create(); - /** - * The Dump Index Endpoint shall support sorting resources. - */ - public function testSorts(): void - { - $schema = new DumpSchema(); + $response = get(route('api.dump.index', $parameters)); - /** @var Sort $sort */ - $sort = collect($schema->fields()) - ->filter(fn (Field $field) => $field instanceof SortableField) - ->map(fn (SortableField $field) => $field->getSort()) - ->random(); + $response->assertJson( + json_decode( + json_encode( + new DumpCollection($dumps, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - SortParser::param() => $sort->format(Arr::random(Direction::cases())), - ]; +test('sorts', function () { + $schema = new DumpSchema(); - $query = new Query($parameters); + /** @var Sort $sort */ + $sort = collect($schema->fields()) + ->filter(fn (Field $field) => $field instanceof SortableField) + ->map(fn (SortableField $field) => $field->getSort()) + ->random(); - Dump::factory()->count($this->faker->randomDigitNotNull())->create(); + $parameters = [ + SortParser::param() => $sort->format(Arr::random(Direction::cases())), + ]; - $response = $this->get(route('api.dump.index', $parameters)); + $query = new Query($parameters); - $dumps = $this->sort(Dump::query(), $query, $schema)->get(); + Dump::factory()->count(fake()->randomDigitNotNull())->create(); - $response->assertJson( - json_decode( - json_encode( - new DumpCollection($dumps, $query) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.dump.index', $parameters)); - /** - * The Dump Index Endpoint shall support filtering by created_at. - */ - public function testCreatedAtFilter(): void - { - $createdFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); + $dumps = $this->sort(Dump::query(), $query, $schema)->get(); - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; + $response->assertJson( + json_decode( + json_encode( + new DumpCollection($dumps, $query) + ->response() + ->getData() + ), + true + ) + ); +}); - Carbon::withTestNow($createdFilter, function () { - Dump::factory()->count($this->faker->randomDigitNotNull())->create(); - }); +test('created at filter', function () { + $createdFilter = fake()->date(); + $excludedDate = fake()->date(); - Carbon::withTestNow($excludedDate, function () { - Dump::factory()->count($this->faker->randomDigitNotNull())->create(); - }); + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; - $dump = Dump::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); + Carbon::withTestNow($createdFilter, function () { + Dump::factory()->count(fake()->randomDigitNotNull())->create(); + }); - $response = $this->get(route('api.dump.index', $parameters)); + Carbon::withTestNow($excludedDate, function () { + Dump::factory()->count(fake()->randomDigitNotNull())->create(); + }); - $response->assertJson( - json_decode( - json_encode( - new DumpCollection($dump, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $dump = Dump::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - /** - * The Dump Index Endpoint shall support filtering by updated_at. - */ - public function testUpdatedAtFilter(): void - { - $updatedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); + $response = get(route('api.dump.index', $parameters)); - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; + $response->assertJson( + json_decode( + json_encode( + new DumpCollection($dump, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - Carbon::withTestNow($updatedFilter, function () { - Dump::factory()->count($this->faker->randomDigitNotNull())->create(); - }); +test('updated at filter', function () { + $updatedFilter = fake()->date(); + $excludedDate = fake()->date(); - Carbon::withTestNow($excludedDate, function () { - Dump::factory()->count($this->faker->randomDigitNotNull())->create(); - }); + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; - $dump = Dump::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); + Carbon::withTestNow($updatedFilter, function () { + Dump::factory()->count(fake()->randomDigitNotNull())->create(); + }); - $response = $this->get(route('api.dump.index', $parameters)); + Carbon::withTestNow($excludedDate, function () { + Dump::factory()->count(fake()->randomDigitNotNull())->create(); + }); - $response->assertJson( - json_decode( - json_encode( - new DumpCollection($dump, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $dump = Dump::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); + + $response = get(route('api.dump.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new DumpCollection($dump, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Admin/Dump/DumpShowTest.php b/tests/Feature/Http/Api/Admin/Dump/DumpShowTest.php index e09c07741..ed05ef8d6 100644 --- a/tests/Feature/Http/Api/Admin/Dump/DumpShowTest.php +++ b/tests/Feature/Http/Api/Admin/Dump/DumpShowTest.php @@ -2,84 +2,67 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Admin\Dump; - use App\Http\Api\Field\Field; use App\Http\Api\Parser\FieldParser; use App\Http\Api\Query\Query; use App\Http\Api\Schema\Admin\DumpSchema; use App\Http\Resources\Admin\Resource\DumpResource; use App\Models\Admin\Dump; -use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; -class DumpShowTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the Dump Show Endpoint shall return a Dump Resource. - */ - public function testDefault(): void - { - $dump = Dump::factory()->create(); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response = $this->get(route('api.dump.show', ['dump' => $dump])); +test('default', function () { + $dump = Dump::factory()->create(); - $response->assertJson( - json_decode( - json_encode( - new DumpResource($dump, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.dump.show', ['dump' => $dump])); - /** - * The Dump Show Endpoint shall forbid access to an unsafe dump. - */ - public function testCannotViewUnsafe(): void - { - $dump = Dump::factory()->unsafe()->create(); + $response->assertJson( + json_decode( + json_encode( + new DumpResource($dump, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $response = $this->get(route('api.dump.show', ['dump' => $dump])); +test('cannot view unsafe', function () { + $dump = Dump::factory()->unsafe()->create(); - $response->assertForbidden(); - } + $response = get(route('api.dump.show', ['dump' => $dump])); - /** - * The Dump Show Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new DumpSchema(); + $response->assertForbidden(); +}); - $fields = collect($schema->fields()); +test('sparse fieldsets', function () { + $schema = new DumpSchema(); - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); + $fields = collect($schema->fields()); - $parameters = [ - FieldParser::param() => [ - DumpResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); - $dump = Dump::factory()->create(); + $parameters = [ + FieldParser::param() => [ + DumpResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; - $response = $this->get(route('api.dump.show', ['dump' => $dump] + $parameters)); + $dump = Dump::factory()->create(); - $response->assertJson( - json_decode( - json_encode( - new DumpResource($dump, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response = get(route('api.dump.show', ['dump' => $dump] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new DumpResource($dump, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Admin/Dump/DumpStoreTest.php b/tests/Feature/Http/Api/Admin/Dump/DumpStoreTest.php index 063ed2fb8..fff0cbe93 100644 --- a/tests/Feature/Http/Api/Admin/Dump/DumpStoreTest.php +++ b/tests/Feature/Http/Api/Admin/Dump/DumpStoreTest.php @@ -2,74 +2,54 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Admin\Dump; - use App\Enums\Auth\CrudPermission; use App\Models\Admin\Dump; use App\Models\Auth\User; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class DumpStoreTest extends TestCase -{ - /** - * The Dump Store Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $dump = Dump::factory()->makeOne(); +use function Pest\Laravel\post; - $response = $this->post(route('api.dump.store', $dump->toArray())); +test('protected', function () { + $dump = Dump::factory()->makeOne(); - $response->assertUnauthorized(); - } + $response = post(route('api.dump.store', $dump->toArray())); - /** - * The Dump Store Endpoint shall forbid users without the create dump permission. - */ - public function testForbidden(): void - { - $dump = Dump::factory()->makeOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $dump = Dump::factory()->makeOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->post(route('api.dump.store', $dump->toArray())); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.dump.store', $dump->toArray())); - /** - * The Dump Store Endpoint shall require the path field. - */ - public function testRequiredFields(): void - { - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Dump::class))->createOne(); + $response->assertForbidden(); +}); - Sanctum::actingAs($user); +test('required fields', function () { + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Dump::class))->createOne(); - $response = $this->post(route('api.dump.store')); + Sanctum::actingAs($user); - $response->assertJsonValidationErrors([ - Dump::ATTRIBUTE_PATH, - ]); - } + $response = post(route('api.dump.store')); - /** - * The Dump Store Endpoint shall create a dump. - */ - public function testCreate(): void - { - $parameters = Dump::factory()->raw(); + $response->assertJsonValidationErrors([ + Dump::ATTRIBUTE_PATH, + ]); +}); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Dump::class))->createOne(); +test('create', function () { + $parameters = Dump::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Dump::class))->createOne(); - $response = $this->post(route('api.dump.store', $parameters)); + Sanctum::actingAs($user); - $response->assertCreated(); - static::assertDatabaseCount(Dump::class, 1); - } -} + $response = post(route('api.dump.store', $parameters)); + + $response->assertCreated(); + $this->assertDatabaseCount(Dump::class, 1); +}); diff --git a/tests/Feature/Http/Api/Admin/Dump/DumpUpdateTest.php b/tests/Feature/Http/Api/Admin/Dump/DumpUpdateTest.php index 420e674df..499dd43f0 100644 --- a/tests/Feature/Http/Api/Admin/Dump/DumpUpdateTest.php +++ b/tests/Feature/Http/Api/Admin/Dump/DumpUpdateTest.php @@ -2,63 +2,47 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Admin\Dump; - use App\Enums\Auth\CrudPermission; use App\Models\Admin\Dump; use App\Models\Auth\User; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class DumpUpdateTest extends TestCase -{ - /** - * The Dump Update Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $dump = Dump::factory()->createOne(); +use function Pest\Laravel\put; - $parameters = Dump::factory()->raw(); +test('protected', function () { + $dump = Dump::factory()->createOne(); - $response = $this->put(route('api.dump.update', ['dump' => $dump] + $parameters)); + $parameters = Dump::factory()->raw(); - $response->assertUnauthorized(); - } + $response = put(route('api.dump.update', ['dump' => $dump] + $parameters)); - /** - * The Dump Update Endpoint shall forbid users without the update dump permission. - */ - public function testForbidden(): void - { - $dump = Dump::factory()->createOne(); + $response->assertUnauthorized(); +}); - $parameters = Dump::factory()->raw(); +test('forbidden', function () { + $dump = Dump::factory()->createOne(); - $user = User::factory()->createOne(); + $parameters = Dump::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->put(route('api.dump.update', ['dump' => $dump] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.dump.update', ['dump' => $dump] + $parameters)); - /** - * The Dump Update Endpoint shall update a dump. - */ - public function testUpdate(): void - { - $dump = Dump::factory()->createOne(); + $response->assertForbidden(); +}); - $parameters = Dump::factory()->raw(); +test('update', function () { + $dump = Dump::factory()->createOne(); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Dump::class))->createOne(); + $parameters = Dump::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Dump::class))->createOne(); - $response = $this->put(route('api.dump.update', ['dump' => $dump] + $parameters)); + Sanctum::actingAs($user); - $response->assertOk(); - } -} + $response = put(route('api.dump.update', ['dump' => $dump] + $parameters)); + + $response->assertOk(); +}); diff --git a/tests/Feature/Http/Api/Admin/Feature/FeatureIndexTest.php b/tests/Feature/Http/Api/Admin/Feature/FeatureIndexTest.php index 2db007e63..4f6a75db5 100644 --- a/tests/Feature/Http/Api/Admin/Feature/FeatureIndexTest.php +++ b/tests/Feature/Http/Api/Admin/Feature/FeatureIndexTest.php @@ -2,9 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Admin\Feature; - -use App\Concerns\Actions\Http\Api\SortsModels; use App\Contracts\Http\Api\Field\SortableField; use App\Enums\Http\Api\Sort\Direction; use App\Http\Api\Criteria\Paging\Criteria; @@ -21,236 +18,206 @@ use App\Http\Resources\Admin\Collection\FeatureCollection; use App\Http\Resources\Admin\Resource\FeatureResource; use App\Models\Admin\Feature; use App\Models\BaseModel; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; use Illuminate\Support\Collection; -use Tests\TestCase; -class FeatureIndexTest extends TestCase -{ - use SortsModels; - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the Feature Index Endpoint shall return a collection of Feature Resources. - */ - public function testDefault(): void - { - $features = Feature::factory()->count($this->faker->randomDigitNotNull())->create(); +uses(App\Concerns\Actions\Http\Api\SortsModels::class); - $response = $this->get(route('api.feature.index')); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response->assertJson( - json_decode( - json_encode( - new FeatureCollection($features, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } +test('default', function () { + $features = Feature::factory()->count(fake()->randomDigitNotNull())->create(); - /** - * The Feature Show Endpoint shall list features of nonnull scope. - */ - public function testNonNullForbidden(): void - { - $nullScopeCount = $this->faker->randomDigitNotNull(); + $response = get(route('api.feature.index')); - $features = Feature::factory() - ->count($nullScopeCount) - ->create(); + $response->assertJson( + json_decode( + json_encode( + new FeatureCollection($features, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - Collection::times($this->faker->randomDigitNotNull(), function () { - Feature::factory()->create([ - Feature::ATTRIBUTE_SCOPE => $this->faker->word(), - ]); - }); +test('non null forbidden', function () { + $nullScopeCount = fake()->randomDigitNotNull(); - $response = $this->get(route('api.feature.index')); + $features = Feature::factory() + ->count($nullScopeCount) + ->create(); - $response->assertJsonCount($nullScopeCount, FeatureCollection::$wrap); - - $response->assertJson( - json_decode( - json_encode( - new FeatureCollection($features, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Feature Index Endpoint shall be paginated. - */ - public function testPaginated(): void - { - Feature::factory()->count($this->faker->randomDigitNotNull())->create(); - - $response = $this->get(route('api.feature.index')); - - $response->assertJsonStructure([ - FeatureCollection::$wrap, - 'links', - 'meta', + Collection::times(fake()->randomDigitNotNull(), function () { + Feature::factory()->create([ + Feature::ATTRIBUTE_SCOPE => fake()->word(), ]); - } + }); - /** - * The Feature Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new FeatureSchema(); + $response = get(route('api.feature.index')); - $fields = collect($schema->fields()); + $response->assertJsonCount($nullScopeCount, FeatureCollection::$wrap); - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); + $response->assertJson( + json_decode( + json_encode( + new FeatureCollection($features, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FieldParser::param() => [ - FeatureResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; +test('paginated', function () { + Feature::factory()->count(fake()->randomDigitNotNull())->create(); - $features = Feature::factory()->count($this->faker->randomDigitNotNull())->create(); + $response = get(route('api.feature.index')); - $response = $this->get(route('api.feature.index', $parameters)); + $response->assertJsonStructure([ + FeatureCollection::$wrap, + 'links', + 'meta', + ]); +}); - $response->assertJson( - json_decode( - json_encode( - new FeatureCollection($features, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } +test('sparse fieldsets', function () { + $schema = new FeatureSchema(); - /** - * The Feature Index Endpoint shall support sorting resources. - */ - public function testSorts(): void - { - $schema = new FeatureSchema(); + $fields = collect($schema->fields()); - /** @var Sort $sort */ - $sort = collect($schema->fields()) - ->filter(fn (Field $field) => $field instanceof SortableField) - ->map(fn (SortableField $field) => $field->getSort()) - ->random(); + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); - $parameters = [ - SortParser::param() => $sort->format(Arr::random(Direction::cases())), - ]; + $parameters = [ + FieldParser::param() => [ + FeatureResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; - $query = new Query($parameters); + $features = Feature::factory()->count(fake()->randomDigitNotNull())->create(); - Feature::factory()->count($this->faker->randomDigitNotNull())->create(); + $response = get(route('api.feature.index', $parameters)); - $response = $this->get(route('api.feature.index', $parameters)); + $response->assertJson( + json_decode( + json_encode( + new FeatureCollection($features, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $features = $this->sort(Feature::query(), $query, $schema)->get(); +test('sorts', function () { + $schema = new FeatureSchema(); - $response->assertJson( - json_decode( - json_encode( - new FeatureCollection($features, $query) - ->response() - ->getData() - ), - true - ) - ); - } + /** @var Sort $sort */ + $sort = collect($schema->fields()) + ->filter(fn (Field $field) => $field instanceof SortableField) + ->map(fn (SortableField $field) => $field->getSort()) + ->random(); - /** - * The Feature Index Endpoint shall support filtering by created_at. - */ - public function testCreatedAtFilter(): void - { - $createdFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); + $parameters = [ + SortParser::param() => $sort->format(Arr::random(Direction::cases())), + ]; - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; + $query = new Query($parameters); - Carbon::withTestNow($createdFilter, function () { - Feature::factory()->count($this->faker->randomDigitNotNull())->create(); - }); + Feature::factory()->count(fake()->randomDigitNotNull())->create(); - Carbon::withTestNow($excludedDate, function () { - Feature::factory()->count($this->faker->randomDigitNotNull())->create(); - }); + $response = get(route('api.feature.index', $parameters)); - $feature = Feature::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); + $features = $this->sort(Feature::query(), $query, $schema)->get(); - $response = $this->get(route('api.feature.index', $parameters)); + $response->assertJson( + json_decode( + json_encode( + new FeatureCollection($features, $query) + ->response() + ->getData() + ), + true + ) + ); +}); - $response->assertJson( - json_decode( - json_encode( - new FeatureCollection($feature, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } +test('created at filter', function () { + $createdFilter = fake()->date(); + $excludedDate = fake()->date(); - /** - * The Feature Index Endpoint shall support filtering by updated_at. - */ - public function testUpdatedAtFilter(): void - { - $updatedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; + Carbon::withTestNow($createdFilter, function () { + Feature::factory()->count(fake()->randomDigitNotNull())->create(); + }); - Carbon::withTestNow($updatedFilter, function () { - Feature::factory()->count($this->faker->randomDigitNotNull())->create(); - }); + Carbon::withTestNow($excludedDate, function () { + Feature::factory()->count(fake()->randomDigitNotNull())->create(); + }); - Carbon::withTestNow($excludedDate, function () { - Feature::factory()->count($this->faker->randomDigitNotNull())->create(); - }); + $feature = Feature::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - $feature = Feature::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); + $response = get(route('api.feature.index', $parameters)); - $response = $this->get(route('api.feature.index', $parameters)); + $response->assertJson( + json_decode( + json_encode( + new FeatureCollection($feature, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $response->assertJson( - json_decode( - json_encode( - new FeatureCollection($feature, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} +test('updated at filter', function () { + $updatedFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($updatedFilter, function () { + Feature::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + Carbon::withTestNow($excludedDate, function () { + Feature::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + $feature = Feature::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); + + $response = get(route('api.feature.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new FeatureCollection($feature, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Admin/Feature/FeatureShowTest.php b/tests/Feature/Http/Api/Admin/Feature/FeatureShowTest.php index 3302303d0..7746e81de 100644 --- a/tests/Feature/Http/Api/Admin/Feature/FeatureShowTest.php +++ b/tests/Feature/Http/Api/Admin/Feature/FeatureShowTest.php @@ -2,86 +2,69 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Admin\Feature; - use App\Http\Api\Field\Field; use App\Http\Api\Parser\FieldParser; use App\Http\Api\Query\Query; use App\Http\Api\Schema\Admin\FeatureSchema; use App\Http\Resources\Admin\Resource\FeatureResource; use App\Models\Admin\Feature; -use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; -class FeatureShowTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the Feature Show Endpoint shall return a Feature Resource. - */ - public function testDefault(): void - { - $feature = Feature::factory()->create(); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response = $this->get(route('api.feature.show', ['feature' => $feature])); +test('default', function () { + $feature = Feature::factory()->create(); - $response->assertJson( - json_decode( - json_encode( - new FeatureResource($feature, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.feature.show', ['feature' => $feature])); - /** - * The Feature Show Endpoint shall forbid showing features of nonnull scope. - */ - public function testNonNullForbidden(): void - { - $feature = Feature::factory()->create([ - Feature::ATTRIBUTE_SCOPE => $this->faker->word(), - ]); + $response->assertJson( + json_decode( + json_encode( + new FeatureResource($feature, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $response = $this->get(route('api.feature.show', ['feature' => $feature])); +test('non null forbidden', function () { + $feature = Feature::factory()->create([ + Feature::ATTRIBUTE_SCOPE => fake()->word(), + ]); - $response->assertForbidden(); - } + $response = get(route('api.feature.show', ['feature' => $feature])); - /** - * The Feature Show Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new FeatureSchema(); + $response->assertForbidden(); +}); - $fields = collect($schema->fields()); +test('sparse fieldsets', function () { + $schema = new FeatureSchema(); - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); + $fields = collect($schema->fields()); - $parameters = [ - FieldParser::param() => [ - FeatureResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); - $feature = Feature::factory()->create(); + $parameters = [ + FieldParser::param() => [ + FeatureResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; - $response = $this->get(route('api.feature.show', ['feature' => $feature] + $parameters)); + $feature = Feature::factory()->create(); - $response->assertJson( - json_decode( - json_encode( - new FeatureResource($feature, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response = get(route('api.feature.show', ['feature' => $feature] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new FeatureResource($feature, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Admin/Feature/FeatureUpdateTest.php b/tests/Feature/Http/Api/Admin/Feature/FeatureUpdateTest.php index b71261b91..abe096237 100644 --- a/tests/Feature/Http/Api/Admin/Feature/FeatureUpdateTest.php +++ b/tests/Feature/Http/Api/Admin/Feature/FeatureUpdateTest.php @@ -2,69 +2,53 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Admin\Feature; - use App\Enums\Auth\CrudPermission; use App\Models\Admin\Feature; use App\Models\Auth\User; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class FeatureUpdateTest extends TestCase -{ - /** - * The Feature Update Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $feature = Feature::factory()->createOne(); +use function Pest\Laravel\put; - $parameters = [ - Feature::ATTRIBUTE_VALUE => ! $feature->value, - ]; +test('protected', function () { + $feature = Feature::factory()->createOne(); - $response = $this->put(route('api.feature.update', ['feature' => $feature] + $parameters)); + $parameters = [ + Feature::ATTRIBUTE_VALUE => ! $feature->value, + ]; - $response->assertUnauthorized(); - } + $response = put(route('api.feature.update', ['feature' => $feature] + $parameters)); - /** - * The Feature Update Endpoint shall forbid users without the update feature permission. - */ - public function testForbidden(): void - { - $feature = Feature::factory()->createOne(); + $response->assertUnauthorized(); +}); - $parameters = [ - Feature::ATTRIBUTE_VALUE => ! $feature->value, - ]; +test('forbidden', function () { + $feature = Feature::factory()->createOne(); - $user = User::factory()->createOne(); + $parameters = [ + Feature::ATTRIBUTE_VALUE => ! $feature->value, + ]; - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->put(route('api.feature.update', ['feature' => $feature] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.feature.update', ['feature' => $feature] + $parameters)); - /** - * The Feature Update Endpoint shall update a feature. - */ - public function testUpdate(): void - { - $feature = Feature::factory()->createOne(); + $response->assertForbidden(); +}); - $parameters = [ - Feature::ATTRIBUTE_VALUE => ! $feature->value, - ]; +test('update', function () { + $feature = Feature::factory()->createOne(); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Feature::class))->createOne(); + $parameters = [ + Feature::ATTRIBUTE_VALUE => ! $feature->value, + ]; - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Feature::class))->createOne(); - $response = $this->put(route('api.feature.update', ['feature' => $feature] + $parameters)); + Sanctum::actingAs($user); - $response->assertOk(); - } -} + $response = put(route('api.feature.update', ['feature' => $feature] + $parameters)); + + $response->assertOk(); +}); diff --git a/tests/Feature/Http/Api/Admin/FeaturedTheme/CurrentFeaturedThemeShowTest.php b/tests/Feature/Http/Api/Admin/FeaturedTheme/CurrentFeaturedThemeShowTest.php index a6b9b0655..56be69a3b 100644 --- a/tests/Feature/Http/Api/Admin/FeaturedTheme/CurrentFeaturedThemeShowTest.php +++ b/tests/Feature/Http/Api/Admin/FeaturedTheme/CurrentFeaturedThemeShowTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Admin\FeaturedTheme; - use App\Http\Api\Field\Field; use App\Http\Api\Include\AllowedInclude; use App\Http\Api\Parser\FieldParser; @@ -20,199 +18,164 @@ use App\Models\Wiki\Artist; use App\Models\Wiki\Image; use App\Models\Wiki\Song; use App\Models\Wiki\Video; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Collection; -use Tests\TestCase; -class CurrentFeaturedThemeShowTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * The Current Featured Theme Show Endpoint shall return a Not Found exception if there are no featured themes. - */ - public function testNotFoundIfNoFeaturedThemes(): void - { - $response = $this->get(route('api.featuredtheme.current.show')); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response->assertNotFound(); - } +test('not found if no featured themes', function () { + $response = get(route('api.featuredtheme.current.show')); - /** - * The Current Featured Theme Show Endpoint shall return a Not Found exception if the featured theme has no start date. - */ - public function testNotFoundIfThemeStartAtNull(): void - { + $response->assertNotFound(); +}); + +test('not found if theme start at null', function () { + FeaturedTheme::factory()->create([ + FeaturedTheme::ATTRIBUTE_START_AT => null, + ]); + + $response = get(route('api.featuredtheme.current.show')); + + $response->assertNotFound(); +}); + +test('not found if theme end at null', function () { + FeaturedTheme::factory()->create([ + FeaturedTheme::ATTRIBUTE_END_AT => null, + ]); + + $response = get(route('api.featuredtheme.current.show')); + + $response->assertNotFound(); +}); + +test('not found if theme start at after now', function () { + FeaturedTheme::factory()->create([ + FeaturedTheme::ATTRIBUTE_START_AT => fake()->dateTimeBetween('+1 day', '+1 year'), + ]); + + $response = get(route('api.featuredtheme.current.show')); + + $response->assertNotFound(); +}); + +test('not found if theme end at before now', function () { + FeaturedTheme::factory()->create([ + FeaturedTheme::ATTRIBUTE_END_AT => fake()->dateTimeBetween(), + ]); + + $response = get(route('api.featuredtheme.current.show')); + + $response->assertNotFound(); +}); + +test('default', function () { + Collection::times(fake()->randomDigitNotNull(), function () { FeaturedTheme::factory()->create([ FeaturedTheme::ATTRIBUTE_START_AT => null, ]); + }); - $response = $this->get(route('api.featuredtheme.current.show')); - - $response->assertNotFound(); - } - - /** - * The Current Featured Theme Show Endpoint shall return a Not Found exception if the featured theme has no end date. - */ - public function testNotFoundIfThemeEndAtNull(): void - { + Collection::times(fake()->randomDigitNotNull(), function () { FeaturedTheme::factory()->create([ FeaturedTheme::ATTRIBUTE_END_AT => null, ]); + }); - $response = $this->get(route('api.featuredtheme.current.show')); - - $response->assertNotFound(); - } - - /** - * The Current Featured Theme Show Endpoint shall return a Not Found exception if the featured theme starts after today. - */ - public function testNotFoundIfThemeStartAtAfterNow(): void - { + Collection::times(fake()->randomDigitNotNull(), function () { FeaturedTheme::factory()->create([ - FeaturedTheme::ATTRIBUTE_START_AT => $this->faker->dateTimeBetween('+1 day', '+1 year'), + FeaturedTheme::ATTRIBUTE_START_AT => fake()->dateTimeBetween('+1 day', '+1 year'), ]); + }); - $response = $this->get(route('api.featuredtheme.current.show')); - - $response->assertNotFound(); - } - - /** - * The Current Featured Theme Show Endpoint shall return a Not Found exception if the featured theme ends before today. - */ - public function testNotFoundIfThemeEndAtBeforeNow(): void - { + Collection::times(fake()->randomDigitNotNull(), function () { FeaturedTheme::factory()->create([ - FeaturedTheme::ATTRIBUTE_END_AT => $this->faker->dateTimeBetween(), + FeaturedTheme::ATTRIBUTE_END_AT => fake()->dateTimeBetween('-1 year', '-1 day'), ]); + }); - $response = $this->get(route('api.featuredtheme.current.show')); + $currentTheme = FeaturedTheme::factory()->create(); - $response->assertNotFound(); - } + $response = get(route('api.featuredtheme.current.show')); - /** - * By default, the Current Featured Theme Show Endpoint shall return a Featured Theme Resource. - */ - public function testDefault(): void - { - Collection::times($this->faker->randomDigitNotNull(), function () { - FeaturedTheme::factory()->create([ - FeaturedTheme::ATTRIBUTE_START_AT => null, - ]); - }); + $response->assertJson( + json_decode( + json_encode( + new FeaturedThemeResource($currentTheme, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - Collection::times($this->faker->randomDigitNotNull(), function () { - FeaturedTheme::factory()->create([ - FeaturedTheme::ATTRIBUTE_END_AT => null, - ]); - }); +test('allowed include paths', function () { + $schema = new FeaturedThemeSchema(); - Collection::times($this->faker->randomDigitNotNull(), function () { - FeaturedTheme::factory()->create([ - FeaturedTheme::ATTRIBUTE_START_AT => $this->faker->dateTimeBetween('+1 day', '+1 year'), - ]); - }); + $allowedIncludes = collect($schema->allowedIncludes()); - Collection::times($this->faker->randomDigitNotNull(), function () { - FeaturedTheme::factory()->create([ - FeaturedTheme::ATTRIBUTE_END_AT => $this->faker->dateTimeBetween('-1 year', '-1 day'), - ]); - }); + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); - $currentTheme = FeaturedTheme::factory()->create(); + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - $response = $this->get(route('api.featuredtheme.current.show')); + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; - $response->assertJson( - json_decode( - json_encode( - new FeaturedThemeResource($currentTheme, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $currentTheme = FeaturedTheme::factory() + ->for( + AnimeThemeEntry::factory() + ->for( + AnimeTheme::factory() + ->for(Anime::factory()->has(Image::factory()->count(fake()->randomDigitNotNull()))) + ->for(Song::factory()->has(Artist::factory()->count(fake()->randomDigitNotNull()))) + ) + ) + ->for(Video::factory()) + ->for(User::factory()) + ->createOne(); - /** - * The Featured Theme Show Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new FeaturedThemeSchema(); + $response = get(route('api.featuredtheme.current.show', $parameters)); - $allowedIncludes = collect($schema->allowedIncludes()); + $response->assertJson( + json_decode( + json_encode( + new FeaturedThemeResource($currentTheme, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); +test('sparse fieldsets', function () { + $schema = new FeaturedThemeSchema(); - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + $fields = collect($schema->fields()); - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); - $currentTheme = FeaturedTheme::factory() - ->for( - AnimeThemeEntry::factory() - ->for( - AnimeTheme::factory() - ->for(Anime::factory()->has(Image::factory()->count($this->faker->randomDigitNotNull()))) - ->for(Song::factory()->has(Artist::factory()->count($this->faker->randomDigitNotNull()))) - ) - ) - ->for(Video::factory()) - ->for(User::factory()) - ->createOne(); + $parameters = [ + FieldParser::param() => [ + FeaturedThemeResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; - $response = $this->get(route('api.featuredtheme.current.show', $parameters)); + $currentTheme = FeaturedTheme::factory()->create(); - $response->assertJson( - json_decode( - json_encode( - new FeaturedThemeResource($currentTheme, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.featuredtheme.current.show', $parameters)); - /** - * The Current Featured Theme Show Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new FeaturedThemeSchema(); - - $fields = collect($schema->fields()); - - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); - - $parameters = [ - FieldParser::param() => [ - FeaturedThemeResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; - - $currentTheme = FeaturedTheme::factory()->create(); - - $response = $this->get(route('api.featuredtheme.current.show', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new FeaturedThemeResource($currentTheme, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response->assertJson( + json_decode( + json_encode( + new FeaturedThemeResource($currentTheme, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Admin/FeaturedTheme/FeaturedThemeDestroyTest.php b/tests/Feature/Http/Api/Admin/FeaturedTheme/FeaturedThemeDestroyTest.php index 7910e774f..9f86a0524 100644 --- a/tests/Feature/Http/Api/Admin/FeaturedTheme/FeaturedThemeDestroyTest.php +++ b/tests/Feature/Http/Api/Admin/FeaturedTheme/FeaturedThemeDestroyTest.php @@ -2,58 +2,42 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Admin\FeaturedTheme; - use App\Enums\Auth\CrudPermission; use App\Models\Admin\FeaturedTheme; use App\Models\Auth\User; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class FeaturedThemeDestroyTest extends TestCase -{ - /** - * The Featured Theme Destroy Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $featuredTheme = FeaturedTheme::factory()->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.featuredtheme.destroy', ['featuredtheme' => $featuredTheme])); +test('protected', function () { + $featuredTheme = FeaturedTheme::factory()->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.featuredtheme.destroy', ['featuredtheme' => $featuredTheme])); - /** - * The Featured Theme Destroy Endpoint shall forbid users without the delete featured theme permission. - */ - public function testForbidden(): void - { - $featuredTheme = FeaturedTheme::factory()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $featuredTheme = FeaturedTheme::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.featuredtheme.destroy', ['featuredtheme' => $featuredTheme])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.featuredtheme.destroy', ['featuredtheme' => $featuredTheme])); - /** - * The FeaturedTheme Destroy Endpoint shall delete the featured theme. - */ - public function testDeleted(): void - { - $featuredTheme = FeaturedTheme::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(FeaturedTheme::class))->createOne(); +test('deleted', function () { + $featuredTheme = FeaturedTheme::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(FeaturedTheme::class))->createOne(); - $response = $this->delete(route('api.featuredtheme.destroy', ['featuredtheme' => $featuredTheme])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertModelMissing($featuredTheme); - } -} + $response = delete(route('api.featuredtheme.destroy', ['featuredtheme' => $featuredTheme])); + + $response->assertOk(); + $this->assertModelMissing($featuredTheme); +}); diff --git a/tests/Feature/Http/Api/Admin/FeaturedTheme/FeaturedThemeIndexTest.php b/tests/Feature/Http/Api/Admin/FeaturedTheme/FeaturedThemeIndexTest.php index 940c74078..6b59718da 100644 --- a/tests/Feature/Http/Api/Admin/FeaturedTheme/FeaturedThemeIndexTest.php +++ b/tests/Feature/Http/Api/Admin/FeaturedTheme/FeaturedThemeIndexTest.php @@ -2,9 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Admin\FeaturedTheme; - -use App\Concerns\Actions\Http\Api\SortsModels; use App\Contracts\Http\Api\Field\SortableField; use App\Enums\Http\Api\Sort\Direction; use App\Http\Api\Criteria\Paging\Criteria; @@ -31,266 +28,236 @@ use App\Models\Wiki\Artist; use App\Models\Wiki\Image; use App\Models\Wiki\Song; use App\Models\Wiki\Video; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; use Illuminate\Support\Collection; -use Tests\TestCase; -class FeaturedThemeIndexTest extends TestCase -{ - use SortsModels; - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the Featured Theme Index Endpoint shall return a collection of Featured Theme Resources. - */ - public function testDefault(): void - { - $publicCount = $this->faker->randomDigitNotNull(); +uses(App\Concerns\Actions\Http\Api\SortsModels::class); - $featuredThemes = FeaturedTheme::factory()->count($publicCount)->create(); +uses(Illuminate\Foundation\Testing\WithFaker::class); - Collection::times($this->faker->randomDigitNotNull(), function () { - FeaturedTheme::factory()->create([ - FeaturedTheme::ATTRIBUTE_START_AT => $this->faker->dateTimeBetween('+1 day', '+1 year'), - ]); - }); +test('default', function () { + $publicCount = fake()->randomDigitNotNull(); - Collection::times($this->faker->randomDigitNotNull(), function () { - FeaturedTheme::factory()->create([ - FeaturedTheme::ATTRIBUTE_START_AT => null, - ]); - }); + $featuredThemes = FeaturedTheme::factory()->count($publicCount)->create(); - $response = $this->get(route('api.featuredtheme.index')); - - $response->assertJsonCount($publicCount, FeaturedThemeCollection::$wrap); - - $response->assertJson( - json_decode( - json_encode( - new FeaturedThemeCollection($featuredThemes, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Featured Theme Index Endpoint shall be paginated. - */ - public function testPaginated(): void - { - FeaturedTheme::factory()->count($this->faker->randomDigitNotNull())->create(); - - $response = $this->get(route('api.featuredtheme.index')); - - $response->assertJsonStructure([ - FeaturedThemeCollection::$wrap, - 'links', - 'meta', + Collection::times(fake()->randomDigitNotNull(), function () { + FeaturedTheme::factory()->create([ + FeaturedTheme::ATTRIBUTE_START_AT => fake()->dateTimeBetween('+1 day', '+1 year'), ]); - } + }); - /** - * The Featured Theme Index Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new FeaturedThemeSchema(); + Collection::times(fake()->randomDigitNotNull(), function () { + FeaturedTheme::factory()->create([ + FeaturedTheme::ATTRIBUTE_START_AT => null, + ]); + }); - $allowedIncludes = collect($schema->allowedIncludes()); + $response = get(route('api.featuredtheme.index')); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $response->assertJsonCount($publicCount, FeaturedThemeCollection::$wrap); - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + $response->assertJson( + json_decode( + json_encode( + new FeaturedThemeCollection($featuredThemes, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; +test('paginated', function () { + FeaturedTheme::factory()->count(fake()->randomDigitNotNull())->create(); - FeaturedTheme::factory() - ->for( - AnimeThemeEntry::factory() - ->for( - AnimeTheme::factory() - ->for(Anime::factory()->has(Image::factory()->count($this->faker->randomDigitNotNull()))) - ->for(Song::factory()->has(Artist::factory()->count($this->faker->randomDigitNotNull()))) - ) - ) - ->for(Video::factory()) - ->for(User::factory()) - ->count($this->faker->randomDigitNotNull()) - ->create(); + $response = get(route('api.featuredtheme.index')); - $featuredThemes = FeaturedTheme::with($includedPaths->all())->get(); + $response->assertJsonStructure([ + FeaturedThemeCollection::$wrap, + 'links', + 'meta', + ]); +}); - $response = $this->get(route('api.featuredtheme.index', $parameters)); +test('allowed include paths', function () { + $schema = new FeaturedThemeSchema(); - $response->assertJson( - json_decode( - json_encode( - new FeaturedThemeCollection($featuredThemes, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $allowedIncludes = collect($schema->allowedIncludes()); - /** - * The Featured Theme Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new FeaturedThemeSchema(); + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); - $fields = collect($schema->fields()); + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; - $parameters = [ - FieldParser::param() => [ - FeaturedThemeResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; + FeaturedTheme::factory() + ->for( + AnimeThemeEntry::factory() + ->for( + AnimeTheme::factory() + ->for(Anime::factory()->has(Image::factory()->count(fake()->randomDigitNotNull()))) + ->for(Song::factory()->has(Artist::factory()->count(fake()->randomDigitNotNull()))) + ) + ) + ->for(Video::factory()) + ->for(User::factory()) + ->count(fake()->randomDigitNotNull()) + ->create(); - $featuredThemes = FeaturedTheme::factory()->count($this->faker->randomDigitNotNull())->create(); + $featuredThemes = FeaturedTheme::with($includedPaths->all())->get(); - $response = $this->get(route('api.featuredtheme.index', $parameters)); + $response = get(route('api.featuredtheme.index', $parameters)); - $response->assertJson( - json_decode( - json_encode( - new FeaturedThemeCollection($featuredThemes, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response->assertJson( + json_decode( + json_encode( + new FeaturedThemeCollection($featuredThemes, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - /** - * The Featured Theme Index Endpoint shall support sorting resources. - */ - public function testSorts(): void - { - $schema = new FeaturedThemeSchema(); +test('sparse fieldsets', function () { + $schema = new FeaturedThemeSchema(); - /** @var Sort $sort */ - $sort = collect($schema->fields()) - ->filter(fn (Field $field) => $field instanceof SortableField) - ->map(fn (SortableField $field) => $field->getSort()) - ->random(); + $fields = collect($schema->fields()); - $parameters = [ - SortParser::param() => $sort->format(Arr::random(Direction::cases())), - ]; + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); - $query = new Query($parameters); + $parameters = [ + FieldParser::param() => [ + FeaturedThemeResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; - FeaturedTheme::factory()->count($this->faker->randomDigitNotNull())->create(); + $featuredThemes = FeaturedTheme::factory()->count(fake()->randomDigitNotNull())->create(); - $response = $this->get(route('api.featuredtheme.index', $parameters)); + $response = get(route('api.featuredtheme.index', $parameters)); - $featuredThemes = $this->sort(FeaturedTheme::query(), $query, $schema)->get(); + $response->assertJson( + json_decode( + json_encode( + new FeaturedThemeCollection($featuredThemes, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $response->assertJson( - json_decode( - json_encode( - new FeaturedThemeCollection($featuredThemes, $query) - ->response() - ->getData() - ), - true - ) - ); - } +test('sorts', function () { + $schema = new FeaturedThemeSchema(); - /** - * The Featured Theme Index Endpoint shall support filtering by created_at. - */ - public function testCreatedAtFilter(): void - { - $createdFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); + /** @var Sort $sort */ + $sort = collect($schema->fields()) + ->filter(fn (Field $field) => $field instanceof SortableField) + ->map(fn (SortableField $field) => $field->getSort()) + ->random(); - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; + $parameters = [ + SortParser::param() => $sort->format(Arr::random(Direction::cases())), + ]; - Carbon::withTestNow($createdFilter, function () { - FeaturedTheme::factory()->count($this->faker->randomDigitNotNull())->create(); - }); + $query = new Query($parameters); - Carbon::withTestNow($excludedDate, function () { - FeaturedTheme::factory()->count($this->faker->randomDigitNotNull())->create(); - }); + FeaturedTheme::factory()->count(fake()->randomDigitNotNull())->create(); - $featuredTheme = FeaturedTheme::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); + $response = get(route('api.featuredtheme.index', $parameters)); - $response = $this->get(route('api.featuredtheme.index', $parameters)); + $featuredThemes = $this->sort(FeaturedTheme::query(), $query, $schema)->get(); - $response->assertJson( - json_decode( - json_encode( - new FeaturedThemeCollection($featuredTheme, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response->assertJson( + json_decode( + json_encode( + new FeaturedThemeCollection($featuredThemes, $query) + ->response() + ->getData() + ), + true + ) + ); +}); - /** - * The Featured Theme Index Endpoint shall support filtering by updated_at. - */ - public function testUpdatedAtFilter(): void - { - $updatedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); +test('created at filter', function () { + $createdFilter = fake()->date(); + $excludedDate = fake()->date(); - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; - Carbon::withTestNow($updatedFilter, function () { - FeaturedTheme::factory()->count($this->faker->randomDigitNotNull())->create(); - }); + Carbon::withTestNow($createdFilter, function () { + FeaturedTheme::factory()->count(fake()->randomDigitNotNull())->create(); + }); - Carbon::withTestNow($excludedDate, function () { - FeaturedTheme::factory()->count($this->faker->randomDigitNotNull())->create(); - }); + Carbon::withTestNow($excludedDate, function () { + FeaturedTheme::factory()->count(fake()->randomDigitNotNull())->create(); + }); - $featuredTheme = FeaturedTheme::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); + $featuredTheme = FeaturedTheme::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - $response = $this->get(route('api.featuredtheme.index', $parameters)); + $response = get(route('api.featuredtheme.index', $parameters)); - $response->assertJson( - json_decode( - json_encode( - new FeaturedThemeCollection($featuredTheme, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response->assertJson( + json_decode( + json_encode( + new FeaturedThemeCollection($featuredTheme, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('updated at filter', function () { + $updatedFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($updatedFilter, function () { + FeaturedTheme::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + Carbon::withTestNow($excludedDate, function () { + FeaturedTheme::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + $featuredTheme = FeaturedTheme::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); + + $response = get(route('api.featuredtheme.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new FeaturedThemeCollection($featuredTheme, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Admin/FeaturedTheme/FeaturedThemeShowTest.php b/tests/Feature/Http/Api/Admin/FeaturedTheme/FeaturedThemeShowTest.php index 6ca7e0122..2c336be9d 100644 --- a/tests/Feature/Http/Api/Admin/FeaturedTheme/FeaturedThemeShowTest.php +++ b/tests/Feature/Http/Api/Admin/FeaturedTheme/FeaturedThemeShowTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Admin\FeaturedTheme; - use App\Http\Api\Field\Field; use App\Http\Api\Include\AllowedInclude; use App\Http\Api\Parser\FieldParser; @@ -20,122 +18,103 @@ use App\Models\Wiki\Artist; use App\Models\Wiki\Image; use App\Models\Wiki\Song; use App\Models\Wiki\Video; -use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; -class FeaturedThemeShowTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * The Featured Theme Show Endpoint shall forbid the user from viewing a featured theme whose start date is in the future. - */ - public function testForbiddenIfFutureStartDate(): void - { - $featuredTheme = FeaturedTheme::factory()->create([ - FeaturedTheme::ATTRIBUTE_START_AT => $this->faker->dateTimeBetween('+1 day', '+1 year'), - ]); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response = $this->get(route('api.featuredtheme.show', ['featuredtheme' => $featuredTheme])); +test('forbidden if future start date', function () { + $featuredTheme = FeaturedTheme::factory()->create([ + FeaturedTheme::ATTRIBUTE_START_AT => fake()->dateTimeBetween('+1 day', '+1 year'), + ]); - $response->assertForbidden(); - } + $response = get(route('api.featuredtheme.show', ['featuredtheme' => $featuredTheme])); - /** - * By default, the Featured Theme Show Endpoint shall return a Featured Theme Resource. - */ - public function testDefault(): void - { - $featuredTheme = FeaturedTheme::factory()->create(); + $response->assertForbidden(); +}); - $response = $this->get(route('api.featuredtheme.show', ['featuredtheme' => $featuredTheme])); +test('default', function () { + $featuredTheme = FeaturedTheme::factory()->create(); - $response->assertJson( - json_decode( - json_encode( - new FeaturedThemeResource($featuredTheme, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.featuredtheme.show', ['featuredtheme' => $featuredTheme])); - /** - * The Featured Theme Show Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new FeaturedThemeSchema(); + $response->assertJson( + json_decode( + json_encode( + new FeaturedThemeResource($featuredTheme, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('allowed include paths', function () { + $schema = new FeaturedThemeSchema(); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $allowedIncludes = collect($schema->allowedIncludes()); - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - $featuredTheme = FeaturedTheme::factory() - ->for( - AnimeThemeEntry::factory() - ->for( - AnimeTheme::factory() - ->for(Anime::factory()->has(Image::factory()->count($this->faker->randomDigitNotNull()))) - ->for(Song::factory()->has(Artist::factory()->count($this->faker->randomDigitNotNull()))) - ) - ) - ->for(Video::factory()) - ->for(User::factory()) - ->createOne(); + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; - $response = $this->get(route('api.featuredtheme.show', ['featuredtheme' => $featuredTheme] + $parameters)); + $featuredTheme = FeaturedTheme::factory() + ->for( + AnimeThemeEntry::factory() + ->for( + AnimeTheme::factory() + ->for(Anime::factory()->has(Image::factory()->count(fake()->randomDigitNotNull()))) + ->for(Song::factory()->has(Artist::factory()->count(fake()->randomDigitNotNull()))) + ) + ) + ->for(Video::factory()) + ->for(User::factory()) + ->createOne(); - $response->assertJson( - json_decode( - json_encode( - new FeaturedThemeResource($featuredTheme, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.featuredtheme.show', ['featuredtheme' => $featuredTheme] + $parameters)); - /** - * The Featured Theme Show Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new FeaturedThemeSchema(); + $response->assertJson( + json_decode( + json_encode( + new FeaturedThemeResource($featuredTheme, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $fields = collect($schema->fields()); +test('sparse fieldsets', function () { + $schema = new FeaturedThemeSchema(); - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); + $fields = collect($schema->fields()); - $parameters = [ - FieldParser::param() => [ - FeaturedThemeResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); - $featuredTheme = FeaturedTheme::factory()->create(); + $parameters = [ + FieldParser::param() => [ + FeaturedThemeResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; - $response = $this->get(route('api.featuredtheme.show', ['featuredtheme' => $featuredTheme] + $parameters)); + $featuredTheme = FeaturedTheme::factory()->create(); - $response->assertJson( - json_decode( - json_encode( - new FeaturedThemeResource($featuredTheme, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response = get(route('api.featuredtheme.show', ['featuredtheme' => $featuredTheme] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new FeaturedThemeResource($featuredTheme, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Admin/FeaturedTheme/FeaturedThemeStoreTest.php b/tests/Feature/Http/Api/Admin/FeaturedTheme/FeaturedThemeStoreTest.php index a61d9631e..716208621 100644 --- a/tests/Feature/Http/Api/Admin/FeaturedTheme/FeaturedThemeStoreTest.php +++ b/tests/Feature/Http/Api/Admin/FeaturedTheme/FeaturedThemeStoreTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Admin\FeaturedTheme; - use App\Enums\Auth\CrudPermission; use App\Enums\Http\Api\Filter\AllowedDateFormat; use App\Models\Admin\FeaturedTheme; @@ -13,131 +11,104 @@ use App\Models\Wiki\Anime\AnimeTheme; use App\Models\Wiki\Anime\Theme\AnimeThemeEntry; use App\Models\Wiki\Video; use App\Pivots\Wiki\AnimeThemeEntryVideo; -use Illuminate\Foundation\Testing\WithFaker; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class FeaturedThemeStoreTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\post; - /** - * The Featured Theme Store Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $featuredTheme = FeaturedTheme::factory()->makeOne(); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response = $this->post(route('api.featuredtheme.store', $featuredTheme->toArray())); +test('protected', function () { + $featuredTheme = FeaturedTheme::factory()->makeOne(); - $response->assertUnauthorized(); - } + $response = post(route('api.featuredtheme.store', $featuredTheme->toArray())); - /** - * The Featured Theme Store Endpoint shall forbid users without the create featured theme permission. - */ - public function testForbidden(): void - { - $featuredTheme = FeaturedTheme::factory()->makeOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $featuredTheme = FeaturedTheme::factory()->makeOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->post(route('api.featuredtheme.store', $featuredTheme->toArray())); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.featuredtheme.store', $featuredTheme->toArray())); - /** - * The Featured Theme Store Endpoint shall require the end_at and start_at fields. - */ - public function testRequiredFields(): void - { - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(FeaturedTheme::class))->createOne(); + $response->assertForbidden(); +}); - Sanctum::actingAs($user); +test('required fields', function () { + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(FeaturedTheme::class))->createOne(); - $response = $this->post(route('api.featuredtheme.store')); + Sanctum::actingAs($user); - $response->assertJsonValidationErrors([ - FeaturedTheme::ATTRIBUTE_END_AT, - FeaturedTheme::ATTRIBUTE_START_AT, - ]); - } + $response = post(route('api.featuredtheme.store')); - /** - * The Featured Theme Store Endpoint shall require the start_at field to be before the end_at field and vice versa. - */ - public function testStartAtBeforeEndDate(): void - { - $parameters = FeaturedTheme::factory()->raw([ - FeaturedTheme::ATTRIBUTE_START_AT => $this->faker->dateTimeBetween('+1 day', '+1 year')->format(AllowedDateFormat::YMDHISU->value), - FeaturedTheme::ATTRIBUTE_END_AT => $this->faker->dateTimeBetween('-1 year', '-1 day')->format(AllowedDateFormat::YMDHISU->value), - ]); + $response->assertJsonValidationErrors([ + FeaturedTheme::ATTRIBUTE_END_AT, + FeaturedTheme::ATTRIBUTE_START_AT, + ]); +}); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(FeaturedTheme::class))->createOne(); +test('start at before end date', function () { + $parameters = FeaturedTheme::factory()->raw([ + FeaturedTheme::ATTRIBUTE_START_AT => fake()->dateTimeBetween('+1 day', '+1 year')->format(AllowedDateFormat::YMDHISU->value), + FeaturedTheme::ATTRIBUTE_END_AT => fake()->dateTimeBetween('-1 year', '-1 day')->format(AllowedDateFormat::YMDHISU->value), + ]); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(FeaturedTheme::class))->createOne(); - $response = $this->post(route('api.featuredtheme.store', $parameters)); + Sanctum::actingAs($user); - $response->assertJsonValidationErrors([ - FeaturedTheme::ATTRIBUTE_START_AT, - FeaturedTheme::ATTRIBUTE_END_AT, - ]); - } + $response = post(route('api.featuredtheme.store', $parameters)); - /** - * The Featured Theme Store Endpoint shall require the entry and video to have an association. - */ - public function testAnimeThemeEntryVideoExists(): void - { - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->create(); + $response->assertJsonValidationErrors([ + FeaturedTheme::ATTRIBUTE_START_AT, + FeaturedTheme::ATTRIBUTE_END_AT, + ]); +}); - $video = Video::factory()->create(); +test('anime theme entry video exists', function () { + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->create(); - $parameters = FeaturedTheme::factory()->raw([ - FeaturedTheme::ATTRIBUTE_ENTRY => $entry->getKey(), - FeaturedTheme::ATTRIBUTE_VIDEO => $video->getKey(), - ]); + $video = Video::factory()->create(); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(FeaturedTheme::class))->createOne(); + $parameters = FeaturedTheme::factory()->raw([ + FeaturedTheme::ATTRIBUTE_ENTRY => $entry->getKey(), + FeaturedTheme::ATTRIBUTE_VIDEO => $video->getKey(), + ]); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(FeaturedTheme::class))->createOne(); - $response = $this->post(route('api.featuredtheme.store', $parameters)); + Sanctum::actingAs($user); - $response->assertJsonValidationErrors([ - FeaturedTheme::ATTRIBUTE_ENTRY, - FeaturedTheme::ATTRIBUTE_VIDEO, - ]); - } + $response = post(route('api.featuredtheme.store', $parameters)); - /** - * The Featured Theme Store Endpoint shall create a featured theme. - */ - public function testCreate(): void - { - $entryVideo = AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->createOne(); + $response->assertJsonValidationErrors([ + FeaturedTheme::ATTRIBUTE_ENTRY, + FeaturedTheme::ATTRIBUTE_VIDEO, + ]); +}); - $parameters = FeaturedTheme::factory()->raw([ - FeaturedTheme::ATTRIBUTE_ENTRY => $entryVideo->entry_id, - FeaturedTheme::ATTRIBUTE_VIDEO => $entryVideo->video_id, - ]); +test('create', function () { + $entryVideo = AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->createOne(); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(FeaturedTheme::class))->createOne(); + $parameters = FeaturedTheme::factory()->raw([ + FeaturedTheme::ATTRIBUTE_ENTRY => $entryVideo->entry_id, + FeaturedTheme::ATTRIBUTE_VIDEO => $entryVideo->video_id, + ]); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(FeaturedTheme::class))->createOne(); - $response = $this->post(route('api.featuredtheme.store', $parameters)); + Sanctum::actingAs($user); - $response->assertCreated(); - static::assertDatabaseCount(FeaturedTheme::class, 1); - } -} + $response = post(route('api.featuredtheme.store', $parameters)); + + $response->assertCreated(); + $this->assertDatabaseCount(FeaturedTheme::class, 1); +}); diff --git a/tests/Feature/Http/Api/Admin/FeaturedTheme/FeaturedThemeUpdateTest.php b/tests/Feature/Http/Api/Admin/FeaturedTheme/FeaturedThemeUpdateTest.php index 31d52ae43..8ea22d96a 100644 --- a/tests/Feature/Http/Api/Admin/FeaturedTheme/FeaturedThemeUpdateTest.php +++ b/tests/Feature/Http/Api/Admin/FeaturedTheme/FeaturedThemeUpdateTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Admin\FeaturedTheme; - use App\Enums\Auth\CrudPermission; use App\Enums\Http\Api\Filter\AllowedDateFormat; use App\Models\Admin\FeaturedTheme; @@ -13,123 +11,100 @@ use App\Models\Wiki\Anime\AnimeTheme; use App\Models\Wiki\Anime\Theme\AnimeThemeEntry; use App\Models\Wiki\Video; use App\Pivots\Wiki\AnimeThemeEntryVideo; -use Illuminate\Foundation\Testing\WithFaker; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class FeaturedThemeUpdateTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\put; - /** - * The Featured Theme Update Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $featuredTheme = FeaturedTheme::factory()->createOne(); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $parameters = FeaturedTheme::factory()->raw(); +test('protected', function () { + $featuredTheme = FeaturedTheme::factory()->createOne(); - $response = $this->put(route('api.featuredtheme.update', ['featuredtheme' => $featuredTheme] + $parameters)); + $parameters = FeaturedTheme::factory()->raw(); - $response->assertUnauthorized(); - } + $response = put(route('api.featuredtheme.update', ['featuredtheme' => $featuredTheme] + $parameters)); - /** - * The Featured Theme Update Endpoint shall forbid users without the update featured theme permission. - */ - public function testForbidden(): void - { - $featuredTheme = FeaturedTheme::factory()->createOne(); + $response->assertUnauthorized(); +}); - $parameters = FeaturedTheme::factory()->raw(); +test('forbidden', function () { + $featuredTheme = FeaturedTheme::factory()->createOne(); - $user = User::factory()->createOne(); + $parameters = FeaturedTheme::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->put(route('api.featuredtheme.update', ['featuredtheme' => $featuredTheme] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.featuredtheme.update', ['featuredtheme' => $featuredTheme] + $parameters)); - /** - * The Featured Update Store Endpoint shall require the start_at field to be before the end_at field and vice versa. - */ - public function testStartAtBeforeEndDate(): void - { - $featuredTheme = FeaturedTheme::factory()->createOne(); + $response->assertForbidden(); +}); - $parameters = FeaturedTheme::factory()->raw([ - FeaturedTheme::ATTRIBUTE_START_AT => $this->faker->dateTimeBetween('+1 day', '+1 year')->format(AllowedDateFormat::YMDHISU->value), - FeaturedTheme::ATTRIBUTE_END_AT => $this->faker->dateTimeBetween('-1 year', '-1 day')->format(AllowedDateFormat::YMDHISU->value), - ]); +test('start at before end date', function () { + $featuredTheme = FeaturedTheme::factory()->createOne(); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(FeaturedTheme::class))->createOne(); + $parameters = FeaturedTheme::factory()->raw([ + FeaturedTheme::ATTRIBUTE_START_AT => fake()->dateTimeBetween('+1 day', '+1 year')->format(AllowedDateFormat::YMDHISU->value), + FeaturedTheme::ATTRIBUTE_END_AT => fake()->dateTimeBetween('-1 year', '-1 day')->format(AllowedDateFormat::YMDHISU->value), + ]); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(FeaturedTheme::class))->createOne(); - $response = $this->put(route('api.featuredtheme.update', ['featuredtheme' => $featuredTheme] + $parameters)); + Sanctum::actingAs($user); - $response->assertJsonValidationErrors([ - FeaturedTheme::ATTRIBUTE_START_AT, - FeaturedTheme::ATTRIBUTE_END_AT, - ]); - } + $response = put(route('api.featuredtheme.update', ['featuredtheme' => $featuredTheme] + $parameters)); - /** - * The Featured Theme Update Endpoint shall require the entry and video to have an association. - */ - public function testAnimeThemeEntryVideoExists(): void - { - $featuredTheme = FeaturedTheme::factory()->createOne(); + $response->assertJsonValidationErrors([ + FeaturedTheme::ATTRIBUTE_START_AT, + FeaturedTheme::ATTRIBUTE_END_AT, + ]); +}); - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->create(); +test('anime theme entry video exists', function () { + $featuredTheme = FeaturedTheme::factory()->createOne(); - $video = Video::factory()->create(); + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->create(); - $parameters = FeaturedTheme::factory()->raw([ - FeaturedTheme::ATTRIBUTE_ENTRY => $entry->getKey(), - FeaturedTheme::ATTRIBUTE_VIDEO => $video->getKey(), - ]); + $video = Video::factory()->create(); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(FeaturedTheme::class))->createOne(); + $parameters = FeaturedTheme::factory()->raw([ + FeaturedTheme::ATTRIBUTE_ENTRY => $entry->getKey(), + FeaturedTheme::ATTRIBUTE_VIDEO => $video->getKey(), + ]); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(FeaturedTheme::class))->createOne(); - $response = $this->put(route('api.featuredtheme.update', ['featuredtheme' => $featuredTheme] + $parameters)); + Sanctum::actingAs($user); - $response->assertJsonValidationErrors([ - FeaturedTheme::ATTRIBUTE_ENTRY, - FeaturedTheme::ATTRIBUTE_VIDEO, - ]); - } + $response = put(route('api.featuredtheme.update', ['featuredtheme' => $featuredTheme] + $parameters)); - /** - * The Featured Theme Update Endpoint shall update a featured theme. - */ - public function testUpdate(): void - { - $featuredTheme = FeaturedTheme::factory()->createOne(); + $response->assertJsonValidationErrors([ + FeaturedTheme::ATTRIBUTE_ENTRY, + FeaturedTheme::ATTRIBUTE_VIDEO, + ]); +}); - $entryVideo = AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->createOne(); +test('update', function () { + $featuredTheme = FeaturedTheme::factory()->createOne(); - $parameters = FeaturedTheme::factory()->raw([ - FeaturedTheme::ATTRIBUTE_ENTRY => $entryVideo->entry_id, - FeaturedTheme::ATTRIBUTE_VIDEO => $entryVideo->video_id, - ]); + $entryVideo = AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->createOne(); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(FeaturedTheme::class))->createOne(); + $parameters = FeaturedTheme::factory()->raw([ + FeaturedTheme::ATTRIBUTE_ENTRY => $entryVideo->entry_id, + FeaturedTheme::ATTRIBUTE_VIDEO => $entryVideo->video_id, + ]); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(FeaturedTheme::class))->createOne(); - $response = $this->put(route('api.featuredtheme.update', ['featuredtheme' => $featuredTheme] + $parameters)); + Sanctum::actingAs($user); - $response->assertOk(); - } -} + $response = put(route('api.featuredtheme.update', ['featuredtheme' => $featuredTheme] + $parameters)); + + $response->assertOk(); +}); diff --git a/tests/Feature/Http/Api/Auth/User/Me/List/ExternalProfile/MyExternalProfileIndexTest.php b/tests/Feature/Http/Api/Auth/User/Me/List/ExternalProfile/MyExternalProfileIndexTest.php index b5be56a2b..3fbdd0bc7 100644 --- a/tests/Feature/Http/Api/Auth/User/Me/List/ExternalProfile/MyExternalProfileIndexTest.php +++ b/tests/Feature/Http/Api/Auth/User/Me/List/ExternalProfile/MyExternalProfileIndexTest.php @@ -2,83 +2,66 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Auth\User\Me\List\ExternalProfile; - use App\Enums\Auth\CrudPermission; use App\Http\Api\Query\Query; use App\Http\Resources\List\Collection\ExternalProfileCollection; use App\Models\Auth\User; use App\Models\List\ExternalProfile; -use Illuminate\Foundation\Testing\WithFaker; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class MyExternalProfileIndexTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * The My External Profile Index Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $response = $this->get(route('api.me.externalprofile.index')); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response->assertUnauthorized(); - } +test('protected', function () { + $response = get(route('api.me.externalprofile.index')); - /** - * The My External Profile Index Endpoint shall forbid users without the view external profile permission. - */ - public function testForbiddenIfMissingPermission(): void - { - $user = User::factory()->createOne(); + $response->assertUnauthorized(); +}); - Sanctum::actingAs($user); +test('forbidden if missing permission', function () { + $user = User::factory()->createOne(); - $response = $this->get(route('api.me.externalprofile.index')); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = get(route('api.me.externalprofile.index')); - /** - * The My External Profile Index Endpoint shall return profiles owned by the user. - */ - public function testOnlySeesOwnedProfiles(): void - { - ExternalProfile::factory() - ->for(User::factory()) - ->count($this->faker->randomDigitNotNull()) - ->create(); + $response->assertForbidden(); +}); - ExternalProfile::factory() - ->count($this->faker->randomDigitNotNull()) - ->create(); +test('only sees owned profiles', function () { + ExternalProfile::factory() + ->for(User::factory()) + ->count(fake()->randomDigitNotNull()) + ->create(); - $user = User::factory()->withPermissions(CrudPermission::VIEW->format(ExternalProfile::class))->createOne(); + ExternalProfile::factory() + ->count(fake()->randomDigitNotNull()) + ->create(); - $profileCount = $this->faker->randomDigitNotNull(); + $user = User::factory()->withPermissions(CrudPermission::VIEW->format(ExternalProfile::class))->createOne(); - $profiles = ExternalProfile::factory() - ->for($user) - ->count($profileCount) - ->create(); + $profileCount = fake()->randomDigitNotNull(); - Sanctum::actingAs($user); + $profiles = ExternalProfile::factory() + ->for($user) + ->count($profileCount) + ->create(); - $response = $this->get(route('api.me.externalprofile.index')); + Sanctum::actingAs($user); - $response->assertJsonCount($profileCount, ExternalProfileCollection::$wrap); + $response = get(route('api.me.externalprofile.index')); - $response->assertJson( - json_decode( - json_encode( - new ExternalProfileCollection($profiles, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response->assertJsonCount($profileCount, ExternalProfileCollection::$wrap); + + $response->assertJson( + json_decode( + json_encode( + new ExternalProfileCollection($profiles, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Auth/User/Me/List/Playlist/MyPlaylistIndexTest.php b/tests/Feature/Http/Api/Auth/User/Me/List/Playlist/MyPlaylistIndexTest.php index 7501893d1..183ff0e60 100644 --- a/tests/Feature/Http/Api/Auth/User/Me/List/Playlist/MyPlaylistIndexTest.php +++ b/tests/Feature/Http/Api/Auth/User/Me/List/Playlist/MyPlaylistIndexTest.php @@ -2,83 +2,66 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Auth\User\Me\List\Playlist; - use App\Enums\Auth\CrudPermission; use App\Http\Api\Query\Query; use App\Http\Resources\List\Collection\PlaylistCollection; use App\Models\Auth\User; use App\Models\List\Playlist; -use Illuminate\Foundation\Testing\WithFaker; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class MyPlaylistIndexTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * The My Playlist Index Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $response = $this->get(route('api.me.playlist.index')); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response->assertUnauthorized(); - } +test('protected', function () { + $response = get(route('api.me.playlist.index')); - /** - * The My Playlist Index Endpoint shall forbid users without the view playlist permission. - */ - public function testForbiddenIfMissingPermission(): void - { - $user = User::factory()->createOne(); + $response->assertUnauthorized(); +}); - Sanctum::actingAs($user); +test('forbidden if missing permission', function () { + $user = User::factory()->createOne(); - $response = $this->get(route('api.me.playlist.index')); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = get(route('api.me.playlist.index')); - /** - * The My Playlist Index Endpoint shall return playlists owned by the user. - */ - public function testOnlySeesOwnedPlaylists(): void - { - Playlist::factory() - ->for(User::factory()) - ->count($this->faker->randomDigitNotNull()) - ->create(); + $response->assertForbidden(); +}); - Playlist::factory() - ->count($this->faker->randomDigitNotNull()) - ->create(); +test('only sees owned playlists', function () { + Playlist::factory() + ->for(User::factory()) + ->count(fake()->randomDigitNotNull()) + ->create(); - $user = User::factory()->withPermissions(CrudPermission::VIEW->format(Playlist::class))->createOne(); + Playlist::factory() + ->count(fake()->randomDigitNotNull()) + ->create(); - $playlistCount = $this->faker->randomDigitNotNull(); + $user = User::factory()->withPermissions(CrudPermission::VIEW->format(Playlist::class))->createOne(); - $playlists = Playlist::factory() - ->for($user) - ->count($playlistCount) - ->create(); + $playlistCount = fake()->randomDigitNotNull(); - Sanctum::actingAs($user); + $playlists = Playlist::factory() + ->for($user) + ->count($playlistCount) + ->create(); - $response = $this->get(route('api.me.playlist.index')); + Sanctum::actingAs($user); - $response->assertJsonCount($playlistCount, PlaylistCollection::$wrap); + $response = get(route('api.me.playlist.index')); - $response->assertJson( - json_decode( - json_encode( - new PlaylistCollection($playlists, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response->assertJsonCount($playlistCount, PlaylistCollection::$wrap); + + $response->assertJson( + json_decode( + json_encode( + new PlaylistCollection($playlists, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Auth/User/Me/MyShowTest.php b/tests/Feature/Http/Api/Auth/User/Me/MyShowTest.php index 0e91e4de7..b7900b100 100644 --- a/tests/Feature/Http/Api/Auth/User/Me/MyShowTest.php +++ b/tests/Feature/Http/Api/Auth/User/Me/MyShowTest.php @@ -2,49 +2,36 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Auth\User\Me; - use App\Http\Api\Query\Query; use App\Http\Resources\Auth\Resource\UserResource; use App\Models\Auth\User; -use Illuminate\Foundation\Testing\WithFaker; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class MyShowTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * The My Show Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $response = $this->get(route('api.me.show')); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response->assertUnauthorized(); - } +test('protected', function () { + $response = get(route('api.me.show')); - /** - * The My Show Endpoint shall return the resource of the current user. - */ - public function testDefault(): void - { - $user = User::factory()->createOne(); + $response->assertUnauthorized(); +}); - Sanctum::actingAs($user); +test('default', function () { + $user = User::factory()->createOne(); - $response = $this->get(route('api.me.show')); + Sanctum::actingAs($user); - $response->assertJson( - json_decode( - json_encode( - new UserResource($user, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response = get(route('api.me.show')); + + $response->assertJson( + json_decode( + json_encode( + new UserResource($user, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Auth/User/Me/Notification/MyNotificationIndexTest.php b/tests/Feature/Http/Api/Auth/User/Me/Notification/MyNotificationIndexTest.php index 492b07186..f4d3c6171 100644 --- a/tests/Feature/Http/Api/Auth/User/Me/Notification/MyNotificationIndexTest.php +++ b/tests/Feature/Http/Api/Auth/User/Me/Notification/MyNotificationIndexTest.php @@ -2,81 +2,64 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Auth\User\Me\Notification; - use App\Enums\Auth\CrudPermission; use App\Http\Api\Query\Query; use App\Http\Resources\User\Collection\NotificationCollection; use App\Models\Auth\User; use App\Models\User\Notification; use Illuminate\Database\Eloquent\Model; -use Illuminate\Foundation\Testing\WithFaker; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class MyNotificationIndexTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * The My Notification Index Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $response = $this->get(route('api.me.notification.index')); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response->assertUnauthorized(); - } +test('protected', function () { + $response = get(route('api.me.notification.index')); - /** - * The My Notification Index Endpoint shall forbid users without the view notification permission. - */ - public function testForbiddenIfMissingPermission(): void - { - $user = User::factory()->createOne(); + $response->assertUnauthorized(); +}); - Sanctum::actingAs($user); +test('forbidden if missing permission', function () { + $user = User::factory()->createOne(); - $response = $this->get(route('api.me.notification.index')); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = get(route('api.me.notification.index')); - /** - * The My Notification Index Endpoint shall return notifications owned by the user. - */ - public function testOnlySeesOwnedNotifications(): void - { - Notification::factory() - ->for(User::factory(), Notification::RELATION_NOTIFIABLE) - ->count($this->faker->randomDigitNotNull()) - ->create(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(CrudPermission::VIEW->format(Notification::class))->createOne(); +test('only sees owned notifications', function () { + Notification::factory() + ->for(User::factory(), Notification::RELATION_NOTIFIABLE) + ->count(fake()->randomDigitNotNull()) + ->create(); - $notificationCount = $this->faker->randomDigitNotNull(); + $user = User::factory()->withPermissions(CrudPermission::VIEW->format(Notification::class))->createOne(); - $notifications = Notification::factory() - ->for($user, Notification::RELATION_NOTIFIABLE) - ->count($notificationCount) - ->create() - ->sortBy(Model::CREATED_AT); + $notificationCount = fake()->randomDigitNotNull(); - Sanctum::actingAs($user); + $notifications = Notification::factory() + ->for($user, Notification::RELATION_NOTIFIABLE) + ->count($notificationCount) + ->create() + ->sortBy(Model::CREATED_AT); - $response = $this->get(route('api.me.notification.index')); + Sanctum::actingAs($user); - $response->assertJsonCount($notificationCount, NotificationCollection::$wrap); + $response = get(route('api.me.notification.index')); - $response->assertJson( - json_decode( - json_encode( - new NotificationCollection($notifications, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response->assertJsonCount($notificationCount, NotificationCollection::$wrap); + + $response->assertJson( + json_decode( + json_encode( + new NotificationCollection($notifications, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Document/Page/PageDestroyTest.php b/tests/Feature/Http/Api/Document/Page/PageDestroyTest.php index 2a56372ce..ad32a4ec3 100644 --- a/tests/Feature/Http/Api/Document/Page/PageDestroyTest.php +++ b/tests/Feature/Http/Api/Document/Page/PageDestroyTest.php @@ -2,74 +2,54 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Document\Page; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Document\Page; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class PageDestroyTest extends TestCase -{ - /** - * The Page Destroy Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $page = Page::factory()->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.page.destroy', ['page' => $page])); +test('protected', function () { + $page = Page::factory()->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.page.destroy', ['page' => $page])); - /** - * The Page Destroy Endpoint shall forbid users without the delete page permission. - */ - public function testForbidden(): void - { - $page = Page::factory()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $page = Page::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.page.destroy', ['page' => $page])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.page.destroy', ['page' => $page])); - /** - * The Page Destroy Endpoint shall forbid users from updating a page that is trashed. - */ - public function testTrashed(): void - { - $page = Page::factory()->trashed()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Page::class))->createOne(); +test('trashed', function () { + $page = Page::factory()->trashed()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Page::class))->createOne(); - $response = $this->delete(route('api.page.destroy', ['page' => $page])); + Sanctum::actingAs($user); - $response->assertNotFound(); - } + $response = delete(route('api.page.destroy', ['page' => $page])); - /** - * The Page Destroy Endpoint shall delete the page. - */ - public function testDeleted(): void - { - $page = Page::factory()->createOne(); + $response->assertNotFound(); +}); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Page::class))->createOne(); +test('deleted', function () { + $page = Page::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Page::class))->createOne(); - $response = $this->delete(route('api.page.destroy', ['page' => $page])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertSoftDeleted($page); - } -} + $response = delete(route('api.page.destroy', ['page' => $page])); + + $response->assertOk(); + $this->assertSoftDeleted($page); +}); diff --git a/tests/Feature/Http/Api/Document/Page/PageForceDeleteTest.php b/tests/Feature/Http/Api/Document/Page/PageForceDeleteTest.php index 1cfba4386..a2ebac6e2 100644 --- a/tests/Feature/Http/Api/Document/Page/PageForceDeleteTest.php +++ b/tests/Feature/Http/Api/Document/Page/PageForceDeleteTest.php @@ -2,58 +2,42 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Document\Page; - use App\Enums\Auth\ExtendedCrudPermission; use App\Models\Auth\User; use App\Models\Document\Page; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class PageForceDeleteTest extends TestCase -{ - /** - * The Page Force Delete Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $page = Page::factory()->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.page.forceDelete', ['page' => $page])); +test('protected', function () { + $page = Page::factory()->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.page.forceDelete', ['page' => $page])); - /** - * The Page Force Delete Endpoint shall forbid users without the force delete page permission. - */ - public function testForbidden(): void - { - $page = Page::factory()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $page = Page::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.page.forceDelete', ['page' => $page])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.page.forceDelete', ['page' => $page])); - /** - * The Page Force Delete Endpoint shall force delete the page. - */ - public function testDeleted(): void - { - $page = Page::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::FORCE_DELETE->format(Page::class))->createOne(); +test('deleted', function () { + $page = Page::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::FORCE_DELETE->format(Page::class))->createOne(); - $response = $this->delete(route('api.page.forceDelete', ['page' => $page])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertModelMissing($page); - } -} + $response = delete(route('api.page.forceDelete', ['page' => $page])); + + $response->assertOk(); + $this->assertModelMissing($page); +}); diff --git a/tests/Feature/Http/Api/Document/Page/PageIndexTest.php b/tests/Feature/Http/Api/Document/Page/PageIndexTest.php index 46d8acceb..b2397c1b2 100644 --- a/tests/Feature/Http/Api/Document/Page/PageIndexTest.php +++ b/tests/Feature/Http/Api/Document/Page/PageIndexTest.php @@ -2,9 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Document\Page; - -use App\Concerns\Actions\Http\Api\SortsModels; use App\Constants\ModelConstants; use App\Contracts\Http\Api\Field\SortableField; use App\Enums\Http\Api\Filter\TrashedStatus; @@ -24,346 +21,304 @@ use App\Http\Resources\Document\Collection\PageCollection; use App\Http\Resources\Document\Resource\PageResource; use App\Models\BaseModel; use App\Models\Document\Page; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; -use Tests\TestCase; -class PageIndexTest extends TestCase -{ - use SortsModels; - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the Page Index Endpoint shall return a collection of Page Resources. - */ - public function testDefault(): void - { - $pages = Page::factory()->count($this->faker->randomDigitNotNull())->create(); +uses(App\Concerns\Actions\Http\Api\SortsModels::class); - $response = $this->get(route('api.page.index')); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response->assertJson( - json_decode( - json_encode( - new PageCollection($pages, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } +test('default', function () { + $pages = Page::factory()->count(fake()->randomDigitNotNull())->create(); - /** - * The Page Index Endpoint shall be paginated. - */ - public function testPaginated(): void - { - Page::factory()->count($this->faker->randomDigitNotNull())->create(); + $response = get(route('api.page.index')); - $response = $this->get(route('api.page.index')); + $response->assertJson( + json_decode( + json_encode( + new PageCollection($pages, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $response->assertJsonStructure([ - PageCollection::$wrap, - 'links', - 'meta', - ]); - } +test('paginated', function () { + Page::factory()->count(fake()->randomDigitNotNull())->create(); - /** - * The Page Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new PageSchema(); + $response = get(route('api.page.index')); - $fields = collect($schema->fields()); + $response->assertJsonStructure([ + PageCollection::$wrap, + 'links', + 'meta', + ]); +}); - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); +test('sparse fieldsets', function () { + $schema = new PageSchema(); - $parameters = [ - FieldParser::param() => [ - PageResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; + $fields = collect($schema->fields()); - $pages = Page::factory()->count($this->faker->randomDigitNotNull())->create(); + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); - $response = $this->get(route('api.page.index', $parameters)); + $parameters = [ + FieldParser::param() => [ + PageResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; - $response->assertJson( - json_decode( - json_encode( - new PageCollection($pages, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $pages = Page::factory()->count(fake()->randomDigitNotNull())->create(); - /** - * The Page Index Endpoint shall support sorting resources. - */ - public function testSorts(): void - { - $schema = new PageSchema(); + $response = get(route('api.page.index', $parameters)); - /** @var Sort $sort */ - $sort = collect($schema->fields()) - ->filter(fn (Field $field) => $field instanceof SortableField) - ->map(fn (SortableField $field) => $field->getSort()) - ->random(); + $response->assertJson( + json_decode( + json_encode( + new PageCollection($pages, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - SortParser::param() => $sort->format(Arr::random(Direction::cases())), - ]; +test('sorts', function () { + $schema = new PageSchema(); - $query = new Query($parameters); + /** @var Sort $sort */ + $sort = collect($schema->fields()) + ->filter(fn (Field $field) => $field instanceof SortableField) + ->map(fn (SortableField $field) => $field->getSort()) + ->random(); - Page::factory()->count($this->faker->randomDigitNotNull())->create(); + $parameters = [ + SortParser::param() => $sort->format(Arr::random(Direction::cases())), + ]; - $response = $this->get(route('api.page.index', $parameters)); + $query = new Query($parameters); - $pages = $this->sort(Page::query(), $query, $schema)->get(); + Page::factory()->count(fake()->randomDigitNotNull())->create(); - $response->assertJson( - json_decode( - json_encode( - new PageCollection($pages, $query) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.page.index', $parameters)); - /** - * The Page Index Endpoint shall support filtering by created_at. - */ - public function testCreatedAtFilter(): void - { - $createdFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); + $pages = $this->sort(Page::query(), $query, $schema)->get(); - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; + $response->assertJson( + json_decode( + json_encode( + new PageCollection($pages, $query) + ->response() + ->getData() + ), + true + ) + ); +}); - Carbon::withTestNow($createdFilter, function () { - Page::factory()->count($this->faker->randomDigitNotNull())->create(); - }); +test('created at filter', function () { + $createdFilter = fake()->date(); + $excludedDate = fake()->date(); - Carbon::withTestNow($excludedDate, function () { - Page::factory()->count($this->faker->randomDigitNotNull())->create(); - }); + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; - $page = Page::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); + Carbon::withTestNow($createdFilter, function () { + Page::factory()->count(fake()->randomDigitNotNull())->create(); + }); - $response = $this->get(route('api.page.index', $parameters)); + Carbon::withTestNow($excludedDate, function () { + Page::factory()->count(fake()->randomDigitNotNull())->create(); + }); - $response->assertJson( - json_decode( - json_encode( - new PageCollection($page, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $page = Page::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - /** - * The Page Index Endpoint shall support filtering by updated_at. - */ - public function testUpdatedAtFilter(): void - { - $updatedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); + $response = get(route('api.page.index', $parameters)); - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; + $response->assertJson( + json_decode( + json_encode( + new PageCollection($page, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - Carbon::withTestNow($updatedFilter, function () { - Page::factory()->count($this->faker->randomDigitNotNull())->create(); - }); +test('updated at filter', function () { + $updatedFilter = fake()->date(); + $excludedDate = fake()->date(); - Carbon::withTestNow($excludedDate, function () { - Page::factory()->count($this->faker->randomDigitNotNull())->create(); - }); + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; - $page = Page::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); + Carbon::withTestNow($updatedFilter, function () { + Page::factory()->count(fake()->randomDigitNotNull())->create(); + }); - $response = $this->get(route('api.page.index', $parameters)); + Carbon::withTestNow($excludedDate, function () { + Page::factory()->count(fake()->randomDigitNotNull())->create(); + }); - $response->assertJson( - json_decode( - json_encode( - new PageCollection($page, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $page = Page::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - /** - * The Page Index Endpoint shall support filtering by trashed. - */ - public function testWithoutTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITHOUT->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; + $response = get(route('api.page.index', $parameters)); - Page::factory()->count($this->faker->randomDigitNotNull())->create(); + $response->assertJson( + json_decode( + json_encode( + new PageCollection($page, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - Page::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); +test('without trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITHOUT->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; - $page = Page::withoutTrashed()->get(); + Page::factory()->count(fake()->randomDigitNotNull())->create(); - $response = $this->get(route('api.page.index', $parameters)); + Page::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); - $response->assertJson( - json_decode( - json_encode( - new PageCollection($page, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $page = Page::withoutTrashed()->get(); - /** - * The Page Index Endpoint shall support filtering by trashed. - */ - public function testWithTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; + $response = get(route('api.page.index', $parameters)); - Page::factory()->count($this->faker->randomDigitNotNull())->create(); + $response->assertJson( + json_decode( + json_encode( + new PageCollection($page, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - Page::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); +test('with trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; - $page = Page::withTrashed()->get(); + Page::factory()->count(fake()->randomDigitNotNull())->create(); - $response = $this->get(route('api.page.index', $parameters)); + Page::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); - $response->assertJson( - json_decode( - json_encode( - new PageCollection($page, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $page = Page::withTrashed()->get(); - /** - * The Page Index Endpoint shall support filtering by trashed. - */ - public function testOnlyTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::ONLY->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; + $response = get(route('api.page.index', $parameters)); - Page::factory()->count($this->faker->randomDigitNotNull())->create(); + $response->assertJson( + json_decode( + json_encode( + new PageCollection($page, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - Page::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); +test('only trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::ONLY->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; - $page = Page::onlyTrashed()->get(); + Page::factory()->count(fake()->randomDigitNotNull())->create(); - $response = $this->get(route('api.page.index', $parameters)); + Page::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); - $response->assertJson( - json_decode( - json_encode( - new PageCollection($page, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $page = Page::onlyTrashed()->get(); - /** - * The Page Index Endpoint shall support filtering by deleted_at. - */ - public function testDeletedAtFilter(): void - { - $deletedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); + $response = get(route('api.page.index', $parameters)); - $parameters = [ - FilterParser::param() => [ - ModelConstants::ATTRIBUTE_DELETED_AT => $deletedFilter, - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; + $response->assertJson( + json_decode( + json_encode( + new PageCollection($page, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - Carbon::withTestNow($deletedFilter, function () { - Page::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - }); +test('deleted at filter', function () { + $deletedFilter = fake()->date(); + $excludedDate = fake()->date(); - Carbon::withTestNow($excludedDate, function () { - Page::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - }); + $parameters = [ + FilterParser::param() => [ + ModelConstants::ATTRIBUTE_DELETED_AT => $deletedFilter, + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; - $page = Page::withTrashed()->where(ModelConstants::ATTRIBUTE_DELETED_AT, $deletedFilter)->get(); + Carbon::withTestNow($deletedFilter, function () { + Page::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + }); - $response = $this->get(route('api.page.index', $parameters)); + Carbon::withTestNow($excludedDate, function () { + Page::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + }); - $response->assertJson( - json_decode( - json_encode( - new PageCollection($page, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $page = Page::withTrashed()->where(ModelConstants::ATTRIBUTE_DELETED_AT, $deletedFilter)->get(); + + $response = get(route('api.page.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new PageCollection($page, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Document/Page/PageRestoreTest.php b/tests/Feature/Http/Api/Document/Page/PageRestoreTest.php index 33e06b4db..4d45f4804 100644 --- a/tests/Feature/Http/Api/Document/Page/PageRestoreTest.php +++ b/tests/Feature/Http/Api/Document/Page/PageRestoreTest.php @@ -2,74 +2,54 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Document\Page; - use App\Enums\Auth\ExtendedCrudPermission; use App\Models\Auth\User; use App\Models\Document\Page; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class PageRestoreTest extends TestCase -{ - /** - * The Page Restore Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $page = Page::factory()->trashed()->createOne(); +use function Pest\Laravel\patch; - $response = $this->patch(route('api.page.restore', ['page' => $page])); +test('protected', function () { + $page = Page::factory()->trashed()->createOne(); - $response->assertUnauthorized(); - } + $response = patch(route('api.page.restore', ['page' => $page])); - /** - * The Page Restore Endpoint shall forbid users without the restore page permission. - */ - public function testForbidden(): void - { - $page = Page::factory()->trashed()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $page = Page::factory()->trashed()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->patch(route('api.page.restore', ['page' => $page])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = patch(route('api.page.restore', ['page' => $page])); - /** - * The Page Restore Endpoint shall forbid users from restoring a page that isn't trashed. - */ - public function testTrashed(): void - { - $page = Page::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(Page::class))->createOne(); +test('trashed', function () { + $page = Page::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(Page::class))->createOne(); - $response = $this->patch(route('api.page.restore', ['page' => $page])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = patch(route('api.page.restore', ['page' => $page])); - /** - * The Page Restore Endpoint shall restore the page. - */ - public function testRestored(): void - { - $page = Page::factory()->trashed()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(Page::class))->createOne(); +test('restored', function () { + $page = Page::factory()->trashed()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(Page::class))->createOne(); - $response = $this->patch(route('api.page.restore', ['page' => $page])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertNotSoftDeleted($page); - } -} + $response = patch(route('api.page.restore', ['page' => $page])); + + $response->assertOk(); + $this->assertNotSoftDeleted($page); +}); diff --git a/tests/Feature/Http/Api/Document/Page/PageShowTest.php b/tests/Feature/Http/Api/Document/Page/PageShowTest.php index c7d462736..c7806cc89 100644 --- a/tests/Feature/Http/Api/Document/Page/PageShowTest.php +++ b/tests/Feature/Http/Api/Document/Page/PageShowTest.php @@ -2,95 +2,78 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Document\Page; - use App\Http\Api\Field\Field; use App\Http\Api\Parser\FieldParser; use App\Http\Api\Query\Query; use App\Http\Api\Schema\Document\PageSchema; use App\Http\Resources\Document\Resource\PageResource; use App\Models\Document\Page; -use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; -class PageShowTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the Page Show Endpoint shall return a Page Resource. - */ - public function testDefault(): void - { - $page = Page::factory()->create(); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response = $this->get(route('api.page.show', ['page' => $page])); +test('default', function () { + $page = Page::factory()->create(); - $response->assertJson( - json_decode( - json_encode( - new PageResource($page, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.page.show', ['page' => $page])); - /** - * The Page Show Endpoint shall return a Page Resource for soft deleted images. - */ - public function testSoftDelete(): void - { - $page = Page::factory()->trashed()->createOne(); + $response->assertJson( + json_decode( + json_encode( + new PageResource($page, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $page->unsetRelations(); +test('soft delete', function () { + $page = Page::factory()->trashed()->createOne(); - $response = $this->get(route('api.page.show', ['page' => $page])); + $page->unsetRelations(); - $response->assertJson( - json_decode( - json_encode( - new PageResource($page, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.page.show', ['page' => $page])); - /** - * The Page Show Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new PageSchema(); + $response->assertJson( + json_decode( + json_encode( + new PageResource($page, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $fields = collect($schema->fields()); +test('sparse fieldsets', function () { + $schema = new PageSchema(); - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); + $fields = collect($schema->fields()); - $parameters = [ - FieldParser::param() => [ - PageResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); - $page = Page::factory()->create(); + $parameters = [ + FieldParser::param() => [ + PageResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; - $response = $this->get(route('api.page.show', ['page' => $page] + $parameters)); + $page = Page::factory()->create(); - $response->assertJson( - json_decode( - json_encode( - new PageResource($page, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response = get(route('api.page.show', ['page' => $page] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new PageResource($page, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Document/Page/PageStoreTest.php b/tests/Feature/Http/Api/Document/Page/PageStoreTest.php index b003f92e0..763e781e7 100644 --- a/tests/Feature/Http/Api/Document/Page/PageStoreTest.php +++ b/tests/Feature/Http/Api/Document/Page/PageStoreTest.php @@ -2,76 +2,56 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Document\Page; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Document\Page; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class PageStoreTest extends TestCase -{ - /** - * The Page Store Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $page = Page::factory()->makeOne(); +use function Pest\Laravel\post; - $response = $this->post(route('api.page.store', $page->toArray())); +test('protected', function () { + $page = Page::factory()->makeOne(); - $response->assertUnauthorized(); - } + $response = post(route('api.page.store', $page->toArray())); - /** - * The Page Store Endpoint shall forbid users without the create page permission. - */ - public function testForbidden(): void - { - $page = Page::factory()->makeOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $page = Page::factory()->makeOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->post(route('api.page.store', $page->toArray())); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.page.store', $page->toArray())); - /** - * The Page Store Endpoint shall require body, name & slug fields. - */ - public function testRequiredFields(): void - { - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Page::class))->createOne(); + $response->assertForbidden(); +}); - Sanctum::actingAs($user); +test('required fields', function () { + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Page::class))->createOne(); - $response = $this->post(route('api.page.store')); + Sanctum::actingAs($user); - $response->assertJsonValidationErrors([ - Page::ATTRIBUTE_BODY, - Page::ATTRIBUTE_NAME, - Page::ATTRIBUTE_SLUG, - ]); - } + $response = post(route('api.page.store')); - /** - * The Page Store Endpoint shall create a page. - */ - public function testCreate(): void - { - $parameters = Page::factory()->raw(); + $response->assertJsonValidationErrors([ + Page::ATTRIBUTE_BODY, + Page::ATTRIBUTE_NAME, + Page::ATTRIBUTE_SLUG, + ]); +}); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Page::class))->createOne(); +test('create', function () { + $parameters = Page::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Page::class))->createOne(); - $response = $this->post(route('api.page.store', $parameters)); + Sanctum::actingAs($user); - $response->assertCreated(); - static::assertDatabaseCount(Page::class, 1); - } -} + $response = post(route('api.page.store', $parameters)); + + $response->assertCreated(); + $this->assertDatabaseCount(Page::class, 1); +}); diff --git a/tests/Feature/Http/Api/Document/Page/PageUpdateTest.php b/tests/Feature/Http/Api/Document/Page/PageUpdateTest.php index a267dc785..2c1c797ba 100644 --- a/tests/Feature/Http/Api/Document/Page/PageUpdateTest.php +++ b/tests/Feature/Http/Api/Document/Page/PageUpdateTest.php @@ -2,81 +2,61 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Document\Page; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Document\Page; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class PageUpdateTest extends TestCase -{ - /** - * The Page Update Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $page = Page::factory()->createOne(); +use function Pest\Laravel\put; - $parameters = Page::factory()->raw(); +test('protected', function () { + $page = Page::factory()->createOne(); - $response = $this->put(route('api.page.update', ['page' => $page] + $parameters)); + $parameters = Page::factory()->raw(); - $response->assertUnauthorized(); - } + $response = put(route('api.page.update', ['page' => $page] + $parameters)); - /** - * The Page Update Endpoint shall forbid users without the update page permission. - */ - public function testForbidden(): void - { - $page = Page::factory()->createOne(); + $response->assertUnauthorized(); +}); - $parameters = Page::factory()->raw(); +test('forbidden', function () { + $page = Page::factory()->createOne(); - $user = User::factory()->createOne(); + $parameters = Page::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->put(route('api.page.update', ['page' => $page] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.page.update', ['page' => $page] + $parameters)); - /** - * The Page Update Endpoint shall forbid users from updating a page that is trashed. - */ - public function testTrashed(): void - { - $page = Page::factory()->trashed()->createOne(); + $response->assertForbidden(); +}); - $parameters = Page::factory()->raw(); +test('trashed', function () { + $page = Page::factory()->trashed()->createOne(); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Page::class))->createOne(); + $parameters = Page::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Page::class))->createOne(); - $response = $this->put(route('api.page.update', ['page' => $page] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.page.update', ['page' => $page] + $parameters)); - /** - * The Page Update Endpoint shall update an page. - */ - public function testUpdate(): void - { - $page = Page::factory()->createOne(); + $response->assertForbidden(); +}); - $parameters = Page::factory()->raw(); +test('update', function () { + $page = Page::factory()->createOne(); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Page::class))->createOne(); + $parameters = Page::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Page::class))->createOne(); - $response = $this->put(route('api.page.update', ['page' => $page] + $parameters)); + Sanctum::actingAs($user); - $response->assertOk(); - } -} + $response = put(route('api.page.update', ['page' => $page] + $parameters)); + + $response->assertOk(); +}); diff --git a/tests/Feature/Http/Api/FallbackTest.php b/tests/Feature/Http/Api/FallbackTest.php index c9cd0432e..520363737 100644 --- a/tests/Feature/Http/Api/FallbackTest.php +++ b/tests/Feature/Http/Api/FallbackTest.php @@ -2,23 +2,14 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api; - use Illuminate\Support\Str; -use Tests\TestCase; -class FallbackTest extends TestCase -{ - /** - * The API shall return an errors object when requests are made to an - * unregistered route. - */ - public function testAbortJson(): void - { - $response = $this->get(route('api.anime.index').Str::random()); +use function Pest\Laravel\get; - $response->assertJsonStructure([ - 'message', - ]); - } -} +test('abort json', function () { + $response = get(route('api.anime.index').Str::random()); + + $response->assertJsonStructure([ + 'message', + ]); +}); diff --git a/tests/Feature/Http/Api/List/External/Entry/ExternalEntryIndexTest.php b/tests/Feature/Http/Api/List/External/Entry/ExternalEntryIndexTest.php index adb0a7ee7..eb9edeb16 100644 --- a/tests/Feature/Http/Api/List/External/Entry/ExternalEntryIndexTest.php +++ b/tests/Feature/Http/Api/List/External/Entry/ExternalEntryIndexTest.php @@ -2,9 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\List\External\Entry; - -use App\Concerns\Actions\Http\Api\SortsModels; use App\Contracts\Http\Api\Field\SortableField; use App\Enums\Auth\CrudPermission; use App\Enums\Http\Api\Sort\Direction; @@ -29,396 +26,344 @@ use App\Models\BaseModel; use App\Models\List\External\ExternalEntry; use App\Models\List\ExternalProfile; use App\Models\Wiki\Anime; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Event; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; + +use function Pest\Laravel\get; + +uses(App\Concerns\Actions\Http\Api\SortsModels::class); + +uses(Illuminate\Foundation\Testing\WithFaker::class); /** - * Class External EntryIndexTest. + * Setup the test environment. */ -class ExternalEntryIndexTest extends TestCase -{ - use SortsModels; - use WithFaker; +beforeEach(function () { + Event::fakeExcept(ExternalProfileCreated::class); +}); - /** - * Setup the test environment. - */ - protected function setUp(): void - { - parent::setUp(); +test('private external entry cannot be publicly viewed', function () { + $profile = ExternalProfile::factory() + ->for(User::factory()) + ->entries(fake()->numberBetween(2, 9)) + ->createOne([ + ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PRIVATE->value, + ]); - Event::fakeExcept(ExternalProfileCreated::class); - } + $response = get(route('api.externalprofile.externalentry.index', ['externalprofile' => $profile])); - /** - * The External Entry Index Endpoint shall forbid a private profile from being publicly viewed. - */ - public function testPrivateExternalEntryCannotBePubliclyViewed(): void - { - $profile = ExternalProfile::factory() - ->for(User::factory()) - ->entries($this->faker->numberBetween(2, 9)) - ->createOne([ - ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PRIVATE->value, - ]); + $response->assertForbidden(); +}); - $response = $this->get(route('api.externalprofile.externalentry.index', ['externalprofile' => $profile])); +test('private external entry cannot be publicly viewed if not owned', function () { + $profile = ExternalProfile::factory() + ->for(User::factory()) + ->entries(fake()->numberBetween(2, 9)) + ->createOne([ + ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PRIVATE->value, + ]); - $response->assertForbidden(); - } + $user = User::factory()->withPermissions(CrudPermission::VIEW->format(ExternalEntry::class))->createOne(); - /** - * The External Entry Index Endpoint shall forbid the user from viewing private profile entries if not owned. - */ - public function testPrivateExternalEntryCannotBePubliclyViewedIfNotOwned(): void - { - $profile = ExternalProfile::factory() - ->for(User::factory()) - ->entries($this->faker->numberBetween(2, 9)) - ->createOne([ - ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PRIVATE->value, - ]); + Sanctum::actingAs($user); - $user = User::factory()->withPermissions(CrudPermission::VIEW->format(ExternalEntry::class))->createOne(); + $response = get(route('api.externalprofile.externalentry.index', ['externalprofile' => $profile])); - Sanctum::actingAs($user); + $response->assertForbidden(); +}); - $response = $this->get(route('api.externalprofile.externalentry.index', ['externalprofile' => $profile])); +test('private external entry can be viewed by owner', function () { + $user = User::factory()->withPermissions(CrudPermission::VIEW->format(ExternalEntry::class))->createOne(); - $response->assertForbidden(); - } + $profile = ExternalProfile::factory() + ->for($user) + ->entries(fake()->numberBetween(2, 9)) + ->createOne([ + ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PRIVATE->value, + ]); - /** - * The External Entry Index Endpoint shall allow private profile entries to be viewed by the owner. - */ - public function testPrivateExternalEntryCanBeViewedByOwner(): void - { - $user = User::factory()->withPermissions(CrudPermission::VIEW->format(ExternalEntry::class))->createOne(); + Sanctum::actingAs($user); - $profile = ExternalProfile::factory() - ->for($user) - ->entries($this->faker->numberBetween(2, 9)) - ->createOne([ - ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PRIVATE->value, - ]); + $response = get(route('api.externalprofile.externalentry.index', ['externalprofile' => $profile])); - Sanctum::actingAs($user); + $response->assertOk(); +}); - $response = $this->get(route('api.externalprofile.externalentry.index', ['externalprofile' => $profile])); +test('public external entry can be viewed', function () { + $profile = ExternalProfile::factory() + ->for(User::factory()) + ->entries(fake()->numberBetween(2, 9)) + ->createOne([ + ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value, + ]); - $response->assertOk(); - } + $response = get(route('api.externalprofile.externalentry.index', ['externalprofile' => $profile])); - /** - * The External Entry Index Endpoint shall allow public profile entries to be viewed. - */ - public function testPublicExternalEntryCanBeViewed(): void - { - $profile = ExternalProfile::factory() - ->for(User::factory()) - ->entries($this->faker->numberBetween(2, 9)) - ->createOne([ - ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value, - ]); + $response->assertOk(); +}); - $response = $this->get(route('api.externalprofile.externalentry.index', ['externalprofile' => $profile])); +test('default', function () { + $entryCount = fake()->randomDigitNotNull(); - $response->assertOk(); - } + $profile = ExternalProfile::factory() + ->has(ExternalEntry::factory()->count($entryCount), ExternalProfile::RELATION_EXTERNAL_ENTRIES) + ->createOne([ + ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value, + ]); - /** - * By default, the External Entry Index Endpoint shall return a collection of External Entry Resources that belong to the External Profile. - */ - public function testDefault(): void - { - $entryCount = $this->faker->randomDigitNotNull(); - - $profile = ExternalProfile::factory() + Collection::times( + fake()->randomDigitNotNull(), + fn () => ExternalProfile::factory() ->has(ExternalEntry::factory()->count($entryCount), ExternalProfile::RELATION_EXTERNAL_ENTRIES) ->createOne([ ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value, - ]); + ]) + ); - Collection::times( - $this->faker->randomDigitNotNull(), - fn () => ExternalProfile::factory() - ->has(ExternalEntry::factory()->count($entryCount), ExternalProfile::RELATION_EXTERNAL_ENTRIES) - ->createOne([ - ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value, - ]) - ); + $response = get(route('api.externalprofile.externalentry.index', ['externalprofile' => $profile])); - $response = $this->get(route('api.externalprofile.externalentry.index', ['externalprofile' => $profile])); + $response->assertJsonCount($entryCount, ExternalEntryCollection::$wrap); - $response->assertJsonCount($entryCount, ExternalEntryCollection::$wrap); + $response->assertJson( + json_decode( + json_encode( + new ExternalEntryCollection($profile->externalentries, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $response->assertJson( - json_decode( - json_encode( - new ExternalEntryCollection($profile->externalentries, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The External Entry Index Endpoint shall be paginated. - */ - public function testPaginated(): void - { - $profile = ExternalProfile::factory() - ->has(ExternalEntry::factory()->count($this->faker->randomDigitNotNull()), ExternalProfile::RELATION_EXTERNAL_ENTRIES) - ->createOne([ - ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value, - ]); - - $response = $this->get(route('api.externalprofile.externalentry.index', ['externalprofile' => $profile])); - - $response->assertJsonStructure([ - ExternalEntryCollection::$wrap, - 'links', - 'meta', +test('paginated', function () { + $profile = ExternalProfile::factory() + ->has(ExternalEntry::factory()->count(fake()->randomDigitNotNull()), ExternalProfile::RELATION_EXTERNAL_ENTRIES) + ->createOne([ + ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value, ]); - } - /** - * The External Entry Index Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new ExternalEntrySchema(); + $response = get(route('api.externalprofile.externalentry.index', ['externalprofile' => $profile])); - $allowedIncludes = collect($schema->allowedIncludes()); + $response->assertJsonStructure([ + ExternalEntryCollection::$wrap, + 'links', + 'meta', + ]); +}); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); +test('allowed include paths', function () { + $schema = new ExternalEntrySchema(); - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + $allowedIncludes = collect($schema->allowedIncludes()); - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); - $profile = ExternalProfile::factory() - ->createOne([ - ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value, - ]); + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - ExternalEntry::factory() + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + $profile = ExternalProfile::factory() + ->createOne([ + ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value, + ]); + + ExternalEntry::factory() + ->for($profile) + ->for(Anime::factory()) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $response = get(route('api.externalprofile.externalentry.index', ['externalprofile' => $profile] + $parameters)); + + $entries = ExternalEntry::with($includedPaths->all())->get(); + + $response->assertJson( + json_decode( + json_encode( + new ExternalEntryCollection($entries, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sparse fieldsets', function () { + $schema = new ExternalEntrySchema(); + + $fields = collect($schema->fields()); + + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + ExternalEntryResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + $profile = ExternalProfile::factory() + ->has(ExternalEntry::factory()->count(fake()->randomDigitNotNull()), ExternalProfile::RELATION_EXTERNAL_ENTRIES) + ->createOne([ + ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value, + ]); + + $response = get(route('api.externalprofile.externalentry.index', ['externalprofile' => $profile] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ExternalEntryCollection($profile->externalentries, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sorts', function () { + $schema = new ExternalEntrySchema(); + + /** @var Sort $sort */ + $sort = collect($schema->fields()) + ->filter(fn (Field $field) => $field instanceof SortableField) + ->map(fn (SortableField $field) => $field->getSort()) + ->random(); + + $parameters = [ + SortParser::param() => $sort->format(Arr::random(Direction::cases())), + ]; + + $profile = ExternalProfile::factory() + ->has(ExternalEntry::factory()->count(fake()->randomDigitNotNull()), ExternalProfile::RELATION_EXTERNAL_ENTRIES) + ->createOne([ + ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value, + ]); + + $query = new Query($parameters); + + $response = get(route('api.externalprofile.externalentry.index', ['externalprofile' => $profile] + $parameters)); + + $entries = $this->sort(ExternalEntry::query(), $query, $schema)->get(); + + $response->assertJson( + json_decode( + json_encode( + new ExternalEntryCollection($entries, $query) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('created at filter', function () { + $createdFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + $profile = ExternalProfile::factory() + ->createOne([ + ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value, + ]); + + Carbon::withTestNow( + $createdFilter, + fn () => ExternalEntry::factory() ->for($profile) - ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) - ->create(); + ->count(fake()->randomDigitNotNull()) + ->create() + ); - $response = $this->get(route('api.externalprofile.externalentry.index', ['externalprofile' => $profile] + $parameters)); + Carbon::withTestNow( + $excludedDate, + fn () => ExternalEntry::factory() + ->for($profile) + ->count(fake()->randomDigitNotNull()) + ->create() + ); - $entries = ExternalEntry::with($includedPaths->all())->get(); + $entries = ExternalEntry::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - $response->assertJson( - json_decode( - json_encode( - new ExternalEntryCollection($entries, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.externalprofile.externalentry.index', ['externalprofile' => $profile] + $parameters)); - /** - * The External Entry Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new ExternalEntrySchema(); + $response->assertJson( + json_decode( + json_encode( + new ExternalEntryCollection($entries, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $fields = collect($schema->fields()); +test('updated at filter', function () { + $updatedFilter = fake()->date(); + $excludedDate = fake()->date(); - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; - $parameters = [ - FieldParser::param() => [ - ExternalEntryResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; + $profile = ExternalProfile::factory() + ->createOne([ + ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value, + ]); - $profile = ExternalProfile::factory() - ->has(ExternalEntry::factory()->count($this->faker->randomDigitNotNull()), ExternalProfile::RELATION_EXTERNAL_ENTRIES) - ->createOne([ - ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value, - ]); + Carbon::withTestNow( + $updatedFilter, + fn () => ExternalEntry::factory() + ->for($profile) + ->count(fake()->randomDigitNotNull()) + ->create() + ); - $response = $this->get(route('api.externalprofile.externalentry.index', ['externalprofile' => $profile] + $parameters)); + Carbon::withTestNow( + $excludedDate, + fn () => ExternalEntry::factory() + ->for($profile) + ->count(fake()->randomDigitNotNull()) + ->create() + ); - $response->assertJson( - json_decode( - json_encode( - new ExternalEntryCollection($profile->externalentries, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $entries = ExternalEntry::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - /** - * The External Entry Index Endpoint shall support sorting resources. - */ - public function testSorts(): void - { - $schema = new ExternalEntrySchema(); + $response = get(route('api.externalprofile.externalentry.index', ['externalprofile' => $profile] + $parameters)); - /** @var Sort $sort */ - $sort = collect($schema->fields()) - ->filter(fn (Field $field) => $field instanceof SortableField) - ->map(fn (SortableField $field) => $field->getSort()) - ->random(); - - $parameters = [ - SortParser::param() => $sort->format(Arr::random(Direction::cases())), - ]; - - $profile = ExternalProfile::factory() - ->has(ExternalEntry::factory()->count($this->faker->randomDigitNotNull()), ExternalProfile::RELATION_EXTERNAL_ENTRIES) - ->createOne([ - ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value, - ]); - - $query = new Query($parameters); - - $response = $this->get(route('api.externalprofile.externalentry.index', ['externalprofile' => $profile] + $parameters)); - - $entries = $this->sort(ExternalEntry::query(), $query, $schema)->get(); - - $response->assertJson( - json_decode( - json_encode( - new ExternalEntryCollection($entries, $query) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The External Entry Index Endpoint shall support filtering by created_at. - */ - public function testCreatedAtFilter(): void - { - $createdFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - $profile = ExternalProfile::factory() - ->createOne([ - ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value, - ]); - - Carbon::withTestNow( - $createdFilter, - fn () => ExternalEntry::factory() - ->for($profile) - ->count($this->faker->randomDigitNotNull()) - ->create() - ); - - Carbon::withTestNow( - $excludedDate, - fn () => ExternalEntry::factory() - ->for($profile) - ->count($this->faker->randomDigitNotNull()) - ->create() - ); - - $entries = ExternalEntry::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - - $response = $this->get(route('api.externalprofile.externalentry.index', ['externalprofile' => $profile] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ExternalEntryCollection($entries, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The External Entry Index Endpoint shall support filtering by updated_at. - */ - public function testUpdatedAtFilter(): void - { - $updatedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - $profile = ExternalProfile::factory() - ->createOne([ - ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value, - ]); - - Carbon::withTestNow( - $updatedFilter, - fn () => ExternalEntry::factory() - ->for($profile) - ->count($this->faker->randomDigitNotNull()) - ->create() - ); - - Carbon::withTestNow( - $excludedDate, - fn () => ExternalEntry::factory() - ->for($profile) - ->count($this->faker->randomDigitNotNull()) - ->create() - ); - - $entries = ExternalEntry::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - - $response = $this->get(route('api.externalprofile.externalentry.index', ['externalprofile' => $profile] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ExternalEntryCollection($entries, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response->assertJson( + json_decode( + json_encode( + new ExternalEntryCollection($entries, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/List/External/Entry/ExternalEntryShowTest.php b/tests/Feature/Http/Api/List/External/Entry/ExternalEntryShowTest.php index d7e8b901e..5d754d242 100644 --- a/tests/Feature/Http/Api/List/External/Entry/ExternalEntryShowTest.php +++ b/tests/Feature/Http/Api/List/External/Entry/ExternalEntryShowTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\List\External\Entry; - use App\Enums\Auth\CrudPermission; use App\Enums\Models\List\ExternalProfileVisibility; use App\Events\List\ExternalProfile\ExternalProfileCreated; @@ -18,248 +16,210 @@ use App\Models\Auth\User; use App\Models\List\External\ExternalEntry; use App\Models\List\ExternalProfile; use App\Models\Wiki\Anime; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Facades\Event; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ExternalEntryShowTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * Setup the test environment. - */ - protected function setUp(): void - { - parent::setUp(); +uses(Illuminate\Foundation\Testing\WithFaker::class); - Event::fakeExcept(ExternalProfileCreated::class); - } +/** + * Setup the test environment. + */ +beforeEach(function () { + Event::fakeExcept(ExternalProfileCreated::class); +}); - /** - * The External Entry Show Endpoint shall forbid a private profile from being publicly viewed. - */ - public function testPrivateExternalEntryCannotBePubliclyViewed(): void - { - $profile = ExternalProfile::factory() - ->for(User::factory()) - ->createOne([ - ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PRIVATE->value, - ]); +test('private external entry cannot be publicly viewed', function () { + $profile = ExternalProfile::factory() + ->for(User::factory()) + ->createOne([ + ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PRIVATE->value, + ]); - $entry = ExternalEntry::factory() - ->for($profile) - ->createOne(); + $entry = ExternalEntry::factory() + ->for($profile) + ->createOne(); - $response = $this->get(route('api.externalprofile.externalentry.show', ['externalprofile' => $profile, 'externalentry' => $entry])); + $response = get(route('api.externalprofile.externalentry.show', ['externalprofile' => $profile, 'externalentry' => $entry])); - $response->assertForbidden(); - } + $response->assertForbidden(); +}); - /** - * The External Entry Show Endpoint shall forbid the user from viewing a private profile entry if not owned. - */ - public function testPrivateExternalEntryCannotBePubliclyViewedIfNotOwned(): void - { - $profile = ExternalProfile::factory() - ->for(User::factory()) - ->createOne([ - ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PRIVATE->value, - ]); +test('private external entry cannot be publicly viewed if not owned', function () { + $profile = ExternalProfile::factory() + ->for(User::factory()) + ->createOne([ + ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PRIVATE->value, + ]); - $entry = ExternalEntry::factory() - ->for($profile) - ->createOne(); + $entry = ExternalEntry::factory() + ->for($profile) + ->createOne(); - $user = User::factory()->withPermissions(CrudPermission::VIEW->format(ExternalEntry::class))->createOne(); + $user = User::factory()->withPermissions(CrudPermission::VIEW->format(ExternalEntry::class))->createOne(); - Sanctum::actingAs($user); + Sanctum::actingAs($user); - $response = $this->get(route('api.externalprofile.externalentry.show', ['externalprofile' => $profile, 'externalentry' => $entry])); + $response = get(route('api.externalprofile.externalentry.show', ['externalprofile' => $profile, 'externalentry' => $entry])); - $response->assertForbidden(); - } + $response->assertForbidden(); +}); - /** - * The External Entry Show Endpoint shall allow a private profile entry to be viewed by the owner. - */ - public function testPrivateExternalEntryCanBeViewedByOwner(): void - { - $user = User::factory()->withPermissions(CrudPermission::VIEW->format(ExternalEntry::class))->createOne(); +test('private external entry can be viewed by owner', function () { + $user = User::factory()->withPermissions(CrudPermission::VIEW->format(ExternalEntry::class))->createOne(); - $profile = ExternalProfile::factory() - ->for($user) - ->createOne([ - ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PRIVATE->value, - ]); + $profile = ExternalProfile::factory() + ->for($user) + ->createOne([ + ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PRIVATE->value, + ]); - $entry = ExternalEntry::factory() - ->for($profile) - ->createOne(); + $entry = ExternalEntry::factory() + ->for($profile) + ->createOne(); - Sanctum::actingAs($user); + Sanctum::actingAs($user); - $response = $this->get(route('api.externalprofile.externalentry.show', ['externalprofile' => $profile, 'externalentry' => $entry])); + $response = get(route('api.externalprofile.externalentry.show', ['externalprofile' => $profile, 'externalentry' => $entry])); - $response->assertOk(); - } + $response->assertOk(); +}); - /** - * The External Entry Show Endpoint shall allow a public profile entry to be viewed. - */ - public function testPublicExternalEntryCanBeViewed(): void - { - $profile = ExternalProfile::factory() - ->for(User::factory()) - ->createOne([ - ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value, - ]); +test('public external entry can be viewed', function () { + $profile = ExternalProfile::factory() + ->for(User::factory()) + ->createOne([ + ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value, + ]); - $entry = ExternalEntry::factory() - ->for($profile) - ->createOne(); + $entry = ExternalEntry::factory() + ->for($profile) + ->createOne(); - $response = $this->get(route('api.externalprofile.externalentry.show', ['externalprofile' => $profile, 'externalentry' => $entry])); + $response = get(route('api.externalprofile.externalentry.show', ['externalprofile' => $profile, 'externalentry' => $entry])); - $response->assertOk(); - } + $response->assertOk(); +}); - /** - * The External Entry Show Endpoint shall scope bindings. - */ - public function testScoped(): void - { - $user = User::factory()->withPermissions(CrudPermission::VIEW->format(ExternalEntry::class))->createOne(); +test('scoped', function () { + $user = User::factory()->withPermissions(CrudPermission::VIEW->format(ExternalEntry::class))->createOne(); - $profile = ExternalProfile::factory() - ->for($user) - ->has(ExternalEntry::factory()->count($this->faker->randomDigitNotNull()), ExternalProfile::RELATION_EXTERNAL_ENTRIES) - ->createOne([ - ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value, - ]); + $profile = ExternalProfile::factory() + ->for($user) + ->has(ExternalEntry::factory()->count(fake()->randomDigitNotNull()), ExternalProfile::RELATION_EXTERNAL_ENTRIES) + ->createOne([ + ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value, + ]); - $entry = ExternalEntry::factory() - ->for(ExternalProfile::factory()->for(User::factory())) - ->createOne(); + $entry = ExternalEntry::factory() + ->for(ExternalProfile::factory()->for(User::factory())) + ->createOne(); - $response = $this->get(route('api.externalprofile.externalentry.show', ['externalprofile' => $profile, 'externalentry' => $entry])); + $response = get(route('api.externalprofile.externalentry.show', ['externalprofile' => $profile, 'externalentry' => $entry])); - $response->assertNotFound(); - } + $response->assertNotFound(); +}); - /** - * By default, the External Entry Show Endpoint shall return an External Entry Resource. - */ - public function testDefault(): void - { - $profile = ExternalProfile::factory() - ->createOne([ - ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value, - ]); +test('default', function () { + $profile = ExternalProfile::factory() + ->createOne([ + ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value, + ]); - $entry = ExternalEntry::factory() - ->for($profile) - ->createOne(); + $entry = ExternalEntry::factory() + ->for($profile) + ->createOne(); - $response = $this->get(route('api.externalprofile.externalentry.show', ['externalprofile' => $profile, 'externalentry' => $entry])); + $response = get(route('api.externalprofile.externalentry.show', ['externalprofile' => $profile, 'externalentry' => $entry])); - $entry->unsetRelations(); + $entry->unsetRelations(); - $response->assertJson( - json_decode( - json_encode( - new ExternalEntryResource($entry, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $response->assertJson( + json_decode( + json_encode( + new ExternalEntryResource($entry, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - /** - * The External Entry Show Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new ExternalEntrySchema(); +test('allowed include paths', function () { + $schema = new ExternalEntrySchema(); - $allowedIncludes = collect($schema->allowedIncludes()); + $allowedIncludes = collect($schema->allowedIncludes()); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; - $profile = ExternalProfile::factory() - ->createOne([ - ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value, - ]); + $profile = ExternalProfile::factory() + ->createOne([ + ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value, + ]); - $entry = ExternalEntry::factory() - ->for($profile) - ->for(Anime::factory()) - ->createOne(); + $entry = ExternalEntry::factory() + ->for($profile) + ->for(Anime::factory()) + ->createOne(); - $response = $this->get(route('api.externalprofile.externalentry.show', ['externalprofile' => $profile, 'externalentry' => $entry] + $parameters)); + $response = get(route('api.externalprofile.externalentry.show', ['externalprofile' => $profile, 'externalentry' => $entry] + $parameters)); - $entry->unsetRelations()->load($includedPaths->all()); + $entry->unsetRelations()->load($includedPaths->all()); - $response->assertJson( - json_decode( - json_encode( - new ExternalEntryResource($entry, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response->assertJson( + json_decode( + json_encode( + new ExternalEntryResource($entry, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - /** - * The External Entry Show Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new ExternalEntrySchema(); +test('sparse fieldsets', function () { + $schema = new ExternalEntrySchema(); - $fields = collect($schema->fields()); + $fields = collect($schema->fields()); - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); - $parameters = [ - FieldParser::param() => [ - ExternalEntryResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; + $parameters = [ + FieldParser::param() => [ + ExternalEntryResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; - $profile = ExternalProfile::factory() - ->createOne([ - ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value, - ]); + $profile = ExternalProfile::factory() + ->createOne([ + ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value, + ]); - $entry = ExternalEntry::factory() - ->for($profile) - ->createOne(); + $entry = ExternalEntry::factory() + ->for($profile) + ->createOne(); - $response = $this->get(route('api.externalprofile.externalentry.show', ['externalprofile' => $profile, 'externalentry' => $entry] + $parameters)); + $response = get(route('api.externalprofile.externalentry.show', ['externalprofile' => $profile, 'externalentry' => $entry] + $parameters)); - $entry->unsetRelations(); + $entry->unsetRelations(); - $response->assertJson( - json_decode( - json_encode( - new ExternalEntryResource($entry, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response->assertJson( + json_decode( + json_encode( + new ExternalEntryResource($entry, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/List/External/ExternalProfileDestroyTest.php b/tests/Feature/Http/Api/List/External/ExternalProfileDestroyTest.php index 17af2f66f..5700fcd6b 100644 --- a/tests/Feature/Http/Api/List/External/ExternalProfileDestroyTest.php +++ b/tests/Feature/Http/Api/List/External/ExternalProfileDestroyTest.php @@ -2,153 +2,122 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\List\External; - use App\Enums\Auth\CrudPermission; use App\Enums\Auth\SpecialPermission; use App\Events\List\ExternalProfile\ExternalProfileCreated; use App\Features\AllowExternalProfileManagement; use App\Models\Auth\User; use App\Models\List\ExternalProfile; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ExternalProfileDestroyTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\delete; - /** - * The External Profile Destroy Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - Event::fakeExcept(ExternalProfileCreated::class); +uses(Illuminate\Foundation\Testing\WithFaker::class); - Feature::activate(AllowExternalProfileManagement::class); +test('protected', function () { + Event::fakeExcept(ExternalProfileCreated::class); - $profile = ExternalProfile::factory()->createOne(); + Feature::activate(AllowExternalProfileManagement::class); - $response = $this->delete(route('api.externalprofile.destroy', ['externalprofile' => $profile])); + $profile = ExternalProfile::factory()->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.externalprofile.destroy', ['externalprofile' => $profile])); - /** - * The External Profile Destroy Endpoint shall forbid users without the delete profile permission. - */ - public function testForbiddenIfMissingPermission(): void - { - Event::fakeExcept(ExternalProfileCreated::class); + $response->assertUnauthorized(); +}); - Feature::activate(AllowExternalProfileManagement::class); +test('forbidden if missing permission', function () { + Event::fakeExcept(ExternalProfileCreated::class); - $profile = ExternalProfile::factory()->createOne(); + Feature::activate(AllowExternalProfileManagement::class); - $user = User::factory()->createOne(); + $profile = ExternalProfile::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.externalprofile.destroy', ['externalprofile' => $profile])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.externalprofile.destroy', ['externalprofile' => $profile])); - /** - * The External Profile Destroy Endpoint shall forbid users from deleting the profile if they don't own it. - */ - public function testForbiddenIfNotOwnExternalProfile(): void - { - Event::fakeExcept(ExternalProfileCreated::class); + $response->assertForbidden(); +}); - Feature::activate(AllowExternalProfileManagement::class); +test('forbidden if not own external profile', function () { + Event::fakeExcept(ExternalProfileCreated::class); - $profile = ExternalProfile::factory() - ->for(User::factory()) - ->createOne(); + Feature::activate(AllowExternalProfileManagement::class); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(ExternalProfile::class))->createOne(); + $profile = ExternalProfile::factory() + ->for(User::factory()) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(ExternalProfile::class))->createOne(); - $response = $this->delete(route('api.externalprofile.destroy', ['externalprofile' => $profile])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.externalprofile.destroy', ['externalprofile' => $profile])); - /** - * The External Profile Destroy Endpoint shall forbid users from destroying profiles - * if the Allow ExternalProfile Management feature is inactive. - */ - public function testForbiddenIfFlagDisabled(): void - { - Event::fakeExcept(ExternalProfileCreated::class); + $response->assertForbidden(); +}); - Feature::deactivate(AllowExternalProfileManagement::class); +test('forbidden if flag disabled', function () { + Event::fakeExcept(ExternalProfileCreated::class); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(ExternalProfile::class))->createOne(); + Feature::deactivate(AllowExternalProfileManagement::class); - $profile = ExternalProfile::factory() - ->for($user) - ->createOne(); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(ExternalProfile::class))->createOne(); - Sanctum::actingAs($user); + $profile = ExternalProfile::factory() + ->for($user) + ->createOne(); - $response = $this->delete(route('api.externalprofile.destroy', ['externalprofile' => $profile])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.externalprofile.destroy', ['externalprofile' => $profile])); - /** - * The External Profile Destroy Endpoint shall delete the profile. - */ - public function testDeleted(): void - { - Event::fakeExcept(ExternalProfileCreated::class); + $response->assertForbidden(); +}); - Feature::activate(AllowExternalProfileManagement::class); +test('deleted', function () { + Event::fakeExcept(ExternalProfileCreated::class); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(ExternalProfile::class))->createOne(); + Feature::activate(AllowExternalProfileManagement::class); - $profile = ExternalProfile::factory() - ->for($user) - ->createOne(); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(ExternalProfile::class))->createOne(); - Sanctum::actingAs($user); + $profile = ExternalProfile::factory() + ->for($user) + ->createOne(); - $response = $this->delete(route('api.externalprofile.destroy', ['externalprofile' => $profile])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertModelMissing($profile); - } + $response = delete(route('api.externalprofile.destroy', ['externalprofile' => $profile])); - /** - * Users with the bypass feature flag permission shall be permitted to destroy profiles - * even if the Allow ExternalProfile Management feature is inactive. - */ - public function testDestroyPermittedForBypass(): void - { - Event::fakeExcept(ExternalProfileCreated::class); + $response->assertOk(); + $this->assertModelMissing($profile); +}); - Feature::activate(AllowExternalProfileManagement::class, $this->faker->boolean()); +test('destroy permitted for bypass', function () { + Event::fakeExcept(ExternalProfileCreated::class); - $user = User::factory() - ->withPermissions( - CrudPermission::DELETE->format(ExternalProfile::class), - SpecialPermission::BYPASS_FEATURE_FLAGS->value - ) - ->createOne(); + Feature::activate(AllowExternalProfileManagement::class, fake()->boolean()); - $profile = ExternalProfile::factory() - ->for($user) - ->createOne(); + $user = User::factory() + ->withPermissions( + CrudPermission::DELETE->format(ExternalProfile::class), + SpecialPermission::BYPASS_FEATURE_FLAGS->value + ) + ->createOne(); - Sanctum::actingAs($user); + $profile = ExternalProfile::factory() + ->for($user) + ->createOne(); - $response = $this->delete(route('api.externalprofile.destroy', ['externalprofile' => $profile])); + Sanctum::actingAs($user); - $response->assertOk(); - } -} + $response = delete(route('api.externalprofile.destroy', ['externalprofile' => $profile])); + + $response->assertOk(); +}); diff --git a/tests/Feature/Http/Api/List/External/ExternalProfileIndexTest.php b/tests/Feature/Http/Api/List/External/ExternalProfileIndexTest.php index 3f5ca94eb..c323a3527 100644 --- a/tests/Feature/Http/Api/List/External/ExternalProfileIndexTest.php +++ b/tests/Feature/Http/Api/List/External/ExternalProfileIndexTest.php @@ -2,10 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\List\External; - -use App\Concerns\Actions\Http\Api\AggregatesFields; -use App\Concerns\Actions\Http\Api\SortsModels; use App\Contracts\Http\Api\Field\SortableField; use App\Enums\Http\Api\Sort\Direction; use App\Enums\Models\List\ExternalProfileVisibility; @@ -27,272 +23,243 @@ use App\Models\Auth\User; use App\Models\BaseModel; use App\Models\List\External\ExternalEntry; use App\Models\List\ExternalProfile; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; -use Tests\TestCase; -class ExternalProfileIndexTest extends TestCase -{ - use AggregatesFields; - use SortsModels; - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the External Profile Index Endpoint shall return a collection of External Profile Resources with public visibility. - */ - public function testDefault(): void - { - $publicCount = $this->faker->randomDigitNotNull(); +uses(App\Concerns\Actions\Http\Api\AggregatesFields::class); - $profiles = ExternalProfile::factory() - ->count($publicCount) - ->create([ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value]); +uses(App\Concerns\Actions\Http\Api\SortsModels::class); - $privateCount = $this->faker->randomDigitNotNull(); +uses(Illuminate\Foundation\Testing\WithFaker::class); - ExternalProfile::factory() - ->count($privateCount) - ->create([ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PRIVATE->value]); +test('default', function () { + $publicCount = fake()->randomDigitNotNull(); - $response = $this->get(route('api.externalprofile.index')); + $profiles = ExternalProfile::factory() + ->count($publicCount) + ->create([ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value]); - $response->assertJsonCount($publicCount, ExternalProfileCollection::$wrap); + $privateCount = fake()->randomDigitNotNull(); - $response->assertJson( - json_decode( - json_encode( - new ExternalProfileCollection($profiles, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + ExternalProfile::factory() + ->count($privateCount) + ->create([ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PRIVATE->value]); - /** - * The External Profile Index Endpoint shall be paginated. - */ - public function testPaginated(): void - { - ExternalProfile::factory() - ->count($this->faker->randomDigitNotNull()) - ->create([ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value]); + $response = get(route('api.externalprofile.index')); - $response = $this->get(route('api.externalprofile.index')); + $response->assertJsonCount($publicCount, ExternalProfileCollection::$wrap); - $response->assertJsonStructure([ - ExternalProfileCollection::$wrap, - 'links', - 'meta', + $response->assertJson( + json_decode( + json_encode( + new ExternalProfileCollection($profiles, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('paginated', function () { + ExternalProfile::factory() + ->count(fake()->randomDigitNotNull()) + ->create([ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value]); + + $response = get(route('api.externalprofile.index')); + + $response->assertJsonStructure([ + ExternalProfileCollection::$wrap, + 'links', + 'meta', + ]); +}); + +test('allowed include paths', function () { + $schema = new ExternalProfileSchema(); + + $allowedIncludes = collect($schema->allowedIncludes()); + + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); + + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; + + ExternalProfile::factory() + ->for(User::factory()) + ->has(ExternalEntry::factory(), ExternalProfile::RELATION_EXTERNAL_ENTRIES) + ->count(fake()->randomDigitNotNull()) + ->create([ + ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value, ]); - } - /** - * The External Profile Index Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new ExternalProfileSchema(); + $profiles = ExternalProfile::with($includedPaths->all())->get(); - $allowedIncludes = collect($schema->allowedIncludes()); + $response = get(route('api.externalprofile.index', $parameters)); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $response->assertJson( + json_decode( + json_encode( + new ExternalProfileCollection($profiles, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); +test('sparse fieldsets', function () { + $schema = new ExternalProfileSchema(); - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; + $fields = collect($schema->fields()); + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + ExternalProfileResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + $profiles = ExternalProfile::factory() + ->count(fake()->randomDigitNotNull()) + ->create([ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value]); + + $response = get(route('api.externalprofile.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ExternalProfileCollection($profiles, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sorts', function () { + $schema = new ExternalProfileSchema(); + + /** @var Sort $sort */ + $sort = collect($schema->fields()) + ->filter(fn (Field $field) => $field instanceof SortableField) + ->map(fn (SortableField $field) => $field->getSort()) + ->random(); + + $parameters = [ + SortParser::param() => $sort->format(Arr::random(Direction::cases())), + ]; + + $query = new Query($parameters); + + ExternalProfile::factory() + ->count(fake()->randomDigitNotNull()) + ->create([ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value]); + + $response = get(route('api.externalprofile.index', $parameters)); + + $builder = ExternalProfile::query(); + $this->withAggregates($builder, $query, $schema); + $profiles = $this->sort($builder, $query, $schema)->get(); + + $response->assertJson( + json_decode( + json_encode( + new ExternalProfileCollection($profiles, $query) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('created at filter', function () { + $createdFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($createdFilter, function () { ExternalProfile::factory() - ->for(User::factory()) - ->has(ExternalEntry::factory(), ExternalProfile::RELATION_EXTERNAL_ENTRIES) - ->count($this->faker->randomDigitNotNull()) - ->create([ - ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value, - ]); - - $profiles = ExternalProfile::with($includedPaths->all())->get(); - - $response = $this->get(route('api.externalprofile.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ExternalProfileCollection($profiles, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The External Profile Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new ExternalProfileSchema(); - - $fields = collect($schema->fields()); - - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); - - $parameters = [ - FieldParser::param() => [ - ExternalProfileResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; - - $profiles = ExternalProfile::factory() - ->count($this->faker->randomDigitNotNull()) + ->count(fake()->randomDigitNotNull()) ->create([ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value]); + }); - $response = $this->get(route('api.externalprofile.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ExternalProfileCollection($profiles, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The External Profile Index Endpoint shall support sorting resources. - */ - public function testSorts(): void - { - $schema = new ExternalProfileSchema(); - - /** @var Sort $sort */ - $sort = collect($schema->fields()) - ->filter(fn (Field $field) => $field instanceof SortableField) - ->map(fn (SortableField $field) => $field->getSort()) - ->random(); - - $parameters = [ - SortParser::param() => $sort->format(Arr::random(Direction::cases())), - ]; - - $query = new Query($parameters); - + Carbon::withTestNow($excludedDate, function () { ExternalProfile::factory() - ->count($this->faker->randomDigitNotNull()) + ->count(fake()->randomDigitNotNull()) ->create([ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value]); + }); - $response = $this->get(route('api.externalprofile.index', $parameters)); + $profiles = ExternalProfile::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - $builder = ExternalProfile::query(); - $this->withAggregates($builder, $query, $schema); - $profiles = $this->sort($builder, $query, $schema)->get(); + $response = get(route('api.externalprofile.index', $parameters)); - $response->assertJson( - json_decode( - json_encode( - new ExternalProfileCollection($profiles, $query) - ->response() - ->getData() - ), - true - ) - ); - } + $response->assertJson( + json_decode( + json_encode( + new ExternalProfileCollection($profiles, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - /** - * The External Profile Index Endpoint shall support filtering by created_at. - */ - public function testCreatedAtFilter(): void - { - $createdFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); +test('updated at filter', function () { + $updatedFilter = fake()->date(); + $excludedDate = fake()->date(); - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; - Carbon::withTestNow($createdFilter, function () { - ExternalProfile::factory() - ->count($this->faker->randomDigitNotNull()) - ->create([ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value]); - }); + Carbon::withTestNow($updatedFilter, function () { + ExternalProfile::factory() + ->count(fake()->randomDigitNotNull()) + ->create([ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value]); + }); - Carbon::withTestNow($excludedDate, function () { - ExternalProfile::factory() - ->count($this->faker->randomDigitNotNull()) - ->create([ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value]); - }); + Carbon::withTestNow($excludedDate, function () { + ExternalProfile::factory() + ->count(fake()->randomDigitNotNull()) + ->create([ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value]); + }); - $profiles = ExternalProfile::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); + $profiles = ExternalProfile::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - $response = $this->get(route('api.externalprofile.index', $parameters)); + $response = get(route('api.externalprofile.index', $parameters)); - $response->assertJson( - json_decode( - json_encode( - new ExternalProfileCollection($profiles, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The External Profile Index Endpoint shall support filtering by updated_at. - */ - public function testUpdatedAtFilter(): void - { - $updatedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($updatedFilter, function () { - ExternalProfile::factory() - ->count($this->faker->randomDigitNotNull()) - ->create([ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value]); - }); - - Carbon::withTestNow($excludedDate, function () { - ExternalProfile::factory() - ->count($this->faker->randomDigitNotNull()) - ->create([ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value]); - }); - - $profiles = ExternalProfile::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - - $response = $this->get(route('api.externalprofile.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ExternalProfileCollection($profiles, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response->assertJson( + json_decode( + json_encode( + new ExternalProfileCollection($profiles, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/List/External/ExternalProfileShowTest.php b/tests/Feature/Http/Api/List/External/ExternalProfileShowTest.php index 9bd1a3e70..6c377d503 100644 --- a/tests/Feature/Http/Api/List/External/ExternalProfileShowTest.php +++ b/tests/Feature/Http/Api/List/External/ExternalProfileShowTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\List\External; - use App\Enums\Auth\CrudPermission; use App\Enums\Models\List\ExternalProfileVisibility; use App\Events\List\ExternalProfile\ExternalProfileCreated; @@ -17,196 +15,165 @@ use App\Http\Resources\List\Resource\ExternalProfileResource; use App\Models\Auth\User; use App\Models\List\External\ExternalEntry; use App\Models\List\ExternalProfile; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Facades\Event; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ExternalProfileShowTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * The External Profile Show Endpoint shall forbid a private profile from being publicly viewed. - */ - public function testPrivateExternalProfileCannotBePubliclyViewed(): void - { - Event::fakeExcept(ExternalProfileCreated::class); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $profile = ExternalProfile::factory() - ->for(User::factory()) - ->createOne([ - ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PRIVATE->value, - ]); +test('private external profile cannot be publicly viewed', function () { + Event::fakeExcept(ExternalProfileCreated::class); - $response = $this->get(route('api.externalprofile.show', ['externalprofile' => $profile])); + $profile = ExternalProfile::factory() + ->for(User::factory()) + ->createOne([ + ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PRIVATE->value, + ]); - $response->assertForbidden(); - } + $response = get(route('api.externalprofile.show', ['externalprofile' => $profile])); - /** - * The External Profile Show Endpoint shall forbid the user from viewing a private profile if not owned. - */ - public function testPrivateExternalProfileCannotBePubliclyIfNotOwned(): void - { - Event::fakeExcept(ExternalProfileCreated::class); + $response->assertForbidden(); +}); - $profile = ExternalProfile::factory() - ->for(User::factory()) - ->createOne([ - ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PRIVATE->value, - ]); +test('private external profile cannot be publicly if not owned', function () { + Event::fakeExcept(ExternalProfileCreated::class); - $user = User::factory()->withPermissions(CrudPermission::VIEW->format(ExternalProfile::class))->createOne(); + $profile = ExternalProfile::factory() + ->for(User::factory()) + ->createOne([ + ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PRIVATE->value, + ]); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::VIEW->format(ExternalProfile::class))->createOne(); - $response = $this->get(route('api.externalprofile.show', ['externalprofile' => $profile])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = get(route('api.externalprofile.show', ['externalprofile' => $profile])); - /** - * The External Profile Show Endpoint shall allow a private profile to be viewed by the owner. - */ - public function testPrivateExternalProfileCanBeViewedByOwner(): void - { - Event::fakeExcept(ExternalProfileCreated::class); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(CrudPermission::VIEW->format(ExternalProfile::class))->createOne(); +test('private external profile can be viewed by owner', function () { + Event::fakeExcept(ExternalProfileCreated::class); - $profile = ExternalProfile::factory() - ->for($user) - ->createOne([ - ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PRIVATE->value, - ]); + $user = User::factory()->withPermissions(CrudPermission::VIEW->format(ExternalProfile::class))->createOne(); - Sanctum::actingAs($user); + $profile = ExternalProfile::factory() + ->for($user) + ->createOne([ + ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PRIVATE->value, + ]); - $response = $this->get(route('api.externalprofile.show', ['externalprofile' => $profile])); + Sanctum::actingAs($user); - $response->assertOk(); - } + $response = get(route('api.externalprofile.show', ['externalprofile' => $profile])); - /** - * The External Profile Show Endpoint shall allow a public profile to be viewed. - */ - public function testPublicExternalProfileCanBeViewed(): void - { - Event::fakeExcept(ExternalProfileCreated::class); + $response->assertOk(); +}); - $profile = ExternalProfile::factory() - ->for(User::factory()) - ->createOne([ - ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value, - ]); +test('public external profile can be viewed', function () { + Event::fakeExcept(ExternalProfileCreated::class); - $response = $this->get(route('api.externalprofile.show', ['externalprofile' => $profile])); + $profile = ExternalProfile::factory() + ->for(User::factory()) + ->createOne([ + ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value, + ]); - $response->assertOk(); - } + $response = get(route('api.externalprofile.show', ['externalprofile' => $profile])); - /** - * By default, the External Profile Show Endpoint shall return a External Profile Resource. - */ - public function testDefault(): void - { - Event::fakeExcept(ExternalProfileCreated::class); + $response->assertOk(); +}); - $profile = ExternalProfile::factory() - ->createOne([ - ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value, - ]); +test('default', function () { + Event::fakeExcept(ExternalProfileCreated::class); - $response = $this->get(route('api.externalprofile.show', ['externalprofile' => $profile])); + $profile = ExternalProfile::factory() + ->createOne([ + ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value, + ]); - $response->assertJson( - json_decode( - json_encode( - new ExternalProfileResource($profile, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.externalprofile.show', ['externalprofile' => $profile])); - /** - * The External Profile Show Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - Event::fakeExcept(ExternalProfileCreated::class); + $response->assertJson( + json_decode( + json_encode( + new ExternalProfileResource($profile, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $schema = new ExternalProfileSchema(); +test('allowed include paths', function () { + Event::fakeExcept(ExternalProfileCreated::class); - $allowedIncludes = collect($schema->allowedIncludes()); + $schema = new ExternalProfileSchema(); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $allowedIncludes = collect($schema->allowedIncludes()); - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - $profile = ExternalProfile::factory() - ->for(User::factory()) - ->has(ExternalEntry::factory(), ExternalProfile::RELATION_EXTERNAL_ENTRIES) - ->createOne([ - ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value, - ]); + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; - $response = $this->get(route('api.externalprofile.show', ['externalprofile' => $profile] + $parameters)); + $profile = ExternalProfile::factory() + ->for(User::factory()) + ->has(ExternalEntry::factory(), ExternalProfile::RELATION_EXTERNAL_ENTRIES) + ->createOne([ + ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value, + ]); - $response->assertJson( - json_decode( - json_encode( - new ExternalProfileResource($profile, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.externalprofile.show', ['externalprofile' => $profile] + $parameters)); - /** - * The External Profile Show Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - Event::fakeExcept(ExternalProfileCreated::class); + $response->assertJson( + json_decode( + json_encode( + new ExternalProfileResource($profile, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $schema = new ExternalProfileSchema(); +test('sparse fieldsets', function () { + Event::fakeExcept(ExternalProfileCreated::class); - $fields = collect($schema->fields()); + $schema = new ExternalProfileSchema(); - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); + $fields = collect($schema->fields()); - $parameters = [ - FieldParser::param() => [ - ExternalProfileResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); - $profile = ExternalProfile::factory() - ->createOne([ - ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value, - ]); + $parameters = [ + FieldParser::param() => [ + ExternalProfileResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; - $response = $this->get(route('api.externalprofile.show', ['externalprofile' => $profile] + $parameters)); + $profile = ExternalProfile::factory() + ->createOne([ + ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value, + ]); - $response->assertJson( - json_decode( - json_encode( - new ExternalProfileResource($profile, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response = get(route('api.externalprofile.show', ['externalprofile' => $profile] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ExternalProfileResource($profile, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/List/External/ExternalProfileStoreTest.php b/tests/Feature/Http/Api/List/External/ExternalProfileStoreTest.php index 0a431f8a2..9af40cfde 100644 --- a/tests/Feature/Http/Api/List/External/ExternalProfileStoreTest.php +++ b/tests/Feature/Http/Api/List/External/ExternalProfileStoreTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\List\External; - use App\Constants\Config\ExternalProfileConstants; use App\Constants\Config\ValidationConstants; use App\Enums\Auth\CrudPermission; @@ -13,304 +11,254 @@ use App\Enums\Rules\ModerationService; use App\Features\AllowExternalProfileManagement; use App\Models\Auth\User; use App\Models\List\ExternalProfile; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Http; use Laravel\Pennant\Feature; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ExternalProfileStoreTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\post; - /** - * The External Profile Store Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - Feature::activate(AllowExternalProfileManagement::class); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $profile = ExternalProfile::factory()->makeOne(); +test('protected', function () { + Feature::activate(AllowExternalProfileManagement::class); - $response = $this->post(route('api.externalprofile.store', $profile->toArray())); + $profile = ExternalProfile::factory()->makeOne(); - $response->assertUnauthorized(); - } + $response = post(route('api.externalprofile.store', $profile->toArray())); - /** - * The External Profile Store Endpoint shall forbid users without the create profile permission. - */ - public function testForbiddenIfMissingPermission(): void - { - Feature::activate(AllowExternalProfileManagement::class); + $response->assertUnauthorized(); +}); - $profile = ExternalProfile::factory()->makeOne(); +test('forbidden if missing permission', function () { + Feature::activate(AllowExternalProfileManagement::class); - $user = User::factory()->createOne(); + $profile = ExternalProfile::factory()->makeOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->post(route('api.externalprofile.store', $profile->toArray())); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.externalprofile.store', $profile->toArray())); - /** - * The External Profile Store Endpoint shall forbid users from creating profiles - * if the Allow ExternalProfile Management feature is inactive. - */ - public function testForbiddenIfFlagDisabled(): void - { - Feature::deactivate(AllowExternalProfileManagement::class); + $response->assertForbidden(); +}); - $visibility = Arr::random(ExternalProfileVisibility::cases()); +test('forbidden if flag disabled', function () { + Feature::deactivate(AllowExternalProfileManagement::class); - $parameters = array_merge( - ExternalProfile::factory()->raw(), - [ExternalProfile::ATTRIBUTE_VISIBILITY => $visibility->localize()], - ); + $visibility = Arr::random(ExternalProfileVisibility::cases()); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(ExternalProfile::class))->createOne(); + $parameters = array_merge( + ExternalProfile::factory()->raw(), + [ExternalProfile::ATTRIBUTE_VISIBILITY => $visibility->localize()], + ); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(ExternalProfile::class))->createOne(); - $response = $this->post(route('api.externalprofile.store', $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.externalprofile.store', $parameters)); - /** - * The External Profile Store Endpoint shall require name & site fields. - */ - public function testRequiredFields(): void - { - Feature::activate(AllowExternalProfileManagement::class); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(ExternalProfile::class))->createOne(); +test('required fields', function () { + Feature::activate(AllowExternalProfileManagement::class); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(ExternalProfile::class))->createOne(); - $response = $this->post(route('api.externalprofile.store')); + Sanctum::actingAs($user); - $response->assertJsonValidationErrors([ - ExternalProfile::ATTRIBUTE_NAME, - ExternalProfile::ATTRIBUTE_SITE, - ]); - } + $response = post(route('api.externalprofile.store')); - /** - * The External Profile Store Endpoint shall create a profile. - */ - public function testCreate(): void - { - Feature::activate(AllowExternalProfileManagement::class); + $response->assertJsonValidationErrors([ + ExternalProfile::ATTRIBUTE_NAME, + ExternalProfile::ATTRIBUTE_SITE, + ]); +}); - $visibility = Arr::random(ExternalProfileVisibility::cases()); +test('create', function () { + Feature::activate(AllowExternalProfileManagement::class); - $parameters = array_merge( - ExternalProfile::factory()->raw(), - [ExternalProfile::ATTRIBUTE_VISIBILITY => $visibility->localize()], - ); + $visibility = Arr::random(ExternalProfileVisibility::cases()); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(ExternalProfile::class))->createOne(); + $parameters = array_merge( + ExternalProfile::factory()->raw(), + [ExternalProfile::ATTRIBUTE_VISIBILITY => $visibility->localize()], + ); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(ExternalProfile::class))->createOne(); - $response = $this->post(route('api.externalprofile.store', $parameters)); + Sanctum::actingAs($user); - $response->assertCreated(); - static::assertDatabaseCount(ExternalProfile::class, 1); - static::assertDatabaseHas(ExternalProfile::class, [ExternalProfile::ATTRIBUTE_USER => $user->getKey()]); - } + $response = post(route('api.externalprofile.store', $parameters)); - /** - * Users with the bypass feature flag permission shall be permitted to create profiles - * even if the Allow ExternalProfile Management feature is inactive. - */ - public function testCreatePermittedForBypass(): void - { - Feature::activate(AllowExternalProfileManagement::class, $this->faker->boolean()); + $response->assertCreated(); + $this->assertDatabaseCount(ExternalProfile::class, 1); + $this->assertDatabaseHas(ExternalProfile::class, [ExternalProfile::ATTRIBUTE_USER => $user->getKey()]); +}); - $visibility = Arr::random(ExternalProfileVisibility::cases()); +test('create permitted for bypass', function () { + Feature::activate(AllowExternalProfileManagement::class, fake()->boolean()); - $parameters = array_merge( - ExternalProfile::factory()->raw(), - [ExternalProfile::ATTRIBUTE_VISIBILITY => $visibility->localize()], - ); + $visibility = Arr::random(ExternalProfileVisibility::cases()); - $user = User::factory() - ->withPermissions( - CrudPermission::CREATE->format(ExternalProfile::class), - SpecialPermission::BYPASS_FEATURE_FLAGS->value - ) - ->createOne(); + $parameters = array_merge( + ExternalProfile::factory()->raw(), + [ExternalProfile::ATTRIBUTE_VISIBILITY => $visibility->localize()], + ); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::CREATE->format(ExternalProfile::class), + SpecialPermission::BYPASS_FEATURE_FLAGS->value + ) + ->createOne(); - $response = $this->post(route('api.externalprofile.store', $parameters)); + Sanctum::actingAs($user); - $response->assertCreated(); - } + $response = post(route('api.externalprofile.store', $parameters)); - /** - * The External Profile Store Endpoint shall forbid users from creating profiles that exceed the user profile limit. - */ - public function testMaxProfileLimit(): void - { - $profileLimit = $this->faker->randomDigitNotNull(); + $response->assertCreated(); +}); - Config::set(ExternalProfileConstants::MAX_PROFILES_QUALIFIED, $profileLimit); - Feature::activate(AllowExternalProfileManagement::class); +test('max profile limit', function () { + $profileLimit = fake()->randomDigitNotNull(); - $visibility = Arr::random(ExternalProfileVisibility::cases()); + Config::set(ExternalProfileConstants::MAX_PROFILES_QUALIFIED, $profileLimit); + Feature::activate(AllowExternalProfileManagement::class); - $parameters = array_merge( - ExternalProfile::factory()->raw(), - [ExternalProfile::ATTRIBUTE_VISIBILITY => $visibility->localize()], - ); + $visibility = Arr::random(ExternalProfileVisibility::cases()); - $user = User::factory() - ->has(ExternalProfile::factory()->count($profileLimit)) - ->withPermissions(CrudPermission::CREATE->format(ExternalProfile::class)) - ->createOne(); + $parameters = array_merge( + ExternalProfile::factory()->raw(), + [ExternalProfile::ATTRIBUTE_VISIBILITY => $visibility->localize()], + ); - Sanctum::actingAs($user); + $user = User::factory() + ->has(ExternalProfile::factory()->count($profileLimit)) + ->withPermissions(CrudPermission::CREATE->format(ExternalProfile::class)) + ->createOne(); - $response = $this->post(route('api.externalprofile.store', $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.externalprofile.store', $parameters)); - /** - * The External Profile Store Endpoint shall permit users with bypass feature flag permission - * to create profiles that exceed the user profile limit. - */ - public function testMaxProfileLimitPermittedForBypass(): void - { - $profileLimit = $this->faker->randomDigitNotNull(); + $response->assertForbidden(); +}); - Config::set(ExternalProfileConstants::MAX_PROFILES_QUALIFIED, $profileLimit); - Feature::activate(AllowExternalProfileManagement::class); +test('max profile limit permitted for bypass', function () { + $profileLimit = fake()->randomDigitNotNull(); - $visibility = Arr::random(ExternalProfileVisibility::cases()); + Config::set(ExternalProfileConstants::MAX_PROFILES_QUALIFIED, $profileLimit); + Feature::activate(AllowExternalProfileManagement::class); - $parameters = array_merge( - ExternalProfile::factory()->raw(), - [ExternalProfile::ATTRIBUTE_VISIBILITY => $visibility->localize()], - ); + $visibility = Arr::random(ExternalProfileVisibility::cases()); - $user = User::factory() - ->has(ExternalProfile::factory()->count($profileLimit)) - ->withPermissions( - CrudPermission::CREATE->format(ExternalProfile::class), - SpecialPermission::BYPASS_FEATURE_FLAGS->value - ) - ->createOne(); + $parameters = array_merge( + ExternalProfile::factory()->raw(), + [ExternalProfile::ATTRIBUTE_VISIBILITY => $visibility->localize()], + ); - Sanctum::actingAs($user); + $user = User::factory() + ->has(ExternalProfile::factory()->count($profileLimit)) + ->withPermissions( + CrudPermission::CREATE->format(ExternalProfile::class), + SpecialPermission::BYPASS_FEATURE_FLAGS->value + ) + ->createOne(); - $response = $this->post(route('api.externalprofile.store', $parameters)); + Sanctum::actingAs($user); - $response->assertCreated(); - } + $response = post(route('api.externalprofile.store', $parameters)); - /** - * The ExternalProfile Store Endpoint shall create a profile if the name is not flagged by OpenAI. - */ - public function testCreatedIfNotFlaggedByOpenAi(): void - { - Feature::activate(AllowExternalProfileManagement::class); - Config::set(ValidationConstants::MODERATION_SERVICE_QUALIFIED, ModerationService::OPENAI->value); + $response->assertCreated(); +}); - Http::fake([ - 'https://api.openai.com/v1/moderations' => Http::response([ - 'results' => [ - 0 => [ - 'flagged' => false, - ], +test('created if not flagged by open ai', function () { + Feature::activate(AllowExternalProfileManagement::class); + Config::set(ValidationConstants::MODERATION_SERVICE_QUALIFIED, ModerationService::OPENAI->value); + + Http::fake([ + 'https://api.openai.com/v1/moderations' => Http::response([ + 'results' => [ + 0 => [ + 'flagged' => false, ], - ]), - ]); + ], + ]), + ]); - $visibility = Arr::random(ExternalProfileVisibility::cases()); + $visibility = Arr::random(ExternalProfileVisibility::cases()); - $parameters = array_merge( - ExternalProfile::factory()->raw(), - [ExternalProfile::ATTRIBUTE_VISIBILITY => $visibility->localize()], - ); + $parameters = array_merge( + ExternalProfile::factory()->raw(), + [ExternalProfile::ATTRIBUTE_VISIBILITY => $visibility->localize()], + ); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(ExternalProfile::class))->createOne(); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(ExternalProfile::class))->createOne(); - Sanctum::actingAs($user); + Sanctum::actingAs($user); - $response = $this->post(route('api.externalprofile.store', $parameters)); + $response = post(route('api.externalprofile.store', $parameters)); - $response->assertCreated(); - } + $response->assertCreated(); +}); - /** - * The External Profile Store Endpoint shall create a profile if the moderation service returns some error. - */ - public function testCreatedIfOpenAiFails(): void - { - Feature::activate(AllowExternalProfileManagement::class); - Config::set(ValidationConstants::MODERATION_SERVICE_QUALIFIED, ModerationService::OPENAI->value); +test('created if open ai fails', function () { + Feature::activate(AllowExternalProfileManagement::class); + Config::set(ValidationConstants::MODERATION_SERVICE_QUALIFIED, ModerationService::OPENAI->value); - Http::fake([ - 'https://api.openai.com/v1/moderations' => Http::response(status: 404), - ]); + Http::fake([ + 'https://api.openai.com/v1/moderations' => Http::response(status: 404), + ]); - $visibility = Arr::random(ExternalProfileVisibility::cases()); + $visibility = Arr::random(ExternalProfileVisibility::cases()); - $parameters = array_merge( - ExternalProfile::factory()->raw(), - [ExternalProfile::ATTRIBUTE_VISIBILITY => $visibility->localize()], - ); + $parameters = array_merge( + ExternalProfile::factory()->raw(), + [ExternalProfile::ATTRIBUTE_VISIBILITY => $visibility->localize()], + ); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(ExternalProfile::class))->createOne(); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(ExternalProfile::class))->createOne(); - Sanctum::actingAs($user); + Sanctum::actingAs($user); - $response = $this->post(route('api.externalprofile.store', $parameters)); + $response = post(route('api.externalprofile.store', $parameters)); - $response->assertCreated(); - } + $response->assertCreated(); +}); - /** - * The External Profile Store Endpoint shall prohibit users from creating profiles with names flagged by OpenAI. - */ - public function testValidationErrorWhenFlaggedByOpenAi(): void - { - Feature::activate(AllowExternalProfileManagement::class); - Config::set(ValidationConstants::MODERATION_SERVICE_QUALIFIED, ModerationService::OPENAI->value); +test('validation error when flagged by open ai', function () { + Feature::activate(AllowExternalProfileManagement::class); + Config::set(ValidationConstants::MODERATION_SERVICE_QUALIFIED, ModerationService::OPENAI->value); - Http::fake([ - 'https://api.openai.com/v1/moderations' => Http::response([ - 'results' => [ - 0 => [ - 'flagged' => true, - ], + Http::fake([ + 'https://api.openai.com/v1/moderations' => Http::response([ + 'results' => [ + 0 => [ + 'flagged' => true, ], - ]), - ]); + ], + ]), + ]); - $visibility = Arr::random(ExternalProfileVisibility::cases()); + $visibility = Arr::random(ExternalProfileVisibility::cases()); - $parameters = array_merge( - ExternalProfile::factory()->raw(), - [ExternalProfile::ATTRIBUTE_VISIBILITY => $visibility->localize()], - ); + $parameters = array_merge( + ExternalProfile::factory()->raw(), + [ExternalProfile::ATTRIBUTE_VISIBILITY => $visibility->localize()], + ); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(ExternalProfile::class))->createOne(); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(ExternalProfile::class))->createOne(); - Sanctum::actingAs($user); + Sanctum::actingAs($user); - $response = $this->post(route('api.externalprofile.store', $parameters)); + $response = post(route('api.externalprofile.store', $parameters)); - $response->assertJsonValidationErrors([ - ExternalProfile::ATTRIBUTE_NAME, - ]); - } -} + $response->assertJsonValidationErrors([ + ExternalProfile::ATTRIBUTE_NAME, + ]); +}); diff --git a/tests/Feature/Http/Api/List/External/ExternalProfileUpdateTest.php b/tests/Feature/Http/Api/List/External/ExternalProfileUpdateTest.php index 27eeb0bf5..7cfd0c9f1 100644 --- a/tests/Feature/Http/Api/List/External/ExternalProfileUpdateTest.php +++ b/tests/Feature/Http/Api/List/External/ExternalProfileUpdateTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\List\External; - use App\Enums\Auth\CrudPermission; use App\Enums\Auth\SpecialPermission; use App\Enums\Models\List\ExternalProfileVisibility; @@ -11,193 +9,164 @@ use App\Events\List\ExternalProfile\ExternalProfileCreated; use App\Features\AllowExternalProfileManagement; use App\Models\Auth\User; use App\Models\List\ExternalProfile; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ExternalProfileUpdateTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\put; - /** - * The External Profile Update Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - Event::fakeExcept(ExternalProfileCreated::class); +uses(Illuminate\Foundation\Testing\WithFaker::class); - Feature::activate(AllowExternalProfileManagement::class); +test('protected', function () { + Event::fakeExcept(ExternalProfileCreated::class); - $profile = ExternalProfile::factory()->createOne(); + Feature::activate(AllowExternalProfileManagement::class); - $visibility = Arr::random(ExternalProfileVisibility::cases()); + $profile = ExternalProfile::factory()->createOne(); - $parameters = array_merge( - ExternalProfile::factory()->raw(), - [ExternalProfile::ATTRIBUTE_VISIBILITY => $visibility->localize()], - ); + $visibility = Arr::random(ExternalProfileVisibility::cases()); - $response = $this->put(route('api.externalprofile.update', ['externalprofile' => $profile] + $parameters)); + $parameters = array_merge( + ExternalProfile::factory()->raw(), + [ExternalProfile::ATTRIBUTE_VISIBILITY => $visibility->localize()], + ); - $response->assertUnauthorized(); - } + $response = put(route('api.externalprofile.update', ['externalprofile' => $profile] + $parameters)); - /** - * The External Profile Update Endpoint shall forbid users without the update profile permission. - */ - public function testForbiddenIfMissingPermission(): void - { - Event::fakeExcept(ExternalProfileCreated::class); + $response->assertUnauthorized(); +}); - Feature::activate(AllowExternalProfileManagement::class); +test('forbidden if missing permission', function () { + Event::fakeExcept(ExternalProfileCreated::class); - $profile = ExternalProfile::factory()->createOne(); + Feature::activate(AllowExternalProfileManagement::class); - $visibility = Arr::random(ExternalProfileVisibility::cases()); + $profile = ExternalProfile::factory()->createOne(); - $parameters = array_merge( - ExternalProfile::factory()->raw(), - [ExternalProfile::ATTRIBUTE_VISIBILITY => $visibility->localize()], - ); + $visibility = Arr::random(ExternalProfileVisibility::cases()); - $user = User::factory()->createOne(); + $parameters = array_merge( + ExternalProfile::factory()->raw(), + [ExternalProfile::ATTRIBUTE_VISIBILITY => $visibility->localize()], + ); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->put(route('api.externalprofile.update', ['externalprofile' => $profile] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.externalprofile.update', ['externalprofile' => $profile] + $parameters)); - /** - * The External Profile Update Endpoint shall forbid users from updating the profile if they don't own it. - */ - public function testForbiddenIfNotOwnExternalProfile(): void - { - Event::fakeExcept(ExternalProfileCreated::class); + $response->assertForbidden(); +}); - Feature::activate(AllowExternalProfileManagement::class); +test('forbidden if not own external profile', function () { + Event::fakeExcept(ExternalProfileCreated::class); - $profile = ExternalProfile::factory() - ->for(User::factory()) - ->createOne(); + Feature::activate(AllowExternalProfileManagement::class); - $visibility = Arr::random(ExternalProfileVisibility::cases()); + $profile = ExternalProfile::factory() + ->for(User::factory()) + ->createOne(); - $parameters = array_merge( - ExternalProfile::factory()->raw(), - [ExternalProfile::ATTRIBUTE_VISIBILITY => $visibility->localize()], - ); + $visibility = Arr::random(ExternalProfileVisibility::cases()); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(ExternalProfile::class))->createOne(); + $parameters = array_merge( + ExternalProfile::factory()->raw(), + [ExternalProfile::ATTRIBUTE_VISIBILITY => $visibility->localize()], + ); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(ExternalProfile::class))->createOne(); - $response = $this->put(route('api.externalprofile.update', ['externalprofile' => $profile] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.externalprofile.update', ['externalprofile' => $profile] + $parameters)); - /** - * The External Profile Update Endpoint shall forbid users from updating profiles - * if the Allow ExternalProfile Management feature is inactive. - */ - public function testForbiddenIfFlagDisabled(): void - { - Event::fakeExcept(ExternalProfileCreated::class); + $response->assertForbidden(); +}); - Feature::deactivate(AllowExternalProfileManagement::class); +test('forbidden if flag disabled', function () { + Event::fakeExcept(ExternalProfileCreated::class); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(ExternalProfile::class))->createOne(); + Feature::deactivate(AllowExternalProfileManagement::class); - $profile = ExternalProfile::factory() - ->for($user) - ->createOne(); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(ExternalProfile::class))->createOne(); - $visibility = Arr::random(ExternalProfileVisibility::cases()); + $profile = ExternalProfile::factory() + ->for($user) + ->createOne(); - $parameters = array_merge( - ExternalProfile::factory()->raw(), - [ - ExternalProfile::ATTRIBUTE_VISIBILITY => $visibility->localize(), - ], - ); + $visibility = Arr::random(ExternalProfileVisibility::cases()); - Sanctum::actingAs($user); + $parameters = array_merge( + ExternalProfile::factory()->raw(), + [ + ExternalProfile::ATTRIBUTE_VISIBILITY => $visibility->localize(), + ], + ); - $response = $this->put(route('api.externalprofile.update', ['externalprofile' => $profile] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.externalprofile.update', ['externalprofile' => $profile] + $parameters)); - /** - * The External Profile Update Endpoint shall update a profile. - */ - public function testUpdate(): void - { - Event::fakeExcept(ExternalProfileCreated::class); + $response->assertForbidden(); +}); - Feature::activate(AllowExternalProfileManagement::class); +test('update', function () { + Event::fakeExcept(ExternalProfileCreated::class); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(ExternalProfile::class))->createOne(); + Feature::activate(AllowExternalProfileManagement::class); - $profile = ExternalProfile::factory() - ->for($user) - ->createOne(); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(ExternalProfile::class))->createOne(); - $visibility = Arr::random(ExternalProfileVisibility::cases()); + $profile = ExternalProfile::factory() + ->for($user) + ->createOne(); - $parameters = array_merge( - ExternalProfile::factory()->raw(), - [ - ExternalProfile::ATTRIBUTE_VISIBILITY => $visibility->localize(), - ], - ); + $visibility = Arr::random(ExternalProfileVisibility::cases()); - Sanctum::actingAs($user); + $parameters = array_merge( + ExternalProfile::factory()->raw(), + [ + ExternalProfile::ATTRIBUTE_VISIBILITY => $visibility->localize(), + ], + ); - $response = $this->put(route('api.externalprofile.update', ['externalprofile' => $profile] + $parameters)); + Sanctum::actingAs($user); - $response->assertOk(); - } + $response = put(route('api.externalprofile.update', ['externalprofile' => $profile] + $parameters)); - /** - * Users with the bypass feature flag permission shall be permitted to update profiles - * even if the Allow ExternalProfile Management feature is inactive. - */ - public function testUpdatePermittedForBypass(): void - { - Event::fakeExcept(ExternalProfileCreated::class); + $response->assertOk(); +}); - Feature::activate(AllowExternalProfileManagement::class, $this->faker->boolean()); +test('update permitted for bypass', function () { + Event::fakeExcept(ExternalProfileCreated::class); - $user = User::factory() - ->withPermissions( - CrudPermission::UPDATE->format(ExternalProfile::class), - SpecialPermission::BYPASS_FEATURE_FLAGS->value - ) - ->createOne(); + Feature::activate(AllowExternalProfileManagement::class, fake()->boolean()); - $profile = ExternalProfile::factory() - ->for($user) - ->createOne(); + $user = User::factory() + ->withPermissions( + CrudPermission::UPDATE->format(ExternalProfile::class), + SpecialPermission::BYPASS_FEATURE_FLAGS->value + ) + ->createOne(); - $visibility = Arr::random(ExternalProfileVisibility::cases()); + $profile = ExternalProfile::factory() + ->for($user) + ->createOne(); - $parameters = array_merge( - ExternalProfile::factory()->raw(), - [ - ExternalProfile::ATTRIBUTE_VISIBILITY => $visibility->localize(), - ], - ); + $visibility = Arr::random(ExternalProfileVisibility::cases()); - Sanctum::actingAs($user); + $parameters = array_merge( + ExternalProfile::factory()->raw(), + [ + ExternalProfile::ATTRIBUTE_VISIBILITY => $visibility->localize(), + ], + ); - $response = $this->put(route('api.externalprofile.update', ['externalprofile' => $profile] + $parameters)); + Sanctum::actingAs($user); - $response->assertOk(); - } -} + $response = put(route('api.externalprofile.update', ['externalprofile' => $profile] + $parameters)); + + $response->assertOk(); +}); diff --git a/tests/Feature/Http/Api/List/Playlist/PlaylistBackwardIndexTest.php b/tests/Feature/Http/Api/List/Playlist/PlaylistBackwardIndexTest.php index 498d20ea2..51e972a9e 100644 --- a/tests/Feature/Http/Api/List/Playlist/PlaylistBackwardIndexTest.php +++ b/tests/Feature/Http/Api/List/Playlist/PlaylistBackwardIndexTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\List\Playlist; - use App\Contracts\Http\Api\Field\SortableField; use App\Enums\Auth\CrudPermission; use App\Enums\Http\Api\Sort\Direction; @@ -27,323 +25,276 @@ use App\Models\Auth\User; use App\Models\BaseModel; use App\Models\List\Playlist; use App\Models\List\Playlist\PlaylistTrack; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Event; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class PlaylistBackwardIndexTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * The Playlist Backward Index Endpoint shall forbid a private playlist from being publicly viewed. - */ - public function testPrivatePlaylistCannotBePubliclyViewed(): void - { - Event::fakeExcept(PlaylistCreated::class); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $playlist = Playlist::factory() - ->for(User::factory()) - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, - ]); +test('private playlist cannot be publicly viewed', function () { + Event::fakeExcept(PlaylistCreated::class); - $response = $this->get(route('api.playlist.backward', ['playlist' => $playlist])); - - $response->assertForbidden(); - } - - /** - * The Playlist Backward Index Endpoint shall forbid the user from viewing private playlist tracks if not owned. - */ - public function testPrivatePlaylistTrackCannotBePubliclyViewedIfNotOwned(): void - { - Event::fakeExcept(PlaylistCreated::class); - - $playlist = Playlist::factory() - ->for(User::factory()) - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, - ]); - - $user = User::factory()->withPermissions(CrudPermission::VIEW->format(PlaylistTrack::class))->createOne(); - - Sanctum::actingAs($user); - - $response = $this->get(route('api.playlist.backward', ['playlist' => $playlist])); - - $response->assertForbidden(); - } - - /** - * The Playlist Backward Index Endpoint shall allow private playlist tracks to be viewed by the owner. - */ - public function testPrivatePlaylistTrackCanBeViewedByOwner(): void - { - Event::fakeExcept(PlaylistCreated::class); - - $user = User::factory()->withPermissions(CrudPermission::VIEW->format(PlaylistTrack::class))->createOne(); - - $playlist = Playlist::factory() - ->for($user) - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, - ]); - - Sanctum::actingAs($user); - - $response = $this->get(route('api.playlist.backward', ['playlist' => $playlist])); - - $response->assertOk(); - } - - /** - * The Playlist Backward Index Endpoint shall allow unlisted playlist tracks to be viewed. - */ - public function testUnlistedPlaylistTrackCanBeViewed(): void - { - Event::fakeExcept(PlaylistCreated::class); - - $playlist = Playlist::factory() - ->for(User::factory()) - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::UNLISTED->value, - ]); - - $response = $this->get(route('api.playlist.backward', ['playlist' => $playlist])); - - $response->assertOk(); - } - - /** - * The Playlist Backward Index Endpoint shall allow public playlist tracks to be viewed. - */ - public function testPublicPlaylistTrackCanBeViewed(): void - { - Event::fakeExcept(PlaylistCreated::class); - - $playlist = Playlist::factory() - ->for(User::factory()) - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); - - $response = $this->get(route('api.playlist.backward', ['playlist' => $playlist])); - - $response->assertOk(); - } - - /** - * By default, the Backward Index Endpoint shall return a collection of Track Resources that belong to the Playlist. - */ - public function testDefault(): void - { - Event::fakeExcept(PlaylistCreated::class); - - $trackCount = $this->faker->numberBetween(2, 9); - - $playlist = Playlist::factory() - ->tracks($trackCount) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); - - Collection::times( - $this->faker->randomDigitNotNull(), - fn () => Playlist::factory() - ->has(PlaylistTrack::factory()->count($trackCount), Playlist::RELATION_TRACKS) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]) - ); - - $response = $this->get(route('api.playlist.backward', ['playlist' => $playlist])); - - $response->assertJsonCount($trackCount, TrackCollection::$wrap); - - $response->assertJson( - json_decode( - json_encode( - new TrackCollection($playlist->tracks->sortByDesc(PlaylistTrack::ATTRIBUTE_ID), new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Playlist Backward Index Endpoint shall be paginated. - */ - public function testPaginated(): void - { - Event::fakeExcept(PlaylistCreated::class); - - $playlist = Playlist::factory() - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); - - $response = $this->get(route('api.playlist.backward', ['playlist' => $playlist])); - - $response->assertJsonStructure([ - TrackCollection::$wrap, - 'links', - 'meta', + $playlist = Playlist::factory() + ->for(User::factory()) + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, ]); - } - /** - * The Playlist Backward Index Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - Event::fakeExcept(PlaylistCreated::class); + $response = get(route('api.playlist.backward', ['playlist' => $playlist])); - $schema = new ForwardBackwardSchema(); + $response->assertForbidden(); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('private playlist track cannot be publicly viewed if not owned', function () { + Event::fakeExcept(PlaylistCreated::class); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); - - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - $playlist = Playlist::factory() - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); - - $response = $this->get(route('api.playlist.backward', ['playlist' => $playlist] + $parameters)); - - $tracks = PlaylistTrack::with($includedPaths->all())->orderByDesc(PlaylistTrack::ATTRIBUTE_ID)->get(); - - $response->assertJson( - json_decode( - json_encode( - new TrackCollection($tracks, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Playlist Backward Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - Event::fakeExcept(PlaylistCreated::class); - - $schema = new ForwardBackwardSchema(); - - $fields = collect($schema->fields()); - - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); - - $parameters = [ - FieldParser::param() => [ - TrackResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; - - $playlist = Playlist::factory() - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); - - $response = $this->get(route('api.playlist.backward', ['playlist' => $playlist] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new TrackCollection($playlist->tracks->sortByDesc(PlaylistTrack::ATTRIBUTE_ID), new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Playlist Backward Index Endpoint shall forbid sorting resources. - */ - public function testSorts(): void - { - Event::fakeExcept(PlaylistCreated::class); - - $schema = new ForwardBackwardSchema(); - - /** @var Sort $sort */ - $sort = collect($schema->fields()) - ->filter(fn (Field $field) => $field instanceof SortableField) - ->map(fn (SortableField $field) => $field->getSort()) - ->random(); - - $parameters = [ - SortParser::param() => $sort->format(Arr::random(Direction::cases())), - ]; - - $playlist = Playlist::factory() - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); - - $response = $this->get(route('api.playlist.backward', ['playlist' => $playlist] + $parameters)); - - $response->assertJsonValidationErrors([ - SortParser::param(), + $playlist = Playlist::factory() + ->for(User::factory()) + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, ]); - } - /** - * The Playlist Backward Index Endpoint shall forbid filter resources. - */ - public function testFilters(): void - { - Event::fakeExcept(PlaylistCreated::class); + $user = User::factory()->withPermissions(CrudPermission::VIEW->format(PlaylistTrack::class))->createOne(); - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_CREATED_AT => $this->faker->date(), - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; + Sanctum::actingAs($user); - $playlist = Playlist::factory() - ->tracks($this->faker->numberBetween(2, 9)) + $response = get(route('api.playlist.backward', ['playlist' => $playlist])); + + $response->assertForbidden(); +}); + +test('private playlist track can be viewed by owner', function () { + Event::fakeExcept(PlaylistCreated::class); + + $user = User::factory()->withPermissions(CrudPermission::VIEW->format(PlaylistTrack::class))->createOne(); + + $playlist = Playlist::factory() + ->for($user) + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, + ]); + + Sanctum::actingAs($user); + + $response = get(route('api.playlist.backward', ['playlist' => $playlist])); + + $response->assertOk(); +}); + +test('unlisted playlist track can be viewed', function () { + Event::fakeExcept(PlaylistCreated::class); + + $playlist = Playlist::factory() + ->for(User::factory()) + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::UNLISTED->value, + ]); + + $response = get(route('api.playlist.backward', ['playlist' => $playlist])); + + $response->assertOk(); +}); + +test('public playlist track can be viewed', function () { + Event::fakeExcept(PlaylistCreated::class); + + $playlist = Playlist::factory() + ->for(User::factory()) + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); + + $response = get(route('api.playlist.backward', ['playlist' => $playlist])); + + $response->assertOk(); +}); + +test('default', function () { + Event::fakeExcept(PlaylistCreated::class); + + $trackCount = fake()->numberBetween(2, 9); + + $playlist = Playlist::factory() + ->tracks($trackCount) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); + + Collection::times( + fake()->randomDigitNotNull(), + fn () => Playlist::factory() + ->has(PlaylistTrack::factory()->count($trackCount), Playlist::RELATION_TRACKS) ->createOne([ Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); + ]) + ); - $response = $this->get(route('api.playlist.backward', ['playlist' => $playlist] + $parameters)); + $response = get(route('api.playlist.backward', ['playlist' => $playlist])); - $response->assertJsonValidationErrors([ - FilterParser::param(), + $response->assertJsonCount($trackCount, TrackCollection::$wrap); + + $response->assertJson( + json_decode( + json_encode( + new TrackCollection($playlist->tracks->sortByDesc(PlaylistTrack::ATTRIBUTE_ID), new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('paginated', function () { + Event::fakeExcept(PlaylistCreated::class); + + $playlist = Playlist::factory() + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, ]); - } -} + + $response = get(route('api.playlist.backward', ['playlist' => $playlist])); + + $response->assertJsonStructure([ + TrackCollection::$wrap, + 'links', + 'meta', + ]); +}); + +test('allowed include paths', function () { + Event::fakeExcept(PlaylistCreated::class); + + $schema = new ForwardBackwardSchema(); + + $allowedIncludes = collect($schema->allowedIncludes()); + + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); + + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + $playlist = Playlist::factory() + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); + + $response = get(route('api.playlist.backward', ['playlist' => $playlist] + $parameters)); + + $tracks = PlaylistTrack::with($includedPaths->all())->orderByDesc(PlaylistTrack::ATTRIBUTE_ID)->get(); + + $response->assertJson( + json_decode( + json_encode( + new TrackCollection($tracks, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sparse fieldsets', function () { + Event::fakeExcept(PlaylistCreated::class); + + $schema = new ForwardBackwardSchema(); + + $fields = collect($schema->fields()); + + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + TrackResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + $playlist = Playlist::factory() + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); + + $response = get(route('api.playlist.backward', ['playlist' => $playlist] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new TrackCollection($playlist->tracks->sortByDesc(PlaylistTrack::ATTRIBUTE_ID), new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sorts', function () { + Event::fakeExcept(PlaylistCreated::class); + + $schema = new ForwardBackwardSchema(); + + /** @var Sort $sort */ + $sort = collect($schema->fields()) + ->filter(fn (Field $field) => $field instanceof SortableField) + ->map(fn (SortableField $field) => $field->getSort()) + ->random(); + + $parameters = [ + SortParser::param() => $sort->format(Arr::random(Direction::cases())), + ]; + + $playlist = Playlist::factory() + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); + + $response = get(route('api.playlist.backward', ['playlist' => $playlist] + $parameters)); + + $response->assertJsonValidationErrors([ + SortParser::param(), + ]); +}); + +test('filters', function () { + Event::fakeExcept(PlaylistCreated::class); + + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_CREATED_AT => fake()->date(), + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + $playlist = Playlist::factory() + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); + + $response = get(route('api.playlist.backward', ['playlist' => $playlist] + $parameters)); + + $response->assertJsonValidationErrors([ + FilterParser::param(), + ]); +}); diff --git a/tests/Feature/Http/Api/List/Playlist/PlaylistDestroyTest.php b/tests/Feature/Http/Api/List/Playlist/PlaylistDestroyTest.php index ff26157a3..955a7a793 100644 --- a/tests/Feature/Http/Api/List/Playlist/PlaylistDestroyTest.php +++ b/tests/Feature/Http/Api/List/Playlist/PlaylistDestroyTest.php @@ -2,153 +2,122 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\List\Playlist; - use App\Enums\Auth\CrudPermission; use App\Enums\Auth\SpecialPermission; use App\Events\List\Playlist\PlaylistCreated; use App\Features\AllowPlaylistManagement; use App\Models\Auth\User; use App\Models\List\Playlist; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class PlaylistDestroyTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\delete; - /** - * The Playlist Destroy Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - Event::fakeExcept(PlaylistCreated::class); +uses(Illuminate\Foundation\Testing\WithFaker::class); - Feature::activate(AllowPlaylistManagement::class); +test('protected', function () { + Event::fakeExcept(PlaylistCreated::class); - $playlist = Playlist::factory()->createOne(); + Feature::activate(AllowPlaylistManagement::class); - $response = $this->delete(route('api.playlist.destroy', ['playlist' => $playlist])); + $playlist = Playlist::factory()->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.playlist.destroy', ['playlist' => $playlist])); - /** - * The Playlist Destroy Endpoint shall forbid users without the delete playlist permission. - */ - public function testForbiddenIfMissingPermission(): void - { - Event::fakeExcept(PlaylistCreated::class); + $response->assertUnauthorized(); +}); - Feature::activate(AllowPlaylistManagement::class); +test('forbidden if missing permission', function () { + Event::fakeExcept(PlaylistCreated::class); - $playlist = Playlist::factory()->createOne(); + Feature::activate(AllowPlaylistManagement::class); - $user = User::factory()->createOne(); + $playlist = Playlist::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.playlist.destroy', ['playlist' => $playlist])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.playlist.destroy', ['playlist' => $playlist])); - /** - * The Playlist Destroy Endpoint shall forbid users from deleting the playlist if they don't own it. - */ - public function testForbiddenIfNotOwnPlaylist(): void - { - Event::fakeExcept(PlaylistCreated::class); + $response->assertForbidden(); +}); - Feature::activate(AllowPlaylistManagement::class); +test('forbidden if not own playlist', function () { + Event::fakeExcept(PlaylistCreated::class); - $playlist = Playlist::factory() - ->for(User::factory()) - ->createOne(); + Feature::activate(AllowPlaylistManagement::class); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Playlist::class))->createOne(); + $playlist = Playlist::factory() + ->for(User::factory()) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Playlist::class))->createOne(); - $response = $this->delete(route('api.playlist.destroy', ['playlist' => $playlist])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.playlist.destroy', ['playlist' => $playlist])); - /** - * The Playlist Destroy Endpoint shall forbid users from destroying playlists - * if the Allow Playlist Management feature is inactive. - */ - public function testForbiddenIfFlagDisabled(): void - { - Event::fakeExcept(PlaylistCreated::class); + $response->assertForbidden(); +}); - Feature::deactivate(AllowPlaylistManagement::class); +test('forbidden if flag disabled', function () { + Event::fakeExcept(PlaylistCreated::class); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Playlist::class))->createOne(); + Feature::deactivate(AllowPlaylistManagement::class); - $playlist = Playlist::factory() - ->for($user) - ->createOne(); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Playlist::class))->createOne(); - Sanctum::actingAs($user); + $playlist = Playlist::factory() + ->for($user) + ->createOne(); - $response = $this->delete(route('api.playlist.destroy', ['playlist' => $playlist])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.playlist.destroy', ['playlist' => $playlist])); - /** - * The Playlist Destroy Endpoint shall delete the playlist. - */ - public function testDeleted(): void - { - Event::fakeExcept(PlaylistCreated::class); + $response->assertForbidden(); +}); - Feature::activate(AllowPlaylistManagement::class); +test('deleted', function () { + Event::fakeExcept(PlaylistCreated::class); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Playlist::class))->createOne(); + Feature::activate(AllowPlaylistManagement::class); - $playlist = Playlist::factory() - ->for($user) - ->createOne(); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Playlist::class))->createOne(); - Sanctum::actingAs($user); + $playlist = Playlist::factory() + ->for($user) + ->createOne(); - $response = $this->delete(route('api.playlist.destroy', ['playlist' => $playlist])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertModelMissing($playlist); - } + $response = delete(route('api.playlist.destroy', ['playlist' => $playlist])); - /** - * Users with the bypass feature flag permission shall be permitted to destroy playlists - * even if the Allow Playlist Management feature is inactive. - */ - public function testDestroyPermittedForBypass(): void - { - Event::fakeExcept(PlaylistCreated::class); + $response->assertOk(); + $this->assertModelMissing($playlist); +}); - Feature::activate(AllowPlaylistManagement::class, $this->faker->boolean()); +test('destroy permitted for bypass', function () { + Event::fakeExcept(PlaylistCreated::class); - $user = User::factory() - ->withPermissions( - CrudPermission::DELETE->format(Playlist::class), - SpecialPermission::BYPASS_FEATURE_FLAGS->value - ) - ->createOne(); + Feature::activate(AllowPlaylistManagement::class, fake()->boolean()); - $playlist = Playlist::factory() - ->for($user) - ->createOne(); + $user = User::factory() + ->withPermissions( + CrudPermission::DELETE->format(Playlist::class), + SpecialPermission::BYPASS_FEATURE_FLAGS->value + ) + ->createOne(); - Sanctum::actingAs($user); + $playlist = Playlist::factory() + ->for($user) + ->createOne(); - $response = $this->delete(route('api.playlist.destroy', ['playlist' => $playlist])); + Sanctum::actingAs($user); - $response->assertOk(); - } -} + $response = delete(route('api.playlist.destroy', ['playlist' => $playlist])); + + $response->assertOk(); +}); diff --git a/tests/Feature/Http/Api/List/Playlist/PlaylistForwardIndexTest.php b/tests/Feature/Http/Api/List/Playlist/PlaylistForwardIndexTest.php index 12c701bce..ae97f0ca6 100644 --- a/tests/Feature/Http/Api/List/Playlist/PlaylistForwardIndexTest.php +++ b/tests/Feature/Http/Api/List/Playlist/PlaylistForwardIndexTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\List\Playlist; - use App\Contracts\Http\Api\Field\SortableField; use App\Enums\Auth\CrudPermission; use App\Enums\Http\Api\Sort\Direction; @@ -27,323 +25,276 @@ use App\Models\Auth\User; use App\Models\BaseModel; use App\Models\List\Playlist; use App\Models\List\Playlist\PlaylistTrack; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Event; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class PlaylistForwardIndexTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * The Playlist Forward Index Endpoint shall forbid a private playlist from being publicly viewed. - */ - public function testPrivatePlaylistCannotBePubliclyViewed(): void - { - Event::fakeExcept(PlaylistCreated::class); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $playlist = Playlist::factory() - ->for(User::factory()) - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, - ]); +test('private playlist cannot be publicly viewed', function () { + Event::fakeExcept(PlaylistCreated::class); - $response = $this->get(route('api.playlist.forward', ['playlist' => $playlist])); - - $response->assertForbidden(); - } - - /** - * The Playlist Forward Index Endpoint shall forbid the user from viewing private playlist tracks if not owned. - */ - public function testPrivatePlaylistTrackCannotBePubliclyViewedIfNotOwned(): void - { - Event::fakeExcept(PlaylistCreated::class); - - $playlist = Playlist::factory() - ->for(User::factory()) - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, - ]); - - $user = User::factory()->withPermissions(CrudPermission::VIEW->format(PlaylistTrack::class))->createOne(); - - Sanctum::actingAs($user); - - $response = $this->get(route('api.playlist.forward', ['playlist' => $playlist])); - - $response->assertForbidden(); - } - - /** - * The Playlist Forward Index Endpoint shall allow private playlist tracks to be viewed by the owner. - */ - public function testPrivatePlaylistTrackCanBeViewedByOwner(): void - { - Event::fakeExcept(PlaylistCreated::class); - - $user = User::factory()->withPermissions(CrudPermission::VIEW->format(PlaylistTrack::class))->createOne(); - - $playlist = Playlist::factory() - ->for($user) - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, - ]); - - Sanctum::actingAs($user); - - $response = $this->get(route('api.playlist.forward', ['playlist' => $playlist])); - - $response->assertOk(); - } - - /** - * The Playlist Forward Index Endpoint shall allow unlisted playlist tracks to be viewed. - */ - public function testUnlistedPlaylistTrackCanBeViewed(): void - { - Event::fakeExcept(PlaylistCreated::class); - - $playlist = Playlist::factory() - ->for(User::factory()) - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::UNLISTED->value, - ]); - - $response = $this->get(route('api.playlist.forward', ['playlist' => $playlist])); - - $response->assertOk(); - } - - /** - * The Playlist Forward Index Endpoint shall allow public playlist tracks to be viewed. - */ - public function testPublicPlaylistTrackCanBeViewed(): void - { - Event::fakeExcept(PlaylistCreated::class); - - $playlist = Playlist::factory() - ->for(User::factory()) - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); - - $response = $this->get(route('api.playlist.forward', ['playlist' => $playlist])); - - $response->assertOk(); - } - - /** - * By default, the Forward Index Endpoint shall return a collection of Track Resources that belong to the Playlist. - */ - public function testDefault(): void - { - Event::fakeExcept(PlaylistCreated::class); - - $trackCount = $this->faker->numberBetween(2, 9); - - $playlist = Playlist::factory() - ->tracks($trackCount) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); - - Collection::times( - $this->faker->randomDigitNotNull(), - fn () => Playlist::factory() - ->has(PlaylistTrack::factory()->count($trackCount), Playlist::RELATION_TRACKS) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]) - ); - - $response = $this->get(route('api.playlist.forward', ['playlist' => $playlist])); - - $response->assertJsonCount($trackCount, TrackCollection::$wrap); - - $response->assertJson( - json_decode( - json_encode( - new TrackCollection($playlist->tracks, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Playlist Forward Index Endpoint shall be paginated. - */ - public function testPaginated(): void - { - Event::fakeExcept(PlaylistCreated::class); - - $playlist = Playlist::factory() - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); - - $response = $this->get(route('api.playlist.forward', ['playlist' => $playlist])); - - $response->assertJsonStructure([ - TrackCollection::$wrap, - 'links', - 'meta', + $playlist = Playlist::factory() + ->for(User::factory()) + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, ]); - } - /** - * The Playlist Forward Index Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - Event::fakeExcept(PlaylistCreated::class); + $response = get(route('api.playlist.forward', ['playlist' => $playlist])); - $schema = new ForwardBackwardSchema(); + $response->assertForbidden(); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('private playlist track cannot be publicly viewed if not owned', function () { + Event::fakeExcept(PlaylistCreated::class); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); - - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - $playlist = Playlist::factory() - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); - - $response = $this->get(route('api.playlist.forward', ['playlist' => $playlist] + $parameters)); - - $tracks = PlaylistTrack::with($includedPaths->all())->get(); - - $response->assertJson( - json_decode( - json_encode( - new TrackCollection($tracks, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Playlist Forward Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - Event::fakeExcept(PlaylistCreated::class); - - $schema = new ForwardBackwardSchema(); - - $fields = collect($schema->fields()); - - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); - - $parameters = [ - FieldParser::param() => [ - TrackResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; - - $playlist = Playlist::factory() - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); - - $response = $this->get(route('api.playlist.forward', ['playlist' => $playlist] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new TrackCollection($playlist->tracks, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Playlist Forward Index Endpoint shall forbid sorting resources. - */ - public function testSorts(): void - { - Event::fakeExcept(PlaylistCreated::class); - - $schema = new ForwardBackwardSchema(); - - /** @var Sort $sort */ - $sort = collect($schema->fields()) - ->filter(fn (Field $field) => $field instanceof SortableField) - ->map(fn (SortableField $field) => $field->getSort()) - ->random(); - - $parameters = [ - SortParser::param() => $sort->format(Arr::random(Direction::cases())), - ]; - - $playlist = Playlist::factory() - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); - - $response = $this->get(route('api.playlist.forward', ['playlist' => $playlist] + $parameters)); - - $response->assertJsonValidationErrors([ - SortParser::param(), + $playlist = Playlist::factory() + ->for(User::factory()) + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, ]); - } - /** - * The Playlist Forward Index Endpoint shall forbid filter resources. - */ - public function testFilters(): void - { - Event::fakeExcept(PlaylistCreated::class); + $user = User::factory()->withPermissions(CrudPermission::VIEW->format(PlaylistTrack::class))->createOne(); - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_CREATED_AT => $this->faker->date(), - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; + Sanctum::actingAs($user); - $playlist = Playlist::factory() - ->tracks($this->faker->numberBetween(2, 9)) + $response = get(route('api.playlist.forward', ['playlist' => $playlist])); + + $response->assertForbidden(); +}); + +test('private playlist track can be viewed by owner', function () { + Event::fakeExcept(PlaylistCreated::class); + + $user = User::factory()->withPermissions(CrudPermission::VIEW->format(PlaylistTrack::class))->createOne(); + + $playlist = Playlist::factory() + ->for($user) + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, + ]); + + Sanctum::actingAs($user); + + $response = get(route('api.playlist.forward', ['playlist' => $playlist])); + + $response->assertOk(); +}); + +test('unlisted playlist track can be viewed', function () { + Event::fakeExcept(PlaylistCreated::class); + + $playlist = Playlist::factory() + ->for(User::factory()) + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::UNLISTED->value, + ]); + + $response = get(route('api.playlist.forward', ['playlist' => $playlist])); + + $response->assertOk(); +}); + +test('public playlist track can be viewed', function () { + Event::fakeExcept(PlaylistCreated::class); + + $playlist = Playlist::factory() + ->for(User::factory()) + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); + + $response = get(route('api.playlist.forward', ['playlist' => $playlist])); + + $response->assertOk(); +}); + +test('default', function () { + Event::fakeExcept(PlaylistCreated::class); + + $trackCount = fake()->numberBetween(2, 9); + + $playlist = Playlist::factory() + ->tracks($trackCount) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); + + Collection::times( + fake()->randomDigitNotNull(), + fn () => Playlist::factory() + ->has(PlaylistTrack::factory()->count($trackCount), Playlist::RELATION_TRACKS) ->createOne([ Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); + ]) + ); - $response = $this->get(route('api.playlist.forward', ['playlist' => $playlist] + $parameters)); + $response = get(route('api.playlist.forward', ['playlist' => $playlist])); - $response->assertJsonValidationErrors([ - FilterParser::param(), + $response->assertJsonCount($trackCount, TrackCollection::$wrap); + + $response->assertJson( + json_decode( + json_encode( + new TrackCollection($playlist->tracks, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('paginated', function () { + Event::fakeExcept(PlaylistCreated::class); + + $playlist = Playlist::factory() + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, ]); - } -} + + $response = get(route('api.playlist.forward', ['playlist' => $playlist])); + + $response->assertJsonStructure([ + TrackCollection::$wrap, + 'links', + 'meta', + ]); +}); + +test('allowed include paths', function () { + Event::fakeExcept(PlaylistCreated::class); + + $schema = new ForwardBackwardSchema(); + + $allowedIncludes = collect($schema->allowedIncludes()); + + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); + + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + $playlist = Playlist::factory() + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); + + $response = get(route('api.playlist.forward', ['playlist' => $playlist] + $parameters)); + + $tracks = PlaylistTrack::with($includedPaths->all())->get(); + + $response->assertJson( + json_decode( + json_encode( + new TrackCollection($tracks, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sparse fieldsets', function () { + Event::fakeExcept(PlaylistCreated::class); + + $schema = new ForwardBackwardSchema(); + + $fields = collect($schema->fields()); + + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + TrackResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + $playlist = Playlist::factory() + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); + + $response = get(route('api.playlist.forward', ['playlist' => $playlist] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new TrackCollection($playlist->tracks, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sorts', function () { + Event::fakeExcept(PlaylistCreated::class); + + $schema = new ForwardBackwardSchema(); + + /** @var Sort $sort */ + $sort = collect($schema->fields()) + ->filter(fn (Field $field) => $field instanceof SortableField) + ->map(fn (SortableField $field) => $field->getSort()) + ->random(); + + $parameters = [ + SortParser::param() => $sort->format(Arr::random(Direction::cases())), + ]; + + $playlist = Playlist::factory() + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); + + $response = get(route('api.playlist.forward', ['playlist' => $playlist] + $parameters)); + + $response->assertJsonValidationErrors([ + SortParser::param(), + ]); +}); + +test('filters', function () { + Event::fakeExcept(PlaylistCreated::class); + + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_CREATED_AT => fake()->date(), + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + $playlist = Playlist::factory() + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); + + $response = get(route('api.playlist.forward', ['playlist' => $playlist] + $parameters)); + + $response->assertJsonValidationErrors([ + FilterParser::param(), + ]); +}); diff --git a/tests/Feature/Http/Api/List/Playlist/PlaylistIndexTest.php b/tests/Feature/Http/Api/List/Playlist/PlaylistIndexTest.php index 4e0d8b5f3..3127dfef9 100644 --- a/tests/Feature/Http/Api/List/Playlist/PlaylistIndexTest.php +++ b/tests/Feature/Http/Api/List/Playlist/PlaylistIndexTest.php @@ -2,10 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\List\Playlist; - -use App\Concerns\Actions\Http\Api\AggregatesFields; -use App\Concerns\Actions\Http\Api\SortsModels; use App\Contracts\Http\Api\Field\SortableField; use App\Enums\Http\Api\Sort\Direction; use App\Enums\Models\List\PlaylistVisibility; @@ -30,323 +26,290 @@ use App\Models\List\Playlist; use App\Models\List\Playlist\PlaylistTrack; use App\Models\Wiki\Image; use Illuminate\Database\Eloquent\Relations\BelongsToMany; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; -use Tests\TestCase; -class PlaylistIndexTest extends TestCase -{ - use AggregatesFields; - use SortsModels; - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the Playlist Index Endpoint shall return a collection of Playlist Resources with public visibility. - */ - public function testDefault(): void - { - $publicCount = $this->faker->randomDigitNotNull(); +uses(App\Concerns\Actions\Http\Api\AggregatesFields::class); - $playlists = Playlist::factory() - ->count($publicCount) - ->create([Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value]); +uses(App\Concerns\Actions\Http\Api\SortsModels::class); - $unlistedCount = $this->faker->randomDigitNotNull(); +uses(Illuminate\Foundation\Testing\WithFaker::class); - Playlist::factory() - ->count($unlistedCount) - ->create([Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::UNLISTED->value]); +test('default', function () { + $publicCount = fake()->randomDigitNotNull(); - $privateCount = $this->faker->randomDigitNotNull(); + $playlists = Playlist::factory() + ->count($publicCount) + ->create([Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value]); - Playlist::factory() - ->count($privateCount) - ->create([Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value]); + $unlistedCount = fake()->randomDigitNotNull(); - $response = $this->get(route('api.playlist.index')); + Playlist::factory() + ->count($unlistedCount) + ->create([Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::UNLISTED->value]); - $response->assertJsonCount($publicCount, PlaylistCollection::$wrap); + $privateCount = fake()->randomDigitNotNull(); - $response->assertJson( - json_decode( - json_encode( - new PlaylistCollection($playlists, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + Playlist::factory() + ->count($privateCount) + ->create([Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value]); - /** - * The Playlist Index Endpoint shall be paginated. - */ - public function testPaginated(): void - { - Playlist::factory() - ->count($this->faker->randomDigitNotNull()) - ->create([Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value]); + $response = get(route('api.playlist.index')); - $response = $this->get(route('api.playlist.index')); + $response->assertJsonCount($publicCount, PlaylistCollection::$wrap); - $response->assertJsonStructure([ - PlaylistCollection::$wrap, - 'links', - 'meta', + $response->assertJson( + json_decode( + json_encode( + new PlaylistCollection($playlists, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('paginated', function () { + Playlist::factory() + ->count(fake()->randomDigitNotNull()) + ->create([Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value]); + + $response = get(route('api.playlist.index')); + + $response->assertJsonStructure([ + PlaylistCollection::$wrap, + 'links', + 'meta', + ]); +}); + +test('allowed include paths', function () { + $schema = new PlaylistSchema(); + + $allowedIncludes = collect($schema->allowedIncludes()); + + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); + + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; + + Playlist::factory() + ->for(User::factory()) + ->has(PlaylistTrack::factory(), Playlist::RELATION_FIRST) + ->has(PlaylistTrack::factory(), Playlist::RELATION_LAST) + ->has(PlaylistTrack::factory()->count(fake()->randomDigitNotNull()), Playlist::RELATION_TRACKS) + ->has(Image::factory()->count(fake()->randomDigitNotNull())) + ->count(fake()->randomDigitNotNull()) + ->create([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, ]); - } - /** - * The Playlist Index Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new PlaylistSchema(); + $playlists = Playlist::with($includedPaths->all())->get(); - $allowedIncludes = collect($schema->allowedIncludes()); + $response = get(route('api.playlist.index', $parameters)); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $response->assertJson( + json_decode( + json_encode( + new PlaylistCollection($playlists, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); +test('sparse fieldsets', function () { + $schema = new PlaylistSchema(); - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; + $fields = collect($schema->fields()); + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + PlaylistResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + $playlists = Playlist::factory() + ->count(fake()->randomDigitNotNull()) + ->create([Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value]); + + $response = get(route('api.playlist.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new PlaylistCollection($playlists, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sorts', function () { + $schema = new PlaylistSchema(); + + /** @var Sort $sort */ + $sort = collect($schema->fields()) + ->filter(fn (Field $field) => $field instanceof SortableField) + ->map(fn (SortableField $field) => $field->getSort()) + ->random(); + + $parameters = [ + SortParser::param() => $sort->format(Arr::random(Direction::cases())), + ]; + + $query = new Query($parameters); + + Playlist::factory() + ->count(fake()->randomDigitNotNull()) + ->create([Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value]); + + $response = get(route('api.playlist.index', $parameters)); + + $builder = Playlist::query(); + $this->withAggregates($builder, $query, $schema); + $playlists = $this->sort($builder, $query, $schema)->get(); + + $response->assertJson( + json_decode( + json_encode( + new PlaylistCollection($playlists, $query) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('created at filter', function () { + $createdFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($createdFilter, function () { Playlist::factory() - ->for(User::factory()) - ->has(PlaylistTrack::factory(), Playlist::RELATION_FIRST) - ->has(PlaylistTrack::factory(), Playlist::RELATION_LAST) - ->has(PlaylistTrack::factory()->count($this->faker->randomDigitNotNull()), Playlist::RELATION_TRACKS) - ->has(Image::factory()->count($this->faker->randomDigitNotNull())) - ->count($this->faker->randomDigitNotNull()) - ->create([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); - - $playlists = Playlist::with($includedPaths->all())->get(); - - $response = $this->get(route('api.playlist.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new PlaylistCollection($playlists, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Playlist Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new PlaylistSchema(); - - $fields = collect($schema->fields()); - - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); - - $parameters = [ - FieldParser::param() => [ - PlaylistResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; - - $playlists = Playlist::factory() - ->count($this->faker->randomDigitNotNull()) + ->count(fake()->randomDigitNotNull()) ->create([Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value]); + }); - $response = $this->get(route('api.playlist.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new PlaylistCollection($playlists, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Playlist Index Endpoint shall support sorting resources. - */ - public function testSorts(): void - { - $schema = new PlaylistSchema(); - - /** @var Sort $sort */ - $sort = collect($schema->fields()) - ->filter(fn (Field $field) => $field instanceof SortableField) - ->map(fn (SortableField $field) => $field->getSort()) - ->random(); - - $parameters = [ - SortParser::param() => $sort->format(Arr::random(Direction::cases())), - ]; - - $query = new Query($parameters); - + Carbon::withTestNow($excludedDate, function () { Playlist::factory() - ->count($this->faker->randomDigitNotNull()) + ->count(fake()->randomDigitNotNull()) ->create([Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value]); + }); - $response = $this->get(route('api.playlist.index', $parameters)); + $playlists = Playlist::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - $builder = Playlist::query(); - $this->withAggregates($builder, $query, $schema); - $playlists = $this->sort($builder, $query, $schema)->get(); + $response = get(route('api.playlist.index', $parameters)); - $response->assertJson( - json_decode( - json_encode( - new PlaylistCollection($playlists, $query) - ->response() - ->getData() - ), - true - ) - ); - } + $response->assertJson( + json_decode( + json_encode( + new PlaylistCollection($playlists, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - /** - * The Playlist Index Endpoint shall support filtering by created_at. - */ - public function testCreatedAtFilter(): void - { - $createdFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); +test('updated at filter', function () { + $updatedFilter = fake()->date(); + $excludedDate = fake()->date(); - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($createdFilter, function () { - Playlist::factory() - ->count($this->faker->randomDigitNotNull()) - ->create([Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value]); - }); - - Carbon::withTestNow($excludedDate, function () { - Playlist::factory() - ->count($this->faker->randomDigitNotNull()) - ->create([Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value]); - }); - - $playlists = Playlist::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - - $response = $this->get(route('api.playlist.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new PlaylistCollection($playlists, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Playlist Index Endpoint shall support filtering by updated_at. - */ - public function testUpdatedAtFilter(): void - { - $updatedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($updatedFilter, function () { - Playlist::factory() - ->count($this->faker->randomDigitNotNull()) - ->create([Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value]); - }); - - Carbon::withTestNow($excludedDate, function () { - Playlist::factory() - ->count($this->faker->randomDigitNotNull()) - ->create([Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value]); - }); - - $playlists = Playlist::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - - $response = $this->get(route('api.playlist.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new PlaylistCollection($playlists, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Playlist Index Endpoint shall support constrained eager loading of images by facet. - */ - public function testImagesByFacet(): void - { - $facetFilter = Arr::random(ImageFacet::cases()); - - $parameters = [ - FilterParser::param() => [ - Image::ATTRIBUTE_FACET => $facetFilter->localize(), - ], - IncludeParser::param() => Playlist::RELATION_IMAGES, - ]; + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + Carbon::withTestNow($updatedFilter, function () { Playlist::factory() - ->has(Image::factory()->count($this->faker->randomDigitNotNull())) - ->count($this->faker->randomDigitNotNull()) - ->create([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); + ->count(fake()->randomDigitNotNull()) + ->create([Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value]); + }); - $playlists = Playlist::with([ - Playlist::RELATION_IMAGES => function (BelongsToMany $query) use ($facetFilter) { - $query->where(Image::ATTRIBUTE_FACET, $facetFilter->value); - }, - ]) - ->get(); + Carbon::withTestNow($excludedDate, function () { + Playlist::factory() + ->count(fake()->randomDigitNotNull()) + ->create([Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value]); + }); - $response = $this->get(route('api.playlist.index', $parameters)); + $playlists = Playlist::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - $response->assertJson( - json_decode( - json_encode( - new PlaylistCollection($playlists, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response = get(route('api.playlist.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new PlaylistCollection($playlists, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('images by facet', function () { + $facetFilter = Arr::random(ImageFacet::cases()); + + $parameters = [ + FilterParser::param() => [ + Image::ATTRIBUTE_FACET => $facetFilter->localize(), + ], + IncludeParser::param() => Playlist::RELATION_IMAGES, + ]; + + Playlist::factory() + ->has(Image::factory()->count(fake()->randomDigitNotNull())) + ->count(fake()->randomDigitNotNull()) + ->create([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); + + $playlists = Playlist::with([ + Playlist::RELATION_IMAGES => function (BelongsToMany $query) use ($facetFilter) { + $query->where(Image::ATTRIBUTE_FACET, $facetFilter->value); + }, + ]) + ->get(); + + $response = get(route('api.playlist.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new PlaylistCollection($playlists, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/List/Playlist/PlaylistShowTest.php b/tests/Feature/Http/Api/List/Playlist/PlaylistShowTest.php index 6bed2906f..635ca3764 100644 --- a/tests/Feature/Http/Api/List/Playlist/PlaylistShowTest.php +++ b/tests/Feature/Http/Api/List/Playlist/PlaylistShowTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\List\Playlist; - use App\Enums\Auth\CrudPermission; use App\Enums\Models\List\PlaylistVisibility; use App\Enums\Models\Wiki\ImageFacet; @@ -21,260 +19,221 @@ use App\Models\List\Playlist; use App\Models\List\Playlist\PlaylistTrack; use App\Models\Wiki\Image; use Illuminate\Database\Eloquent\Relations\BelongsToMany; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Event; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class PlaylistShowTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * The Playlist Show Endpoint shall forbid a private playlist from being publicly viewed. - */ - public function testPrivatePlaylistCannotBePubliclyViewed(): void - { - Event::fakeExcept(PlaylistCreated::class); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $playlist = Playlist::factory() - ->for(User::factory()) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, - ]); +test('private playlist cannot be publicly viewed', function () { + Event::fakeExcept(PlaylistCreated::class); - $response = $this->get(route('api.playlist.show', ['playlist' => $playlist])); - - $response->assertForbidden(); - } - - /** - * The Playlist Show Endpoint shall forbid the user from viewing a private playlist if not owned. - */ - public function testPrivatePlaylistCannotBePubliclyIfNotOwned(): void - { - Event::fakeExcept(PlaylistCreated::class); - - $playlist = Playlist::factory() - ->for(User::factory()) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, - ]); - - $user = User::factory()->withPermissions(CrudPermission::VIEW->format(Playlist::class))->createOne(); - - Sanctum::actingAs($user); - - $response = $this->get(route('api.playlist.show', ['playlist' => $playlist])); - - $response->assertForbidden(); - } - - /** - * The Playlist Show Endpoint shall allow a private playlist to be viewed by the owner. - */ - public function testPrivatePlaylistCanBeViewedByOwner(): void - { - Event::fakeExcept(PlaylistCreated::class); - - $user = User::factory()->withPermissions(CrudPermission::VIEW->format(Playlist::class))->createOne(); - - $playlist = Playlist::factory() - ->for($user) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, - ]); - - Sanctum::actingAs($user); - - $response = $this->get(route('api.playlist.show', ['playlist' => $playlist])); - - $response->assertOk(); - } - - /** - * The Playlist Show Endpoint shall allow an unlisted playlist to be viewed. - */ - public function testUnlistedPlaylistCanBeViewed(): void - { - Event::fakeExcept(PlaylistCreated::class); - - $playlist = Playlist::factory() - ->for(User::factory()) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::UNLISTED->value, - ]); - - $response = $this->get(route('api.playlist.show', ['playlist' => $playlist])); - - $response->assertOk(); - } - - /** - * The Playlist Show Endpoint shall allow a public playlist to be viewed. - */ - public function testPublicPlaylistCanBeViewed(): void - { - Event::fakeExcept(PlaylistCreated::class); - - $playlist = Playlist::factory() - ->for(User::factory()) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); - - $response = $this->get(route('api.playlist.show', ['playlist' => $playlist])); - - $response->assertOk(); - } - - /** - * By default, the Playlist Show Endpoint shall return a Playlist Resource. - */ - public function testDefault(): void - { - Event::fakeExcept(PlaylistCreated::class); - - $playlist = Playlist::factory() - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); - - $response = $this->get(route('api.playlist.show', ['playlist' => $playlist])); - - $response->assertJson( - json_decode( - json_encode( - new PlaylistResource($playlist, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Playlist Show Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - Event::fakeExcept(PlaylistCreated::class); - - $schema = new PlaylistSchema(); - - $allowedIncludes = collect($schema->allowedIncludes()); - - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); - - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; - - $playlist = Playlist::factory() - ->for(User::factory()) - ->has(PlaylistTrack::factory(), Playlist::RELATION_FIRST) - ->has(PlaylistTrack::factory(), Playlist::RELATION_LAST) - ->has(PlaylistTrack::factory()->count($this->faker->randomDigitNotNull()), Playlist::RELATION_TRACKS) - ->has(Image::factory()->count($this->faker->randomDigitNotNull())) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); - - $response = $this->get(route('api.playlist.show', ['playlist' => $playlist] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new PlaylistResource($playlist, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Playlist Show Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - Event::fakeExcept(PlaylistCreated::class); - - $schema = new PlaylistSchema(); - - $fields = collect($schema->fields()); - - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); - - $parameters = [ - FieldParser::param() => [ - PlaylistResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; - - $playlist = Playlist::factory() - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); - - $response = $this->get(route('api.playlist.show', ['playlist' => $playlist] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new PlaylistResource($playlist, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Playlist Show Endpoint shall support constrained eager loading of images by facet. - */ - public function testImagesByFacet(): void - { - Event::fakeExcept(PlaylistCreated::class); - - $facetFilter = Arr::random(ImageFacet::cases()); - - $parameters = [ - FilterParser::param() => [ - Image::ATTRIBUTE_FACET => $facetFilter->localize(), - ], - IncludeParser::param() => Playlist::RELATION_IMAGES, - ]; - - $playlist = Playlist::factory() - ->has(Image::factory()->count($this->faker->randomDigitNotNull())) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); - - $playlist->unsetRelations()->load([ - Playlist::RELATION_IMAGES => function (BelongsToMany $query) use ($facetFilter) { - $query->where(Image::ATTRIBUTE_FACET, $facetFilter->value); - }, + $playlist = Playlist::factory() + ->for(User::factory()) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, ]); - $response = $this->get(route('api.playlist.show', ['playlist' => $playlist] + $parameters)); + $response = get(route('api.playlist.show', ['playlist' => $playlist])); - $response->assertJson( - json_decode( - json_encode( - new PlaylistResource($playlist, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response->assertForbidden(); +}); + +test('private playlist cannot be publicly if not owned', function () { + Event::fakeExcept(PlaylistCreated::class); + + $playlist = Playlist::factory() + ->for(User::factory()) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, + ]); + + $user = User::factory()->withPermissions(CrudPermission::VIEW->format(Playlist::class))->createOne(); + + Sanctum::actingAs($user); + + $response = get(route('api.playlist.show', ['playlist' => $playlist])); + + $response->assertForbidden(); +}); + +test('private playlist can be viewed by owner', function () { + Event::fakeExcept(PlaylistCreated::class); + + $user = User::factory()->withPermissions(CrudPermission::VIEW->format(Playlist::class))->createOne(); + + $playlist = Playlist::factory() + ->for($user) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, + ]); + + Sanctum::actingAs($user); + + $response = get(route('api.playlist.show', ['playlist' => $playlist])); + + $response->assertOk(); +}); + +test('unlisted playlist can be viewed', function () { + Event::fakeExcept(PlaylistCreated::class); + + $playlist = Playlist::factory() + ->for(User::factory()) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::UNLISTED->value, + ]); + + $response = get(route('api.playlist.show', ['playlist' => $playlist])); + + $response->assertOk(); +}); + +test('public playlist can be viewed', function () { + Event::fakeExcept(PlaylistCreated::class); + + $playlist = Playlist::factory() + ->for(User::factory()) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); + + $response = get(route('api.playlist.show', ['playlist' => $playlist])); + + $response->assertOk(); +}); + +test('default', function () { + Event::fakeExcept(PlaylistCreated::class); + + $playlist = Playlist::factory() + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); + + $response = get(route('api.playlist.show', ['playlist' => $playlist])); + + $response->assertJson( + json_decode( + json_encode( + new PlaylistResource($playlist, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('allowed include paths', function () { + Event::fakeExcept(PlaylistCreated::class); + + $schema = new PlaylistSchema(); + + $allowedIncludes = collect($schema->allowedIncludes()); + + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); + + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; + + $playlist = Playlist::factory() + ->for(User::factory()) + ->has(PlaylistTrack::factory(), Playlist::RELATION_FIRST) + ->has(PlaylistTrack::factory(), Playlist::RELATION_LAST) + ->has(PlaylistTrack::factory()->count(fake()->randomDigitNotNull()), Playlist::RELATION_TRACKS) + ->has(Image::factory()->count(fake()->randomDigitNotNull())) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); + + $response = get(route('api.playlist.show', ['playlist' => $playlist] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new PlaylistResource($playlist, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sparse fieldsets', function () { + Event::fakeExcept(PlaylistCreated::class); + + $schema = new PlaylistSchema(); + + $fields = collect($schema->fields()); + + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + PlaylistResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + $playlist = Playlist::factory() + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); + + $response = get(route('api.playlist.show', ['playlist' => $playlist] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new PlaylistResource($playlist, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('images by facet', function () { + Event::fakeExcept(PlaylistCreated::class); + + $facetFilter = Arr::random(ImageFacet::cases()); + + $parameters = [ + FilterParser::param() => [ + Image::ATTRIBUTE_FACET => $facetFilter->localize(), + ], + IncludeParser::param() => Playlist::RELATION_IMAGES, + ]; + + $playlist = Playlist::factory() + ->has(Image::factory()->count(fake()->randomDigitNotNull())) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); + + $playlist->unsetRelations()->load([ + Playlist::RELATION_IMAGES => function (BelongsToMany $query) use ($facetFilter) { + $query->where(Image::ATTRIBUTE_FACET, $facetFilter->value); + }, + ]); + + $response = get(route('api.playlist.show', ['playlist' => $playlist] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new PlaylistResource($playlist, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/List/Playlist/PlaylistStoreTest.php b/tests/Feature/Http/Api/List/Playlist/PlaylistStoreTest.php index 29a4b4b74..606b3a485 100644 --- a/tests/Feature/Http/Api/List/Playlist/PlaylistStoreTest.php +++ b/tests/Feature/Http/Api/List/Playlist/PlaylistStoreTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\List\Playlist; - use App\Constants\Config\PlaylistConstants; use App\Constants\Config\ValidationConstants; use App\Enums\Auth\CrudPermission; @@ -13,304 +11,254 @@ use App\Enums\Rules\ModerationService; use App\Features\AllowPlaylistManagement; use App\Models\Auth\User; use App\Models\List\Playlist; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Http; use Laravel\Pennant\Feature; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class PlaylistStoreTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\post; - /** - * The Playlist Store Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - Feature::activate(AllowPlaylistManagement::class); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $playlist = Playlist::factory()->makeOne(); +test('protected', function () { + Feature::activate(AllowPlaylistManagement::class); - $response = $this->post(route('api.playlist.store', $playlist->toArray())); + $playlist = Playlist::factory()->makeOne(); - $response->assertUnauthorized(); - } + $response = post(route('api.playlist.store', $playlist->toArray())); - /** - * The Playlist Store Endpoint shall forbid users without the create playlist permission. - */ - public function testForbiddenIfMissingPermission(): void - { - Feature::activate(AllowPlaylistManagement::class); + $response->assertUnauthorized(); +}); - $playlist = Playlist::factory()->makeOne(); +test('forbidden if missing permission', function () { + Feature::activate(AllowPlaylistManagement::class); - $user = User::factory()->createOne(); + $playlist = Playlist::factory()->makeOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->post(route('api.playlist.store', $playlist->toArray())); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.playlist.store', $playlist->toArray())); - /** - * The Playlist Store Endpoint shall forbid users from creating playlists - * if the Allow Playlist Management feature is inactive. - */ - public function testForbiddenIfFlagDisabled(): void - { - Feature::deactivate(AllowPlaylistManagement::class); + $response->assertForbidden(); +}); - $visibility = Arr::random(PlaylistVisibility::cases()); +test('forbidden if flag disabled', function () { + Feature::deactivate(AllowPlaylistManagement::class); - $parameters = array_merge( - Playlist::factory()->raw(), - [Playlist::ATTRIBUTE_VISIBILITY => $visibility->localize()], - ); + $visibility = Arr::random(PlaylistVisibility::cases()); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Playlist::class))->createOne(); + $parameters = array_merge( + Playlist::factory()->raw(), + [Playlist::ATTRIBUTE_VISIBILITY => $visibility->localize()], + ); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Playlist::class))->createOne(); - $response = $this->post(route('api.playlist.store', $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.playlist.store', $parameters)); - /** - * The Playlist Store Endpoint shall require name & visibility fields. - */ - public function testRequiredFields(): void - { - Feature::activate(AllowPlaylistManagement::class); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Playlist::class))->createOne(); +test('required fields', function () { + Feature::activate(AllowPlaylistManagement::class); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Playlist::class))->createOne(); - $response = $this->post(route('api.playlist.store')); + Sanctum::actingAs($user); - $response->assertJsonValidationErrors([ - Playlist::ATTRIBUTE_NAME, - Playlist::ATTRIBUTE_VISIBILITY, - ]); - } + $response = post(route('api.playlist.store')); - /** - * The Playlist Store Endpoint shall create a playlist. - */ - public function testCreate(): void - { - Feature::activate(AllowPlaylistManagement::class); + $response->assertJsonValidationErrors([ + Playlist::ATTRIBUTE_NAME, + Playlist::ATTRIBUTE_VISIBILITY, + ]); +}); - $visibility = Arr::random(PlaylistVisibility::cases()); +test('create', function () { + Feature::activate(AllowPlaylistManagement::class); - $parameters = array_merge( - Playlist::factory()->raw(), - [Playlist::ATTRIBUTE_VISIBILITY => $visibility->localize()], - ); + $visibility = Arr::random(PlaylistVisibility::cases()); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Playlist::class))->createOne(); + $parameters = array_merge( + Playlist::factory()->raw(), + [Playlist::ATTRIBUTE_VISIBILITY => $visibility->localize()], + ); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Playlist::class))->createOne(); - $response = $this->post(route('api.playlist.store', $parameters)); + Sanctum::actingAs($user); - $response->assertCreated(); - static::assertDatabaseCount(Playlist::class, 1); - static::assertDatabaseHas(Playlist::class, [Playlist::ATTRIBUTE_USER => $user->getKey()]); - } + $response = post(route('api.playlist.store', $parameters)); - /** - * Users with the bypass feature flag permission shall be permitted to create playlists - * even if the Allow Playlist Management feature is inactive. - */ - public function testCreatePermittedForBypass(): void - { - Feature::activate(AllowPlaylistManagement::class, $this->faker->boolean()); + $response->assertCreated(); + $this->assertDatabaseCount(Playlist::class, 1); + $this->assertDatabaseHas(Playlist::class, [Playlist::ATTRIBUTE_USER => $user->getKey()]); +}); - $visibility = Arr::random(PlaylistVisibility::cases()); +test('create permitted for bypass', function () { + Feature::activate(AllowPlaylistManagement::class, fake()->boolean()); - $parameters = array_merge( - Playlist::factory()->raw(), - [Playlist::ATTRIBUTE_VISIBILITY => $visibility->localize()], - ); + $visibility = Arr::random(PlaylistVisibility::cases()); - $user = User::factory() - ->withPermissions( - CrudPermission::CREATE->format(Playlist::class), - SpecialPermission::BYPASS_FEATURE_FLAGS->value - ) - ->createOne(); + $parameters = array_merge( + Playlist::factory()->raw(), + [Playlist::ATTRIBUTE_VISIBILITY => $visibility->localize()], + ); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::CREATE->format(Playlist::class), + SpecialPermission::BYPASS_FEATURE_FLAGS->value + ) + ->createOne(); - $response = $this->post(route('api.playlist.store', $parameters)); + Sanctum::actingAs($user); - $response->assertCreated(); - } + $response = post(route('api.playlist.store', $parameters)); - /** - * The Playlist Store Endpoint shall forbid users from creating playlists that exceed the user playlist limit. - */ - public function testMaxTrackLimit(): void - { - $playlistLimit = $this->faker->randomDigitNotNull(); + $response->assertCreated(); +}); - Config::set(PlaylistConstants::MAX_PLAYLISTS_QUALIFIED, $playlistLimit); - Feature::activate(AllowPlaylistManagement::class); +test('max track limit', function () { + $playlistLimit = fake()->randomDigitNotNull(); - $visibility = Arr::random(PlaylistVisibility::cases()); + Config::set(PlaylistConstants::MAX_PLAYLISTS_QUALIFIED, $playlistLimit); + Feature::activate(AllowPlaylistManagement::class); - $parameters = array_merge( - Playlist::factory()->raw(), - [Playlist::ATTRIBUTE_VISIBILITY => $visibility->localize()], - ); + $visibility = Arr::random(PlaylistVisibility::cases()); - $user = User::factory() - ->has(Playlist::factory()->count($playlistLimit)) - ->withPermissions(CrudPermission::CREATE->format(Playlist::class)) - ->createOne(); + $parameters = array_merge( + Playlist::factory()->raw(), + [Playlist::ATTRIBUTE_VISIBILITY => $visibility->localize()], + ); - Sanctum::actingAs($user); + $user = User::factory() + ->has(Playlist::factory()->count($playlistLimit)) + ->withPermissions(CrudPermission::CREATE->format(Playlist::class)) + ->createOne(); - $response = $this->post(route('api.playlist.store', $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.playlist.store', $parameters)); - /** - * The Playlist Store Endpoint shall permit users with bypass feature flag permission - * to create playlists that exceed the user playlist limit. - */ - public function testMaxTrackLimitPermittedForBypass(): void - { - $playlistLimit = $this->faker->randomDigitNotNull(); + $response->assertForbidden(); +}); - Config::set(PlaylistConstants::MAX_PLAYLISTS_QUALIFIED, $playlistLimit); - Feature::activate(AllowPlaylistManagement::class); +test('max track limit permitted for bypass', function () { + $playlistLimit = fake()->randomDigitNotNull(); - $visibility = Arr::random(PlaylistVisibility::cases()); + Config::set(PlaylistConstants::MAX_PLAYLISTS_QUALIFIED, $playlistLimit); + Feature::activate(AllowPlaylistManagement::class); - $parameters = array_merge( - Playlist::factory()->raw(), - [Playlist::ATTRIBUTE_VISIBILITY => $visibility->localize()], - ); + $visibility = Arr::random(PlaylistVisibility::cases()); - $user = User::factory() - ->has(Playlist::factory()->count($playlistLimit)) - ->withPermissions( - CrudPermission::CREATE->format(Playlist::class), - SpecialPermission::BYPASS_FEATURE_FLAGS->value - ) - ->createOne(); + $parameters = array_merge( + Playlist::factory()->raw(), + [Playlist::ATTRIBUTE_VISIBILITY => $visibility->localize()], + ); - Sanctum::actingAs($user); + $user = User::factory() + ->has(Playlist::factory()->count($playlistLimit)) + ->withPermissions( + CrudPermission::CREATE->format(Playlist::class), + SpecialPermission::BYPASS_FEATURE_FLAGS->value + ) + ->createOne(); - $response = $this->post(route('api.playlist.store', $parameters)); + Sanctum::actingAs($user); - $response->assertCreated(); - } + $response = post(route('api.playlist.store', $parameters)); - /** - * The Playlist Store Endpoint shall create a playlist if the name is not flagged by OpenAI. - */ - public function testCreatedIfNotFlaggedByOpenAi(): void - { - Feature::activate(AllowPlaylistManagement::class); - Config::set(ValidationConstants::MODERATION_SERVICE_QUALIFIED, ModerationService::OPENAI->value); + $response->assertCreated(); +}); - Http::fake([ - 'https://api.openai.com/v1/moderations' => Http::response([ - 'results' => [ - 0 => [ - 'flagged' => false, - ], +test('created if not flagged by open ai', function () { + Feature::activate(AllowPlaylistManagement::class); + Config::set(ValidationConstants::MODERATION_SERVICE_QUALIFIED, ModerationService::OPENAI->value); + + Http::fake([ + 'https://api.openai.com/v1/moderations' => Http::response([ + 'results' => [ + 0 => [ + 'flagged' => false, ], - ]), - ]); + ], + ]), + ]); - $visibility = Arr::random(PlaylistVisibility::cases()); + $visibility = Arr::random(PlaylistVisibility::cases()); - $parameters = array_merge( - Playlist::factory()->raw(), - [Playlist::ATTRIBUTE_VISIBILITY => $visibility->localize()], - ); + $parameters = array_merge( + Playlist::factory()->raw(), + [Playlist::ATTRIBUTE_VISIBILITY => $visibility->localize()], + ); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Playlist::class))->createOne(); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Playlist::class))->createOne(); - Sanctum::actingAs($user); + Sanctum::actingAs($user); - $response = $this->post(route('api.playlist.store', $parameters)); + $response = post(route('api.playlist.store', $parameters)); - $response->assertCreated(); - } + $response->assertCreated(); +}); - /** - * The Playlist Store Endpoint shall create a playlist if the moderation service returns some error. - */ - public function testCreatedIfOpenAiFails(): void - { - Feature::activate(AllowPlaylistManagement::class); - Config::set(ValidationConstants::MODERATION_SERVICE_QUALIFIED, ModerationService::OPENAI->value); +test('created if open ai fails', function () { + Feature::activate(AllowPlaylistManagement::class); + Config::set(ValidationConstants::MODERATION_SERVICE_QUALIFIED, ModerationService::OPENAI->value); - Http::fake([ - 'https://api.openai.com/v1/moderations' => Http::response(status: 404), - ]); + Http::fake([ + 'https://api.openai.com/v1/moderations' => Http::response(status: 404), + ]); - $visibility = Arr::random(PlaylistVisibility::cases()); + $visibility = Arr::random(PlaylistVisibility::cases()); - $parameters = array_merge( - Playlist::factory()->raw(), - [Playlist::ATTRIBUTE_VISIBILITY => $visibility->localize()], - ); + $parameters = array_merge( + Playlist::factory()->raw(), + [Playlist::ATTRIBUTE_VISIBILITY => $visibility->localize()], + ); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Playlist::class))->createOne(); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Playlist::class))->createOne(); - Sanctum::actingAs($user); + Sanctum::actingAs($user); - $response = $this->post(route('api.playlist.store', $parameters)); + $response = post(route('api.playlist.store', $parameters)); - $response->assertCreated(); - } + $response->assertCreated(); +}); - /** - * The Playlist Store Endpoint shall prohibit users from creating playlists with names flagged by OpenAI. - */ - public function testValidationErrorWhenFlaggedByOpenAi(): void - { - Feature::activate(AllowPlaylistManagement::class); - Config::set(ValidationConstants::MODERATION_SERVICE_QUALIFIED, ModerationService::OPENAI->value); +test('validation error when flagged by open ai', function () { + Feature::activate(AllowPlaylistManagement::class); + Config::set(ValidationConstants::MODERATION_SERVICE_QUALIFIED, ModerationService::OPENAI->value); - Http::fake([ - 'https://api.openai.com/v1/moderations' => Http::response([ - 'results' => [ - 0 => [ - 'flagged' => true, - ], + Http::fake([ + 'https://api.openai.com/v1/moderations' => Http::response([ + 'results' => [ + 0 => [ + 'flagged' => true, ], - ]), - ]); + ], + ]), + ]); - $visibility = Arr::random(PlaylistVisibility::cases()); + $visibility = Arr::random(PlaylistVisibility::cases()); - $parameters = array_merge( - Playlist::factory()->raw(), - [Playlist::ATTRIBUTE_VISIBILITY => $visibility->localize()], - ); + $parameters = array_merge( + Playlist::factory()->raw(), + [Playlist::ATTRIBUTE_VISIBILITY => $visibility->localize()], + ); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Playlist::class))->createOne(); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Playlist::class))->createOne(); - Sanctum::actingAs($user); + Sanctum::actingAs($user); - $response = $this->post(route('api.playlist.store', $parameters)); + $response = post(route('api.playlist.store', $parameters)); - $response->assertJsonValidationErrors([ - Playlist::ATTRIBUTE_NAME, - ]); - } -} + $response->assertJsonValidationErrors([ + Playlist::ATTRIBUTE_NAME, + ]); +}); diff --git a/tests/Feature/Http/Api/List/Playlist/PlaylistUpdateTest.php b/tests/Feature/Http/Api/List/Playlist/PlaylistUpdateTest.php index e671f4600..86484e4db 100644 --- a/tests/Feature/Http/Api/List/Playlist/PlaylistUpdateTest.php +++ b/tests/Feature/Http/Api/List/Playlist/PlaylistUpdateTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\List\Playlist; - use App\Constants\Config\ValidationConstants; use App\Enums\Auth\CrudPermission; use App\Enums\Auth\SpecialPermission; @@ -13,317 +11,276 @@ use App\Events\List\Playlist\PlaylistCreated; use App\Features\AllowPlaylistManagement; use App\Models\Auth\User; use App\Models\List\Playlist; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Http; use Laravel\Pennant\Feature; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class PlaylistUpdateTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\put; - /** - * The Playlist Update Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - Event::fakeExcept(PlaylistCreated::class); +uses(Illuminate\Foundation\Testing\WithFaker::class); - Feature::activate(AllowPlaylistManagement::class); +test('protected', function () { + Event::fakeExcept(PlaylistCreated::class); - $playlist = Playlist::factory()->createOne(); + Feature::activate(AllowPlaylistManagement::class); - $visibility = Arr::random(PlaylistVisibility::cases()); + $playlist = Playlist::factory()->createOne(); - $parameters = array_merge( - Playlist::factory()->raw(), - [Playlist::ATTRIBUTE_VISIBILITY => $visibility->localize()], - ); + $visibility = Arr::random(PlaylistVisibility::cases()); - $response = $this->put(route('api.playlist.update', ['playlist' => $playlist] + $parameters)); + $parameters = array_merge( + Playlist::factory()->raw(), + [Playlist::ATTRIBUTE_VISIBILITY => $visibility->localize()], + ); - $response->assertUnauthorized(); - } + $response = put(route('api.playlist.update', ['playlist' => $playlist] + $parameters)); - /** - * The Playlist Update Endpoint shall forbid users without the update playlist permission. - */ - public function testForbiddenIfMissingPermission(): void - { - Event::fakeExcept(PlaylistCreated::class); + $response->assertUnauthorized(); +}); - Feature::activate(AllowPlaylistManagement::class); +test('forbidden if missing permission', function () { + Event::fakeExcept(PlaylistCreated::class); - $playlist = Playlist::factory()->createOne(); + Feature::activate(AllowPlaylistManagement::class); - $visibility = Arr::random(PlaylistVisibility::cases()); + $playlist = Playlist::factory()->createOne(); - $parameters = array_merge( - Playlist::factory()->raw(), - [Playlist::ATTRIBUTE_VISIBILITY => $visibility->localize()], - ); + $visibility = Arr::random(PlaylistVisibility::cases()); - $user = User::factory()->createOne(); + $parameters = array_merge( + Playlist::factory()->raw(), + [Playlist::ATTRIBUTE_VISIBILITY => $visibility->localize()], + ); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->put(route('api.playlist.update', ['playlist' => $playlist] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.playlist.update', ['playlist' => $playlist] + $parameters)); - /** - * The Playlist Update Endpoint shall forbid users from updating the playlist if they don't own it. - */ - public function testForbiddenIfNotOwnPlaylist(): void - { - Event::fakeExcept(PlaylistCreated::class); + $response->assertForbidden(); +}); - Feature::activate(AllowPlaylistManagement::class); +test('forbidden if not own playlist', function () { + Event::fakeExcept(PlaylistCreated::class); - $playlist = Playlist::factory() - ->for(User::factory()) - ->createOne(); + Feature::activate(AllowPlaylistManagement::class); - $visibility = Arr::random(PlaylistVisibility::cases()); + $playlist = Playlist::factory() + ->for(User::factory()) + ->createOne(); - $parameters = array_merge( - Playlist::factory()->raw(), - [Playlist::ATTRIBUTE_VISIBILITY => $visibility->localize()], - ); + $visibility = Arr::random(PlaylistVisibility::cases()); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Playlist::class))->createOne(); + $parameters = array_merge( + Playlist::factory()->raw(), + [Playlist::ATTRIBUTE_VISIBILITY => $visibility->localize()], + ); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Playlist::class))->createOne(); - $response = $this->put(route('api.playlist.update', ['playlist' => $playlist] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.playlist.update', ['playlist' => $playlist] + $parameters)); - /** - * The Playlist Update Endpoint shall forbid users from updating playlists - * if the Allow Playlist Management feature is inactive. - */ - public function testForbiddenIfFlagDisabled(): void - { - Event::fakeExcept(PlaylistCreated::class); + $response->assertForbidden(); +}); - Feature::deactivate(AllowPlaylistManagement::class); +test('forbidden if flag disabled', function () { + Event::fakeExcept(PlaylistCreated::class); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Playlist::class))->createOne(); + Feature::deactivate(AllowPlaylistManagement::class); - $playlist = Playlist::factory() - ->for($user) - ->createOne(); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Playlist::class))->createOne(); - $visibility = Arr::random(PlaylistVisibility::cases()); + $playlist = Playlist::factory() + ->for($user) + ->createOne(); - $parameters = array_merge( - Playlist::factory()->raw(), - [ - Playlist::ATTRIBUTE_VISIBILITY => $visibility->localize(), - ], - ); + $visibility = Arr::random(PlaylistVisibility::cases()); - Sanctum::actingAs($user); + $parameters = array_merge( + Playlist::factory()->raw(), + [ + Playlist::ATTRIBUTE_VISIBILITY => $visibility->localize(), + ], + ); - $response = $this->put(route('api.playlist.update', ['playlist' => $playlist] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.playlist.update', ['playlist' => $playlist] + $parameters)); - /** - * The Playlist Update Endpoint shall update a playlist. - */ - public function testUpdate(): void - { - Event::fakeExcept(PlaylistCreated::class); + $response->assertForbidden(); +}); - Feature::activate(AllowPlaylistManagement::class); +test('update', function () { + Event::fakeExcept(PlaylistCreated::class); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Playlist::class))->createOne(); + Feature::activate(AllowPlaylistManagement::class); - $playlist = Playlist::factory() - ->for($user) - ->createOne(); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Playlist::class))->createOne(); - $visibility = Arr::random(PlaylistVisibility::cases()); + $playlist = Playlist::factory() + ->for($user) + ->createOne(); - $parameters = array_merge( - Playlist::factory()->raw(), - [ - Playlist::ATTRIBUTE_VISIBILITY => $visibility->localize(), - ], - ); + $visibility = Arr::random(PlaylistVisibility::cases()); - Sanctum::actingAs($user); + $parameters = array_merge( + Playlist::factory()->raw(), + [ + Playlist::ATTRIBUTE_VISIBILITY => $visibility->localize(), + ], + ); - $response = $this->put(route('api.playlist.update', ['playlist' => $playlist] + $parameters)); + Sanctum::actingAs($user); - $response->assertOk(); - } + $response = put(route('api.playlist.update', ['playlist' => $playlist] + $parameters)); - /** - * Users with the bypass feature flag permission shall be permitted to update playlists - * even if the Allow Playlist Management feature is inactive. - */ - public function testUpdatePermittedForBypass(): void - { - Event::fakeExcept(PlaylistCreated::class); + $response->assertOk(); +}); - Feature::activate(AllowPlaylistManagement::class, $this->faker->boolean()); +test('update permitted for bypass', function () { + Event::fakeExcept(PlaylistCreated::class); - $user = User::factory() - ->withPermissions( - CrudPermission::UPDATE->format(Playlist::class), - SpecialPermission::BYPASS_FEATURE_FLAGS->value - ) - ->createOne(); + Feature::activate(AllowPlaylistManagement::class, fake()->boolean()); - $playlist = Playlist::factory() - ->for($user) - ->createOne(); + $user = User::factory() + ->withPermissions( + CrudPermission::UPDATE->format(Playlist::class), + SpecialPermission::BYPASS_FEATURE_FLAGS->value + ) + ->createOne(); - $visibility = Arr::random(PlaylistVisibility::cases()); + $playlist = Playlist::factory() + ->for($user) + ->createOne(); - $parameters = array_merge( - Playlist::factory()->raw(), - [ - Playlist::ATTRIBUTE_VISIBILITY => $visibility->localize(), - ], - ); + $visibility = Arr::random(PlaylistVisibility::cases()); - Sanctum::actingAs($user); + $parameters = array_merge( + Playlist::factory()->raw(), + [ + Playlist::ATTRIBUTE_VISIBILITY => $visibility->localize(), + ], + ); - $response = $this->put(route('api.playlist.update', ['playlist' => $playlist] + $parameters)); + Sanctum::actingAs($user); - $response->assertOk(); - } + $response = put(route('api.playlist.update', ['playlist' => $playlist] + $parameters)); - /** - * The Playlist Update Endpoint shall update a playlist if the name is not flagged by OpenAI. - */ - public function testUpdatedIfNotFlaggedByOpenAi(): void - { - Event::fakeExcept(PlaylistCreated::class); + $response->assertOk(); +}); - Feature::activate(AllowPlaylistManagement::class); - Config::set(ValidationConstants::MODERATION_SERVICE_QUALIFIED, ModerationService::OPENAI->value); +test('updated if not flagged by open ai', function () { + Event::fakeExcept(PlaylistCreated::class); - Http::fake([ - 'https://api.openai.com/v1/moderations' => Http::response([ - 'results' => [ - 0 => [ - 'flagged' => false, - ], + Feature::activate(AllowPlaylistManagement::class); + Config::set(ValidationConstants::MODERATION_SERVICE_QUALIFIED, ModerationService::OPENAI->value); + + Http::fake([ + 'https://api.openai.com/v1/moderations' => Http::response([ + 'results' => [ + 0 => [ + 'flagged' => false, ], - ]), - ]); - - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Playlist::class))->createOne(); - - $playlist = Playlist::factory() - ->for($user) - ->createOne(); - - $visibility = Arr::random(PlaylistVisibility::cases()); - - $parameters = array_merge( - Playlist::factory()->raw(), - [ - Playlist::ATTRIBUTE_VISIBILITY => $visibility->localize(), ], - ); + ]), + ]); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Playlist::class))->createOne(); - $response = $this->put(route('api.playlist.update', ['playlist' => $playlist] + $parameters)); + $playlist = Playlist::factory() + ->for($user) + ->createOne(); - $response->assertOk(); - } + $visibility = Arr::random(PlaylistVisibility::cases()); - /** - * The Playlist Update Endpoint shall update a playlist if the moderation service returns some error. - */ - public function testUpdatedIfOpenAiFails(): void - { - Event::fakeExcept(PlaylistCreated::class); + $parameters = array_merge( + Playlist::factory()->raw(), + [ + Playlist::ATTRIBUTE_VISIBILITY => $visibility->localize(), + ], + ); - Feature::activate(AllowPlaylistManagement::class); - Config::set(ValidationConstants::MODERATION_SERVICE_QUALIFIED, ModerationService::OPENAI->value); + Sanctum::actingAs($user); - Http::fake([ - 'https://api.openai.com/v1/moderations' => Http::response(status: 404), - ]); + $response = put(route('api.playlist.update', ['playlist' => $playlist] + $parameters)); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Playlist::class))->createOne(); + $response->assertOk(); +}); - $playlist = Playlist::factory() - ->for($user) - ->createOne(); +test('updated if open ai fails', function () { + Event::fakeExcept(PlaylistCreated::class); - $visibility = Arr::random(PlaylistVisibility::cases()); + Feature::activate(AllowPlaylistManagement::class); + Config::set(ValidationConstants::MODERATION_SERVICE_QUALIFIED, ModerationService::OPENAI->value); - $parameters = array_merge( - Playlist::factory()->raw(), - [ - Playlist::ATTRIBUTE_VISIBILITY => $visibility->localize(), - ], - ); + Http::fake([ + 'https://api.openai.com/v1/moderations' => Http::response(status: 404), + ]); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Playlist::class))->createOne(); - $response = $this->put(route('api.playlist.update', ['playlist' => $playlist] + $parameters)); + $playlist = Playlist::factory() + ->for($user) + ->createOne(); - $response->assertOk(); - } + $visibility = Arr::random(PlaylistVisibility::cases()); - /** - * The Playlist Update Endpoint shall prohibit users from updating playlists with names flagged by OpenAI. - */ - public function testValidationErrorWhenFlaggedByOpenAi(): void - { - Event::fakeExcept(PlaylistCreated::class); + $parameters = array_merge( + Playlist::factory()->raw(), + [ + Playlist::ATTRIBUTE_VISIBILITY => $visibility->localize(), + ], + ); - Feature::activate(AllowPlaylistManagement::class); - Config::set(ValidationConstants::MODERATION_SERVICE_QUALIFIED, ModerationService::OPENAI->value); + Sanctum::actingAs($user); - Http::fake([ - 'https://api.openai.com/v1/moderations' => Http::response([ - 'results' => [ - 0 => [ - 'flagged' => true, - ], + $response = put(route('api.playlist.update', ['playlist' => $playlist] + $parameters)); + + $response->assertOk(); +}); + +test('validation error when flagged by open ai', function () { + Event::fakeExcept(PlaylistCreated::class); + + Feature::activate(AllowPlaylistManagement::class); + Config::set(ValidationConstants::MODERATION_SERVICE_QUALIFIED, ModerationService::OPENAI->value); + + Http::fake([ + 'https://api.openai.com/v1/moderations' => Http::response([ + 'results' => [ + 0 => [ + 'flagged' => true, ], - ]), - ]); - - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Playlist::class))->createOne(); - - $playlist = Playlist::factory() - ->for($user) - ->createOne(); - - $visibility = Arr::random(PlaylistVisibility::cases()); - - $parameters = array_merge( - Playlist::factory()->raw(), - [ - Playlist::ATTRIBUTE_VISIBILITY => $visibility->localize(), ], - ); + ]), + ]); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Playlist::class))->createOne(); - $response = $this->put(route('api.playlist.update', ['playlist' => $playlist] + $parameters)); + $playlist = Playlist::factory() + ->for($user) + ->createOne(); - $response->assertJsonValidationErrors([ - Playlist::ATTRIBUTE_NAME, - ]); - } -} + $visibility = Arr::random(PlaylistVisibility::cases()); + + $parameters = array_merge( + Playlist::factory()->raw(), + [ + Playlist::ATTRIBUTE_VISIBILITY => $visibility->localize(), + ], + ); + + Sanctum::actingAs($user); + + $response = put(route('api.playlist.update', ['playlist' => $playlist] + $parameters)); + + $response->assertJsonValidationErrors([ + Playlist::ATTRIBUTE_NAME, + ]); +}); diff --git a/tests/Feature/Http/Api/List/Playlist/Track/TrackBackwardIndexTest.php b/tests/Feature/Http/Api/List/Playlist/Track/TrackBackwardIndexTest.php index a99d5445a..c89bb373b 100644 --- a/tests/Feature/Http/Api/List/Playlist/Track/TrackBackwardIndexTest.php +++ b/tests/Feature/Http/Api/List/Playlist/Track/TrackBackwardIndexTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\List\Playlist\Track; - use App\Contracts\Http\Api\Field\SortableField; use App\Enums\Auth\CrudPermission; use App\Enums\Http\Api\Sort\Direction; @@ -29,342 +27,295 @@ use App\Models\BaseModel; use App\Models\List\Playlist; use App\Models\List\Playlist\BackwardPlaylistTrack; use App\Models\List\Playlist\PlaylistTrack; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Event; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class TrackBackwardIndexTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * The Track Backward Index Endpoint shall forbid a private playlist from being publicly viewed. - */ - public function testPrivatePlaylistCannotBePubliclyViewed(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $playlist = Playlist::factory() - ->for(User::factory()) - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, - ]); +test('private playlist cannot be publicly viewed', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $track = PlaylistTrack::query()->inRandomOrder()->first(); - - $response = $this->get(route('api.playlist.track.backward', ['playlist' => $playlist, 'track' => $track])); - - $response->assertForbidden(); - } - - /** - * The Track Backward Index Endpoint shall forbid the user from viewing private playlist tracks if not owned. - */ - public function testPrivatePlaylistTrackCannotBePubliclyViewedIfNotOwned(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - - $playlist = Playlist::factory() - ->for(User::factory()) - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, - ]); - - $track = PlaylistTrack::query()->inRandomOrder()->first(); - - $user = User::factory()->withPermissions(CrudPermission::VIEW->format(PlaylistTrack::class))->createOne(); - - Sanctum::actingAs($user); - - $response = $this->get(route('api.playlist.track.backward', ['playlist' => $playlist, 'track' => $track])); - - $response->assertForbidden(); - } - - /** - * The Track Backward Index Endpoint shall allow private playlist tracks to be viewed by the owner. - */ - public function testPrivatePlaylistTrackCanBeViewedByOwner(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - - $user = User::factory()->withPermissions(CrudPermission::VIEW->format(PlaylistTrack::class))->createOne(); - - $playlist = Playlist::factory() - ->for($user) - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, - ]); - - $track = PlaylistTrack::query()->inRandomOrder()->first(); - - Sanctum::actingAs($user); - - $response = $this->get(route('api.playlist.track.backward', ['playlist' => $playlist, 'track' => $track])); - - $response->assertOk(); - } - - /** - * The Track Backward Index Endpoint shall allow unlisted playlist tracks to be viewed. - */ - public function testUnlistedPlaylistTrackCanBeViewed(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - - $playlist = Playlist::factory() - ->for(User::factory()) - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::UNLISTED->value, - ]); - - $track = PlaylistTrack::query()->inRandomOrder()->first(); - - $response = $this->get(route('api.playlist.track.backward', ['playlist' => $playlist, 'track' => $track])); - - $response->assertOk(); - } - - /** - * The Track Backward Index Endpoint shall allow public playlist tracks to be viewed. - */ - public function testPublicPlaylistTrackCanBeViewed(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - - $playlist = Playlist::factory() - ->for(User::factory()) - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); - - $track = PlaylistTrack::query()->inRandomOrder()->first(); - - $response = $this->get(route('api.playlist.track.backward', ['playlist' => $playlist, 'track' => $track])); - - $response->assertOk(); - } - - /** - * By default, the Track Backward Index Endpoint shall return a collection of Track Resources that belong to the Playlist. - */ - public function testDefault(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - - $trackCount = $this->faker->numberBetween(2, 9); - - $playlist = Playlist::factory() - ->tracks($trackCount) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); - - /** @var BackwardPlaylistTrack $track */ - $track = BackwardPlaylistTrack::query()->inRandomOrder()->first(); - - $response = $this->get(route('api.playlist.track.backward', ['playlist' => $playlist, 'track' => $track])); - - $tracks = $track->descendants()->get(); - - $response->assertJsonCount($tracks->count(), TrackCollection::$wrap); - - $response->assertJson( - json_decode( - json_encode( - new TrackCollection($tracks, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Track Backward Index Endpoint shall be paginated. - */ - public function testPaginated(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - - $playlist = Playlist::factory() - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); - - $track = PlaylistTrack::query()->inRandomOrder()->first(); - - $response = $this->get(route('api.playlist.track.backward', ['playlist' => $playlist, 'track' => $track])); - - $response->assertJsonStructure([ - TrackCollection::$wrap, - 'links', - 'meta', + $playlist = Playlist::factory() + ->for(User::factory()) + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, ]); - } - /** - * The Track Backward Index Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $track = PlaylistTrack::query()->inRandomOrder()->first(); - $schema = new ForwardBackwardSchema(); + $response = get(route('api.playlist.track.backward', ['playlist' => $playlist, 'track' => $track])); - $allowedIncludes = collect($schema->allowedIncludes()); + $response->assertForbidden(); +}); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); +test('private playlist track cannot be publicly viewed if not owned', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - $playlist = Playlist::factory() - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); - - /** @var BackwardPlaylistTrack $track */ - $track = BackwardPlaylistTrack::query()->inRandomOrder()->first(); - - $response = $this->get(route('api.playlist.track.backward', ['playlist' => $playlist, 'track' => $track] + $parameters)); - - $tracks = $track->descendants() - ->get() - ->load($includedPaths->all()); - - $response->assertJson( - json_decode( - json_encode( - new TrackCollection($tracks, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Track Backward Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - - $schema = new ForwardBackwardSchema(); - - $fields = collect($schema->fields()); - - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); - - $parameters = [ - FieldParser::param() => [ - TrackResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; - - $playlist = Playlist::factory() - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); - - /** @var BackwardPlaylistTrack $track */ - $track = BackwardPlaylistTrack::query()->inRandomOrder()->first(); - - $response = $this->get(route('api.playlist.track.backward', ['playlist' => $playlist, 'track' => $track] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new TrackCollection($track->descendants()->get(), new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Track Backward Index Endpoint shall forbid sorting resources. - */ - public function testSorts(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - - $schema = new ForwardBackwardSchema(); - - /** @var Sort $sort */ - $sort = collect($schema->fields()) - ->filter(fn (Field $field) => $field instanceof SortableField) - ->map(fn (SortableField $field) => $field->getSort()) - ->random(); - - $parameters = [ - SortParser::param() => $sort->format(Arr::random(Direction::cases())), - ]; - - $playlist = Playlist::factory() - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); - - $track = PlaylistTrack::query()->inRandomOrder()->first(); - - $response = $this->get(route('api.playlist.track.backward', ['playlist' => $playlist, 'track' => $track] + $parameters)); - - $response->assertJsonValidationErrors([ - SortParser::param(), + $playlist = Playlist::factory() + ->for(User::factory()) + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, ]); - } - /** - * The Track Backward Index Endpoint shall forbid filter resources. - */ - public function testFilters(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $track = PlaylistTrack::query()->inRandomOrder()->first(); - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_CREATED_AT => $this->faker->date(), - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; + $user = User::factory()->withPermissions(CrudPermission::VIEW->format(PlaylistTrack::class))->createOne(); - $playlist = Playlist::factory() - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); + Sanctum::actingAs($user); - $track = PlaylistTrack::query()->inRandomOrder()->first(); + $response = get(route('api.playlist.track.backward', ['playlist' => $playlist, 'track' => $track])); - $response = $this->get(route('api.playlist.track.backward', ['playlist' => $playlist, 'track' => $track] + $parameters)); + $response->assertForbidden(); +}); - $response->assertJsonValidationErrors([ - FilterParser::param(), +test('private playlist track can be viewed by owner', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + + $user = User::factory()->withPermissions(CrudPermission::VIEW->format(PlaylistTrack::class))->createOne(); + + $playlist = Playlist::factory() + ->for($user) + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, ]); - } -} + + $track = PlaylistTrack::query()->inRandomOrder()->first(); + + Sanctum::actingAs($user); + + $response = get(route('api.playlist.track.backward', ['playlist' => $playlist, 'track' => $track])); + + $response->assertOk(); +}); + +test('unlisted playlist track can be viewed', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + + $playlist = Playlist::factory() + ->for(User::factory()) + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::UNLISTED->value, + ]); + + $track = PlaylistTrack::query()->inRandomOrder()->first(); + + $response = get(route('api.playlist.track.backward', ['playlist' => $playlist, 'track' => $track])); + + $response->assertOk(); +}); + +test('public playlist track can be viewed', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + + $playlist = Playlist::factory() + ->for(User::factory()) + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); + + $track = PlaylistTrack::query()->inRandomOrder()->first(); + + $response = get(route('api.playlist.track.backward', ['playlist' => $playlist, 'track' => $track])); + + $response->assertOk(); +}); + +test('default', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + + $trackCount = fake()->numberBetween(2, 9); + + $playlist = Playlist::factory() + ->tracks($trackCount) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); + + /** @var BackwardPlaylistTrack $track */ + $track = BackwardPlaylistTrack::query()->inRandomOrder()->first(); + + $response = get(route('api.playlist.track.backward', ['playlist' => $playlist, 'track' => $track])); + + $tracks = $track->descendants()->get(); + + $response->assertJsonCount($tracks->count(), TrackCollection::$wrap); + + $response->assertJson( + json_decode( + json_encode( + new TrackCollection($tracks, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('paginated', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + + $playlist = Playlist::factory() + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); + + $track = PlaylistTrack::query()->inRandomOrder()->first(); + + $response = get(route('api.playlist.track.backward', ['playlist' => $playlist, 'track' => $track])); + + $response->assertJsonStructure([ + TrackCollection::$wrap, + 'links', + 'meta', + ]); +}); + +test('allowed include paths', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + + $schema = new ForwardBackwardSchema(); + + $allowedIncludes = collect($schema->allowedIncludes()); + + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); + + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + $playlist = Playlist::factory() + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); + + /** @var BackwardPlaylistTrack $track */ + $track = BackwardPlaylistTrack::query()->inRandomOrder()->first(); + + $response = get(route('api.playlist.track.backward', ['playlist' => $playlist, 'track' => $track] + $parameters)); + + $tracks = $track->descendants() + ->get() + ->load($includedPaths->all()); + + $response->assertJson( + json_decode( + json_encode( + new TrackCollection($tracks, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sparse fieldsets', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + + $schema = new ForwardBackwardSchema(); + + $fields = collect($schema->fields()); + + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + TrackResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + $playlist = Playlist::factory() + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); + + /** @var BackwardPlaylistTrack $track */ + $track = BackwardPlaylistTrack::query()->inRandomOrder()->first(); + + $response = get(route('api.playlist.track.backward', ['playlist' => $playlist, 'track' => $track] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new TrackCollection($track->descendants()->get(), new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sorts', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + + $schema = new ForwardBackwardSchema(); + + /** @var Sort $sort */ + $sort = collect($schema->fields()) + ->filter(fn (Field $field) => $field instanceof SortableField) + ->map(fn (SortableField $field) => $field->getSort()) + ->random(); + + $parameters = [ + SortParser::param() => $sort->format(Arr::random(Direction::cases())), + ]; + + $playlist = Playlist::factory() + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); + + $track = PlaylistTrack::query()->inRandomOrder()->first(); + + $response = get(route('api.playlist.track.backward', ['playlist' => $playlist, 'track' => $track] + $parameters)); + + $response->assertJsonValidationErrors([ + SortParser::param(), + ]); +}); + +test('filters', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_CREATED_AT => fake()->date(), + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + $playlist = Playlist::factory() + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); + + $track = PlaylistTrack::query()->inRandomOrder()->first(); + + $response = get(route('api.playlist.track.backward', ['playlist' => $playlist, 'track' => $track] + $parameters)); + + $response->assertJsonValidationErrors([ + FilterParser::param(), + ]); +}); diff --git a/tests/Feature/Http/Api/List/Playlist/Track/TrackDestroyTest.php b/tests/Feature/Http/Api/List/Playlist/Track/TrackDestroyTest.php index 1cc010ea9..671c59a83 100644 --- a/tests/Feature/Http/Api/List/Playlist/Track/TrackDestroyTest.php +++ b/tests/Feature/Http/Api/List/Playlist/Track/TrackDestroyTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\List\Playlist\Track; - use App\Enums\Auth\CrudPermission; use App\Enums\Auth\SpecialPermission; use App\Enums\Models\List\PlaylistVisibility; @@ -13,303 +11,258 @@ use App\Features\AllowPlaylistManagement; use App\Models\Auth\User; use App\Models\List\Playlist; use App\Models\List\Playlist\PlaylistTrack; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class TrackDestroyTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\delete; - /** - * The Track Destroy Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); +uses(Illuminate\Foundation\Testing\WithFaker::class); - Feature::activate(AllowPlaylistManagement::class); +test('protected', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $track = PlaylistTrack::factory() - ->for(Playlist::factory()) - ->createOne(); + Feature::activate(AllowPlaylistManagement::class); - $response = $this->delete(route('api.playlist.track.destroy', ['playlist' => $track->playlist, 'track' => $track])); + $track = PlaylistTrack::factory() + ->for(Playlist::factory()) + ->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.playlist.track.destroy', ['playlist' => $track->playlist, 'track' => $track])); - /** - * The Track Destroy Endpoint shall forbid users without the delete playlist track permission. - */ - public function testForbiddenIfMissingPermission(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $response->assertUnauthorized(); +}); - Feature::activate(AllowPlaylistManagement::class); +test('forbidden if missing permission', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $track = PlaylistTrack::factory() - ->for(Playlist::factory()) - ->createOne(); + Feature::activate(AllowPlaylistManagement::class); - $user = User::factory()->createOne(); + $track = PlaylistTrack::factory() + ->for(Playlist::factory()) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.playlist.track.destroy', ['playlist' => $track->playlist, 'track' => $track])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.playlist.track.destroy', ['playlist' => $track->playlist, 'track' => $track])); - /** - * The Track Destroy Endpoint shall forbid users from deleting the track if they don't own the playlist. - */ - public function testForbiddenIfNotOwnPlaylist(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $response->assertForbidden(); +}); - Feature::activate(AllowPlaylistManagement::class); +test('forbidden if not own playlist', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $track = PlaylistTrack::factory() - ->for(Playlist::factory()->for(User::factory())) - ->createOne(); + Feature::activate(AllowPlaylistManagement::class); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(PlaylistTrack::class))->createOne(); + $track = PlaylistTrack::factory() + ->for(Playlist::factory()->for(User::factory())) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(PlaylistTrack::class))->createOne(); - $response = $this->delete(route('api.playlist.track.destroy', ['playlist' => $track->playlist, 'track' => $track])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.playlist.track.destroy', ['playlist' => $track->playlist, 'track' => $track])); - /** - * The Track Destroy Endpoint shall forbid users from destroying playlists tracks - * if the Allow Playlist Management feature is inactive. - */ - public function testForbiddenIfFlagDisabled(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $response->assertForbidden(); +}); - Feature::deactivate(AllowPlaylistManagement::class); +test('forbidden if flag disabled', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(PlaylistTrack::class))->createOne(); + Feature::deactivate(AllowPlaylistManagement::class); - $playlist = Playlist::factory() - ->for($user) - ->createOne(); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(PlaylistTrack::class))->createOne(); - $track = PlaylistTrack::factory() - ->for($playlist) - ->createOne(); + $playlist = Playlist::factory() + ->for($user) + ->createOne(); - Sanctum::actingAs($user); + $track = PlaylistTrack::factory() + ->for($playlist) + ->createOne(); - $response = $this->delete(route('api.playlist.track.destroy', ['playlist' => $playlist, 'track' => $track])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.playlist.track.destroy', ['playlist' => $playlist, 'track' => $track])); - /** - * The Track Destroy Endpoint shall scope bindings. - */ - public function testScoped(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $response->assertForbidden(); +}); - Feature::activate(AllowPlaylistManagement::class); +test('scoped', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(PlaylistTrack::class))->createOne(); + Feature::activate(AllowPlaylistManagement::class); - $playlist = Playlist::factory() - ->for($user) - ->has(PlaylistTrack::factory()->count($this->faker->randomDigitNotNull()), Playlist::RELATION_TRACKS) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(PlaylistTrack::class))->createOne(); - $track = PlaylistTrack::factory() - ->for(Playlist::factory()->for(User::factory())) - ->createOne(); + $playlist = Playlist::factory() + ->for($user) + ->has(PlaylistTrack::factory()->count(fake()->randomDigitNotNull()), Playlist::RELATION_TRACKS) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); - Sanctum::actingAs($user); + $track = PlaylistTrack::factory() + ->for(Playlist::factory()->for(User::factory())) + ->createOne(); - $response = $this->delete(route('api.playlist.track.destroy', ['playlist' => $playlist, 'track' => $track])); + Sanctum::actingAs($user); - $response->assertNotFound(); - } + $response = delete(route('api.playlist.track.destroy', ['playlist' => $playlist, 'track' => $track])); - /** - * The Track Destroy Endpoint shall delete the sole track. - */ - public function testDeleted(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $response->assertNotFound(); +}); - Feature::activate(AllowPlaylistManagement::class); +test('deleted', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(PlaylistTrack::class))->createOne(); + Feature::activate(AllowPlaylistManagement::class); - $playlist = Playlist::factory() - ->for($user) - ->createOne(); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(PlaylistTrack::class))->createOne(); - $track = PlaylistTrack::factory() - ->for($playlist) - ->createOne(); + $playlist = Playlist::factory() + ->for($user) + ->createOne(); - Sanctum::actingAs($user); + $track = PlaylistTrack::factory() + ->for($playlist) + ->createOne(); - $response = $this->delete(route('api.playlist.track.destroy', ['playlist' => $playlist, 'track' => $track])); + Sanctum::actingAs($user); - $response->assertOk(); + $response = delete(route('api.playlist.track.destroy', ['playlist' => $playlist, 'track' => $track])); - $playlist->refresh(); + $response->assertOk(); - static::assertModelMissing($track); - static::assertTrue($playlist->first()->doesntExist()); - static::assertTrue($playlist->last()->doesntExist()); - } + $playlist->refresh(); - /** - * Users with the bypass feature flag permission shall be permitted to destroy playlist tracks - * even if the Allow Playlist Management feature is inactive. - */ - public function testDestroyPermittedForBypass(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $this->assertModelMissing($track); + $this->assertTrue($playlist->first()->doesntExist()); + $this->assertTrue($playlist->last()->doesntExist()); +}); - Feature::activate(AllowPlaylistManagement::class, $this->faker->boolean()); +test('destroy permitted for bypass', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $user = User::factory() - ->withPermissions( - CrudPermission::DELETE->format(PlaylistTrack::class), - SpecialPermission::BYPASS_FEATURE_FLAGS->value - ) - ->createOne(); + Feature::activate(AllowPlaylistManagement::class, fake()->boolean()); - $playlist = Playlist::factory() - ->for($user) - ->createOne(); + $user = User::factory() + ->withPermissions( + CrudPermission::DELETE->format(PlaylistTrack::class), + SpecialPermission::BYPASS_FEATURE_FLAGS->value + ) + ->createOne(); - $track = PlaylistTrack::factory() - ->for($playlist) - ->createOne(); + $playlist = Playlist::factory() + ->for($user) + ->createOne(); - Sanctum::actingAs($user); + $track = PlaylistTrack::factory() + ->for($playlist) + ->createOne(); - $response = $this->delete(route('api.playlist.track.destroy', ['playlist' => $playlist, 'track' => $track])); + Sanctum::actingAs($user); - $response->assertOk(); - } + $response = delete(route('api.playlist.track.destroy', ['playlist' => $playlist, 'track' => $track])); - /** - * The Track Destroy Endpoint shall delete the first track. - */ - public function testDestroyFirst(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $response->assertOk(); +}); - Feature::activate(AllowPlaylistManagement::class); +test('destroy first', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(PlaylistTrack::class))->createOne(); + Feature::activate(AllowPlaylistManagement::class); - $playlist = Playlist::factory() - ->for($user) - ->tracks($this->faker->numberBetween(3, 9)) - ->createOne(); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(PlaylistTrack::class))->createOne(); - $first = $playlist->first; - $second = $first->next; + $playlist = Playlist::factory() + ->for($user) + ->tracks(fake()->numberBetween(3, 9)) + ->createOne(); - Sanctum::actingAs($user); + $first = $playlist->first; + $second = $first->next; - $response = $this->delete(route('api.playlist.track.destroy', ['playlist' => $playlist, 'track' => $first])); + Sanctum::actingAs($user); - $response->assertOk(); + $response = delete(route('api.playlist.track.destroy', ['playlist' => $playlist, 'track' => $first])); - $playlist->refresh(); - $second->refresh(); + $response->assertOk(); - static::assertModelMissing($first); - static::assertTrue($playlist->first()->is($second)); - static::assertTrue($second->previous()->doesntExist()); - } + $playlist->refresh(); + $second->refresh(); - /** - * The Track Destroy Endpoint shall delete the last track. - */ - public function testDestroyLast(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $this->assertModelMissing($first); + $this->assertTrue($playlist->first()->is($second)); + $this->assertTrue($second->previous()->doesntExist()); +}); - Feature::activate(AllowPlaylistManagement::class); +test('destroy last', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(PlaylistTrack::class))->createOne(); + Feature::activate(AllowPlaylistManagement::class); - $playlist = Playlist::factory() - ->for($user) - ->tracks($this->faker->numberBetween(3, 9)) - ->createOne(); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(PlaylistTrack::class))->createOne(); - $last = $playlist->last; - $previous = $last->previous; + $playlist = Playlist::factory() + ->for($user) + ->tracks(fake()->numberBetween(3, 9)) + ->createOne(); - Sanctum::actingAs($user); + $last = $playlist->last; + $previous = $last->previous; - $response = $this->delete(route('api.playlist.track.destroy', ['playlist' => $playlist, 'track' => $last])); + Sanctum::actingAs($user); - $response->assertOk(); + $response = delete(route('api.playlist.track.destroy', ['playlist' => $playlist, 'track' => $last])); - $playlist->refresh(); - $previous->refresh(); + $response->assertOk(); - static::assertModelMissing($last); - static::assertTrue($playlist->last()->is($previous)); - static::assertTrue($previous->next()->doesntExist()); - } + $playlist->refresh(); + $previous->refresh(); - /** - * The Track Destroy Endpoint shall delete the second track. - */ - public function testDestroySecond(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $this->assertModelMissing($last); + $this->assertTrue($playlist->last()->is($previous)); + $this->assertTrue($previous->next()->doesntExist()); +}); - Feature::activate(AllowPlaylistManagement::class); +test('destroy second', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(PlaylistTrack::class))->createOne(); + Feature::activate(AllowPlaylistManagement::class); - $playlist = Playlist::factory() - ->for($user) - ->tracks(3) - ->createOne(); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(PlaylistTrack::class))->createOne(); - $first = $playlist->first; - $second = $first->next; - $third = $playlist->last; + $playlist = Playlist::factory() + ->for($user) + ->tracks(3) + ->createOne(); - Sanctum::actingAs($user); + $first = $playlist->first; + $second = $first->next; + $third = $playlist->last; - $response = $this->delete(route('api.playlist.track.destroy', ['playlist' => $playlist, 'track' => $second])); + Sanctum::actingAs($user); - $response->assertOk(); + $response = delete(route('api.playlist.track.destroy', ['playlist' => $playlist, 'track' => $second])); - $playlist->refresh(); - $first->refresh(); - $third->refresh(); + $response->assertOk(); - static::assertModelMissing($second); + $playlist->refresh(); + $first->refresh(); + $third->refresh(); - static::assertTrue($playlist->first()->is($first)); - static::assertTrue($playlist->last()->is($third)); + $this->assertModelMissing($second); - static::assertTrue($first->previous()->doesntExist()); - static::assertTrue($first->next()->is($third)); + $this->assertTrue($playlist->first()->is($first)); + $this->assertTrue($playlist->last()->is($third)); - static::assertTrue($third->previous()->is($first)); - static::assertTrue($third->next()->doesntExist()); - } -} + $this->assertTrue($first->previous()->doesntExist()); + $this->assertTrue($first->next()->is($third)); + + $this->assertTrue($third->previous()->is($first)); + $this->assertTrue($third->next()->doesntExist()); +}); diff --git a/tests/Feature/Http/Api/List/Playlist/Track/TrackForwardIndexTest.php b/tests/Feature/Http/Api/List/Playlist/Track/TrackForwardIndexTest.php index e7c93fbe4..4d6b9fdfe 100644 --- a/tests/Feature/Http/Api/List/Playlist/Track/TrackForwardIndexTest.php +++ b/tests/Feature/Http/Api/List/Playlist/Track/TrackForwardIndexTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\List\Playlist\Track; - use App\Contracts\Http\Api\Field\SortableField; use App\Enums\Auth\CrudPermission; use App\Enums\Http\Api\Sort\Direction; @@ -29,342 +27,295 @@ use App\Models\BaseModel; use App\Models\List\Playlist; use App\Models\List\Playlist\ForwardPlaylistTrack; use App\Models\List\Playlist\PlaylistTrack; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Event; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class TrackForwardIndexTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * The Track Forward Index Endpoint shall forbid a private playlist from being publicly viewed. - */ - public function testPrivatePlaylistCannotBePubliclyViewed(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $playlist = Playlist::factory() - ->for(User::factory()) - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, - ]); +test('private playlist cannot be publicly viewed', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $track = PlaylistTrack::query()->inRandomOrder()->first(); - - $response = $this->get(route('api.playlist.track.forward', ['playlist' => $playlist, 'track' => $track])); - - $response->assertForbidden(); - } - - /** - * The Track Forward Index Endpoint shall forbid the user from viewing private playlist tracks if not owned. - */ - public function testPrivatePlaylistTrackCannotBePubliclyViewedIfNotOwned(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - - $playlist = Playlist::factory() - ->for(User::factory()) - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, - ]); - - $track = PlaylistTrack::query()->inRandomOrder()->first(); - - $user = User::factory()->withPermissions(CrudPermission::VIEW->format(PlaylistTrack::class))->createOne(); - - Sanctum::actingAs($user); - - $response = $this->get(route('api.playlist.track.forward', ['playlist' => $playlist, 'track' => $track])); - - $response->assertForbidden(); - } - - /** - * The Track Forward Index Endpoint shall allow private playlist tracks to be viewed by the owner. - */ - public function testPrivatePlaylistTrackCanBeViewedByOwner(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - - $user = User::factory()->withPermissions(CrudPermission::VIEW->format(PlaylistTrack::class))->createOne(); - - $playlist = Playlist::factory() - ->for($user) - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, - ]); - - $track = PlaylistTrack::query()->inRandomOrder()->first(); - - Sanctum::actingAs($user); - - $response = $this->get(route('api.playlist.track.forward', ['playlist' => $playlist, 'track' => $track])); - - $response->assertOk(); - } - - /** - * The Track Forward Index Endpoint shall allow unlisted playlist tracks to be viewed. - */ - public function testUnlistedPlaylistTrackCanBeViewed(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - - $playlist = Playlist::factory() - ->for(User::factory()) - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::UNLISTED->value, - ]); - - $track = PlaylistTrack::query()->inRandomOrder()->first(); - - $response = $this->get(route('api.playlist.track.forward', ['playlist' => $playlist, 'track' => $track])); - - $response->assertOk(); - } - - /** - * The Track Forward Index Endpoint shall allow public playlist tracks to be viewed. - */ - public function testPublicPlaylistTrackCanBeViewed(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - - $playlist = Playlist::factory() - ->for(User::factory()) - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); - - $track = PlaylistTrack::query()->inRandomOrder()->first(); - - $response = $this->get(route('api.playlist.track.forward', ['playlist' => $playlist, 'track' => $track])); - - $response->assertOk(); - } - - /** - * By default, the Track Forward Index Endpoint shall return a collection of Track Resources that belong to the Playlist. - */ - public function testDefault(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - - $trackCount = $this->faker->numberBetween(2, 9); - - $playlist = Playlist::factory() - ->tracks($trackCount) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); - - /** @var ForwardPlaylistTrack $track */ - $track = ForwardPlaylistTrack::query()->inRandomOrder()->first(); - - $response = $this->get(route('api.playlist.track.forward', ['playlist' => $playlist, 'track' => $track])); - - $tracks = $track->descendants()->get(); - - $response->assertJsonCount($tracks->count(), TrackCollection::$wrap); - - $response->assertJson( - json_decode( - json_encode( - new TrackCollection($tracks, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Track Forward Index Endpoint shall be paginated. - */ - public function testPaginated(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - - $playlist = Playlist::factory() - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); - - $track = PlaylistTrack::query()->inRandomOrder()->first(); - - $response = $this->get(route('api.playlist.track.forward', ['playlist' => $playlist, 'track' => $track])); - - $response->assertJsonStructure([ - TrackCollection::$wrap, - 'links', - 'meta', + $playlist = Playlist::factory() + ->for(User::factory()) + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, ]); - } - /** - * The Track Forward Index Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $track = PlaylistTrack::query()->inRandomOrder()->first(); - $schema = new ForwardBackwardSchema(); + $response = get(route('api.playlist.track.forward', ['playlist' => $playlist, 'track' => $track])); - $allowedIncludes = collect($schema->allowedIncludes()); + $response->assertForbidden(); +}); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); +test('private playlist track cannot be publicly viewed if not owned', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - $playlist = Playlist::factory() - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); - - /** @var ForwardPlaylistTrack $track */ - $track = ForwardPlaylistTrack::query()->inRandomOrder()->first(); - - $response = $this->get(route('api.playlist.track.forward', ['playlist' => $playlist, 'track' => $track] + $parameters)); - - $tracks = $track->descendants() - ->get() - ->load($includedPaths->all()); - - $response->assertJson( - json_decode( - json_encode( - new TrackCollection($tracks, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Track Forward Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - - $schema = new ForwardBackwardSchema(); - - $fields = collect($schema->fields()); - - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); - - $parameters = [ - FieldParser::param() => [ - TrackResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; - - $playlist = Playlist::factory() - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); - - /** @var ForwardPlaylistTrack $track */ - $track = ForwardPlaylistTrack::query()->inRandomOrder()->first(); - - $response = $this->get(route('api.playlist.track.forward', ['playlist' => $playlist, 'track' => $track] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new TrackCollection($track->descendants()->get(), new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Track Forward Index Endpoint shall forbid sorting resources. - */ - public function testSorts(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - - $schema = new ForwardBackwardSchema(); - - /** @var Sort $sort */ - $sort = collect($schema->fields()) - ->filter(fn (Field $field) => $field instanceof SortableField) - ->map(fn (SortableField $field) => $field->getSort()) - ->random(); - - $parameters = [ - SortParser::param() => $sort->format(Arr::random(Direction::cases())), - ]; - - $playlist = Playlist::factory() - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); - - $track = PlaylistTrack::query()->inRandomOrder()->first(); - - $response = $this->get(route('api.playlist.track.forward', ['playlist' => $playlist, 'track' => $track] + $parameters)); - - $response->assertJsonValidationErrors([ - SortParser::param(), + $playlist = Playlist::factory() + ->for(User::factory()) + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, ]); - } - /** - * The Track Forward Index Endpoint shall forbid filter resources. - */ - public function testFilters(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $track = PlaylistTrack::query()->inRandomOrder()->first(); - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_CREATED_AT => $this->faker->date(), - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; + $user = User::factory()->withPermissions(CrudPermission::VIEW->format(PlaylistTrack::class))->createOne(); - $playlist = Playlist::factory() - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); + Sanctum::actingAs($user); - $track = PlaylistTrack::query()->inRandomOrder()->first(); + $response = get(route('api.playlist.track.forward', ['playlist' => $playlist, 'track' => $track])); - $response = $this->get(route('api.playlist.track.forward', ['playlist' => $playlist, 'track' => $track] + $parameters)); + $response->assertForbidden(); +}); - $response->assertJsonValidationErrors([ - FilterParser::param(), +test('private playlist track can be viewed by owner', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + + $user = User::factory()->withPermissions(CrudPermission::VIEW->format(PlaylistTrack::class))->createOne(); + + $playlist = Playlist::factory() + ->for($user) + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, ]); - } -} + + $track = PlaylistTrack::query()->inRandomOrder()->first(); + + Sanctum::actingAs($user); + + $response = get(route('api.playlist.track.forward', ['playlist' => $playlist, 'track' => $track])); + + $response->assertOk(); +}); + +test('unlisted playlist track can be viewed', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + + $playlist = Playlist::factory() + ->for(User::factory()) + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::UNLISTED->value, + ]); + + $track = PlaylistTrack::query()->inRandomOrder()->first(); + + $response = get(route('api.playlist.track.forward', ['playlist' => $playlist, 'track' => $track])); + + $response->assertOk(); +}); + +test('public playlist track can be viewed', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + + $playlist = Playlist::factory() + ->for(User::factory()) + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); + + $track = PlaylistTrack::query()->inRandomOrder()->first(); + + $response = get(route('api.playlist.track.forward', ['playlist' => $playlist, 'track' => $track])); + + $response->assertOk(); +}); + +test('default', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + + $trackCount = fake()->numberBetween(2, 9); + + $playlist = Playlist::factory() + ->tracks($trackCount) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); + + /** @var ForwardPlaylistTrack $track */ + $track = ForwardPlaylistTrack::query()->inRandomOrder()->first(); + + $response = get(route('api.playlist.track.forward', ['playlist' => $playlist, 'track' => $track])); + + $tracks = $track->descendants()->get(); + + $response->assertJsonCount($tracks->count(), TrackCollection::$wrap); + + $response->assertJson( + json_decode( + json_encode( + new TrackCollection($tracks, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('paginated', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + + $playlist = Playlist::factory() + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); + + $track = PlaylistTrack::query()->inRandomOrder()->first(); + + $response = get(route('api.playlist.track.forward', ['playlist' => $playlist, 'track' => $track])); + + $response->assertJsonStructure([ + TrackCollection::$wrap, + 'links', + 'meta', + ]); +}); + +test('allowed include paths', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + + $schema = new ForwardBackwardSchema(); + + $allowedIncludes = collect($schema->allowedIncludes()); + + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); + + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + $playlist = Playlist::factory() + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); + + /** @var ForwardPlaylistTrack $track */ + $track = ForwardPlaylistTrack::query()->inRandomOrder()->first(); + + $response = get(route('api.playlist.track.forward', ['playlist' => $playlist, 'track' => $track] + $parameters)); + + $tracks = $track->descendants() + ->get() + ->load($includedPaths->all()); + + $response->assertJson( + json_decode( + json_encode( + new TrackCollection($tracks, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sparse fieldsets', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + + $schema = new ForwardBackwardSchema(); + + $fields = collect($schema->fields()); + + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + TrackResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + $playlist = Playlist::factory() + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); + + /** @var ForwardPlaylistTrack $track */ + $track = ForwardPlaylistTrack::query()->inRandomOrder()->first(); + + $response = get(route('api.playlist.track.forward', ['playlist' => $playlist, 'track' => $track] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new TrackCollection($track->descendants()->get(), new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sorts', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + + $schema = new ForwardBackwardSchema(); + + /** @var Sort $sort */ + $sort = collect($schema->fields()) + ->filter(fn (Field $field) => $field instanceof SortableField) + ->map(fn (SortableField $field) => $field->getSort()) + ->random(); + + $parameters = [ + SortParser::param() => $sort->format(Arr::random(Direction::cases())), + ]; + + $playlist = Playlist::factory() + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); + + $track = PlaylistTrack::query()->inRandomOrder()->first(); + + $response = get(route('api.playlist.track.forward', ['playlist' => $playlist, 'track' => $track] + $parameters)); + + $response->assertJsonValidationErrors([ + SortParser::param(), + ]); +}); + +test('filters', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_CREATED_AT => fake()->date(), + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + $playlist = Playlist::factory() + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); + + $track = PlaylistTrack::query()->inRandomOrder()->first(); + + $response = get(route('api.playlist.track.forward', ['playlist' => $playlist, 'track' => $track] + $parameters)); + + $response->assertJsonValidationErrors([ + FilterParser::param(), + ]); +}); diff --git a/tests/Feature/Http/Api/List/Playlist/Track/TrackIndexTest.php b/tests/Feature/Http/Api/List/Playlist/Track/TrackIndexTest.php index 509d9b468..67a9d4f78 100644 --- a/tests/Feature/Http/Api/List/Playlist/Track/TrackIndexTest.php +++ b/tests/Feature/Http/Api/List/Playlist/Track/TrackIndexTest.php @@ -2,9 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\List\Playlist\Track; - -use App\Concerns\Actions\Http\Api\SortsModels; use App\Contracts\Http\Api\Field\SortableField; use App\Enums\Auth\CrudPermission; use App\Enums\Http\Api\Sort\Direction; @@ -29,426 +26,376 @@ use App\Models\BaseModel; use App\Models\List\Playlist; use App\Models\List\Playlist\PlaylistTrack; use App\Models\Wiki\Video; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Event; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class TrackIndexTest extends TestCase -{ - use SortsModels; - use WithFaker; +use function Pest\Laravel\get; - /** - * The Track Index Endpoint shall forbid a private playlist from being publicly viewed. - */ - public function testPrivatePlaylistTrackCannotBePubliclyViewed(): void - { - Event::fakeExcept(PlaylistCreated::class); +uses(App\Concerns\Actions\Http\Api\SortsModels::class); - $playlist = Playlist::factory() - ->for(User::factory()) - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, - ]); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response = $this->get(route('api.playlist.track.index', ['playlist' => $playlist])); +test('private playlist track cannot be publicly viewed', function () { + Event::fakeExcept(PlaylistCreated::class); - $response->assertForbidden(); - } + $playlist = Playlist::factory() + ->for(User::factory()) + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, + ]); - /** - * The Track Index Endpoint shall forbid the user from viewing private playlist tracks if not owned. - */ - public function testPrivatePlaylistTrackCannotBePubliclyViewedIfNotOwned(): void - { - Event::fakeExcept(PlaylistCreated::class); + $response = get(route('api.playlist.track.index', ['playlist' => $playlist])); - $playlist = Playlist::factory() - ->for(User::factory()) - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, - ]); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(CrudPermission::VIEW->format(PlaylistTrack::class))->createOne(); +test('private playlist track cannot be publicly viewed if not owned', function () { + Event::fakeExcept(PlaylistCreated::class); - Sanctum::actingAs($user); + $playlist = Playlist::factory() + ->for(User::factory()) + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, + ]); - $response = $this->get(route('api.playlist.track.index', ['playlist' => $playlist])); + $user = User::factory()->withPermissions(CrudPermission::VIEW->format(PlaylistTrack::class))->createOne(); - $response->assertForbidden(); - } + Sanctum::actingAs($user); - /** - * The Track Index Endpoint shall allow private playlist tracks to be viewed by the owner. - */ - public function testPrivatePlaylistTrackCanBeViewedByOwner(): void - { - Event::fakeExcept(PlaylistCreated::class); + $response = get(route('api.playlist.track.index', ['playlist' => $playlist])); - $user = User::factory()->withPermissions(CrudPermission::VIEW->format(PlaylistTrack::class))->createOne(); + $response->assertForbidden(); +}); - $playlist = Playlist::factory() - ->for($user) - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, - ]); +test('private playlist track can be viewed by owner', function () { + Event::fakeExcept(PlaylistCreated::class); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::VIEW->format(PlaylistTrack::class))->createOne(); - $response = $this->get(route('api.playlist.track.index', ['playlist' => $playlist])); + $playlist = Playlist::factory() + ->for($user) + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, + ]); - $response->assertOk(); - } + Sanctum::actingAs($user); - /** - * The Track Index Endpoint shall allow unlisted playlist tracks to be viewed. - */ - public function testUnlistedPlaylistTrackCanBeViewed(): void - { - Event::fakeExcept(PlaylistCreated::class); + $response = get(route('api.playlist.track.index', ['playlist' => $playlist])); - $playlist = Playlist::factory() - ->for(User::factory()) - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::UNLISTED->value, - ]); + $response->assertOk(); +}); - $response = $this->get(route('api.playlist.track.index', ['playlist' => $playlist])); +test('unlisted playlist track can be viewed', function () { + Event::fakeExcept(PlaylistCreated::class); - $response->assertOk(); - } + $playlist = Playlist::factory() + ->for(User::factory()) + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::UNLISTED->value, + ]); - /** - * The Track Index Endpoint shall allow public playlist tracks to be viewed. - */ - public function testPublicPlaylistTrackCanBeViewed(): void - { - Event::fakeExcept(PlaylistCreated::class); + $response = get(route('api.playlist.track.index', ['playlist' => $playlist])); - $playlist = Playlist::factory() - ->for(User::factory()) - ->tracks($this->faker->numberBetween(2, 9)) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); + $response->assertOk(); +}); - $response = $this->get(route('api.playlist.track.index', ['playlist' => $playlist])); +test('public playlist track can be viewed', function () { + Event::fakeExcept(PlaylistCreated::class); - $response->assertOk(); - } + $playlist = Playlist::factory() + ->for(User::factory()) + ->tracks(fake()->numberBetween(2, 9)) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); - /** - * By default, the Track Index Endpoint shall return a collection of Track Resources that belong to the Playlist. - */ - public function testDefault(): void - { - Event::fakeExcept(PlaylistCreated::class); + $response = get(route('api.playlist.track.index', ['playlist' => $playlist])); - $trackCount = $this->faker->randomDigitNotNull(); + $response->assertOk(); +}); - $playlist = Playlist::factory() +test('default', function () { + Event::fakeExcept(PlaylistCreated::class); + + $trackCount = fake()->randomDigitNotNull(); + + $playlist = Playlist::factory() + ->has(PlaylistTrack::factory()->count($trackCount), Playlist::RELATION_TRACKS) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); + + Collection::times( + fake()->randomDigitNotNull(), + fn () => Playlist::factory() ->has(PlaylistTrack::factory()->count($trackCount), Playlist::RELATION_TRACKS) ->createOne([ Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); + ]) + ); - Collection::times( - $this->faker->randomDigitNotNull(), - fn () => Playlist::factory() - ->has(PlaylistTrack::factory()->count($trackCount), Playlist::RELATION_TRACKS) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]) - ); + $response = get(route('api.playlist.track.index', ['playlist' => $playlist])); - $response = $this->get(route('api.playlist.track.index', ['playlist' => $playlist])); + $response->assertJsonCount($trackCount, TrackCollection::$wrap); - $response->assertJsonCount($trackCount, TrackCollection::$wrap); + $response->assertJson( + json_decode( + json_encode( + new TrackCollection($playlist->tracks, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $response->assertJson( - json_decode( - json_encode( - new TrackCollection($playlist->tracks, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } +test('paginated', function () { + Event::fakeExcept(PlaylistCreated::class); - /** - * The Track Index Endpoint shall be paginated. - */ - public function testPaginated(): void - { - Event::fakeExcept(PlaylistCreated::class); - - $playlist = Playlist::factory() - ->has(PlaylistTrack::factory()->count($this->faker->randomDigitNotNull()), Playlist::RELATION_TRACKS) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); - - $response = $this->get(route('api.playlist.track.index', ['playlist' => $playlist])); - - $response->assertJsonStructure([ - TrackCollection::$wrap, - 'links', - 'meta', + $playlist = Playlist::factory() + ->has(PlaylistTrack::factory()->count(fake()->randomDigitNotNull()), Playlist::RELATION_TRACKS) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, ]); - } - /** - * The Track Index Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - Event::fakeExcept(PlaylistCreated::class); + $response = get(route('api.playlist.track.index', ['playlist' => $playlist])); - $schema = new TrackSchema(); + $response->assertJsonStructure([ + TrackCollection::$wrap, + 'links', + 'meta', + ]); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('allowed include paths', function () { + Event::fakeExcept(PlaylistCreated::class); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $schema = new TrackSchema(); - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + $allowedIncludes = collect($schema->allowedIncludes()); - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); - $playlist = Playlist::factory() - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - PlaylistTrack::factory() + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + $playlist = Playlist::factory() + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); + + PlaylistTrack::factory() + ->for($playlist) + ->for(Video::factory()) + ->for(PlaylistTrack::factory()->for($playlist), PlaylistTrack::RELATION_PREVIOUS) + ->for(PlaylistTrack::factory()->for($playlist), PlaylistTrack::RELATION_NEXT) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $response = get(route('api.playlist.track.index', ['playlist' => $playlist] + $parameters)); + + $tracks = PlaylistTrack::with($includedPaths->all())->get(); + + $response->assertJson( + json_decode( + json_encode( + new TrackCollection($tracks, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sparse fieldsets', function () { + Event::fakeExcept(PlaylistCreated::class); + + $schema = new TrackSchema(); + + $fields = collect($schema->fields()); + + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + TrackResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + $playlist = Playlist::factory() + ->has(PlaylistTrack::factory()->count(fake()->randomDigitNotNull()), Playlist::RELATION_TRACKS) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); + + $response = get(route('api.playlist.track.index', ['playlist' => $playlist] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new TrackCollection($playlist->tracks, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sorts', function () { + Event::fakeExcept(PlaylistCreated::class); + + $schema = new TrackSchema(); + + /** @var Sort $sort */ + $sort = collect($schema->fields()) + ->filter(fn (Field $field) => $field instanceof SortableField) + ->map(fn (SortableField $field) => $field->getSort()) + ->random(); + + $parameters = [ + SortParser::param() => $sort->format(Arr::random(Direction::cases())), + ]; + + $playlist = Playlist::factory() + ->has(PlaylistTrack::factory()->count(fake()->randomDigitNotNull()), Playlist::RELATION_TRACKS) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); + + $query = new Query($parameters); + + $response = get(route('api.playlist.track.index', ['playlist' => $playlist] + $parameters)); + + $tracks = $this->sort(PlaylistTrack::query(), $query, $schema)->get(); + + $response->assertJson( + json_decode( + json_encode( + new TrackCollection($tracks, $query) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('created at filter', function () { + Event::fakeExcept(PlaylistCreated::class); + + $createdFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + $playlist = Playlist::factory() + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); + + Carbon::withTestNow( + $createdFilter, + fn () => PlaylistTrack::factory() ->for($playlist) - ->for(Video::factory()) - ->for(PlaylistTrack::factory()->for($playlist), PlaylistTrack::RELATION_PREVIOUS) - ->for(PlaylistTrack::factory()->for($playlist), PlaylistTrack::RELATION_NEXT) - ->count($this->faker->randomDigitNotNull()) - ->create(); + ->count(fake()->randomDigitNotNull()) + ->create() + ); - $response = $this->get(route('api.playlist.track.index', ['playlist' => $playlist] + $parameters)); + Carbon::withTestNow( + $excludedDate, + fn () => PlaylistTrack::factory() + ->for($playlist) + ->count(fake()->randomDigitNotNull()) + ->create() + ); - $tracks = PlaylistTrack::with($includedPaths->all())->get(); + $tracks = PlaylistTrack::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - $response->assertJson( - json_decode( - json_encode( - new TrackCollection($tracks, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.playlist.track.index', ['playlist' => $playlist] + $parameters)); - /** - * The Track Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - Event::fakeExcept(PlaylistCreated::class); + $response->assertJson( + json_decode( + json_encode( + new TrackCollection($tracks, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $schema = new TrackSchema(); +test('updated at filter', function () { + Event::fakeExcept(PlaylistCreated::class); - $fields = collect($schema->fields()); + $updatedFilter = fake()->date(); + $excludedDate = fake()->date(); - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; - $parameters = [ - FieldParser::param() => [ - TrackResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; + $playlist = Playlist::factory() + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); - $playlist = Playlist::factory() - ->has(PlaylistTrack::factory()->count($this->faker->randomDigitNotNull()), Playlist::RELATION_TRACKS) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); + Carbon::withTestNow( + $updatedFilter, + fn () => PlaylistTrack::factory() + ->for($playlist) + ->count(fake()->randomDigitNotNull()) + ->create() + ); - $response = $this->get(route('api.playlist.track.index', ['playlist' => $playlist] + $parameters)); + Carbon::withTestNow( + $excludedDate, + fn () => PlaylistTrack::factory() + ->for($playlist) + ->count(fake()->randomDigitNotNull()) + ->create() + ); - $response->assertJson( - json_decode( - json_encode( - new TrackCollection($playlist->tracks, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $tracks = PlaylistTrack::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - /** - * The Track Index Endpoint shall support sorting resources. - */ - public function testSorts(): void - { - Event::fakeExcept(PlaylistCreated::class); + $response = get(route('api.playlist.track.index', ['playlist' => $playlist] + $parameters)); - $schema = new TrackSchema(); - - /** @var Sort $sort */ - $sort = collect($schema->fields()) - ->filter(fn (Field $field) => $field instanceof SortableField) - ->map(fn (SortableField $field) => $field->getSort()) - ->random(); - - $parameters = [ - SortParser::param() => $sort->format(Arr::random(Direction::cases())), - ]; - - $playlist = Playlist::factory() - ->has(PlaylistTrack::factory()->count($this->faker->randomDigitNotNull()), Playlist::RELATION_TRACKS) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); - - $query = new Query($parameters); - - $response = $this->get(route('api.playlist.track.index', ['playlist' => $playlist] + $parameters)); - - $tracks = $this->sort(PlaylistTrack::query(), $query, $schema)->get(); - - $response->assertJson( - json_decode( - json_encode( - new TrackCollection($tracks, $query) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Track Index Endpoint shall support filtering by created_at. - */ - public function testCreatedAtFilter(): void - { - Event::fakeExcept(PlaylistCreated::class); - - $createdFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - $playlist = Playlist::factory() - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); - - Carbon::withTestNow( - $createdFilter, - fn () => PlaylistTrack::factory() - ->for($playlist) - ->count($this->faker->randomDigitNotNull()) - ->create() - ); - - Carbon::withTestNow( - $excludedDate, - fn () => PlaylistTrack::factory() - ->for($playlist) - ->count($this->faker->randomDigitNotNull()) - ->create() - ); - - $tracks = PlaylistTrack::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - - $response = $this->get(route('api.playlist.track.index', ['playlist' => $playlist] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new TrackCollection($tracks, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Track Index Endpoint shall support filtering by updated_at. - */ - public function testUpdatedAtFilter(): void - { - Event::fakeExcept(PlaylistCreated::class); - - $updatedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - $playlist = Playlist::factory() - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); - - Carbon::withTestNow( - $updatedFilter, - fn () => PlaylistTrack::factory() - ->for($playlist) - ->count($this->faker->randomDigitNotNull()) - ->create() - ); - - Carbon::withTestNow( - $excludedDate, - fn () => PlaylistTrack::factory() - ->for($playlist) - ->count($this->faker->randomDigitNotNull()) - ->create() - ); - - $tracks = PlaylistTrack::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - - $response = $this->get(route('api.playlist.track.index', ['playlist' => $playlist] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new TrackCollection($tracks, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response->assertJson( + json_decode( + json_encode( + new TrackCollection($tracks, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/List/Playlist/Track/TrackShowTest.php b/tests/Feature/Http/Api/List/Playlist/Track/TrackShowTest.php index 6346676fc..887bd9d43 100644 --- a/tests/Feature/Http/Api/List/Playlist/Track/TrackShowTest.php +++ b/tests/Feature/Http/Api/List/Playlist/Track/TrackShowTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\List\Playlist\Track; - use App\Enums\Auth\CrudPermission; use App\Enums\Models\List\PlaylistVisibility; use App\Events\List\Playlist\PlaylistCreated; @@ -19,278 +17,239 @@ use App\Models\Auth\User; use App\Models\List\Playlist; use App\Models\List\Playlist\PlaylistTrack; use App\Models\Wiki\Video; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Facades\Event; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class TrackShowTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * The Track Show Endpoint shall forbid a private playlist from being publicly viewed. - */ - public function testPrivatePlaylistTrackCannotBePubliclyViewed(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $playlist = Playlist::factory() - ->for(User::factory()) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, - ]); +test('private playlist track cannot be publicly viewed', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $track = PlaylistTrack::factory() - ->for($playlist) - ->createOne(); + $playlist = Playlist::factory() + ->for(User::factory()) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, + ]); - $response = $this->get(route('api.playlist.track.show', ['playlist' => $playlist, 'track' => $track])); + $track = PlaylistTrack::factory() + ->for($playlist) + ->createOne(); - $response->assertForbidden(); - } + $response = get(route('api.playlist.track.show', ['playlist' => $playlist, 'track' => $track])); - /** - * The Track Show Endpoint shall forbid the user from viewing a private playlist track if not owned. - */ - public function testPrivatePlaylistTrackCannotBePubliclyViewedIfNotOwned(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $response->assertForbidden(); +}); - $playlist = Playlist::factory() - ->for(User::factory()) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, - ]); +test('private playlist track cannot be publicly viewed if not owned', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $track = PlaylistTrack::factory() - ->for($playlist) - ->createOne(); + $playlist = Playlist::factory() + ->for(User::factory()) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, + ]); - $user = User::factory()->withPermissions(CrudPermission::VIEW->format(PlaylistTrack::class))->createOne(); + $track = PlaylistTrack::factory() + ->for($playlist) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::VIEW->format(PlaylistTrack::class))->createOne(); - $response = $this->get(route('api.playlist.track.show', ['playlist' => $playlist, 'track' => $track])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = get(route('api.playlist.track.show', ['playlist' => $playlist, 'track' => $track])); - /** - * The Track Show Endpoint shall allow a private playlist track to be viewed by the owner. - */ - public function testPrivatePlaylistTrackCanBeViewedByOwner(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(CrudPermission::VIEW->format(PlaylistTrack::class))->createOne(); +test('private playlist track can be viewed by owner', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $playlist = Playlist::factory() - ->for($user) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, - ]); + $user = User::factory()->withPermissions(CrudPermission::VIEW->format(PlaylistTrack::class))->createOne(); - $track = PlaylistTrack::factory() - ->for($playlist) - ->createOne(); + $playlist = Playlist::factory() + ->for($user) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, + ]); - Sanctum::actingAs($user); + $track = PlaylistTrack::factory() + ->for($playlist) + ->createOne(); - $response = $this->get(route('api.playlist.track.show', ['playlist' => $playlist, 'track' => $track])); + Sanctum::actingAs($user); - $response->assertOk(); - } + $response = get(route('api.playlist.track.show', ['playlist' => $playlist, 'track' => $track])); - /** - * The Track Show Endpoint shall allow an unlisted playlist track to be viewed. - */ - public function testUnlistedPlaylistTrackCanBeViewed(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $response->assertOk(); +}); - $playlist = Playlist::factory() - ->for(User::factory()) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::UNLISTED->value, - ]); +test('unlisted playlist track can be viewed', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $track = PlaylistTrack::factory() - ->for($playlist) - ->createOne(); + $playlist = Playlist::factory() + ->for(User::factory()) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::UNLISTED->value, + ]); - $response = $this->get(route('api.playlist.track.show', ['playlist' => $playlist, 'track' => $track])); + $track = PlaylistTrack::factory() + ->for($playlist) + ->createOne(); - $response->assertOk(); - } + $response = get(route('api.playlist.track.show', ['playlist' => $playlist, 'track' => $track])); - /** - * The Track Show Endpoint shall allow a public playlist track to be viewed. - */ - public function testPublicPlaylistTrackCanBeViewed(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $response->assertOk(); +}); - $playlist = Playlist::factory() - ->for(User::factory()) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); +test('public playlist track can be viewed', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $track = PlaylistTrack::factory() - ->for($playlist) - ->createOne(); + $playlist = Playlist::factory() + ->for(User::factory()) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); - $response = $this->get(route('api.playlist.track.show', ['playlist' => $playlist, 'track' => $track])); + $track = PlaylistTrack::factory() + ->for($playlist) + ->createOne(); - $response->assertOk(); - } + $response = get(route('api.playlist.track.show', ['playlist' => $playlist, 'track' => $track])); - /** - * The Track Show Endpoint shall scope bindings. - */ - public function testScoped(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $response->assertOk(); +}); - $user = User::factory()->withPermissions(CrudPermission::VIEW->format(PlaylistTrack::class))->createOne(); +test('scoped', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $playlist = Playlist::factory() - ->for($user) - ->has(PlaylistTrack::factory()->count($this->faker->randomDigitNotNull()), Playlist::RELATION_TRACKS) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); + $user = User::factory()->withPermissions(CrudPermission::VIEW->format(PlaylistTrack::class))->createOne(); - $track = PlaylistTrack::factory() - ->for(Playlist::factory()->for(User::factory())) - ->createOne(); + $playlist = Playlist::factory() + ->for($user) + ->has(PlaylistTrack::factory()->count(fake()->randomDigitNotNull()), Playlist::RELATION_TRACKS) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); - $response = $this->get(route('api.playlist.track.show', ['playlist' => $playlist, 'track' => $track])); + $track = PlaylistTrack::factory() + ->for(Playlist::factory()->for(User::factory())) + ->createOne(); - $response->assertNotFound(); - } + $response = get(route('api.playlist.track.show', ['playlist' => $playlist, 'track' => $track])); - /** - * By default, the Track Show Endpoint shall return a Track Resource. - */ - public function testDefault(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $response->assertNotFound(); +}); - $playlist = Playlist::factory() - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); +test('default', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $track = PlaylistTrack::factory() - ->for($playlist) - ->createOne(); + $playlist = Playlist::factory() + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); - $response = $this->get(route('api.playlist.track.show', ['playlist' => $playlist, 'track' => $track])); + $track = PlaylistTrack::factory() + ->for($playlist) + ->createOne(); - $track->unsetRelations(); + $response = get(route('api.playlist.track.show', ['playlist' => $playlist, 'track' => $track])); - $response->assertJson( - json_decode( - json_encode( - new TrackResource($track, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $track->unsetRelations(); - /** - * The Track Show Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $response->assertJson( + json_decode( + json_encode( + new TrackResource($track, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $schema = new TrackSchema(); +test('allowed include paths', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $allowedIncludes = collect($schema->allowedIncludes()); + $schema = new TrackSchema(); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $allowedIncludes = collect($schema->allowedIncludes()); - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - $playlist = Playlist::factory() - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; - $track = PlaylistTrack::factory() - ->for($playlist) - ->for(Video::factory()) - ->for(PlaylistTrack::factory()->for($playlist), PlaylistTrack::RELATION_PREVIOUS) - ->for(PlaylistTrack::factory()->for($playlist), PlaylistTrack::RELATION_NEXT) - ->createOne(); + $playlist = Playlist::factory() + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); - $response = $this->get(route('api.playlist.track.show', ['playlist' => $playlist, 'track' => $track] + $parameters)); + $track = PlaylistTrack::factory() + ->for($playlist) + ->for(Video::factory()) + ->for(PlaylistTrack::factory()->for($playlist), PlaylistTrack::RELATION_PREVIOUS) + ->for(PlaylistTrack::factory()->for($playlist), PlaylistTrack::RELATION_NEXT) + ->createOne(); - $track->unsetRelations()->load($includedPaths->all()); + $response = get(route('api.playlist.track.show', ['playlist' => $playlist, 'track' => $track] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new TrackResource($track, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $track->unsetRelations()->load($includedPaths->all()); - /** - * The Track Show Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $response->assertJson( + json_decode( + json_encode( + new TrackResource($track, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $schema = new TrackSchema(); +test('sparse fieldsets', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $fields = collect($schema->fields()); + $schema = new TrackSchema(); - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); + $fields = collect($schema->fields()); - $parameters = [ - FieldParser::param() => [ - TrackResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); - $playlist = Playlist::factory() - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); + $parameters = [ + FieldParser::param() => [ + TrackResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; - $track = PlaylistTrack::factory() - ->for($playlist) - ->createOne(); + $playlist = Playlist::factory() + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); - $response = $this->get(route('api.playlist.track.show', ['playlist' => $playlist, 'track' => $track] + $parameters)); + $track = PlaylistTrack::factory() + ->for($playlist) + ->createOne(); - $track->unsetRelations(); + $response = get(route('api.playlist.track.show', ['playlist' => $playlist, 'track' => $track] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new TrackResource($track, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $track->unsetRelations(); + + $response->assertJson( + json_decode( + json_encode( + new TrackResource($track, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/List/Playlist/Track/TrackStoreTest.php b/tests/Feature/Http/Api/List/Playlist/Track/TrackStoreTest.php index 390aa757d..99375ed78 100644 --- a/tests/Feature/Http/Api/List/Playlist/Track/TrackStoreTest.php +++ b/tests/Feature/Http/Api/List/Playlist/Track/TrackStoreTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\List\Playlist\Track; - use App\Constants\Config\PlaylistConstants; use App\Enums\Auth\CrudPermission; use App\Enums\Auth\SpecialPermission; @@ -18,735 +16,661 @@ use App\Models\Wiki\Anime\AnimeTheme; use App\Models\Wiki\Anime\Theme\AnimeThemeEntry; use App\Models\Wiki\Video; use App\Pivots\Wiki\AnimeThemeEntryVideo; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class TrackStoreTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\post; - /** - * The Track Destroy Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - Event::fakeExcept(PlaylistCreated::class); +uses(Illuminate\Foundation\Testing\WithFaker::class); - Feature::activate(AllowPlaylistManagement::class); +test('protected', function () { + Event::fakeExcept(PlaylistCreated::class); - $entryVideo = AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->createOne(); + Feature::activate(AllowPlaylistManagement::class); - $playlist = Playlist::factory()->createOne(); + $entryVideo = AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->createOne(); - $track = PlaylistTrack::factory() - ->for($playlist) - ->for($entryVideo->animethemeentry) - ->for($entryVideo->video) - ->makeOne(); + $playlist = Playlist::factory()->createOne(); - $response = $this->post(route('api.playlist.track.store', ['playlist' => $playlist] + $track->toArray())); + $track = PlaylistTrack::factory() + ->for($playlist) + ->for($entryVideo->animethemeentry) + ->for($entryVideo->video) + ->makeOne(); - $response->assertUnauthorized(); - } + $response = post(route('api.playlist.track.store', ['playlist' => $playlist] + $track->toArray())); - /** - * The Track Store Endpoint shall forbid users without the create playlist track permission. - */ - public function testForbiddenIfMissingPermission(): void - { - Event::fakeExcept(PlaylistCreated::class); + $response->assertUnauthorized(); +}); - Feature::activate(AllowPlaylistManagement::class); +test('forbidden if missing permission', function () { + Event::fakeExcept(PlaylistCreated::class); - $entryVideo = AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->createOne(); + Feature::activate(AllowPlaylistManagement::class); - $playlist = Playlist::factory()->createOne(); + $entryVideo = AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->createOne(); - $track = PlaylistTrack::factory() - ->for($playlist) - ->for($entryVideo->animethemeentry) - ->for($entryVideo->video) - ->makeOne(); + $playlist = Playlist::factory()->createOne(); - $user = User::factory()->createOne(); + $track = PlaylistTrack::factory() + ->for($playlist) + ->for($entryVideo->animethemeentry) + ->for($entryVideo->video) + ->makeOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->post(route('api.playlist.track.store', ['playlist' => $playlist] + $track->toArray())); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.playlist.track.store', ['playlist' => $playlist] + $track->toArray())); - /** - * The Track Store Endpoint shall forbid users from creating a track if they don't own the playlist. - */ - public function testForbiddenIfNotOwnPlaylist(): void - { - Event::fakeExcept(PlaylistCreated::class); + $response->assertForbidden(); +}); - Feature::activate(AllowPlaylistManagement::class); +test('forbidden if not own playlist', function () { + Event::fakeExcept(PlaylistCreated::class); - $entryVideo = AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->createOne(); + Feature::activate(AllowPlaylistManagement::class); - $playlist = Playlist::factory() - ->for(User::factory()) - ->createOne(); + $entryVideo = AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->createOne(); - $track = PlaylistTrack::factory() - ->for($playlist) - ->for($entryVideo->animethemeentry) - ->for($entryVideo->video) - ->makeOne(); + $playlist = Playlist::factory() + ->for(User::factory()) + ->createOne(); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(PlaylistTrack::class))->createOne(); + $track = PlaylistTrack::factory() + ->for($playlist) + ->for($entryVideo->animethemeentry) + ->for($entryVideo->video) + ->makeOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(PlaylistTrack::class))->createOne(); - $response = $this->post(route('api.playlist.track.store', ['playlist' => $playlist] + $track->toArray())); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.playlist.track.store', ['playlist' => $playlist] + $track->toArray())); - /** - * The Track Store Endpoint shall forbid users from creating playlist tracks - * if the Allow Playlist Management feature is inactive. - */ - public function testForbiddenIfFlagDisabled(): void - { - Event::fakeExcept(PlaylistCreated::class); + $response->assertForbidden(); +}); - Feature::deactivate(AllowPlaylistManagement::class); +test('forbidden if flag disabled', function () { + Event::fakeExcept(PlaylistCreated::class); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(PlaylistTrack::class))->createOne(); + Feature::deactivate(AllowPlaylistManagement::class); - $entryVideo = AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->createOne(); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(PlaylistTrack::class))->createOne(); - $playlist = Playlist::factory() - ->for($user) - ->createOne(); + $entryVideo = AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->createOne(); - $track = PlaylistTrack::factory() - ->for($playlist) - ->for($entryVideo->animethemeentry) - ->for($entryVideo->video) - ->makeOne(); + $playlist = Playlist::factory() + ->for($user) + ->createOne(); - Sanctum::actingAs($user); + $track = PlaylistTrack::factory() + ->for($playlist) + ->for($entryVideo->animethemeentry) + ->for($entryVideo->video) + ->makeOne(); - $response = $this->post(route('api.playlist.track.store', ['playlist' => $playlist] + $track->toArray())); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.playlist.track.store', ['playlist' => $playlist] + $track->toArray())); - /** - * The Track Store Endpoint shall require the entry & video field. - */ - public function testRequiredFields(): void - { - Event::fakeExcept(PlaylistCreated::class); + $response->assertForbidden(); +}); - Feature::activate(AllowPlaylistManagement::class); +test('required fields', function () { + Event::fakeExcept(PlaylistCreated::class); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(PlaylistTrack::class))->createOne(); + Feature::activate(AllowPlaylistManagement::class); - $playlist = Playlist::factory() - ->for($user) - ->createOne(); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(PlaylistTrack::class))->createOne(); - Sanctum::actingAs($user); + $playlist = Playlist::factory() + ->for($user) + ->createOne(); - $response = $this->post(route('api.playlist.track.store', ['playlist' => $playlist])); + Sanctum::actingAs($user); - $response->assertJsonValidationErrors([ - PlaylistTrack::ATTRIBUTE_ENTRY, - PlaylistTrack::ATTRIBUTE_VIDEO, + $response = post(route('api.playlist.track.store', ['playlist' => $playlist])); + + $response->assertJsonValidationErrors([ + PlaylistTrack::ATTRIBUTE_ENTRY, + PlaylistTrack::ATTRIBUTE_VIDEO, + ]); +}); + +test('anime theme entry video exists', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + + Feature::activate(AllowPlaylistManagement::class); + + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->create(); + + $video = Video::factory()->create(); + + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(PlaylistTrack::class))->createOne(); + + $playlist = Playlist::factory() + ->for($user) + ->createOne(); + + $track = PlaylistTrack::factory() + ->for($playlist) + ->makeOne([ + PlaylistTrack::ATTRIBUTE_ENTRY => $entry->getKey(), + PlaylistTrack::ATTRIBUTE_VIDEO => $video->getKey(), ]); - } - /** - * The Playlist Track Store Endpoint shall require the entry and video to have an association. - */ - public function testAnimeThemeEntryVideoExists(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + Sanctum::actingAs($user); - Feature::activate(AllowPlaylistManagement::class); + $response = post(route('api.playlist.track.store', ['playlist' => $playlist] + $track->toArray())); - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->create(); + $response->assertJsonValidationErrors([ + PlaylistTrack::ATTRIBUTE_ENTRY, + PlaylistTrack::ATTRIBUTE_VIDEO, + ]); +}); - $video = Video::factory()->create(); +test('prohibits next and previous', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(PlaylistTrack::class))->createOne(); + Feature::activate(AllowPlaylistManagement::class); - $playlist = Playlist::factory() - ->for($user) - ->createOne(); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(PlaylistTrack::class))->createOne(); - $track = PlaylistTrack::factory() - ->for($playlist) - ->makeOne([ - PlaylistTrack::ATTRIBUTE_ENTRY => $entry->getKey(), - PlaylistTrack::ATTRIBUTE_VIDEO => $video->getKey(), - ]); + $entryVideoPrevious = AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->createOne(); - Sanctum::actingAs($user); + $entryVideoNext = AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->createOne(); - $response = $this->post(route('api.playlist.track.store', ['playlist' => $playlist] + $track->toArray())); + $entryVideo = AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->createOne(); - $response->assertJsonValidationErrors([ - PlaylistTrack::ATTRIBUTE_ENTRY, - PlaylistTrack::ATTRIBUTE_VIDEO, + $playlist = Playlist::factory() + ->for($user) + ->createOne(); + + $previous = PlaylistTrack::factory() + ->for($playlist) + ->for($entryVideoPrevious->animethemeentry) + ->for($entryVideoPrevious->video) + ->createOne(); + + $next = PlaylistTrack::factory() + ->for($playlist) + ->for($entryVideoNext->animethemeentry) + ->for($entryVideoNext->video) + ->createOne(); + + $track = PlaylistTrack::factory() + ->for($playlist) + ->for($entryVideo->animethemeentry) + ->for($entryVideo->video) + ->makeOne([ + PlaylistTrack::RELATION_PREVIOUS => $previous->getRouteKey(), + PlaylistTrack::RELATION_NEXT => $next->getRouteKey(), ]); - } - /** - * The Track Store Endpoint shall prohibit the next and previous fields from both being present. - */ - public function testProhibitsNextAndPrevious(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + Sanctum::actingAs($user); - Feature::activate(AllowPlaylistManagement::class); + $response = post(route('api.playlist.track.store', ['playlist' => $playlist] + $track->toArray())); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(PlaylistTrack::class))->createOne(); + $response->assertJsonValidationErrors([ + PlaylistTrack::RELATION_NEXT, + PlaylistTrack::RELATION_PREVIOUS, + ]); +}); - $entryVideoPrevious = AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->createOne(); +test('scope next', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $entryVideoNext = AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->createOne(); + Feature::activate(AllowPlaylistManagement::class); - $entryVideo = AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->createOne(); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(PlaylistTrack::class))->createOne(); - $playlist = Playlist::factory() - ->for($user) - ->createOne(); + $entryVideoNext = AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->createOne(); - $previous = PlaylistTrack::factory() - ->for($playlist) - ->for($entryVideoPrevious->animethemeentry) - ->for($entryVideoPrevious->video) - ->createOne(); + $entryVideo = AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->createOne(); - $next = PlaylistTrack::factory() - ->for($playlist) - ->for($entryVideoNext->animethemeentry) - ->for($entryVideoNext->video) - ->createOne(); + $playlist = Playlist::factory() + ->for($user) + ->createOne(); - $track = PlaylistTrack::factory() - ->for($playlist) - ->for($entryVideo->animethemeentry) - ->for($entryVideo->video) - ->makeOne([ - PlaylistTrack::RELATION_PREVIOUS => $previous->getRouteKey(), - PlaylistTrack::RELATION_NEXT => $next->getRouteKey(), - ]); + $next = PlaylistTrack::factory() + ->for(Playlist::factory()) + ->for($entryVideoNext->animethemeentry) + ->for($entryVideoNext->video) + ->createOne(); - Sanctum::actingAs($user); - - $response = $this->post(route('api.playlist.track.store', ['playlist' => $playlist] + $track->toArray())); - - $response->assertJsonValidationErrors([ - PlaylistTrack::RELATION_NEXT, - PlaylistTrack::RELATION_PREVIOUS, + $track = PlaylistTrack::factory() + ->for($playlist) + ->for($entryVideo->animethemeentry) + ->for($entryVideo->video) + ->makeOne([ + PlaylistTrack::RELATION_NEXT => $next->getRouteKey(), ]); - } - /** - * The Track Store Endpoint shall restrict the next track to a track within the playlist. - */ - public function testScopeNext(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + Sanctum::actingAs($user); - Feature::activate(AllowPlaylistManagement::class); + $response = post(route('api.playlist.track.store', ['playlist' => $playlist] + $track->toArray())); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(PlaylistTrack::class))->createOne(); + $response->assertJsonValidationErrors([ + PlaylistTrack::RELATION_NEXT, + ]); +}); - $entryVideoNext = AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->createOne(); +test('scope previous', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $entryVideo = AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->createOne(); + Feature::activate(AllowPlaylistManagement::class); - $playlist = Playlist::factory() - ->for($user) - ->createOne(); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(PlaylistTrack::class))->createOne(); - $next = PlaylistTrack::factory() - ->for(Playlist::factory()) - ->for($entryVideoNext->animethemeentry) - ->for($entryVideoNext->video) - ->createOne(); + $entryVideoPrevious = AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->createOne(); - $track = PlaylistTrack::factory() - ->for($playlist) - ->for($entryVideo->animethemeentry) - ->for($entryVideo->video) - ->makeOne([ - PlaylistTrack::RELATION_NEXT => $next->getRouteKey(), - ]); + $entryVideo = AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->createOne(); - Sanctum::actingAs($user); + $playlist = Playlist::factory() + ->for($user) + ->createOne(); - $response = $this->post(route('api.playlist.track.store', ['playlist' => $playlist] + $track->toArray())); + $previous = PlaylistTrack::factory() + ->for(Playlist::factory()) + ->for($entryVideoPrevious->animethemeentry) + ->for($entryVideoPrevious->video) + ->createOne(); - $response->assertJsonValidationErrors([ - PlaylistTrack::RELATION_NEXT, + $track = PlaylistTrack::factory() + ->for($playlist) + ->for($entryVideo->animethemeentry) + ->for($entryVideo->video) + ->makeOne([ + PlaylistTrack::RELATION_PREVIOUS => $previous->getRouteKey(), ]); - } - /** - * The Track Store Endpoint shall restrict the next track to a track within the playlist. - */ - public function testScopePrevious(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + Sanctum::actingAs($user); - Feature::activate(AllowPlaylistManagement::class); + $response = post(route('api.playlist.track.store', ['playlist' => $playlist] + $track->toArray())); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(PlaylistTrack::class))->createOne(); + $response->assertJsonValidationErrors([ + PlaylistTrack::RELATION_PREVIOUS, + ]); +}); - $entryVideoPrevious = AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->createOne(); +test('create', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $entryVideo = AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->createOne(); + Feature::activate(AllowPlaylistManagement::class); - $playlist = Playlist::factory() - ->for($user) - ->createOne(); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(PlaylistTrack::class))->createOne(); - $previous = PlaylistTrack::factory() - ->for(Playlist::factory()) - ->for($entryVideoPrevious->animethemeentry) - ->for($entryVideoPrevious->video) - ->createOne(); + $entryVideo = AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->createOne(); - $track = PlaylistTrack::factory() - ->for($playlist) - ->for($entryVideo->animethemeentry) - ->for($entryVideo->video) - ->makeOne([ - PlaylistTrack::RELATION_PREVIOUS => $previous->getRouteKey(), - ]); + $playlist = Playlist::factory() + ->for($user) + ->createOne(); - Sanctum::actingAs($user); + $track = PlaylistTrack::factory() + ->for($playlist) + ->for($entryVideo->animethemeentry) + ->for($entryVideo->video) + ->makeOne(); - $response = $this->post(route('api.playlist.track.store', ['playlist' => $playlist] + $track->toArray())); + Sanctum::actingAs($user); - $response->assertJsonValidationErrors([ - PlaylistTrack::RELATION_PREVIOUS, + $response = post(route('api.playlist.track.store', ['playlist' => $playlist] + $track->toArray())); + + $response->assertCreated(); + + $track = PlaylistTrack::query()->first(); + $playlist->refresh(); + + $this->assertDatabaseCount(PlaylistTrack::class, 1); + + $this->assertTrue($playlist->first()->is($track)); + $this->assertTrue($playlist->last()->is($track)); +}); + +test('create after last track', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + + Feature::activate(AllowPlaylistManagement::class); + + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(PlaylistTrack::class))->createOne(); + + $entryVideo = AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->createOne(); + + $trackCount = fake()->numberBetween(2, 9); + + $playlist = Playlist::factory() + ->for($user) + ->tracks($trackCount) + ->createOne(); + + $last = $playlist->last; + + $track = PlaylistTrack::factory() + ->for($playlist) + ->for($entryVideo->animethemeentry) + ->for($entryVideo->video) + ->makeOne([ + PlaylistTrack::RELATION_PREVIOUS => $last->getRouteKey(), ]); - } - /** - * The Track Store Endpoint shall create a playlist track. - */ - public function testCreate(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + Sanctum::actingAs($user); - Feature::activate(AllowPlaylistManagement::class); + $response = post(route('api.playlist.track.store', ['playlist' => $playlist] + $track->toArray())); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(PlaylistTrack::class))->createOne(); + $response->assertCreated(); - $entryVideo = AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->createOne(); + /** @var PlaylistTrack $track */ + $track = PlaylistTrack::query()->latest()->first(); + $playlist->refresh(); + $last->refresh(); - $playlist = Playlist::factory() - ->for($user) - ->createOne(); + $this->assertDatabaseCount(PlaylistTrack::class, $trackCount + 1); - $track = PlaylistTrack::factory() - ->for($playlist) - ->for($entryVideo->animethemeentry) - ->for($entryVideo->video) - ->makeOne(); + $this->assertTrue($playlist->last()->is($track)); - Sanctum::actingAs($user); + $this->assertTrue($last->next()->is($track)); - $response = $this->post(route('api.playlist.track.store', ['playlist' => $playlist] + $track->toArray())); + $this->assertTrue($track->previous()->is($last)); + $this->assertTrue($track->next()->doesntExist()); +}); - $response->assertCreated(); +test('create after first track', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $track = PlaylistTrack::query()->first(); - $playlist->refresh(); + Feature::activate(AllowPlaylistManagement::class); - static::assertDatabaseCount(PlaylistTrack::class, 1); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(PlaylistTrack::class))->createOne(); - static::assertTrue($playlist->first()->is($track)); - static::assertTrue($playlist->last()->is($track)); - } + $entryVideo = AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->createOne(); - /** - * The Track Store Endpoint shall allow inserting after tracks including the last track. - */ - public function testCreateAfterLastTrack(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $trackCount = fake()->numberBetween(2, 9); - Feature::activate(AllowPlaylistManagement::class); + $playlist = Playlist::factory() + ->for($user) + ->tracks($trackCount) + ->createOne(); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(PlaylistTrack::class))->createOne(); + $first = $playlist->first; + $next = $first->next; - $entryVideo = AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->createOne(); + $track = PlaylistTrack::factory() + ->for($playlist) + ->for($entryVideo->animethemeentry) + ->for($entryVideo->video) + ->makeOne([ + PlaylistTrack::RELATION_PREVIOUS => $first->getRouteKey(), + ]); - $trackCount = $this->faker->numberBetween(2, 9); + Sanctum::actingAs($user); - $playlist = Playlist::factory() - ->for($user) - ->tracks($trackCount) - ->createOne(); + $response = post(route('api.playlist.track.store', ['playlist' => $playlist] + $track->toArray())); - $last = $playlist->last; + $response->assertCreated(); - $track = PlaylistTrack::factory() - ->for($playlist) - ->for($entryVideo->animethemeentry) - ->for($entryVideo->video) - ->makeOne([ - PlaylistTrack::RELATION_PREVIOUS => $last->getRouteKey(), - ]); + /** @var PlaylistTrack $track */ + $track = PlaylistTrack::query()->latest()->first(); + $playlist->refresh(); + $first->refresh(); - Sanctum::actingAs($user); + $this->assertDatabaseCount(PlaylistTrack::class, $trackCount + 1); - $response = $this->post(route('api.playlist.track.store', ['playlist' => $playlist] + $track->toArray())); + $this->assertTrue($playlist->first()->is($first)); - $response->assertCreated(); + $this->assertTrue($first->next()->is($track)); - /** @var PlaylistTrack $track */ - $track = PlaylistTrack::query()->latest()->first(); - $playlist->refresh(); - $last->refresh(); + $this->assertTrue($track->previous()->is($first)); + $this->assertTrue($track->next()->is($next)); +}); - static::assertDatabaseCount(PlaylistTrack::class, $trackCount + 1); +test('create before last track', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - static::assertTrue($playlist->last()->is($track)); + Feature::activate(AllowPlaylistManagement::class); - static::assertTrue($last->next()->is($track)); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(PlaylistTrack::class))->createOne(); - static::assertTrue($track->previous()->is($last)); - static::assertTrue($track->next()->doesntExist()); - } + $entryVideo = AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->createOne(); - /** - * The Track Store Endpoint shall allow inserting after tracks including the first track. - */ - public function testCreateAfterFirstTrack(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $trackCount = fake()->numberBetween(2, 9); - Feature::activate(AllowPlaylistManagement::class); + $playlist = Playlist::factory() + ->for($user) + ->tracks($trackCount) + ->createOne(); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(PlaylistTrack::class))->createOne(); + $last = $playlist->last; + $previous = $last->previous; - $entryVideo = AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->createOne(); + $track = PlaylistTrack::factory() + ->for($playlist) + ->for($entryVideo->animethemeentry) + ->for($entryVideo->video) + ->makeOne([ + PlaylistTrack::RELATION_NEXT => $last->getRouteKey(), + ]); - $trackCount = $this->faker->numberBetween(2, 9); + Sanctum::actingAs($user); - $playlist = Playlist::factory() - ->for($user) - ->tracks($trackCount) - ->createOne(); + $response = post(route('api.playlist.track.store', ['playlist' => $playlist] + $track->toArray())); - $first = $playlist->first; - $next = $first->next; + $response->assertCreated(); - $track = PlaylistTrack::factory() - ->for($playlist) - ->for($entryVideo->animethemeentry) - ->for($entryVideo->video) - ->makeOne([ - PlaylistTrack::RELATION_PREVIOUS => $first->getRouteKey(), - ]); + /** @var PlaylistTrack $track */ + $track = PlaylistTrack::query()->latest()->first(); + $playlist->refresh(); + $last->refresh(); - Sanctum::actingAs($user); + $this->assertDatabaseCount(PlaylistTrack::class, $trackCount + 1); - $response = $this->post(route('api.playlist.track.store', ['playlist' => $playlist] + $track->toArray())); + $this->assertTrue($playlist->last()->is($last)); - $response->assertCreated(); + $this->assertTrue($last->previous()->is($track)); - /** @var PlaylistTrack $track */ - $track = PlaylistTrack::query()->latest()->first(); - $playlist->refresh(); - $first->refresh(); + $this->assertTrue($track->previous()->is($previous)); + $this->assertTrue($track->next()->is($last)); +}); - static::assertDatabaseCount(PlaylistTrack::class, $trackCount + 1); +test('create before first track', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - static::assertTrue($playlist->first()->is($first)); + Feature::activate(AllowPlaylistManagement::class); - static::assertTrue($first->next()->is($track)); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(PlaylistTrack::class))->createOne(); - static::assertTrue($track->previous()->is($first)); - static::assertTrue($track->next()->is($next)); - } + $entryVideo = AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->createOne(); - /** - * The Track Store Endpoint shall allow inserting before tracks including the last track. - */ - public function testCreateBeforeLastTrack(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $trackCount = fake()->numberBetween(2, 9); - Feature::activate(AllowPlaylistManagement::class); + $playlist = Playlist::factory() + ->for($user) + ->tracks($trackCount) + ->createOne(); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(PlaylistTrack::class))->createOne(); + $first = $playlist->first; - $entryVideo = AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->createOne(); + $track = PlaylistTrack::factory() + ->for($playlist) + ->for($entryVideo->animethemeentry) + ->for($entryVideo->video) + ->makeOne([ + PlaylistTrack::RELATION_NEXT => $first->getRouteKey(), + ]); - $trackCount = $this->faker->numberBetween(2, 9); + Sanctum::actingAs($user); - $playlist = Playlist::factory() - ->for($user) - ->tracks($trackCount) - ->createOne(); + $response = post(route('api.playlist.track.store', ['playlist' => $playlist] + $track->toArray())); - $last = $playlist->last; - $previous = $last->previous; + $response->assertCreated(); - $track = PlaylistTrack::factory() - ->for($playlist) - ->for($entryVideo->animethemeentry) - ->for($entryVideo->video) - ->makeOne([ - PlaylistTrack::RELATION_NEXT => $last->getRouteKey(), - ]); + /** @var PlaylistTrack $track */ + $track = PlaylistTrack::query()->latest()->first(); + $playlist->refresh(); + $first->refresh(); - Sanctum::actingAs($user); + $this->assertDatabaseCount(PlaylistTrack::class, $trackCount + 1); - $response = $this->post(route('api.playlist.track.store', ['playlist' => $playlist] + $track->toArray())); + $this->assertTrue($playlist->first()->is($track)); - $response->assertCreated(); + $this->assertTrue($track->previous()->doesntExist()); + $this->assertTrue($track->next()->is($first)); +}); - /** @var PlaylistTrack $track */ - $track = PlaylistTrack::query()->latest()->first(); - $playlist->refresh(); - $last->refresh(); +test('create permitted for bypass', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - static::assertDatabaseCount(PlaylistTrack::class, $trackCount + 1); + Feature::activate(AllowPlaylistManagement::class, fake()->boolean()); - static::assertTrue($playlist->last()->is($last)); + $user = User::factory() + ->withPermissions( + CrudPermission::CREATE->format(PlaylistTrack::class), + SpecialPermission::BYPASS_FEATURE_FLAGS->value + ) + ->createOne(); - static::assertTrue($last->previous()->is($track)); + $entryVideo = AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->createOne(); - static::assertTrue($track->previous()->is($previous)); - static::assertTrue($track->next()->is($last)); - } + $playlist = Playlist::factory() + ->for($user) + ->createOne(); - /** - * The Track Store Endpoint shall allow inserting before tracks including the first track. - */ - public function testCreateBeforeFirstTrack(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $track = PlaylistTrack::factory() + ->for($playlist) + ->for($entryVideo->animethemeentry) + ->for($entryVideo->video) + ->makeOne(); - Feature::activate(AllowPlaylistManagement::class); + Sanctum::actingAs($user); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(PlaylistTrack::class))->createOne(); + $response = post(route('api.playlist.track.store', ['playlist' => $playlist] + $track->toArray())); - $entryVideo = AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->createOne(); + $response->assertCreated(); +}); - $trackCount = $this->faker->numberBetween(2, 9); +test('max track limit', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $playlist = Playlist::factory() - ->for($user) - ->tracks($trackCount) - ->createOne(); + $trackLimit = fake()->randomDigitNotNull(); - $first = $playlist->first; + Config::set(PlaylistConstants::MAX_TRACKS_QUALIFIED, $trackLimit); + Feature::activate(AllowPlaylistManagement::class); - $track = PlaylistTrack::factory() - ->for($playlist) - ->for($entryVideo->animethemeentry) - ->for($entryVideo->video) - ->makeOne([ - PlaylistTrack::RELATION_NEXT => $first->getRouteKey(), - ]); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(PlaylistTrack::class))->createOne(); - Sanctum::actingAs($user); + $entryVideo = AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->createOne(); - $response = $this->post(route('api.playlist.track.store', ['playlist' => $playlist] + $track->toArray())); + $playlist = Playlist::factory() + ->tracks($trackLimit) + ->for($user) + ->createOne(); - $response->assertCreated(); + $track = PlaylistTrack::factory() + ->for($playlist) + ->for($entryVideo->animethemeentry) + ->for($entryVideo->video) + ->makeOne(); - /** @var PlaylistTrack $track */ - $track = PlaylistTrack::query()->latest()->first(); - $playlist->refresh(); - $first->refresh(); + Sanctum::actingAs($user); - static::assertDatabaseCount(PlaylistTrack::class, $trackCount + 1); + $response = post(route('api.playlist.track.store', ['playlist' => $playlist] + $track->toArray())); - static::assertTrue($playlist->first()->is($track)); + $response->assertForbidden(); +}); - static::assertTrue($track->previous()->doesntExist()); - static::assertTrue($track->next()->is($first)); - } +test('max track limit permitted for bypass', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - /** - * Users with the bypass feature flag permission shall be permitted to create playlist tracks - * even if the Allow Playlist Management feature is inactive. - */ - public function testCreatePermittedForBypass(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $trackLimit = fake()->randomDigitNotNull(); - Feature::activate(AllowPlaylistManagement::class, $this->faker->boolean()); + Config::set(PlaylistConstants::MAX_TRACKS_QUALIFIED, $trackLimit); + Feature::activate(AllowPlaylistManagement::class); - $user = User::factory() - ->withPermissions( - CrudPermission::CREATE->format(PlaylistTrack::class), - SpecialPermission::BYPASS_FEATURE_FLAGS->value - ) - ->createOne(); + $user = User::factory() + ->withPermissions( + CrudPermission::CREATE->format(PlaylistTrack::class), + SpecialPermission::BYPASS_FEATURE_FLAGS->value + ) + ->createOne(); - $entryVideo = AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->createOne(); + $entryVideo = AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->createOne(); - $playlist = Playlist::factory() - ->for($user) - ->createOne(); + $playlist = Playlist::factory() + ->tracks($trackLimit) + ->for($user) + ->createOne(); - $track = PlaylistTrack::factory() - ->for($playlist) - ->for($entryVideo->animethemeentry) - ->for($entryVideo->video) - ->makeOne(); + $track = PlaylistTrack::factory() + ->for($playlist) + ->for($entryVideo->animethemeentry) + ->for($entryVideo->video) + ->makeOne(); - Sanctum::actingAs($user); + Sanctum::actingAs($user); - $response = $this->post(route('api.playlist.track.store', ['playlist' => $playlist] + $track->toArray())); + $response = post(route('api.playlist.track.store', ['playlist' => $playlist] + $track->toArray())); - $response->assertCreated(); - } - - /** - * The Track Store Endpoint shall forbid users from creating playlists that exceed the max track limit. - */ - public function testMaxTrackLimit(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - - $trackLimit = $this->faker->randomDigitNotNull(); - - Config::set(PlaylistConstants::MAX_TRACKS_QUALIFIED, $trackLimit); - Feature::activate(AllowPlaylistManagement::class); - - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(PlaylistTrack::class))->createOne(); - - $entryVideo = AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->createOne(); - - $playlist = Playlist::factory() - ->tracks($trackLimit) - ->for($user) - ->createOne(); - - $track = PlaylistTrack::factory() - ->for($playlist) - ->for($entryVideo->animethemeentry) - ->for($entryVideo->video) - ->makeOne(); - - Sanctum::actingAs($user); - - $response = $this->post(route('api.playlist.track.store', ['playlist' => $playlist] + $track->toArray())); - - $response->assertForbidden(); - } - - /** - * The Track Store Endpoint shall permit users with bypass feature flag permission - * to create playlists that exceed the max track limit. - */ - public function testMaxTrackLimitPermittedForBypass(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - - $trackLimit = $this->faker->randomDigitNotNull(); - - Config::set(PlaylistConstants::MAX_TRACKS_QUALIFIED, $trackLimit); - Feature::activate(AllowPlaylistManagement::class); - - $user = User::factory() - ->withPermissions( - CrudPermission::CREATE->format(PlaylistTrack::class), - SpecialPermission::BYPASS_FEATURE_FLAGS->value - ) - ->createOne(); - - $entryVideo = AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->createOne(); - - $playlist = Playlist::factory() - ->tracks($trackLimit) - ->for($user) - ->createOne(); - - $track = PlaylistTrack::factory() - ->for($playlist) - ->for($entryVideo->animethemeentry) - ->for($entryVideo->video) - ->makeOne(); - - Sanctum::actingAs($user); - - $response = $this->post(route('api.playlist.track.store', ['playlist' => $playlist] + $track->toArray())); - - $response->assertCreated(); - } -} + $response->assertCreated(); +}); diff --git a/tests/Feature/Http/Api/List/Playlist/Track/TrackUpdateTest.php b/tests/Feature/Http/Api/List/Playlist/Track/TrackUpdateTest.php index 2ac97976c..06484b6cc 100644 --- a/tests/Feature/Http/Api/List/Playlist/Track/TrackUpdateTest.php +++ b/tests/Feature/Http/Api/List/Playlist/Track/TrackUpdateTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\List\Playlist\Track; - use App\Enums\Auth\CrudPermission; use App\Enums\Auth\SpecialPermission; use App\Enums\Models\List\PlaylistVisibility; @@ -14,820 +12,735 @@ use App\Models\Auth\User; use App\Models\List\Playlist; use App\Models\List\Playlist\PlaylistTrack; use App\Models\Wiki\Video; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class TrackUpdateTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\put; - /** - * The Track Destroy Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); +uses(Illuminate\Foundation\Testing\WithFaker::class); - Feature::activate(AllowPlaylistManagement::class); +test('protected', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $playlist = Playlist::factory()->createOne(); + Feature::activate(AllowPlaylistManagement::class); - $track = PlaylistTrack::factory() - ->for($playlist) - ->createOne(); + $playlist = Playlist::factory()->createOne(); - $parameters = array_merge( - PlaylistTrack::factory()->raw(), - [PlaylistTrack::ATTRIBUTE_VIDEO => Video::factory()->createOne()->getKey()], - ); + $track = PlaylistTrack::factory() + ->for($playlist) + ->createOne(); - $response = $this->put(route('api.playlist.track.update', ['playlist' => $playlist, 'track' => $track] + $parameters)); + $parameters = array_merge( + PlaylistTrack::factory()->raw(), + [PlaylistTrack::ATTRIBUTE_VIDEO => Video::factory()->createOne()->getKey()], + ); - $response->assertUnauthorized(); - } + $response = put(route('api.playlist.track.update', ['playlist' => $playlist, 'track' => $track] + $parameters)); - /** - * The Track Update Endpoint shall forbid users without the update playlist track permission. - */ - public function testForbiddenIfMissingPermission(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $response->assertUnauthorized(); +}); - Feature::activate(AllowPlaylistManagement::class); +test('forbidden if missing permission', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $playlist = Playlist::factory()->createOne(); + Feature::activate(AllowPlaylistManagement::class); - $track = PlaylistTrack::factory() - ->for($playlist) - ->createOne(); + $playlist = Playlist::factory()->createOne(); - $parameters = array_merge( - PlaylistTrack::factory()->raw(), - [PlaylistTrack::ATTRIBUTE_VIDEO => Video::factory()->createOne()->getKey()], - ); + $track = PlaylistTrack::factory() + ->for($playlist) + ->createOne(); - $user = User::factory()->createOne(); + $parameters = array_merge( + PlaylistTrack::factory()->raw(), + [PlaylistTrack::ATTRIBUTE_VIDEO => Video::factory()->createOne()->getKey()], + ); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->put(route('api.playlist.track.update', ['playlist' => $playlist, 'track' => $track] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.playlist.track.update', ['playlist' => $playlist, 'track' => $track] + $parameters)); - /** - * The Track Update Endpoint shall forbid users from updating the track if they don't the playlist. - */ - public function testForbiddenIfNotOwnPlaylist(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $response->assertForbidden(); +}); - Feature::activate(AllowPlaylistManagement::class); +test('forbidden if not own playlist', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $playlist = Playlist::factory() - ->for(User::factory()) - ->createOne(); + Feature::activate(AllowPlaylistManagement::class); - $track = PlaylistTrack::factory() - ->for($playlist) - ->createOne(); + $playlist = Playlist::factory() + ->for(User::factory()) + ->createOne(); - $parameters = array_merge( - PlaylistTrack::factory()->raw(), - [PlaylistTrack::ATTRIBUTE_VIDEO => Video::factory()->createOne()->getKey()], - ); + $track = PlaylistTrack::factory() + ->for($playlist) + ->createOne(); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(PlaylistTrack::class))->createOne(); + $parameters = array_merge( + PlaylistTrack::factory()->raw(), + [PlaylistTrack::ATTRIBUTE_VIDEO => Video::factory()->createOne()->getKey()], + ); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(PlaylistTrack::class))->createOne(); - $response = $this->put(route('api.playlist.track.update', ['playlist' => $playlist, 'track' => $track] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.playlist.track.update', ['playlist' => $playlist, 'track' => $track] + $parameters)); - /** - * The Track Update Endpoint shall scope bindings. - */ - public function testScoped(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $response->assertForbidden(); +}); - Feature::activate(AllowPlaylistManagement::class); +test('scoped', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(PlaylistTrack::class))->createOne(); + Feature::activate(AllowPlaylistManagement::class); - $playlist = Playlist::factory() - ->for($user) - ->has(PlaylistTrack::factory()->count($this->faker->randomDigitNotNull()), Playlist::RELATION_TRACKS) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(PlaylistTrack::class))->createOne(); - $track = PlaylistTrack::factory() - ->for(Playlist::factory()->for(User::factory())) - ->createOne(); - - $parameters = array_merge( - PlaylistTrack::factory()->raw(), - [PlaylistTrack::ATTRIBUTE_VIDEO => Video::factory()->createOne()->getKey()], - ); - - Sanctum::actingAs($user); - - $response = $this->put(route('api.playlist.track.update', ['playlist' => $playlist, 'track' => $track] + $parameters)); - - $response->assertNotFound(); - } - - /** - * The Track Update Endpoint shall restrict the previous track to a track within the playlist. - */ - public function testScopePrevious(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - - Feature::activate(AllowPlaylistManagement::class); - - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(PlaylistTrack::class))->createOne(); - - $playlist = Playlist::factory() - ->for($user) - ->createOne(); - - $track = PlaylistTrack::factory() - ->for($playlist) - ->createOne(); - - $previous = PlaylistTrack::factory() - ->for(Playlist::factory()) - ->createOne(); - - $parameters = array_merge( - PlaylistTrack::factory()->raw(), - [ - PlaylistTrack::ATTRIBUTE_VIDEO => Video::factory()->createOne()->getKey(), - PlaylistTrack::RELATION_PREVIOUS => $previous->getRouteKey(), - ], - ); - - Sanctum::actingAs($user); - - $response = $this->put(route('api.playlist.track.update', ['playlist' => $playlist, 'track' => $track] + $parameters)); - - $response->assertJsonValidationErrors([ - PlaylistTrack::RELATION_PREVIOUS, + $playlist = Playlist::factory() + ->for($user) + ->has(PlaylistTrack::factory()->count(fake()->randomDigitNotNull()), Playlist::RELATION_TRACKS) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, ]); - } - /** - * The Track Update Endpoint shall forbid the previous track to be itself. - */ - public function testPreviousIsNotSelf(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $track = PlaylistTrack::factory() + ->for(Playlist::factory()->for(User::factory())) + ->createOne(); - Feature::activate(AllowPlaylistManagement::class); + $parameters = array_merge( + PlaylistTrack::factory()->raw(), + [PlaylistTrack::ATTRIBUTE_VIDEO => Video::factory()->createOne()->getKey()], + ); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(PlaylistTrack::class))->createOne(); + Sanctum::actingAs($user); - $playlist = Playlist::factory() - ->for($user) - ->createOne(); + $response = put(route('api.playlist.track.update', ['playlist' => $playlist, 'track' => $track] + $parameters)); - $track = PlaylistTrack::factory() - ->for($playlist) - ->createOne(); + $response->assertNotFound(); +}); - $parameters = array_merge( - PlaylistTrack::factory()->raw(), - [ - PlaylistTrack::ATTRIBUTE_VIDEO => Video::factory()->createOne()->getKey(), - PlaylistTrack::RELATION_PREVIOUS => $track->getRouteKey(), - ], - ); +test('scope previous', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - Sanctum::actingAs($user); + Feature::activate(AllowPlaylistManagement::class); - $response = $this->put(route('api.playlist.track.update', ['playlist' => $playlist, 'track' => $track] + $parameters)); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(PlaylistTrack::class))->createOne(); - $response->assertJsonValidationErrors([ - PlaylistTrack::RELATION_PREVIOUS, - ]); - } + $playlist = Playlist::factory() + ->for($user) + ->createOne(); - /** - * The Track Update Endpoint shall restrict the next track to a track within the playlist. - */ - public function testScopeNext(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $track = PlaylistTrack::factory() + ->for($playlist) + ->createOne(); - Feature::activate(AllowPlaylistManagement::class); + $previous = PlaylistTrack::factory() + ->for(Playlist::factory()) + ->createOne(); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(PlaylistTrack::class))->createOne(); - - $playlist = Playlist::factory() - ->for($user) - ->createOne(); + $parameters = array_merge( + PlaylistTrack::factory()->raw(), + [ + PlaylistTrack::ATTRIBUTE_VIDEO => Video::factory()->createOne()->getKey(), + PlaylistTrack::RELATION_PREVIOUS => $previous->getRouteKey(), + ], + ); - $track = PlaylistTrack::factory() - ->for($playlist) - ->createOne(); + Sanctum::actingAs($user); - $next = PlaylistTrack::factory() - ->for(Playlist::factory()) - ->createOne(); + $response = put(route('api.playlist.track.update', ['playlist' => $playlist, 'track' => $track] + $parameters)); - $parameters = array_merge( - PlaylistTrack::factory()->raw(), - [ - PlaylistTrack::ATTRIBUTE_VIDEO => Video::factory()->createOne()->getKey(), - PlaylistTrack::RELATION_NEXT => $next->getRouteKey(), - ], - ); - - Sanctum::actingAs($user); + $response->assertJsonValidationErrors([ + PlaylistTrack::RELATION_PREVIOUS, + ]); +}); - $response = $this->put(route('api.playlist.track.update', ['playlist' => $playlist, 'track' => $track] + $parameters)); +test('previous is not self', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $response->assertJsonValidationErrors([ - PlaylistTrack::RELATION_NEXT, - ]); - } + Feature::activate(AllowPlaylistManagement::class); - /** - * The Track Update Endpoint shall forbid the next track to be itself. - */ - public function testNextIsNotSelf(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - - Feature::activate(AllowPlaylistManagement::class); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(PlaylistTrack::class))->createOne(); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(PlaylistTrack::class))->createOne(); + $playlist = Playlist::factory() + ->for($user) + ->createOne(); - $playlist = Playlist::factory() - ->for($user) - ->createOne(); + $track = PlaylistTrack::factory() + ->for($playlist) + ->createOne(); - $track = PlaylistTrack::factory() - ->for($playlist) - ->createOne(); + $parameters = array_merge( + PlaylistTrack::factory()->raw(), + [ + PlaylistTrack::ATTRIBUTE_VIDEO => Video::factory()->createOne()->getKey(), + PlaylistTrack::RELATION_PREVIOUS => $track->getRouteKey(), + ], + ); - $parameters = array_merge( - PlaylistTrack::factory()->raw(), - [ - PlaylistTrack::ATTRIBUTE_VIDEO => Video::factory()->createOne()->getKey(), - PlaylistTrack::RELATION_NEXT => $track->getRouteKey(), - ], - ); + Sanctum::actingAs($user); - Sanctum::actingAs($user); + $response = put(route('api.playlist.track.update', ['playlist' => $playlist, 'track' => $track] + $parameters)); - $response = $this->put(route('api.playlist.track.update', ['playlist' => $playlist, 'track' => $track] + $parameters)); + $response->assertJsonValidationErrors([ + PlaylistTrack::RELATION_PREVIOUS, + ]); +}); - $response->assertJsonValidationErrors([ - PlaylistTrack::RELATION_NEXT, - ]); - } +test('scope next', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - /** - * The Track Store Endpoint shall prohibit the next and previous fields from both being present. - */ - public function testProhibitsNextAndPrevious(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + Feature::activate(AllowPlaylistManagement::class); - Feature::activate(AllowPlaylistManagement::class); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(PlaylistTrack::class))->createOne(); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(PlaylistTrack::class))->createOne(); + $playlist = Playlist::factory() + ->for($user) + ->createOne(); - $playlist = Playlist::factory() - ->for($user) - ->createOne(); + $track = PlaylistTrack::factory() + ->for($playlist) + ->createOne(); - $previous = PlaylistTrack::factory() - ->for($playlist) - ->createOne(); + $next = PlaylistTrack::factory() + ->for(Playlist::factory()) + ->createOne(); - $next = PlaylistTrack::factory() - ->for($playlist) - ->createOne(); + $parameters = array_merge( + PlaylistTrack::factory()->raw(), + [ + PlaylistTrack::ATTRIBUTE_VIDEO => Video::factory()->createOne()->getKey(), + PlaylistTrack::RELATION_NEXT => $next->getRouteKey(), + ], + ); - $track = PlaylistTrack::factory() - ->for($playlist) - ->for(Video::factory()) - ->createOne(); + Sanctum::actingAs($user); - $parameters = array_merge( - PlaylistTrack::factory()->raw(), - [ - PlaylistTrack::RELATION_NEXT => $next->getRouteKey(), - PlaylistTrack::RELATION_PREVIOUS => $previous->getRouteKey(), - ], - ); + $response = put(route('api.playlist.track.update', ['playlist' => $playlist, 'track' => $track] + $parameters)); - Sanctum::actingAs($user); + $response->assertJsonValidationErrors([ + PlaylistTrack::RELATION_NEXT, + ]); +}); - $response = $this->put(route('api.playlist.track.update', ['playlist' => $playlist, 'track' => $track] + $parameters)); +test('next is not self', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $response->assertJsonValidationErrors([ - PlaylistTrack::RELATION_NEXT, - PlaylistTrack::RELATION_PREVIOUS, - ]); - } + Feature::activate(AllowPlaylistManagement::class); - /** - * The Playlist Update Endpoint shall forbid users from updating playlists - * if the Allow Playlist Management feature is inactive. - */ - public function testForbiddenIfFlagDisabled(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(PlaylistTrack::class))->createOne(); - Feature::deactivate(AllowPlaylistManagement::class); + $playlist = Playlist::factory() + ->for($user) + ->createOne(); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(PlaylistTrack::class))->createOne(); + $track = PlaylistTrack::factory() + ->for($playlist) + ->createOne(); - $playlist = Playlist::factory() - ->for($user) - ->createOne(); + $parameters = array_merge( + PlaylistTrack::factory()->raw(), + [ + PlaylistTrack::ATTRIBUTE_VIDEO => Video::factory()->createOne()->getKey(), + PlaylistTrack::RELATION_NEXT => $track->getRouteKey(), + ], + ); - $track = PlaylistTrack::factory() - ->for($playlist) - ->createOne(); + Sanctum::actingAs($user); - $parameters = array_merge( - PlaylistTrack::factory()->raw(), - [ - PlaylistTrack::ATTRIBUTE_VIDEO => Video::factory()->createOne()->getKey(), - ], - ); + $response = put(route('api.playlist.track.update', ['playlist' => $playlist, 'track' => $track] + $parameters)); - Sanctum::actingAs($user); + $response->assertJsonValidationErrors([ + PlaylistTrack::RELATION_NEXT, + ]); +}); - $response = $this->put(route('api.playlist.track.update', ['playlist' => $playlist, 'track' => $track] + $parameters)); +test('prohibits next and previous', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $response->assertForbidden(); - } + Feature::activate(AllowPlaylistManagement::class); - /** - * The Track Update Endpoint shall update a playlist track. - */ - public function testUpdate(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(PlaylistTrack::class))->createOne(); - Feature::activate(AllowPlaylistManagement::class); + $playlist = Playlist::factory() + ->for($user) + ->createOne(); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(PlaylistTrack::class))->createOne(); + $previous = PlaylistTrack::factory() + ->for($playlist) + ->createOne(); - $playlist = Playlist::factory() - ->for($user) - ->createOne(); + $next = PlaylistTrack::factory() + ->for($playlist) + ->createOne(); - $track = PlaylistTrack::factory() - ->for($playlist) - ->createOne(); + $track = PlaylistTrack::factory() + ->for($playlist) + ->for(Video::factory()) + ->createOne(); - $parameters = array_merge( - PlaylistTrack::factory()->raw(), - [ - PlaylistTrack::ATTRIBUTE_VIDEO => Video::factory()->createOne()->getKey(), - ], - ); + $parameters = array_merge( + PlaylistTrack::factory()->raw(), + [ + PlaylistTrack::RELATION_NEXT => $next->getRouteKey(), + PlaylistTrack::RELATION_PREVIOUS => $previous->getRouteKey(), + ], + ); - Sanctum::actingAs($user); + Sanctum::actingAs($user); - $response = $this->put(route('api.playlist.track.update', ['playlist' => $playlist, 'track' => $track] + $parameters)); + $response = put(route('api.playlist.track.update', ['playlist' => $playlist, 'track' => $track] + $parameters)); - $response->assertOk(); - } + $response->assertJsonValidationErrors([ + PlaylistTrack::RELATION_NEXT, + PlaylistTrack::RELATION_PREVIOUS, + ]); +}); - /** - * The Track Update Endpoint shall insert the first track after the second track. - */ - public function testInsertFirstAfterSecond(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); +test('forbidden if flag disabled', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - Feature::activate(AllowPlaylistManagement::class); + Feature::deactivate(AllowPlaylistManagement::class); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(PlaylistTrack::class))->createOne(); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(PlaylistTrack::class))->createOne(); - $playlist = Playlist::factory() - ->for($user) - ->tracks(3) - ->createOne(); + $playlist = Playlist::factory() + ->for($user) + ->createOne(); - $first = $playlist->first; - $second = $first->next; - $third = $playlist->last; + $track = PlaylistTrack::factory() + ->for($playlist) + ->createOne(); - $parameters = [ - PlaylistTrack::RELATION_PREVIOUS => $second->getRouteKey(), - ]; + $parameters = array_merge( + PlaylistTrack::factory()->raw(), + [ + PlaylistTrack::ATTRIBUTE_VIDEO => Video::factory()->createOne()->getKey(), + ], + ); - Sanctum::actingAs($user); + Sanctum::actingAs($user); - $response = $this->put(route('api.playlist.track.update', ['playlist' => $playlist, 'track' => $first] + $parameters)); + $response = put(route('api.playlist.track.update', ['playlist' => $playlist, 'track' => $track] + $parameters)); - $response->assertOk(); + $response->assertForbidden(); +}); - $playlist->refresh(); - $first->refresh(); - $second->refresh(); - $third->refresh(); +test('update', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - static::assertTrue($playlist->first()->is($second)); - static::assertTrue($playlist->last()->is($third)); + Feature::activate(AllowPlaylistManagement::class); - static::assertTrue($first->previous()->is($second)); - static::assertTrue($first->next()->is($third)); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(PlaylistTrack::class))->createOne(); - static::assertTrue($second->previous()->doesntExist()); - static::assertTrue($second->next()->is($first)); + $playlist = Playlist::factory() + ->for($user) + ->createOne(); - static::assertTrue($third->previous()->is($first)); - static::assertTrue($third->next()->doesntExist()); - } + $track = PlaylistTrack::factory() + ->for($playlist) + ->createOne(); - /** - * The Track Update Endpoint shall insert the first track after the third track. - */ - public function testInsertFirstAfterThird(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $parameters = array_merge( + PlaylistTrack::factory()->raw(), + [ + PlaylistTrack::ATTRIBUTE_VIDEO => Video::factory()->createOne()->getKey(), + ], + ); - Feature::activate(AllowPlaylistManagement::class); + Sanctum::actingAs($user); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(PlaylistTrack::class))->createOne(); + $response = put(route('api.playlist.track.update', ['playlist' => $playlist, 'track' => $track] + $parameters)); - $playlist = Playlist::factory() - ->for($user) - ->tracks(3) - ->createOne(); + $response->assertOk(); +}); - $first = $playlist->first; - $second = $first->next; - $third = $playlist->last; +test('insert first after second', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $parameters = [ - PlaylistTrack::RELATION_PREVIOUS => $third->getRouteKey(), - ]; + Feature::activate(AllowPlaylistManagement::class); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(PlaylistTrack::class))->createOne(); - $response = $this->put(route('api.playlist.track.update', ['playlist' => $playlist, 'track' => $first] + $parameters)); + $playlist = Playlist::factory() + ->for($user) + ->tracks(3) + ->createOne(); - $response->assertOk(); + $first = $playlist->first; + $second = $first->next; + $third = $playlist->last; - $playlist->refresh(); - $first->refresh(); - $second->refresh(); - $third->refresh(); + $parameters = [ + PlaylistTrack::RELATION_PREVIOUS => $second->getRouteKey(), + ]; - static::assertTrue($playlist->first()->is($second)); - static::assertTrue($playlist->last()->is($first)); + Sanctum::actingAs($user); - static::assertTrue($first->previous()->is($third)); - static::assertTrue($first->next()->doesntExist()); + $response = put(route('api.playlist.track.update', ['playlist' => $playlist, 'track' => $first] + $parameters)); - static::assertTrue($second->previous()->doesntExist()); - static::assertTrue($second->next()->is($third)); + $response->assertOk(); - static::assertTrue($third->previous()->is($second)); - static::assertTrue($third->next()->is($first)); - } + $playlist->refresh(); + $first->refresh(); + $second->refresh(); + $third->refresh(); - /** - * The Track Update Endpoint shall insert the first track before the third track. - */ - public function testInsertFirstBeforeThird(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $this->assertTrue($playlist->first()->is($second)); + $this->assertTrue($playlist->last()->is($third)); - Feature::activate(AllowPlaylistManagement::class); + $this->assertTrue($first->previous()->is($second)); + $this->assertTrue($first->next()->is($third)); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(PlaylistTrack::class))->createOne(); + $this->assertTrue($second->previous()->doesntExist()); + $this->assertTrue($second->next()->is($first)); - $playlist = Playlist::factory() - ->for($user) - ->tracks(3) - ->createOne(); + $this->assertTrue($third->previous()->is($first)); + $this->assertTrue($third->next()->doesntExist()); +}); - $first = $playlist->first; - $second = $first->next; - $third = $playlist->last; +test('insert first after third', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $parameters = [ - PlaylistTrack::RELATION_NEXT => $third->getRouteKey(), - ]; + Feature::activate(AllowPlaylistManagement::class); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(PlaylistTrack::class))->createOne(); - $response = $this->put(route('api.playlist.track.update', ['playlist' => $playlist, 'track' => $first] + $parameters)); + $playlist = Playlist::factory() + ->for($user) + ->tracks(3) + ->createOne(); - $response->assertOk(); + $first = $playlist->first; + $second = $first->next; + $third = $playlist->last; - $playlist->refresh(); - $first->refresh(); - $second->refresh(); - $third->refresh(); + $parameters = [ + PlaylistTrack::RELATION_PREVIOUS => $third->getRouteKey(), + ]; - static::assertTrue($playlist->first()->is($second)); - static::assertTrue($playlist->last()->is($third)); + Sanctum::actingAs($user); - static::assertTrue($first->previous()->is($second)); - static::assertTrue($first->next()->is($third)); + $response = put(route('api.playlist.track.update', ['playlist' => $playlist, 'track' => $first] + $parameters)); - static::assertTrue($second->previous()->doesntExist()); - static::assertTrue($second->next()->is($first)); + $response->assertOk(); - static::assertTrue($third->previous()->is($first)); - static::assertTrue($third->next()->doesntExist()); - } + $playlist->refresh(); + $first->refresh(); + $second->refresh(); + $third->refresh(); - /** - * The Track Update Endpoint shall insert the second track after the third track. - */ - public function testInsertSecondAfterThird(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $this->assertTrue($playlist->first()->is($second)); + $this->assertTrue($playlist->last()->is($first)); - Feature::activate(AllowPlaylistManagement::class); + $this->assertTrue($first->previous()->is($third)); + $this->assertTrue($first->next()->doesntExist()); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(PlaylistTrack::class))->createOne(); + $this->assertTrue($second->previous()->doesntExist()); + $this->assertTrue($second->next()->is($third)); - $playlist = Playlist::factory() - ->for($user) - ->tracks(3) - ->createOne(); + $this->assertTrue($third->previous()->is($second)); + $this->assertTrue($third->next()->is($first)); +}); - $first = $playlist->first; - $second = $first->next; - $third = $playlist->last; +test('insert first before third', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $parameters = [ - PlaylistTrack::RELATION_PREVIOUS => $third->getRouteKey(), - ]; + Feature::activate(AllowPlaylistManagement::class); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(PlaylistTrack::class))->createOne(); - $response = $this->put(route('api.playlist.track.update', ['playlist' => $playlist, 'track' => $second] + $parameters)); + $playlist = Playlist::factory() + ->for($user) + ->tracks(3) + ->createOne(); - $response->assertOk(); + $first = $playlist->first; + $second = $first->next; + $third = $playlist->last; - $playlist->refresh(); - $first->refresh(); - $second->refresh(); - $third->refresh(); + $parameters = [ + PlaylistTrack::RELATION_NEXT => $third->getRouteKey(), + ]; - static::assertTrue($playlist->first()->is($first)); - static::assertTrue($playlist->last()->is($second)); + Sanctum::actingAs($user); - static::assertTrue($first->previous()->doesntExist()); - static::assertTrue($first->next()->is($third)); + $response = put(route('api.playlist.track.update', ['playlist' => $playlist, 'track' => $first] + $parameters)); - static::assertTrue($second->previous()->is($third)); - static::assertTrue($second->next()->doesntExist()); + $response->assertOk(); - static::assertTrue($third->previous()->is($first)); - static::assertTrue($third->next()->is($second)); - } + $playlist->refresh(); + $first->refresh(); + $second->refresh(); + $third->refresh(); - /** - * The Track Update Endpoint shall insert the second track before the first track. - */ - public function testInsertSecondBeforeFirst(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $this->assertTrue($playlist->first()->is($second)); + $this->assertTrue($playlist->last()->is($third)); - Feature::activate(AllowPlaylistManagement::class); + $this->assertTrue($first->previous()->is($second)); + $this->assertTrue($first->next()->is($third)); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(PlaylistTrack::class))->createOne(); + $this->assertTrue($second->previous()->doesntExist()); + $this->assertTrue($second->next()->is($first)); - $playlist = Playlist::factory() - ->for($user) - ->tracks(3) - ->createOne(); + $this->assertTrue($third->previous()->is($first)); + $this->assertTrue($third->next()->doesntExist()); +}); - $first = $playlist->first; - $second = $first->next; - $third = $playlist->last; +test('insert second after third', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $parameters = [ - PlaylistTrack::RELATION_NEXT => $first->getRouteKey(), - ]; + Feature::activate(AllowPlaylistManagement::class); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(PlaylistTrack::class))->createOne(); - $response = $this->put(route('api.playlist.track.update', ['playlist' => $playlist, 'track' => $second] + $parameters)); + $playlist = Playlist::factory() + ->for($user) + ->tracks(3) + ->createOne(); - $response->assertOk(); + $first = $playlist->first; + $second = $first->next; + $third = $playlist->last; - $playlist->refresh(); - $first->refresh(); - $second->refresh(); - $third->refresh(); + $parameters = [ + PlaylistTrack::RELATION_PREVIOUS => $third->getRouteKey(), + ]; - static::assertTrue($playlist->first()->is($second)); - static::assertTrue($playlist->last()->is($third)); + Sanctum::actingAs($user); - static::assertTrue($first->previous()->is($second)); - static::assertTrue($first->next()->is($third)); + $response = put(route('api.playlist.track.update', ['playlist' => $playlist, 'track' => $second] + $parameters)); - static::assertTrue($second->previous()->doesntExist()); - static::assertTrue($second->next()->is($first)); + $response->assertOk(); - static::assertTrue($third->previous()->is($first)); - static::assertTrue($third->next()->doesntExist()); - } + $playlist->refresh(); + $first->refresh(); + $second->refresh(); + $third->refresh(); - /** - * The Track Update Endpoint shall insert the third track after the first track. - */ - public function testInsertThirdAfterFirst(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $this->assertTrue($playlist->first()->is($first)); + $this->assertTrue($playlist->last()->is($second)); - Feature::activate(AllowPlaylistManagement::class); + $this->assertTrue($first->previous()->doesntExist()); + $this->assertTrue($first->next()->is($third)); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(PlaylistTrack::class))->createOne(); + $this->assertTrue($second->previous()->is($third)); + $this->assertTrue($second->next()->doesntExist()); - $playlist = Playlist::factory() - ->for($user) - ->tracks(3) - ->createOne(); + $this->assertTrue($third->previous()->is($first)); + $this->assertTrue($third->next()->is($second)); +}); - $first = $playlist->first; - $second = $first->next; - $third = $playlist->last; +test('insert second before first', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $parameters = [ - PlaylistTrack::RELATION_PREVIOUS => $first->getRouteKey(), - ]; + Feature::activate(AllowPlaylistManagement::class); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(PlaylistTrack::class))->createOne(); - $response = $this->put(route('api.playlist.track.update', ['playlist' => $playlist, 'track' => $third] + $parameters)); + $playlist = Playlist::factory() + ->for($user) + ->tracks(3) + ->createOne(); - $response->assertOk(); + $first = $playlist->first; + $second = $first->next; + $third = $playlist->last; - $playlist->refresh(); - $first->refresh(); - $second->refresh(); - $third->refresh(); + $parameters = [ + PlaylistTrack::RELATION_NEXT => $first->getRouteKey(), + ]; - static::assertTrue($playlist->first()->is($first)); - static::assertTrue($playlist->last()->is($second)); + Sanctum::actingAs($user); - static::assertTrue($first->previous()->doesntExist()); - static::assertTrue($first->next()->is($third)); + $response = put(route('api.playlist.track.update', ['playlist' => $playlist, 'track' => $second] + $parameters)); - static::assertTrue($second->previous()->is($third)); - static::assertTrue($second->next()->doesntExist()); + $response->assertOk(); - static::assertTrue($third->previous()->is($first)); - static::assertTrue($third->next()->is($second)); - } + $playlist->refresh(); + $first->refresh(); + $second->refresh(); + $third->refresh(); - /** - * The Track Update Endpoint shall insert the third track before the second track. - */ - public function testInsertThirdBeforeSecond(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $this->assertTrue($playlist->first()->is($second)); + $this->assertTrue($playlist->last()->is($third)); - Feature::activate(AllowPlaylistManagement::class); + $this->assertTrue($first->previous()->is($second)); + $this->assertTrue($first->next()->is($third)); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(PlaylistTrack::class))->createOne(); + $this->assertTrue($second->previous()->doesntExist()); + $this->assertTrue($second->next()->is($first)); - $playlist = Playlist::factory() - ->for($user) - ->tracks(3) - ->createOne(); + $this->assertTrue($third->previous()->is($first)); + $this->assertTrue($third->next()->doesntExist()); +}); - $first = $playlist->first; - $second = $first->next; - $third = $playlist->last; +test('insert third after first', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $parameters = [ - PlaylistTrack::RELATION_NEXT => $second->getRouteKey(), - ]; + Feature::activate(AllowPlaylistManagement::class); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(PlaylistTrack::class))->createOne(); - $response = $this->put(route('api.playlist.track.update', ['playlist' => $playlist, 'track' => $third] + $parameters)); + $playlist = Playlist::factory() + ->for($user) + ->tracks(3) + ->createOne(); - $response->assertOk(); + $first = $playlist->first; + $second = $first->next; + $third = $playlist->last; - $playlist->refresh(); - $first->refresh(); - $second->refresh(); - $third->refresh(); + $parameters = [ + PlaylistTrack::RELATION_PREVIOUS => $first->getRouteKey(), + ]; - static::assertTrue($playlist->first()->is($first)); - static::assertTrue($playlist->last()->is($second)); + Sanctum::actingAs($user); - static::assertTrue($first->previous()->doesntExist()); - static::assertTrue($first->next()->is($third)); + $response = put(route('api.playlist.track.update', ['playlist' => $playlist, 'track' => $third] + $parameters)); - static::assertTrue($second->previous()->is($third)); - static::assertTrue($second->next()->doesntExist()); + $response->assertOk(); - static::assertTrue($third->previous()->is($first)); - static::assertTrue($third->next()->is($second)); - } + $playlist->refresh(); + $first->refresh(); + $second->refresh(); + $third->refresh(); - /** - * The Track Update Endpoint shall insert the third track before the first track. - */ - public function testInsertThirdBeforeFirst(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $this->assertTrue($playlist->first()->is($first)); + $this->assertTrue($playlist->last()->is($second)); - Feature::activate(AllowPlaylistManagement::class); + $this->assertTrue($first->previous()->doesntExist()); + $this->assertTrue($first->next()->is($third)); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(PlaylistTrack::class))->createOne(); + $this->assertTrue($second->previous()->is($third)); + $this->assertTrue($second->next()->doesntExist()); - $playlist = Playlist::factory() - ->for($user) - ->tracks(3) - ->createOne(); + $this->assertTrue($third->previous()->is($first)); + $this->assertTrue($third->next()->is($second)); +}); - $first = $playlist->first; - $second = $first->next; - $third = $playlist->last; +test('insert third before second', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $parameters = [ - PlaylistTrack::RELATION_NEXT => $first->getRouteKey(), - ]; + Feature::activate(AllowPlaylistManagement::class); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(PlaylistTrack::class))->createOne(); - $response = $this->put(route('api.playlist.track.update', ['playlist' => $playlist, 'track' => $third] + $parameters)); + $playlist = Playlist::factory() + ->for($user) + ->tracks(3) + ->createOne(); - $response->assertOk(); + $first = $playlist->first; + $second = $first->next; + $third = $playlist->last; - $playlist->refresh(); - $first->refresh(); - $second->refresh(); - $third->refresh(); + $parameters = [ + PlaylistTrack::RELATION_NEXT => $second->getRouteKey(), + ]; - static::assertTrue($playlist->first()->is($third)); - static::assertTrue($playlist->last()->is($second)); + Sanctum::actingAs($user); - static::assertTrue($first->previous()->is($third)); - static::assertTrue($first->next()->is($second)); + $response = put(route('api.playlist.track.update', ['playlist' => $playlist, 'track' => $third] + $parameters)); - static::assertTrue($second->previous()->is($first)); - static::assertTrue($second->next()->doesntExist()); + $response->assertOk(); - static::assertTrue($third->previous()->doesntExist()); - static::assertTrue($third->next()->is($first)); - } + $playlist->refresh(); + $first->refresh(); + $second->refresh(); + $third->refresh(); - /** - * Users with the bypass feature flag permission shall be permitted to update playlist tracks - * even if the Allow Playlist Management feature is inactive. - */ - public function testUpdatePermittedForBypass(): void - { - Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + $this->assertTrue($playlist->first()->is($first)); + $this->assertTrue($playlist->last()->is($second)); - Feature::activate(AllowPlaylistManagement::class, $this->faker->boolean()); + $this->assertTrue($first->previous()->doesntExist()); + $this->assertTrue($first->next()->is($third)); - $user = User::factory() - ->withPermissions( - CrudPermission::UPDATE->format(PlaylistTrack::class), - SpecialPermission::BYPASS_FEATURE_FLAGS->value - ) - ->createOne(); + $this->assertTrue($second->previous()->is($third)); + $this->assertTrue($second->next()->doesntExist()); - $playlist = Playlist::factory() - ->for($user) - ->createOne(); + $this->assertTrue($third->previous()->is($first)); + $this->assertTrue($third->next()->is($second)); +}); - $track = PlaylistTrack::factory() - ->for($playlist) - ->createOne(); +test('insert third before first', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); - $parameters = array_merge( - PlaylistTrack::factory()->raw(), - [ - PlaylistTrack::ATTRIBUTE_VIDEO => Video::factory()->createOne()->getKey(), - ], - ); + Feature::activate(AllowPlaylistManagement::class); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(PlaylistTrack::class))->createOne(); - $response = $this->put(route('api.playlist.track.update', ['playlist' => $playlist, 'track' => $track] + $parameters)); + $playlist = Playlist::factory() + ->for($user) + ->tracks(3) + ->createOne(); - $response->assertOk(); - } -} + $first = $playlist->first; + $second = $first->next; + $third = $playlist->last; + + $parameters = [ + PlaylistTrack::RELATION_NEXT => $first->getRouteKey(), + ]; + + Sanctum::actingAs($user); + + $response = put(route('api.playlist.track.update', ['playlist' => $playlist, 'track' => $third] + $parameters)); + + $response->assertOk(); + + $playlist->refresh(); + $first->refresh(); + $second->refresh(); + $third->refresh(); + + $this->assertTrue($playlist->first()->is($third)); + $this->assertTrue($playlist->last()->is($second)); + + $this->assertTrue($first->previous()->is($third)); + $this->assertTrue($first->next()->is($second)); + + $this->assertTrue($second->previous()->is($first)); + $this->assertTrue($second->next()->doesntExist()); + + $this->assertTrue($third->previous()->doesntExist()); + $this->assertTrue($third->next()->is($first)); +}); + +test('update permitted for bypass', function () { + Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]); + + Feature::activate(AllowPlaylistManagement::class, fake()->boolean()); + + $user = User::factory() + ->withPermissions( + CrudPermission::UPDATE->format(PlaylistTrack::class), + SpecialPermission::BYPASS_FEATURE_FLAGS->value + ) + ->createOne(); + + $playlist = Playlist::factory() + ->for($user) + ->createOne(); + + $track = PlaylistTrack::factory() + ->for($playlist) + ->createOne(); + + $parameters = array_merge( + PlaylistTrack::factory()->raw(), + [ + PlaylistTrack::ATTRIBUTE_VIDEO => Video::factory()->createOne()->getKey(), + ], + ); + + Sanctum::actingAs($user); + + $response = put(route('api.playlist.track.update', ['playlist' => $playlist, 'track' => $track] + $parameters)); + + $response->assertOk(); +}); diff --git a/tests/Feature/Http/Api/Pivot/List/PlaylistImage/PlaylistImageDestroyTest.php b/tests/Feature/Http/Api/Pivot/List/PlaylistImage/PlaylistImageDestroyTest.php index f11b9ce49..84025dab4 100644 --- a/tests/Feature/Http/Api/Pivot/List/PlaylistImage/PlaylistImageDestroyTest.php +++ b/tests/Feature/Http/Api/Pivot/List/PlaylistImage/PlaylistImageDestroyTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\List\PlaylistImage; - use App\Enums\Auth\CrudPermission; use App\Enums\Auth\SpecialPermission; use App\Events\List\Playlist\PlaylistCreated; @@ -12,199 +10,166 @@ use App\Models\Auth\User; use App\Models\List\Playlist; use App\Models\Wiki\Image; use App\Pivots\List\PlaylistImage; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class PlaylistImageDestroyTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\delete; - /** - * The Playlist Image Destroy Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - Event::fakeExcept(PlaylistCreated::class); +uses(Illuminate\Foundation\Testing\WithFaker::class); - Feature::activate(AllowPlaylistManagement::class); +test('protected', function () { + Event::fakeExcept(PlaylistCreated::class); - $playlistImage = PlaylistImage::factory() - ->for(Playlist::factory()) - ->for(Image::factory()) - ->createOne(); + Feature::activate(AllowPlaylistManagement::class); - $response = $this->delete(route('api.playlistimage.destroy', ['playlist' => $playlistImage->playlist, 'image' => $playlistImage->image])); + $playlistImage = PlaylistImage::factory() + ->for(Playlist::factory()) + ->for(Image::factory()) + ->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.playlistimage.destroy', ['playlist' => $playlistImage->playlist, 'image' => $playlistImage->image])); - /** - * The Playlist Image Destroy Endpoint shall forbid users without the delete playlist & delete image permissions. - */ - public function testForbiddenIfMissingPermission(): void - { - Event::fakeExcept(PlaylistCreated::class); + $response->assertUnauthorized(); +}); - Feature::activate(AllowPlaylistManagement::class); +test('forbidden if missing permission', function () { + Event::fakeExcept(PlaylistCreated::class); - $playlistImage = PlaylistImage::factory() - ->for(Playlist::factory()) - ->for(Image::factory()) - ->createOne(); + Feature::activate(AllowPlaylistManagement::class); - $user = User::factory()->createOne(); + $playlistImage = PlaylistImage::factory() + ->for(Playlist::factory()) + ->for(Image::factory()) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.playlistimage.destroy', ['playlist' => $playlistImage->playlist, 'image' => $playlistImage->image])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.playlistimage.destroy', ['playlist' => $playlistImage->playlist, 'image' => $playlistImage->image])); - /** - * The Playlist Image Destroy Endpoint shall forbid users from deleting the playlist image if they don't own the playlist. - */ - public function testForbiddenIfNotOwnPlaylist(): void - { - Event::fakeExcept(PlaylistCreated::class); + $response->assertForbidden(); +}); - Feature::activate(AllowPlaylistManagement::class); +test('forbidden if not own playlist', function () { + Event::fakeExcept(PlaylistCreated::class); - $playlistImage = PlaylistImage::factory() - ->for(Playlist::factory()->for(User::factory())) - ->for(Image::factory()) - ->createOne(); + Feature::activate(AllowPlaylistManagement::class); - $user = User::factory() - ->withPermissions( - CrudPermission::DELETE->format(Playlist::class), - CrudPermission::DELETE->format(Image::class) - ) - ->createOne(); + $playlistImage = PlaylistImage::factory() + ->for(Playlist::factory()->for(User::factory())) + ->for(Image::factory()) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::DELETE->format(Playlist::class), + CrudPermission::DELETE->format(Image::class) + ) + ->createOne(); - $response = $this->delete(route('api.playlistimage.destroy', ['playlist' => $playlistImage->playlist, 'image' => $playlistImage->image])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.playlistimage.destroy', ['playlist' => $playlistImage->playlist, 'image' => $playlistImage->image])); - /** - * The Playlist Image Destroy Endpoint shall forbid users from destroying playlist images - * if the Allow Playlist Management feature is inactive. - */ - public function testForbiddenIfFlagDisabled(): void - { - Event::fakeExcept(PlaylistCreated::class); + $response->assertForbidden(); +}); - Feature::deactivate(AllowPlaylistManagement::class); +test('forbidden if flag disabled', function () { + Event::fakeExcept(PlaylistCreated::class); - $user = User::factory() - ->withPermissions( - CrudPermission::DELETE->format(Playlist::class), - CrudPermission::DELETE->format(Image::class) - ) - ->createOne(); + Feature::deactivate(AllowPlaylistManagement::class); - $playlistImage = PlaylistImage::factory() - ->for(Playlist::factory()->for($user)) - ->for(Image::factory()) - ->createOne(); + $user = User::factory() + ->withPermissions( + CrudPermission::DELETE->format(Playlist::class), + CrudPermission::DELETE->format(Image::class) + ) + ->createOne(); - Sanctum::actingAs($user); + $playlistImage = PlaylistImage::factory() + ->for(Playlist::factory()->for($user)) + ->for(Image::factory()) + ->createOne(); - $response = $this->delete(route('api.playlistimage.destroy', ['playlist' => $playlistImage->playlist, 'image' => $playlistImage->image])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.playlistimage.destroy', ['playlist' => $playlistImage->playlist, 'image' => $playlistImage->image])); - /** - * The Playlist Image Destroy Endpoint shall return an error if the playlist image does not exist. - */ - public function testNotFound(): void - { - Event::fakeExcept(PlaylistCreated::class); + $response->assertForbidden(); +}); - Feature::activate(AllowPlaylistManagement::class); +test('not found', function () { + Event::fakeExcept(PlaylistCreated::class); - $user = User::factory() - ->withPermissions( - CrudPermission::DELETE->format(Playlist::class), - CrudPermission::DELETE->format(Image::class) - ) - ->createOne(); + Feature::activate(AllowPlaylistManagement::class); - $playlist = Playlist::factory() - ->for($user) - ->createOne(); - $image = Image::factory()->createOne(); + $user = User::factory() + ->withPermissions( + CrudPermission::DELETE->format(Playlist::class), + CrudPermission::DELETE->format(Image::class) + ) + ->createOne(); - Sanctum::actingAs($user); + $playlist = Playlist::factory() + ->for($user) + ->createOne(); + $image = Image::factory()->createOne(); - $response = $this->delete(route('api.playlistimage.destroy', ['playlist' => $playlist, 'image' => $image])); + Sanctum::actingAs($user); - $response->assertNotFound(); - } + $response = delete(route('api.playlistimage.destroy', ['playlist' => $playlist, 'image' => $image])); - /** - * The Playlist Image Destroy Endpoint shall delete the playlist image. - */ - public function testDeleted(): void - { - Event::fakeExcept(PlaylistCreated::class); + $response->assertNotFound(); +}); - Feature::activate(AllowPlaylistManagement::class); +test('deleted', function () { + Event::fakeExcept(PlaylistCreated::class); - $user = User::factory() - ->withPermissions( - CrudPermission::DELETE->format(Playlist::class), - CrudPermission::DELETE->format(Image::class) - ) - ->createOne(); + Feature::activate(AllowPlaylistManagement::class); - $playlistImage = PlaylistImage::factory() - ->for(Playlist::factory()->for($user)) - ->for(Image::factory()) - ->createOne(); + $user = User::factory() + ->withPermissions( + CrudPermission::DELETE->format(Playlist::class), + CrudPermission::DELETE->format(Image::class) + ) + ->createOne(); - Sanctum::actingAs($user); + $playlistImage = PlaylistImage::factory() + ->for(Playlist::factory()->for($user)) + ->for(Image::factory()) + ->createOne(); - $response = $this->delete(route('api.playlistimage.destroy', ['playlist' => $playlistImage->playlist, 'image' => $playlistImage->image])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertModelMissing($playlistImage); - } + $response = delete(route('api.playlistimage.destroy', ['playlist' => $playlistImage->playlist, 'image' => $playlistImage->image])); - /** - * Users with the bypass feature flag permission shall be permitted to destroy playlist images - * even if the Allow Playlist Management feature is inactive. - */ - public function testDestroyPermittedForBypass(): void - { - Event::fakeExcept(PlaylistCreated::class); + $response->assertOk(); + $this->assertModelMissing($playlistImage); +}); - Feature::activate(AllowPlaylistManagement::class, $this->faker->boolean()); +test('destroy permitted for bypass', function () { + Event::fakeExcept(PlaylistCreated::class); - $user = User::factory() - ->withPermissions( - CrudPermission::DELETE->format(Playlist::class), - CrudPermission::DELETE->format(Image::class), - SpecialPermission::BYPASS_FEATURE_FLAGS->value - ) - ->createOne(); + Feature::activate(AllowPlaylistManagement::class, fake()->boolean()); - $playlistImage = PlaylistImage::factory() - ->for(Playlist::factory()->for($user)) - ->for(Image::factory()) - ->createOne(); + $user = User::factory() + ->withPermissions( + CrudPermission::DELETE->format(Playlist::class), + CrudPermission::DELETE->format(Image::class), + SpecialPermission::BYPASS_FEATURE_FLAGS->value + ) + ->createOne(); - Sanctum::actingAs($user); + $playlistImage = PlaylistImage::factory() + ->for(Playlist::factory()->for($user)) + ->for(Image::factory()) + ->createOne(); - $response = $this->delete(route('api.playlistimage.destroy', ['playlist' => $playlistImage->playlist, 'image' => $playlistImage->image])); + Sanctum::actingAs($user); - $response->assertOk(); - } -} + $response = delete(route('api.playlistimage.destroy', ['playlist' => $playlistImage->playlist, 'image' => $playlistImage->image])); + + $response->assertOk(); +}); diff --git a/tests/Feature/Http/Api/Pivot/List/PlaylistImage/PlaylistImageIndexTest.php b/tests/Feature/Http/Api/Pivot/List/PlaylistImage/PlaylistImageIndexTest.php index d09e401f7..1212f0ec4 100644 --- a/tests/Feature/Http/Api/Pivot/List/PlaylistImage/PlaylistImageIndexTest.php +++ b/tests/Feature/Http/Api/Pivot/List/PlaylistImage/PlaylistImageIndexTest.php @@ -2,9 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\List\PlaylistImage; - -use App\Concerns\Actions\Http\Api\SortsModels; use App\Contracts\Http\Api\Field\SortableField; use App\Enums\Http\Api\Sort\Direction; use App\Enums\Models\List\PlaylistVisibility; @@ -30,25 +27,246 @@ use App\Pivots\BasePivot; use App\Pivots\List\PlaylistImage; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; use Illuminate\Support\Collection; -use Tests\TestCase; -class PlaylistImageIndexTest extends TestCase -{ - use SortsModels; - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the Playlist Image Index Endpoint shall return a collection of Playlist Image Resources. - */ - public function testDefault(): void - { - $publicCount = $this->faker->randomDigitNotNull(); +uses(App\Concerns\Actions\Http\Api\SortsModels::class); - Collection::times($publicCount, function () { +uses(Illuminate\Foundation\Testing\WithFaker::class); + +test('default', function () { + $publicCount = fake()->randomDigitNotNull(); + + Collection::times($publicCount, function () { + PlaylistImage::factory() + ->for( + Playlist::factory() + ->for(User::factory()) + ->state([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]) + ) + ->for(Image::factory()) + ->create(); + }); + + Collection::times(fake()->randomDigitNotNull(), function () { + PlaylistImage::factory() + ->for( + Playlist::factory() + ->for(User::factory()) + ->state([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::UNLISTED->value, + ]) + ) + ->for(Image::factory()) + ->create(); + }); + + Collection::times(fake()->randomDigitNotNull(), function () { + PlaylistImage::factory() + ->for( + Playlist::factory() + ->for(User::factory()) + ->state([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, + ]) + ) + ->for(Image::factory()) + ->create(); + }); + + $playlistImages = PlaylistImage::query() + ->whereHas(PlaylistImage::RELATION_PLAYLIST, function (Builder $relationBuilder) { + $relationBuilder->where(Playlist::ATTRIBUTE_VISIBILITY, PlaylistVisibility::PUBLIC->value); + }) + ->get(); + + $response = get(route('api.playlistimage.index')); + + $response->assertJsonCount($publicCount, PlaylistImageCollection::$wrap); + + $response->assertJson( + json_decode( + json_encode( + new PlaylistImageCollection($playlistImages, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('paginated', function () { + Collection::times(fake()->randomDigitNotNull(), function () { + PlaylistImage::factory() + ->for( + Playlist::factory() + ->for(User::factory()) + ->state([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]) + ) + ->for(Image::factory()) + ->create(); + }); + + $response = get(route('api.playlistimage.index')); + + $response->assertJsonStructure([ + PlaylistImageCollection::$wrap, + 'links', + 'meta', + ]); +}); + +test('allowed include paths', function () { + $schema = new PlaylistImageSchema(); + + $allowedIncludes = collect($schema->allowedIncludes()); + + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); + + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + PlaylistImage::factory() + ->for( + Playlist::factory() + ->for(User::factory()) + ->state([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]) + ) + ->for(Image::factory()) + ->create(); + }); + + $response = get(route('api.playlistimage.index', $parameters)); + + $playlistImages = PlaylistImage::with($includedPaths->all())->get(); + + $response->assertJson( + json_decode( + json_encode( + new PlaylistImageCollection($playlistImages, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sparse fieldsets', function () { + $schema = new PlaylistImageSchema(); + + $fields = collect($schema->fields()); + + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + PlaylistImageResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + PlaylistImage::factory() + ->for( + Playlist::factory() + ->for(User::factory()) + ->state([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]) + ) + ->for(Image::factory()) + ->create(); + }); + + $response = get(route('api.playlistimage.index', $parameters)); + + $playlistImages = PlaylistImage::all(); + + $response->assertJson( + json_decode( + json_encode( + new PlaylistImageCollection($playlistImages, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sorts', function () { + $schema = new PlaylistImageSchema(); + + /** @var Sort $sort */ + $sort = collect($schema->fields()) + ->filter(fn (Field $field) => $field instanceof SortableField) + ->map(fn (SortableField $field) => $field->getSort()) + ->random(); + + $parameters = [ + SortParser::param() => $sort->format(Arr::random(Direction::cases())), + ]; + + $query = new Query($parameters); + + Collection::times(fake()->randomDigitNotNull(), function () { + PlaylistImage::factory() + ->for( + Playlist::factory() + ->for(User::factory()) + ->state([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]) + ) + ->for(Image::factory()) + ->create(); + }); + + $response = get(route('api.playlistimage.index', $parameters)); + + $playlistImages = $this->sort(PlaylistImage::query(), $query, $schema)->get(); + + $response->assertJson( + json_decode( + json_encode( + new PlaylistImageCollection($playlistImages, $query) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('created at filter', function () { + $createdFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BasePivot::ATTRIBUTE_CREATED_AT => $createdFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($createdFilter, function () { + Collection::times(fake()->randomDigitNotNull(), function () { PlaylistImage::factory() ->for( Playlist::factory() @@ -60,61 +278,10 @@ class PlaylistImageIndexTest extends TestCase ->for(Image::factory()) ->create(); }); + }); - Collection::times($this->faker->randomDigitNotNull(), function () { - PlaylistImage::factory() - ->for( - Playlist::factory() - ->for(User::factory()) - ->state([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::UNLISTED->value, - ]) - ) - ->for(Image::factory()) - ->create(); - }); - - Collection::times($this->faker->randomDigitNotNull(), function () { - PlaylistImage::factory() - ->for( - Playlist::factory() - ->for(User::factory()) - ->state([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, - ]) - ) - ->for(Image::factory()) - ->create(); - }); - - $playlistImages = PlaylistImage::query() - ->whereHas(PlaylistImage::RELATION_PLAYLIST, function (Builder $relationBuilder) { - $relationBuilder->where(Playlist::ATTRIBUTE_VISIBILITY, PlaylistVisibility::PUBLIC->value); - }) - ->get(); - - $response = $this->get(route('api.playlistimage.index')); - - $response->assertJsonCount($publicCount, PlaylistImageCollection::$wrap); - - $response->assertJson( - json_decode( - json_encode( - new PlaylistImageCollection($playlistImages, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Playlist Image Index Endpoint shall be paginated. - */ - public function testPaginated(): void - { - Collection::times($this->faker->randomDigitNotNull(), function () { + Carbon::withTestNow($excludedDate, function () { + Collection::times(fake()->randomDigitNotNull(), function () { PlaylistImage::factory() ->for( Playlist::factory() @@ -126,34 +293,39 @@ class PlaylistImageIndexTest extends TestCase ->for(Image::factory()) ->create(); }); + }); - $response = $this->get(route('api.playlistimage.index')); + $playlistImages = PlaylistImage::query()->where(BasePivot::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - $response->assertJsonStructure([ - PlaylistImageCollection::$wrap, - 'links', - 'meta', - ]); - } + $response = get(route('api.playlistimage.index', $parameters)); - /** - * The Playlist Image Index Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new PlaylistImageSchema(); + $response->assertJson( + json_decode( + json_encode( + new PlaylistImageCollection($playlistImages, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('updated at filter', function () { + $updatedFilter = fake()->date(); + $excludedDate = fake()->date(); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $parameters = [ + FilterParser::param() => [ + BasePivot::ATTRIBUTE_UPDATED_AT => $updatedFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { + Carbon::withTestNow($updatedFilter, function () { + Collection::times(fake()->randomDigitNotNull(), function () { PlaylistImage::factory() ->for( Playlist::factory() @@ -165,41 +337,10 @@ class PlaylistImageIndexTest extends TestCase ->for(Image::factory()) ->create(); }); + }); - $response = $this->get(route('api.playlistimage.index', $parameters)); - - $playlistImages = PlaylistImage::with($includedPaths->all())->get(); - - $response->assertJson( - json_decode( - json_encode( - new PlaylistImageCollection($playlistImages, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Playlist Image Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new PlaylistImageSchema(); - - $fields = collect($schema->fields()); - - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); - - $parameters = [ - FieldParser::param() => [ - PlaylistImageResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { + Carbon::withTestNow($excludedDate, function () { + Collection::times(fake()->randomDigitNotNull(), function () { PlaylistImage::factory() ->for( Playlist::factory() @@ -211,242 +352,64 @@ class PlaylistImageIndexTest extends TestCase ->for(Image::factory()) ->create(); }); + }); - $response = $this->get(route('api.playlistimage.index', $parameters)); + $playlistImages = PlaylistImage::query()->where(BasePivot::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - $playlistImages = PlaylistImage::all(); + $response = get(route('api.playlistimage.index', $parameters)); - $response->assertJson( - json_decode( - json_encode( - new PlaylistImageCollection($playlistImages, new Query($parameters)) - ->response() - ->getData() - ), - true + $response->assertJson( + json_decode( + json_encode( + new PlaylistImageCollection($playlistImages, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('images by facet', function () { + $facetFilter = Arr::random(ImageFacet::cases()); + + $parameters = [ + FilterParser::param() => [ + Image::ATTRIBUTE_FACET => $facetFilter->localize(), + ], + IncludeParser::param() => PlaylistImage::RELATION_IMAGE, + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + PlaylistImage::factory() + ->for( + Playlist::factory() + ->for(User::factory()) + ->state([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]) ) - ); - } + ->for(Image::factory()) + ->create(); + }); - /** - * The Playlist Image Index Endpoint shall support sorting resources. - */ - public function testSorts(): void - { - $schema = new PlaylistImageSchema(); + $response = get(route('api.playlistimage.index', $parameters)); - /** @var Sort $sort */ - $sort = collect($schema->fields()) - ->filter(fn (Field $field) => $field instanceof SortableField) - ->map(fn (SortableField $field) => $field->getSort()) - ->random(); + $playlistImages = PlaylistImage::with([ + PlaylistImage::RELATION_IMAGE => function (BelongsTo $query) use ($facetFilter) { + $query->where(Image::ATTRIBUTE_FACET, $facetFilter->value); + }, + ]) + ->get(); - $parameters = [ - SortParser::param() => $sort->format(Arr::random(Direction::cases())), - ]; - - $query = new Query($parameters); - - Collection::times($this->faker->randomDigitNotNull(), function () { - PlaylistImage::factory() - ->for( - Playlist::factory() - ->for(User::factory()) - ->state([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]) - ) - ->for(Image::factory()) - ->create(); - }); - - $response = $this->get(route('api.playlistimage.index', $parameters)); - - $playlistImages = $this->sort(PlaylistImage::query(), $query, $schema)->get(); - - $response->assertJson( - json_decode( - json_encode( - new PlaylistImageCollection($playlistImages, $query) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Playlist Image Index Endpoint shall support filtering by created_at. - */ - public function testCreatedAtFilter(): void - { - $createdFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BasePivot::ATTRIBUTE_CREATED_AT => $createdFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($createdFilter, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - PlaylistImage::factory() - ->for( - Playlist::factory() - ->for(User::factory()) - ->state([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]) - ) - ->for(Image::factory()) - ->create(); - }); - }); - - Carbon::withTestNow($excludedDate, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - PlaylistImage::factory() - ->for( - Playlist::factory() - ->for(User::factory()) - ->state([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]) - ) - ->for(Image::factory()) - ->create(); - }); - }); - - $playlistImages = PlaylistImage::query()->where(BasePivot::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - - $response = $this->get(route('api.playlistimage.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new PlaylistImageCollection($playlistImages, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Playlist Image Index Endpoint shall support filtering by updated_at. - */ - public function testUpdatedAtFilter(): void - { - $updatedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BasePivot::ATTRIBUTE_UPDATED_AT => $updatedFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($updatedFilter, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - PlaylistImage::factory() - ->for( - Playlist::factory() - ->for(User::factory()) - ->state([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]) - ) - ->for(Image::factory()) - ->create(); - }); - }); - - Carbon::withTestNow($excludedDate, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - PlaylistImage::factory() - ->for( - Playlist::factory() - ->for(User::factory()) - ->state([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]) - ) - ->for(Image::factory()) - ->create(); - }); - }); - - $playlistImages = PlaylistImage::query()->where(BasePivot::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - - $response = $this->get(route('api.playlistimage.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new PlaylistImageCollection($playlistImages, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Playlist Image Index Endpoint shall support constrained eager loading of images by facet. - */ - public function testImagesByFacet(): void - { - $facetFilter = Arr::random(ImageFacet::cases()); - - $parameters = [ - FilterParser::param() => [ - Image::ATTRIBUTE_FACET => $facetFilter->localize(), - ], - IncludeParser::param() => PlaylistImage::RELATION_IMAGE, - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { - PlaylistImage::factory() - ->for( - Playlist::factory() - ->for(User::factory()) - ->state([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]) - ) - ->for(Image::factory()) - ->create(); - }); - - $response = $this->get(route('api.playlistimage.index', $parameters)); - - $playlistImages = PlaylistImage::with([ - PlaylistImage::RELATION_IMAGE => function (BelongsTo $query) use ($facetFilter) { - $query->where(Image::ATTRIBUTE_FACET, $facetFilter->value); - }, - ]) - ->get(); - - $response->assertJson( - json_decode( - json_encode( - new PlaylistImageCollection($playlistImages, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response->assertJson( + json_decode( + json_encode( + new PlaylistImageCollection($playlistImages, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Pivot/List/PlaylistImage/PlaylistImageShowTest.php b/tests/Feature/Http/Api/Pivot/List/PlaylistImage/PlaylistImageShowTest.php index 44aa9062b..9b63b363c 100644 --- a/tests/Feature/Http/Api/Pivot/List/PlaylistImage/PlaylistImageShowTest.php +++ b/tests/Feature/Http/Api/Pivot/List/PlaylistImage/PlaylistImageShowTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\List\PlaylistImage; - use App\Enums\Auth\CrudPermission; use App\Enums\Models\List\PlaylistVisibility; use App\Enums\Models\Wiki\ImageFacet; @@ -21,328 +19,285 @@ use App\Models\List\Playlist; use App\Models\Wiki\Image; use App\Pivots\List\PlaylistImage; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Event; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class PlaylistImageShowTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * The Playlist Image Show Endpoint shall return an error if the playlist image does not exist. - */ - public function testNotFound(): void - { - Event::fakeExcept(PlaylistCreated::class); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $playlist = Playlist::factory() - ->for(User::factory()) - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); - $image = Image::factory()->createOne(); +test('not found', function () { + Event::fakeExcept(PlaylistCreated::class); - $response = $this->get(route('api.playlistimage.show', ['playlist' => $playlist, 'image' => $image])); - - $response->assertNotFound(); - } - - /** - * The Playlist Image Show Endpoint shall forbid a private playlist image from being publicly viewed. - */ - public function testPrivatePlaylistImageCannotBePubliclyViewed(): void - { - Event::fakeExcept(PlaylistCreated::class); - - $playlistImage = PlaylistImage::factory() - ->for( - Playlist::factory() - ->for(User::factory()) - ->state([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, - ]) - ) - ->for(Image::factory()) - ->createOne(); - - $response = $this->get(route('api.playlistimage.show', ['playlist' => $playlistImage->playlist, 'image' => $playlistImage->image])); - - $response->assertForbidden(); - } - - /** - * The Playlist Image Show Endpoint shall forbid the user from viewing a private playlist image if not owned. - */ - public function testPrivatePlaylistImageCannotBePubliclyIfNotOwned(): void - { - Event::fakeExcept(PlaylistCreated::class); - - $playlistImage = PlaylistImage::factory() - ->for( - Playlist::factory() - ->for(User::factory()) - ->state([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, - ]) - ) - ->for(Image::factory()) - ->createOne(); - - $user = User::factory()->withPermissions(CrudPermission::VIEW->format(Playlist::class))->createOne(); - - Sanctum::actingAs($user); - - $response = $this->get(route('api.playlistimage.show', ['playlist' => $playlistImage->playlist, 'image' => $playlistImage->image])); - - $response->assertForbidden(); - } - - /** - * The Playlist Image Show Endpoint shall allow a private playlist image to be viewed by the owner. - */ - public function testPrivatePlaylistImageCanBeViewedByOwner(): void - { - Event::fakeExcept(PlaylistCreated::class); - - $user = User::factory()->withPermissions(CrudPermission::VIEW->format(Playlist::class))->createOne(); - - $playlistImage = PlaylistImage::factory() - ->for( - Playlist::factory() - ->for($user) - ->state([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, - ]) - ) - ->for(Image::factory()) - ->createOne(); - - Sanctum::actingAs($user); - - $response = $this->get(route('api.playlistimage.show', ['playlist' => $playlistImage->playlist, 'image' => $playlistImage->image])); - - $response->assertOk(); - } - - /** - * The Playlist Image Show Endpoint shall allow an unlisted playlist image to be viewed. - */ - public function testUnlistedPlaylistImageCanBeViewed(): void - { - Event::fakeExcept(PlaylistCreated::class); - - $playlistImage = PlaylistImage::factory() - ->for( - Playlist::factory() - ->for(User::factory()) - ->state([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::UNLISTED->value, - ]) - ) - ->for(Image::factory()) - ->createOne(); - - $response = $this->get(route('api.playlistimage.show', ['playlist' => $playlistImage->playlist, 'image' => $playlistImage->image])); - - $response->assertOk(); - } - - /** - * The Playlist Image Show Endpoint shall allow a public playlist image to be viewed. - */ - public function testPublicPlaylistCanBeViewed(): void - { - Event::fakeExcept(PlaylistCreated::class); - - $playlistImage = PlaylistImage::factory() - ->for( - Playlist::factory() - ->for(User::factory()) - ->state([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]) - ) - ->for(Image::factory()) - ->createOne(); - - $response = $this->get(route('api.playlistimage.show', ['playlist' => $playlistImage->playlist, 'image' => $playlistImage->image])); - - $response->assertOk(); - } - - /** - * By default, the Playlist Image Show Endpoint shall return an Playlist Image Resource. - */ - public function testDefault(): void - { - Event::fakeExcept(PlaylistCreated::class); - - $playlistImage = PlaylistImage::factory() - ->for( - Playlist::factory() - ->for(User::factory()) - ->state([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]) - ) - ->for(Image::factory()) - ->createOne(); - - $response = $this->get(route('api.playlistimage.show', ['playlist' => $playlistImage->playlist, 'image' => $playlistImage->image])); - - $playlistImage->unsetRelations(); - - $response->assertJson( - json_decode( - json_encode( - new PlaylistImageResource($playlistImage, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Playlist Image Show Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - Event::fakeExcept(PlaylistCreated::class); - - $schema = new PlaylistImageSchema(); - - $allowedIncludes = collect($schema->allowedIncludes()); - - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); - - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; - - $playlistImage = PlaylistImage::factory() - ->for( - Playlist::factory() - ->for(User::factory()) - ->state([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]) - ) - ->for(Image::factory()) - ->createOne(); - - $response = $this->get(route('api.playlistimage.show', ['playlist' => $playlistImage->playlist, 'image' => $playlistImage->image] + $parameters)); - - $playlistImage->unsetRelations()->load($includedPaths->all()); - - $response->assertJson( - json_decode( - json_encode( - new PlaylistImageResource($playlistImage, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Playlist Image Show Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - Event::fakeExcept(PlaylistCreated::class); - - $schema = new PlaylistImageSchema(); - - $fields = collect($schema->fields()); - - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); - - $parameters = [ - FieldParser::param() => [ - PlaylistImageResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; - - $playlistImage = PlaylistImage::factory() - ->for( - Playlist::factory() - ->for(User::factory()) - ->state([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]) - ) - ->for(Image::factory()) - ->createOne(); - - $response = $this->get(route('api.playlistimage.show', ['playlist' => $playlistImage->playlist, 'image' => $playlistImage->image] + $parameters)); - - $playlistImage->unsetRelations(); - - $response->assertJson( - json_decode( - json_encode( - new PlaylistImageResource($playlistImage, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Playlist Image Show Endpoint shall support constrained eager loading of images by facet. - */ - public function testImagesByFacet(): void - { - Event::fakeExcept(PlaylistCreated::class); - - $facetFilter = Arr::random(ImageFacet::cases()); - - $parameters = [ - FilterParser::param() => [ - Image::ATTRIBUTE_FACET => $facetFilter->localize(), - ], - IncludeParser::param() => PlaylistImage::RELATION_IMAGE, - ]; - - $playlistImage = PlaylistImage::factory() - ->for( - Playlist::factory() - ->for(User::factory()) - ->state([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]) - ) - ->for(Image::factory()) - ->createOne(); - - $response = $this->get(route('api.playlistimage.show', ['playlist' => $playlistImage->playlist, 'image' => $playlistImage->image] + $parameters)); - - $playlistImage->unsetRelations()->load([ - PlaylistImage::RELATION_IMAGE => function (BelongsTo $query) use ($facetFilter) { - $query->where(Image::ATTRIBUTE_FACET, $facetFilter->value); - }, + $playlist = Playlist::factory() + ->for(User::factory()) + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, ]); + $image = Image::factory()->createOne(); - $response->assertJson( - json_decode( - json_encode( - new PlaylistImageResource($playlistImage, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response = get(route('api.playlistimage.show', ['playlist' => $playlist, 'image' => $image])); + + $response->assertNotFound(); +}); + +test('private playlist image cannot be publicly viewed', function () { + Event::fakeExcept(PlaylistCreated::class); + + $playlistImage = PlaylistImage::factory() + ->for( + Playlist::factory() + ->for(User::factory()) + ->state([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, + ]) + ) + ->for(Image::factory()) + ->createOne(); + + $response = get(route('api.playlistimage.show', ['playlist' => $playlistImage->playlist, 'image' => $playlistImage->image])); + + $response->assertForbidden(); +}); + +test('private playlist image cannot be publicly if not owned', function () { + Event::fakeExcept(PlaylistCreated::class); + + $playlistImage = PlaylistImage::factory() + ->for( + Playlist::factory() + ->for(User::factory()) + ->state([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, + ]) + ) + ->for(Image::factory()) + ->createOne(); + + $user = User::factory()->withPermissions(CrudPermission::VIEW->format(Playlist::class))->createOne(); + + Sanctum::actingAs($user); + + $response = get(route('api.playlistimage.show', ['playlist' => $playlistImage->playlist, 'image' => $playlistImage->image])); + + $response->assertForbidden(); +}); + +test('private playlist image can be viewed by owner', function () { + Event::fakeExcept(PlaylistCreated::class); + + $user = User::factory()->withPermissions(CrudPermission::VIEW->format(Playlist::class))->createOne(); + + $playlistImage = PlaylistImage::factory() + ->for( + Playlist::factory() + ->for($user) + ->state([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PRIVATE->value, + ]) + ) + ->for(Image::factory()) + ->createOne(); + + Sanctum::actingAs($user); + + $response = get(route('api.playlistimage.show', ['playlist' => $playlistImage->playlist, 'image' => $playlistImage->image])); + + $response->assertOk(); +}); + +test('unlisted playlist image can be viewed', function () { + Event::fakeExcept(PlaylistCreated::class); + + $playlistImage = PlaylistImage::factory() + ->for( + Playlist::factory() + ->for(User::factory()) + ->state([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::UNLISTED->value, + ]) + ) + ->for(Image::factory()) + ->createOne(); + + $response = get(route('api.playlistimage.show', ['playlist' => $playlistImage->playlist, 'image' => $playlistImage->image])); + + $response->assertOk(); +}); + +test('public playlist can be viewed', function () { + Event::fakeExcept(PlaylistCreated::class); + + $playlistImage = PlaylistImage::factory() + ->for( + Playlist::factory() + ->for(User::factory()) + ->state([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]) + ) + ->for(Image::factory()) + ->createOne(); + + $response = get(route('api.playlistimage.show', ['playlist' => $playlistImage->playlist, 'image' => $playlistImage->image])); + + $response->assertOk(); +}); + +test('default', function () { + Event::fakeExcept(PlaylistCreated::class); + + $playlistImage = PlaylistImage::factory() + ->for( + Playlist::factory() + ->for(User::factory()) + ->state([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]) + ) + ->for(Image::factory()) + ->createOne(); + + $response = get(route('api.playlistimage.show', ['playlist' => $playlistImage->playlist, 'image' => $playlistImage->image])); + + $playlistImage->unsetRelations(); + + $response->assertJson( + json_decode( + json_encode( + new PlaylistImageResource($playlistImage, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('allowed include paths', function () { + Event::fakeExcept(PlaylistCreated::class); + + $schema = new PlaylistImageSchema(); + + $allowedIncludes = collect($schema->allowedIncludes()); + + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); + + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; + + $playlistImage = PlaylistImage::factory() + ->for( + Playlist::factory() + ->for(User::factory()) + ->state([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]) + ) + ->for(Image::factory()) + ->createOne(); + + $response = get(route('api.playlistimage.show', ['playlist' => $playlistImage->playlist, 'image' => $playlistImage->image] + $parameters)); + + $playlistImage->unsetRelations()->load($includedPaths->all()); + + $response->assertJson( + json_decode( + json_encode( + new PlaylistImageResource($playlistImage, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sparse fieldsets', function () { + Event::fakeExcept(PlaylistCreated::class); + + $schema = new PlaylistImageSchema(); + + $fields = collect($schema->fields()); + + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + PlaylistImageResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + $playlistImage = PlaylistImage::factory() + ->for( + Playlist::factory() + ->for(User::factory()) + ->state([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]) + ) + ->for(Image::factory()) + ->createOne(); + + $response = get(route('api.playlistimage.show', ['playlist' => $playlistImage->playlist, 'image' => $playlistImage->image] + $parameters)); + + $playlistImage->unsetRelations(); + + $response->assertJson( + json_decode( + json_encode( + new PlaylistImageResource($playlistImage, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('images by facet', function () { + Event::fakeExcept(PlaylistCreated::class); + + $facetFilter = Arr::random(ImageFacet::cases()); + + $parameters = [ + FilterParser::param() => [ + Image::ATTRIBUTE_FACET => $facetFilter->localize(), + ], + IncludeParser::param() => PlaylistImage::RELATION_IMAGE, + ]; + + $playlistImage = PlaylistImage::factory() + ->for( + Playlist::factory() + ->for(User::factory()) + ->state([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]) + ) + ->for(Image::factory()) + ->createOne(); + + $response = get(route('api.playlistimage.show', ['playlist' => $playlistImage->playlist, 'image' => $playlistImage->image] + $parameters)); + + $playlistImage->unsetRelations()->load([ + PlaylistImage::RELATION_IMAGE => function (BelongsTo $query) use ($facetFilter) { + $query->where(Image::ATTRIBUTE_FACET, $facetFilter->value); + }, + ]); + + $response->assertJson( + json_decode( + json_encode( + new PlaylistImageResource($playlistImage, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Pivot/List/PlaylistImage/PlaylistImageStoreTest.php b/tests/Feature/Http/Api/Pivot/List/PlaylistImage/PlaylistImageStoreTest.php index f54846d16..adad20049 100644 --- a/tests/Feature/Http/Api/Pivot/List/PlaylistImage/PlaylistImageStoreTest.php +++ b/tests/Feature/Http/Api/Pivot/List/PlaylistImage/PlaylistImageStoreTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\List\PlaylistImage; - use App\Enums\Auth\CrudPermission; use App\Enums\Auth\SpecialPermission; use App\Events\List\Playlist\PlaylistCreated; @@ -12,139 +10,114 @@ use App\Models\Auth\User; use App\Models\List\Playlist; use App\Models\Wiki\Image; use App\Pivots\List\PlaylistImage; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class PlaylistImageStoreTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\post; - /** - * The Playlist Image Store Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - Event::fakeExcept(PlaylistCreated::class); +uses(Illuminate\Foundation\Testing\WithFaker::class); - Feature::activate(AllowPlaylistManagement::class); +test('protected', function () { + Event::fakeExcept(PlaylistCreated::class); - $playlist = Playlist::factory()->createOne(); - $image = Image::factory()->createOne(); + Feature::activate(AllowPlaylistManagement::class); - $response = $this->post(route('api.playlistimage.store', ['playlist' => $playlist, 'image' => $image])); + $playlist = Playlist::factory()->createOne(); + $image = Image::factory()->createOne(); - $response->assertUnauthorized(); - } + $response = post(route('api.playlistimage.store', ['playlist' => $playlist, 'image' => $image])); - /** - * The Playlist Image Store Endpoint shall forbid users without the create playlist & create image permissions. - */ - public function testForbiddenIfMissingPermission(): void - { - Event::fakeExcept(PlaylistCreated::class); + $response->assertUnauthorized(); +}); - Feature::activate(AllowPlaylistManagement::class); +test('forbidden if missing permission', function () { + Event::fakeExcept(PlaylistCreated::class); - $playlist = Playlist::factory()->createOne(); - $image = Image::factory()->createOne(); + Feature::activate(AllowPlaylistManagement::class); - $user = User::factory()->createOne(); + $playlist = Playlist::factory()->createOne(); + $image = Image::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->post(route('api.playlistimage.store', ['playlist' => $playlist, 'image' => $image])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.playlistimage.store', ['playlist' => $playlist, 'image' => $image])); - /** - * The Playlist Image Store Endpoint shall forbid users from creating playlist images - * if the Allow Playlist Management feature is inactive. - */ - public function testForbiddenIfFlagDisabled(): void - { - Event::fakeExcept(PlaylistCreated::class); + $response->assertForbidden(); +}); - Feature::deactivate(AllowPlaylistManagement::class); +test('forbidden if flag disabled', function () { + Event::fakeExcept(PlaylistCreated::class); - $playlist = Playlist::factory()->createOne(); - $image = Image::factory()->createOne(); + Feature::deactivate(AllowPlaylistManagement::class); - $user = User::factory() - ->withPermissions( - CrudPermission::CREATE->format(Playlist::class), - CrudPermission::CREATE->format(Image::class) - ) - ->createOne(); + $playlist = Playlist::factory()->createOne(); + $image = Image::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::CREATE->format(Playlist::class), + CrudPermission::CREATE->format(Image::class) + ) + ->createOne(); - $response = $this->post(route('api.playlistimage.store', ['playlist' => $playlist, 'image' => $image])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.playlistimage.store', ['playlist' => $playlist, 'image' => $image])); - /** - * The Playlist Image Store Endpoint shall create an playlist image. - */ - public function testCreate(): void - { - Event::fakeExcept(PlaylistCreated::class); + $response->assertForbidden(); +}); - Feature::activate(AllowPlaylistManagement::class); +test('create', function () { + Event::fakeExcept(PlaylistCreated::class); - $image = Image::factory()->createOne(); + Feature::activate(AllowPlaylistManagement::class); - $user = User::factory() - ->withPermissions( - CrudPermission::CREATE->format(Playlist::class), - CrudPermission::CREATE->format(Image::class) - ) - ->createOne(); + $image = Image::factory()->createOne(); - $playlist = Playlist::factory() - ->for($user) - ->createOne(); + $user = User::factory() + ->withPermissions( + CrudPermission::CREATE->format(Playlist::class), + CrudPermission::CREATE->format(Image::class) + ) + ->createOne(); - Sanctum::actingAs($user); + $playlist = Playlist::factory() + ->for($user) + ->createOne(); - $response = $this->post(route('api.playlistimage.store', ['playlist' => $playlist, 'image' => $image])); + Sanctum::actingAs($user); - $response->assertCreated(); - static::assertDatabaseCount(PlaylistImage::class, 1); - } + $response = post(route('api.playlistimage.store', ['playlist' => $playlist, 'image' => $image])); - /** - * Users with the bypass feature flag permission shall be permitted to create playlist images - * even if the Allow Playlist Management feature is inactive. - */ - public function testCreatePermittedForBypass(): void - { - Event::fakeExcept(PlaylistCreated::class); + $response->assertCreated(); + $this->assertDatabaseCount(PlaylistImage::class, 1); +}); - Feature::activate(AllowPlaylistManagement::class, $this->faker->boolean()); +test('create permitted for bypass', function () { + Event::fakeExcept(PlaylistCreated::class); - $image = Image::factory()->createOne(); + Feature::activate(AllowPlaylistManagement::class, fake()->boolean()); - $user = User::factory() - ->withPermissions( - CrudPermission::CREATE->format(Playlist::class), - CrudPermission::CREATE->format(Image::class), - SpecialPermission::BYPASS_FEATURE_FLAGS->value - ) - ->createOne(); + $image = Image::factory()->createOne(); - $playlist = Playlist::factory() - ->for($user) - ->createOne(); + $user = User::factory() + ->withPermissions( + CrudPermission::CREATE->format(Playlist::class), + CrudPermission::CREATE->format(Image::class), + SpecialPermission::BYPASS_FEATURE_FLAGS->value + ) + ->createOne(); - Sanctum::actingAs($user); + $playlist = Playlist::factory() + ->for($user) + ->createOne(); - $response = $this->post(route('api.playlistimage.store', ['playlist' => $playlist, 'image' => $image])); + Sanctum::actingAs($user); - $response->assertCreated(); - } -} + $response = post(route('api.playlistimage.store', ['playlist' => $playlist, 'image' => $image])); + + $response->assertCreated(); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/AnimeImage/AnimeImageDestroyTest.php b/tests/Feature/Http/Api/Pivot/Wiki/AnimeImage/AnimeImageDestroyTest.php index 3a3b4ec0d..4287eea7a 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/AnimeImage/AnimeImageDestroyTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/AnimeImage/AnimeImageDestroyTest.php @@ -2,96 +2,76 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\AnimeImage; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Anime; use App\Models\Wiki\Image; use App\Pivots\Wiki\AnimeImage; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class AnimeImageDestroyTest extends TestCase -{ - /** - * The Anime Image Destroy Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $animeImage = AnimeImage::factory() - ->for(Anime::factory()) - ->for(Image::factory()) - ->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.animeimage.destroy', ['anime' => $animeImage->anime, 'image' => $animeImage->image])); +test('protected', function () { + $animeImage = AnimeImage::factory() + ->for(Anime::factory()) + ->for(Image::factory()) + ->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.animeimage.destroy', ['anime' => $animeImage->anime, 'image' => $animeImage->image])); - /** - * The Anime Image Destroy Endpoint shall forbid users without the delete anime & delete image permissions. - */ - public function testForbidden(): void - { - $animeImage = AnimeImage::factory() - ->for(Anime::factory()) - ->for(Image::factory()) - ->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $animeImage = AnimeImage::factory() + ->for(Anime::factory()) + ->for(Image::factory()) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.animeimage.destroy', ['anime' => $animeImage->anime, 'image' => $animeImage->image])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.animeimage.destroy', ['anime' => $animeImage->anime, 'image' => $animeImage->image])); - /** - * The Anime Image Destroy Endpoint shall return an error if the anime image does not exist. - */ - public function testNotFound(): void - { - $anime = Anime::factory()->createOne(); - $image = Image::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory() - ->withPermissions( - CrudPermission::DELETE->format(Anime::class), - CrudPermission::DELETE->format(Image::class) - ) - ->createOne(); +test('not found', function () { + $anime = Anime::factory()->createOne(); + $image = Image::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::DELETE->format(Anime::class), + CrudPermission::DELETE->format(Image::class) + ) + ->createOne(); - $response = $this->delete(route('api.animeimage.destroy', ['anime' => $anime, 'image' => $image])); + Sanctum::actingAs($user); - $response->assertNotFound(); - } + $response = delete(route('api.animeimage.destroy', ['anime' => $anime, 'image' => $image])); - /** - * The Anime Image Destroy Endpoint shall delete the anime image. - */ - public function testDeleted(): void - { - $animeImage = AnimeImage::factory() - ->for(Anime::factory()) - ->for(Image::factory()) - ->createOne(); + $response->assertNotFound(); +}); - $user = User::factory() - ->withPermissions( - CrudPermission::DELETE->format(Anime::class), - CrudPermission::DELETE->format(Image::class) - ) - ->createOne(); +test('deleted', function () { + $animeImage = AnimeImage::factory() + ->for(Anime::factory()) + ->for(Image::factory()) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::DELETE->format(Anime::class), + CrudPermission::DELETE->format(Image::class) + ) + ->createOne(); - $response = $this->delete(route('api.animeimage.destroy', ['anime' => $animeImage->anime, 'image' => $animeImage->image])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertModelMissing($animeImage); - } -} + $response = delete(route('api.animeimage.destroy', ['anime' => $animeImage->anime, 'image' => $animeImage->image])); + + $response->assertOk(); + $this->assertModelMissing($animeImage); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/AnimeImage/AnimeImageIndexTest.php b/tests/Feature/Http/Api/Pivot/Wiki/AnimeImage/AnimeImageIndexTest.php index 1261fbacd..543964fb7 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/AnimeImage/AnimeImageIndexTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/AnimeImage/AnimeImageIndexTest.php @@ -2,9 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\AnimeImage; - -use App\Concerns\Actions\Http\Api\SortsModels; use App\Contracts\Http\Api\Field\SortableField; use App\Enums\Http\Api\Sort\Direction; use App\Enums\Models\Wiki\AnimeMediaFormat; @@ -29,461 +26,415 @@ use App\Models\Wiki\Image; use App\Pivots\BasePivot; use App\Pivots\Wiki\AnimeImage; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; use Illuminate\Support\Collection; -use Tests\TestCase; -class AnimeImageIndexTest extends TestCase -{ - use SortsModels; - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the Anime Image Index Endpoint shall return a collection of Anime Image Resources. - */ - public function testDefault(): void - { - Collection::times($this->faker->randomDigitNotNull(), function () { +uses(App\Concerns\Actions\Http\Api\SortsModels::class); + +uses(Illuminate\Foundation\Testing\WithFaker::class); + +test('default', function () { + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeImage::factory() + ->for(Anime::factory()) + ->for(Image::factory()) + ->create(); + }); + + $animeImages = AnimeImage::all(); + + $response = get(route('api.animeimage.index')); + + $response->assertJson( + json_decode( + json_encode( + new AnimeImageCollection($animeImages, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('paginated', function () { + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeImage::factory() + ->for(Anime::factory()) + ->for(Image::factory()) + ->create(); + }); + + $response = get(route('api.animeimage.index')); + + $response->assertJsonStructure([ + AnimeImageCollection::$wrap, + 'links', + 'meta', + ]); +}); + +test('allowed include paths', function () { + $schema = new AnimeImageSchema(); + + $allowedIncludes = collect($schema->allowedIncludes()); + + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); + + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeImage::factory() + ->for(Anime::factory()) + ->for(Image::factory()) + ->create(); + }); + + $response = get(route('api.animeimage.index', $parameters)); + + $animeImages = AnimeImage::with($includedPaths->all())->get(); + + $response->assertJson( + json_decode( + json_encode( + new AnimeImageCollection($animeImages, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sparse fieldsets', function () { + $schema = new AnimeImageSchema(); + + $fields = collect($schema->fields()); + + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + AnimeImageResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeImage::factory() + ->for(Anime::factory()) + ->for(Image::factory()) + ->create(); + }); + + $response = get(route('api.animeimage.index', $parameters)); + + $animeImages = AnimeImage::all(); + + $response->assertJson( + json_decode( + json_encode( + new AnimeImageCollection($animeImages, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sorts', function () { + $schema = new AnimeImageSchema(); + + /** @var Sort $sort */ + $sort = collect($schema->fields()) + ->filter(fn (Field $field) => $field instanceof SortableField) + ->map(fn (SortableField $field) => $field->getSort()) + ->random(); + + $parameters = [ + SortParser::param() => $sort->format(Arr::random(Direction::cases())), + ]; + + $query = new Query($parameters); + + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeImage::factory() + ->for(Anime::factory()) + ->for(Image::factory()) + ->create(); + }); + + $response = get(route('api.animeimage.index', $parameters)); + + $animeImages = $this->sort(AnimeImage::query(), $query, $schema)->get(); + + $response->assertJson( + json_decode( + json_encode( + new AnimeImageCollection($animeImages, $query) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('created at filter', function () { + $createdFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BasePivot::ATTRIBUTE_CREATED_AT => $createdFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($createdFilter, function () { + Collection::times(fake()->randomDigitNotNull(), function () { AnimeImage::factory() ->for(Anime::factory()) ->for(Image::factory()) ->create(); }); + }); - $animeImages = AnimeImage::all(); - - $response = $this->get(route('api.animeimage.index')); - - $response->assertJson( - json_decode( - json_encode( - new AnimeImageCollection($animeImages, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Image Index Endpoint shall be paginated. - */ - public function testPaginated(): void - { - Collection::times($this->faker->randomDigitNotNull(), function () { + Carbon::withTestNow($excludedDate, function () { + Collection::times(fake()->randomDigitNotNull(), function () { AnimeImage::factory() ->for(Anime::factory()) ->for(Image::factory()) ->create(); }); + }); - $response = $this->get(route('api.animeimage.index')); + $animeImages = AnimeImage::query()->where(BasePivot::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - $response->assertJsonStructure([ - AnimeImageCollection::$wrap, - 'links', - 'meta', - ]); - } + $response = get(route('api.animeimage.index', $parameters)); - /** - * The Anime Image Index Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new AnimeImageSchema(); + $response->assertJson( + json_decode( + json_encode( + new AnimeImageCollection($animeImages, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('updated at filter', function () { + $updatedFilter = fake()->date(); + $excludedDate = fake()->date(); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $parameters = [ + FilterParser::param() => [ + BasePivot::ATTRIBUTE_UPDATED_AT => $updatedFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { + Carbon::withTestNow($updatedFilter, function () { + Collection::times(fake()->randomDigitNotNull(), function () { AnimeImage::factory() ->for(Anime::factory()) ->for(Image::factory()) ->create(); }); + }); - $response = $this->get(route('api.animeimage.index', $parameters)); - - $animeImages = AnimeImage::with($includedPaths->all())->get(); - - $response->assertJson( - json_decode( - json_encode( - new AnimeImageCollection($animeImages, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Image Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new AnimeImageSchema(); - - $fields = collect($schema->fields()); - - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); - - $parameters = [ - FieldParser::param() => [ - AnimeImageResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { + Carbon::withTestNow($excludedDate, function () { + Collection::times(fake()->randomDigitNotNull(), function () { AnimeImage::factory() ->for(Anime::factory()) ->for(Image::factory()) ->create(); }); + }); - $response = $this->get(route('api.animeimage.index', $parameters)); + $animeImages = AnimeImage::query()->where(BasePivot::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - $animeImages = AnimeImage::all(); + $response = get(route('api.animeimage.index', $parameters)); - $response->assertJson( - json_decode( - json_encode( - new AnimeImageCollection($animeImages, new Query($parameters)) - ->response() - ->getData() - ), - true + $response->assertJson( + json_decode( + json_encode( + new AnimeImageCollection($animeImages, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('images by facet', function () { + $facetFilter = Arr::random(ImageFacet::cases()); + + $parameters = [ + FilterParser::param() => [ + Image::ATTRIBUTE_FACET => $facetFilter->localize(), + ], + IncludeParser::param() => AnimeImage::RELATION_IMAGE, + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeImage::factory() + ->for(Anime::factory()) + ->for(Image::factory()) + ->create(); + }); + + $response = get(route('api.animeimage.index', $parameters)); + + $animeImages = AnimeImage::with([ + AnimeImage::RELATION_IMAGE => function (BelongsTo $query) use ($facetFilter) { + $query->where(Image::ATTRIBUTE_FACET, $facetFilter->value); + }, + ]) + ->get(); + + $response->assertJson( + json_decode( + json_encode( + new AnimeImageCollection($animeImages, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by media format', function () { + $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), + ], + IncludeParser::param() => AnimeImage::RELATION_ANIME, + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeImage::factory() + ->for(Anime::factory()) + ->for(Image::factory()) + ->create(); + }); + + $response = get(route('api.animeimage.index', $parameters)); + + $animeImages = AnimeImage::with([ + AnimeImage::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { + $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); + }, + ]) + ->get(); + + $response->assertJson( + json_decode( + json_encode( + new AnimeImageCollection($animeImages, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by season', function () { + $seasonFilter = Arr::random(AnimeSeason::cases()); + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), + ], + IncludeParser::param() => AnimeImage::RELATION_ANIME, + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeImage::factory() + ->for(Anime::factory()) + ->for(Image::factory()) + ->create(); + }); + + $response = get(route('api.animeimage.index', $parameters)); + + $animeImages = AnimeImage::with([ + AnimeImage::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { + $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); + }, + ]) + ->get(); + + $response->assertJson( + json_decode( + json_encode( + new AnimeImageCollection($animeImages, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by year', function () { + $yearFilter = intval(fake()->year()); + $excludedYear = $yearFilter + 1; + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_YEAR => $yearFilter, + ], + IncludeParser::param() => AnimeImage::RELATION_ANIME, + ]; + + Collection::times(fake()->randomDigitNotNull(), function () use ($yearFilter, $excludedYear) { + AnimeImage::factory() + ->for( + Anime::factory() + ->state([ + Anime::ATTRIBUTE_YEAR => fake()->boolean() ? $yearFilter : $excludedYear, + ]) ) - ); - } + ->for(Image::factory()) + ->create(); + }); - /** - * The Anime Image Index Endpoint shall support sorting resources. - */ - public function testSorts(): void - { - $schema = new AnimeImageSchema(); + $response = get(route('api.animeimage.index', $parameters)); - /** @var Sort $sort */ - $sort = collect($schema->fields()) - ->filter(fn (Field $field) => $field instanceof SortableField) - ->map(fn (SortableField $field) => $field->getSort()) - ->random(); + $animeImages = AnimeImage::with([ + AnimeImage::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { + $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); + }, + ]) + ->get(); - $parameters = [ - SortParser::param() => $sort->format(Arr::random(Direction::cases())), - ]; - - $query = new Query($parameters); - - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeImage::factory() - ->for(Anime::factory()) - ->for(Image::factory()) - ->create(); - }); - - $response = $this->get(route('api.animeimage.index', $parameters)); - - $animeImages = $this->sort(AnimeImage::query(), $query, $schema)->get(); - - $response->assertJson( - json_decode( - json_encode( - new AnimeImageCollection($animeImages, $query) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Image Index Endpoint shall support filtering by created_at. - */ - public function testCreatedAtFilter(): void - { - $createdFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BasePivot::ATTRIBUTE_CREATED_AT => $createdFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($createdFilter, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeImage::factory() - ->for(Anime::factory()) - ->for(Image::factory()) - ->create(); - }); - }); - - Carbon::withTestNow($excludedDate, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeImage::factory() - ->for(Anime::factory()) - ->for(Image::factory()) - ->create(); - }); - }); - - $animeImages = AnimeImage::query()->where(BasePivot::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - - $response = $this->get(route('api.animeimage.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeImageCollection($animeImages, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Image Index Endpoint shall support filtering by updated_at. - */ - public function testUpdatedAtFilter(): void - { - $updatedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BasePivot::ATTRIBUTE_UPDATED_AT => $updatedFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($updatedFilter, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeImage::factory() - ->for(Anime::factory()) - ->for(Image::factory()) - ->create(); - }); - }); - - Carbon::withTestNow($excludedDate, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeImage::factory() - ->for(Anime::factory()) - ->for(Image::factory()) - ->create(); - }); - }); - - $animeImages = AnimeImage::query()->where(BasePivot::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - - $response = $this->get(route('api.animeimage.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeImageCollection($animeImages, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Image Index Endpoint shall support constrained eager loading of images by facet. - */ - public function testImagesByFacet(): void - { - $facetFilter = Arr::random(ImageFacet::cases()); - - $parameters = [ - FilterParser::param() => [ - Image::ATTRIBUTE_FACET => $facetFilter->localize(), - ], - IncludeParser::param() => AnimeImage::RELATION_IMAGE, - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeImage::factory() - ->for(Anime::factory()) - ->for(Image::factory()) - ->create(); - }); - - $response = $this->get(route('api.animeimage.index', $parameters)); - - $animeImages = AnimeImage::with([ - AnimeImage::RELATION_IMAGE => function (BelongsTo $query) use ($facetFilter) { - $query->where(Image::ATTRIBUTE_FACET, $facetFilter->value); - }, - ]) - ->get(); - - $response->assertJson( - json_decode( - json_encode( - new AnimeImageCollection($animeImages, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Image Show Endpoint shall support constrained eager loading of anime by media format. - */ - public function testAnimeByMediaFormat(): void - { - $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), - ], - IncludeParser::param() => AnimeImage::RELATION_ANIME, - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeImage::factory() - ->for(Anime::factory()) - ->for(Image::factory()) - ->create(); - }); - - $response = $this->get(route('api.animeimage.index', $parameters)); - - $animeImages = AnimeImage::with([ - AnimeImage::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { - $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); - }, - ]) - ->get(); - - $response->assertJson( - json_decode( - json_encode( - new AnimeImageCollection($animeImages, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Image Show Endpoint shall support constrained eager loading of anime by season. - */ - public function testAnimeBySeason(): void - { - $seasonFilter = Arr::random(AnimeSeason::cases()); - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), - ], - IncludeParser::param() => AnimeImage::RELATION_ANIME, - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeImage::factory() - ->for(Anime::factory()) - ->for(Image::factory()) - ->create(); - }); - - $response = $this->get(route('api.animeimage.index', $parameters)); - - $animeImages = AnimeImage::with([ - AnimeImage::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { - $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); - }, - ]) - ->get(); - - $response->assertJson( - json_decode( - json_encode( - new AnimeImageCollection($animeImages, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Image Show Endpoint shall support constrained eager loading of anime by year. - */ - public function testAnimeByYear(): void - { - $yearFilter = intval($this->faker->year()); - $excludedYear = $yearFilter + 1; - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_YEAR => $yearFilter, - ], - IncludeParser::param() => AnimeImage::RELATION_ANIME, - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () use ($yearFilter, $excludedYear) { - AnimeImage::factory() - ->for( - Anime::factory() - ->state([ - Anime::ATTRIBUTE_YEAR => $this->faker->boolean() ? $yearFilter : $excludedYear, - ]) - ) - ->for(Image::factory()) - ->create(); - }); - - $response = $this->get(route('api.animeimage.index', $parameters)); - - $animeImages = AnimeImage::with([ - AnimeImage::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { - $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); - }, - ]) - ->get(); - - $response->assertJson( - json_decode( - json_encode( - new AnimeImageCollection($animeImages, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response->assertJson( + json_decode( + json_encode( + new AnimeImageCollection($animeImages, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/AnimeImage/AnimeImageShowTest.php b/tests/Feature/Http/Api/Pivot/Wiki/AnimeImage/AnimeImageShowTest.php index 681158096..9b4a7f1d8 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/AnimeImage/AnimeImageShowTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/AnimeImage/AnimeImageShowTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\AnimeImage; - use App\Enums\Models\Wiki\AnimeMediaFormat; use App\Enums\Models\Wiki\AnimeSeason; use App\Enums\Models\Wiki\ImageFacet; @@ -19,288 +17,253 @@ use App\Models\Wiki\Anime; use App\Models\Wiki\Image; use App\Pivots\Wiki\AnimeImage; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; -use Tests\TestCase; -class AnimeImageShowTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * The Anime Image Show Endpoint shall return an error if the anime image does not exist. - */ - public function testNotFound(): void - { - $anime = Anime::factory()->createOne(); - $image = Image::factory()->createOne(); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response = $this->get(route('api.animeimage.show', ['anime' => $anime, 'image' => $image])); +test('not found', function () { + $anime = Anime::factory()->createOne(); + $image = Image::factory()->createOne(); - $response->assertNotFound(); - } + $response = get(route('api.animeimage.show', ['anime' => $anime, 'image' => $image])); - /** - * By default, the Anime Image Show Endpoint shall return an Anime Image Resource. - */ - public function testDefault(): void - { - $animeImage = AnimeImage::factory() - ->for(Anime::factory()) - ->for(Image::factory()) - ->createOne(); + $response->assertNotFound(); +}); - $response = $this->get(route('api.animeimage.show', ['anime' => $animeImage->anime, 'image' => $animeImage->image])); +test('default', function () { + $animeImage = AnimeImage::factory() + ->for(Anime::factory()) + ->for(Image::factory()) + ->createOne(); - $animeImage->unsetRelations(); + $response = get(route('api.animeimage.show', ['anime' => $animeImage->anime, 'image' => $animeImage->image])); - $response->assertJson( - json_decode( - json_encode( - new AnimeImageResource($animeImage, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $animeImage->unsetRelations(); - /** - * The Anime Image Show Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new AnimeImageSchema(); + $response->assertJson( + json_decode( + json_encode( + new AnimeImageResource($animeImage, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('allowed include paths', function () { + $schema = new AnimeImageSchema(); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $allowedIncludes = collect($schema->allowedIncludes()); - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - $animeImage = AnimeImage::factory() - ->for(Anime::factory()) - ->for(Image::factory()) - ->createOne(); + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; - $response = $this->get(route('api.animeimage.show', ['anime' => $animeImage->anime, 'image' => $animeImage->image] + $parameters)); + $animeImage = AnimeImage::factory() + ->for(Anime::factory()) + ->for(Image::factory()) + ->createOne(); - $animeImage->unsetRelations()->load($includedPaths->all()); + $response = get(route('api.animeimage.show', ['anime' => $animeImage->anime, 'image' => $animeImage->image] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new AnimeImageResource($animeImage, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $animeImage->unsetRelations()->load($includedPaths->all()); - /** - * The Anime Image Show Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new AnimeImageSchema(); + $response->assertJson( + json_decode( + json_encode( + new AnimeImageResource($animeImage, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $fields = collect($schema->fields()); +test('sparse fieldsets', function () { + $schema = new AnimeImageSchema(); - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); + $fields = collect($schema->fields()); - $parameters = [ - FieldParser::param() => [ - AnimeImageResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); - $animeImage = AnimeImage::factory() - ->for(Anime::factory()) - ->for(Image::factory()) - ->createOne(); + $parameters = [ + FieldParser::param() => [ + AnimeImageResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; - $response = $this->get(route('api.animeimage.show', ['anime' => $animeImage->anime, 'image' => $animeImage->image] + $parameters)); + $animeImage = AnimeImage::factory() + ->for(Anime::factory()) + ->for(Image::factory()) + ->createOne(); - $animeImage->unsetRelations(); + $response = get(route('api.animeimage.show', ['anime' => $animeImage->anime, 'image' => $animeImage->image] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new AnimeImageResource($animeImage, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $animeImage->unsetRelations(); - /** - * The Anime Image Show Endpoint shall support constrained eager loading of images by facet. - */ - public function testImagesByFacet(): void - { - $facetFilter = Arr::random(ImageFacet::cases()); + $response->assertJson( + json_decode( + json_encode( + new AnimeImageResource($animeImage, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Image::ATTRIBUTE_FACET => $facetFilter->localize(), - ], - IncludeParser::param() => AnimeImage::RELATION_IMAGE, - ]; +test('images by facet', function () { + $facetFilter = Arr::random(ImageFacet::cases()); - $animeImage = AnimeImage::factory() - ->for(Anime::factory()) - ->for(Image::factory()) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + Image::ATTRIBUTE_FACET => $facetFilter->localize(), + ], + IncludeParser::param() => AnimeImage::RELATION_IMAGE, + ]; - $response = $this->get(route('api.animeimage.show', ['anime' => $animeImage->anime, 'image' => $animeImage->image] + $parameters)); + $animeImage = AnimeImage::factory() + ->for(Anime::factory()) + ->for(Image::factory()) + ->createOne(); - $animeImage->unsetRelations()->load([ - AnimeImage::RELATION_IMAGE => function (BelongsTo $query) use ($facetFilter) { - $query->where(Image::ATTRIBUTE_FACET, $facetFilter->value); - }, - ]); + $response = get(route('api.animeimage.show', ['anime' => $animeImage->anime, 'image' => $animeImage->image] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new AnimeImageResource($animeImage, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $animeImage->unsetRelations()->load([ + AnimeImage::RELATION_IMAGE => function (BelongsTo $query) use ($facetFilter) { + $query->where(Image::ATTRIBUTE_FACET, $facetFilter->value); + }, + ]); - /** - * The Anime Image Show Endpoint shall support constrained eager loading of anime by media format. - */ - public function testAnimeByMediaFormat(): void - { - $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); + $response->assertJson( + json_decode( + json_encode( + new AnimeImageResource($animeImage, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), - ], - IncludeParser::param() => AnimeImage::RELATION_ANIME, - ]; +test('anime by media format', function () { + $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); - $animeImage = AnimeImage::factory() - ->for(Anime::factory()) - ->for(Image::factory()) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), + ], + IncludeParser::param() => AnimeImage::RELATION_ANIME, + ]; - $response = $this->get(route('api.animeimage.show', ['anime' => $animeImage->anime, 'image' => $animeImage->image] + $parameters)); + $animeImage = AnimeImage::factory() + ->for(Anime::factory()) + ->for(Image::factory()) + ->createOne(); - $animeImage->unsetRelations()->load([ - AnimeImage::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { - $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); - }, - ]); + $response = get(route('api.animeimage.show', ['anime' => $animeImage->anime, 'image' => $animeImage->image] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new AnimeImageResource($animeImage, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $animeImage->unsetRelations()->load([ + AnimeImage::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { + $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); + }, + ]); - /** - * The Anime Image Show Endpoint shall support constrained eager loading of anime by season. - */ - public function testAnimeBySeason(): void - { - $seasonFilter = Arr::random(AnimeSeason::cases()); + $response->assertJson( + json_decode( + json_encode( + new AnimeImageResource($animeImage, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), - ], - IncludeParser::param() => AnimeImage::RELATION_ANIME, - ]; +test('anime by season', function () { + $seasonFilter = Arr::random(AnimeSeason::cases()); - $animeImage = AnimeImage::factory() - ->for(Anime::factory()) - ->for(Image::factory()) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), + ], + IncludeParser::param() => AnimeImage::RELATION_ANIME, + ]; - $response = $this->get(route('api.animeimage.show', ['anime' => $animeImage->anime, 'image' => $animeImage->image] + $parameters)); + $animeImage = AnimeImage::factory() + ->for(Anime::factory()) + ->for(Image::factory()) + ->createOne(); - $animeImage->unsetRelations()->load([ - AnimeImage::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { - $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); - }, - ]); + $response = get(route('api.animeimage.show', ['anime' => $animeImage->anime, 'image' => $animeImage->image] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new AnimeImageResource($animeImage, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $animeImage->unsetRelations()->load([ + AnimeImage::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { + $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); + }, + ]); - /** - * The Anime Image Show Endpoint shall support constrained eager loading of anime by year. - */ - public function testAnimeByYear(): void - { - $yearFilter = intval($this->faker->year()); - $excludedYear = $yearFilter + 1; + $response->assertJson( + json_decode( + json_encode( + new AnimeImageResource($animeImage, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_YEAR => $yearFilter, - ], - IncludeParser::param() => AnimeImage::RELATION_ANIME, - ]; +test('anime by year', function () { + $yearFilter = intval(fake()->year()); + $excludedYear = $yearFilter + 1; - $animeImage = AnimeImage::factory() - ->for( - Anime::factory() - ->state([ - Anime::ATTRIBUTE_YEAR => $this->faker->boolean() ? $yearFilter : $excludedYear, - ]) - ) - ->for(Image::factory()) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_YEAR => $yearFilter, + ], + IncludeParser::param() => AnimeImage::RELATION_ANIME, + ]; - $response = $this->get(route('api.animeimage.show', ['anime' => $animeImage->anime, 'image' => $animeImage->image] + $parameters)); + $animeImage = AnimeImage::factory() + ->for( + Anime::factory() + ->state([ + Anime::ATTRIBUTE_YEAR => fake()->boolean() ? $yearFilter : $excludedYear, + ]) + ) + ->for(Image::factory()) + ->createOne(); - $animeImage->unsetRelations()->load([ - AnimeImage::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { - $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); - }, - ]); + $response = get(route('api.animeimage.show', ['anime' => $animeImage->anime, 'image' => $animeImage->image] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new AnimeImageResource($animeImage, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $animeImage->unsetRelations()->load([ + AnimeImage::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { + $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); + }, + ]); + + $response->assertJson( + json_decode( + json_encode( + new AnimeImageResource($animeImage, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/AnimeImage/AnimeImageStoreTest.php b/tests/Feature/Http/Api/Pivot/Wiki/AnimeImage/AnimeImageStoreTest.php index 200b4e21d..3f27ae2c8 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/AnimeImage/AnimeImageStoreTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/AnimeImage/AnimeImageStoreTest.php @@ -2,68 +2,52 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\AnimeImage; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Anime; use App\Models\Wiki\Image; use App\Pivots\Wiki\AnimeImage; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class AnimeImageStoreTest extends TestCase -{ - /** - * The Anime Image Store Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $anime = Anime::factory()->createOne(); - $image = Image::factory()->createOne(); +use function Pest\Laravel\post; - $response = $this->post(route('api.animeimage.store', ['anime' => $anime, 'image' => $image])); +test('protected', function () { + $anime = Anime::factory()->createOne(); + $image = Image::factory()->createOne(); - $response->assertUnauthorized(); - } + $response = post(route('api.animeimage.store', ['anime' => $anime, 'image' => $image])); - /** - * The Anime Image Store Endpoint shall forbid users without the create anime & create image permissions. - */ - public function testForbidden(): void - { - $anime = Anime::factory()->createOne(); - $image = Image::factory()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $anime = Anime::factory()->createOne(); + $image = Image::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->post(route('api.animeimage.store', ['anime' => $anime, 'image' => $image])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.animeimage.store', ['anime' => $anime, 'image' => $image])); - /** - * The Anime Image Store Endpoint shall create an anime image. - */ - public function testCreate(): void - { - $anime = Anime::factory()->createOne(); - $image = Image::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory() - ->withPermissions( - CrudPermission::CREATE->format(Anime::class), - CrudPermission::CREATE->format(Image::class) - ) - ->createOne(); +test('create', function () { + $anime = Anime::factory()->createOne(); + $image = Image::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::CREATE->format(Anime::class), + CrudPermission::CREATE->format(Image::class) + ) + ->createOne(); - $response = $this->post(route('api.animeimage.store', ['anime' => $anime, 'image' => $image])); + Sanctum::actingAs($user); - $response->assertCreated(); - static::assertDatabaseCount(AnimeImage::class, 1); - } -} + $response = post(route('api.animeimage.store', ['anime' => $anime, 'image' => $image])); + + $response->assertCreated(); + $this->assertDatabaseCount(AnimeImage::class, 1); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/AnimeResource/AnimeResourceDestroyTest.php b/tests/Feature/Http/Api/Pivot/Wiki/AnimeResource/AnimeResourceDestroyTest.php index 714db5909..4049599df 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/AnimeResource/AnimeResourceDestroyTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/AnimeResource/AnimeResourceDestroyTest.php @@ -2,96 +2,76 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\AnimeResource; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Anime; use App\Models\Wiki\ExternalResource; use App\Pivots\Wiki\AnimeResource; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class AnimeResourceDestroyTest extends TestCase -{ - /** - * The Anime Resource Destroy Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $animeResource = AnimeResource::factory() - ->for(Anime::factory()) - ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) - ->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.animeresource.destroy', ['anime' => $animeResource->anime, 'resource' => $animeResource->resource])); +test('protected', function () { + $animeResource = AnimeResource::factory() + ->for(Anime::factory()) + ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) + ->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.animeresource.destroy', ['anime' => $animeResource->anime, 'resource' => $animeResource->resource])); - /** - * The Anime Resource Destroy Endpoint shall forbid users without the delete anime & delete resource permissions. - */ - public function testForbidden(): void - { - $animeResource = AnimeResource::factory() - ->for(Anime::factory()) - ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) - ->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $animeResource = AnimeResource::factory() + ->for(Anime::factory()) + ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.animeresource.destroy', ['anime' => $animeResource->anime, 'resource' => $animeResource->resource])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.animeresource.destroy', ['anime' => $animeResource->anime, 'resource' => $animeResource->resource])); - /** - * The Anime Resource Destroy Endpoint shall return an error if the anime resource does not exist. - */ - public function testNotFound(): void - { - $anime = Anime::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory() - ->withPermissions( - CrudPermission::DELETE->format(Anime::class), - CrudPermission::DELETE->format(ExternalResource::class) - ) - ->createOne(); +test('not found', function () { + $anime = Anime::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::DELETE->format(Anime::class), + CrudPermission::DELETE->format(ExternalResource::class) + ) + ->createOne(); - $response = $this->delete(route('api.animeresource.destroy', ['anime' => $anime, 'resource' => $resource])); + Sanctum::actingAs($user); - $response->assertNotFound(); - } + $response = delete(route('api.animeresource.destroy', ['anime' => $anime, 'resource' => $resource])); - /** - * The Anime Resource Destroy Endpoint shall delete the anime resource. - */ - public function testDeleted(): void - { - $animeResource = AnimeResource::factory() - ->for(Anime::factory()) - ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) - ->createOne(); + $response->assertNotFound(); +}); - $user = User::factory() - ->withPermissions( - CrudPermission::DELETE->format(Anime::class), - CrudPermission::DELETE->format(ExternalResource::class) - ) - ->createOne(); +test('deleted', function () { + $animeResource = AnimeResource::factory() + ->for(Anime::factory()) + ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::DELETE->format(Anime::class), + CrudPermission::DELETE->format(ExternalResource::class) + ) + ->createOne(); - $response = $this->delete(route('api.animeresource.destroy', ['anime' => $animeResource->anime, 'resource' => $animeResource->resource])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertModelMissing($animeResource); - } -} + $response = delete(route('api.animeresource.destroy', ['anime' => $animeResource->anime, 'resource' => $animeResource->resource])); + + $response->assertOk(); + $this->assertModelMissing($animeResource); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/AnimeResource/AnimeResourceIndexTest.php b/tests/Feature/Http/Api/Pivot/Wiki/AnimeResource/AnimeResourceIndexTest.php index 17ce292b5..5f2ff2786 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/AnimeResource/AnimeResourceIndexTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/AnimeResource/AnimeResourceIndexTest.php @@ -2,9 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\AnimeResource; - -use App\Concerns\Actions\Http\Api\SortsModels; use App\Contracts\Http\Api\Field\SortableField; use App\Enums\Http\Api\Sort\Direction; use App\Enums\Models\Wiki\AnimeMediaFormat; @@ -29,461 +26,415 @@ use App\Models\Wiki\ExternalResource; use App\Pivots\BasePivot; use App\Pivots\Wiki\AnimeResource; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; use Illuminate\Support\Collection; -use Tests\TestCase; -class AnimeResourceIndexTest extends TestCase -{ - use SortsModels; - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the Anime Resource Index Endpoint shall return a collection of Anime Resource Resources. - */ - public function testDefault(): void - { - Collection::times($this->faker->randomDigitNotNull(), function () { +uses(App\Concerns\Actions\Http\Api\SortsModels::class); + +uses(Illuminate\Foundation\Testing\WithFaker::class); + +test('default', function () { + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeResource::factory() + ->for(Anime::factory()) + ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) + ->create(); + }); + + $animeResources = AnimeResource::all(); + + $response = get(route('api.animeresource.index')); + + $response->assertJson( + json_decode( + json_encode( + new AnimeResourceCollection($animeResources, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('paginated', function () { + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeResource::factory() + ->for(Anime::factory()) + ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) + ->create(); + }); + + $response = get(route('api.animeresource.index')); + + $response->assertJsonStructure([ + AnimeResourceCollection::$wrap, + 'links', + 'meta', + ]); +}); + +test('allowed include paths', function () { + $schema = new AnimeResourceSchema(); + + $allowedIncludes = collect($schema->allowedIncludes()); + + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); + + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeResource::factory() + ->for(Anime::factory()) + ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) + ->create(); + }); + + $response = get(route('api.animeresource.index', $parameters)); + + $animeResources = AnimeResource::with($includedPaths->all())->get(); + + $response->assertJson( + json_decode( + json_encode( + new AnimeResourceCollection($animeResources, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sparse fieldsets', function () { + $schema = new AnimeResourceSchema(); + + $fields = collect($schema->fields()); + + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + AnimeResourceResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeResource::factory() + ->for(Anime::factory()) + ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) + ->create(); + }); + + $response = get(route('api.animeresource.index', $parameters)); + + $animeResources = AnimeResource::all(); + + $response->assertJson( + json_decode( + json_encode( + new AnimeResourceCollection($animeResources, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sorts', function () { + $schema = new AnimeResourceSchema(); + + /** @var Sort $sort */ + $sort = collect($schema->fields()) + ->filter(fn (Field $field) => $field instanceof SortableField) + ->map(fn (SortableField $field) => $field->getSort()) + ->random(); + + $parameters = [ + SortParser::param() => $sort->format(Arr::random(Direction::cases())), + ]; + + $query = new Query($parameters); + + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeResource::factory() + ->for(Anime::factory()) + ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) + ->create(); + }); + + $response = get(route('api.animeresource.index', $parameters)); + + $animeResources = $this->sort(AnimeResource::query(), $query, $schema)->get(); + + $response->assertJson( + json_decode( + json_encode( + new AnimeResourceCollection($animeResources, $query) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('created at filter', function () { + $createdFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BasePivot::ATTRIBUTE_CREATED_AT => $createdFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($createdFilter, function () { + Collection::times(fake()->randomDigitNotNull(), function () { AnimeResource::factory() ->for(Anime::factory()) ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) ->create(); }); + }); - $animeResources = AnimeResource::all(); - - $response = $this->get(route('api.animeresource.index')); - - $response->assertJson( - json_decode( - json_encode( - new AnimeResourceCollection($animeResources, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * Anime Resource Index Endpoint shall be paginated. - */ - public function testPaginated(): void - { - Collection::times($this->faker->randomDigitNotNull(), function () { + Carbon::withTestNow($excludedDate, function () { + Collection::times(fake()->randomDigitNotNull(), function () { AnimeResource::factory() ->for(Anime::factory()) ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) ->create(); }); + }); - $response = $this->get(route('api.animeresource.index')); + $animeResources = AnimeResource::query()->where(BasePivot::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - $response->assertJsonStructure([ - AnimeResourceCollection::$wrap, - 'links', - 'meta', - ]); - } + $response = get(route('api.animeresource.index', $parameters)); - /** - * The Anime Resource Index Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new AnimeResourceSchema(); + $response->assertJson( + json_decode( + json_encode( + new AnimeResourceCollection($animeResources, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('updated at filter', function () { + $updatedFilter = fake()->date(); + $excludedDate = fake()->date(); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $parameters = [ + FilterParser::param() => [ + BasePivot::ATTRIBUTE_UPDATED_AT => $updatedFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { + Carbon::withTestNow($updatedFilter, function () { + Collection::times(fake()->randomDigitNotNull(), function () { AnimeResource::factory() ->for(Anime::factory()) ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) ->create(); }); + }); - $response = $this->get(route('api.animeresource.index', $parameters)); - - $animeResources = AnimeResource::with($includedPaths->all())->get(); - - $response->assertJson( - json_decode( - json_encode( - new AnimeResourceCollection($animeResources, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Resource Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new AnimeResourceSchema(); - - $fields = collect($schema->fields()); - - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); - - $parameters = [ - FieldParser::param() => [ - AnimeResourceResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { + Carbon::withTestNow($excludedDate, function () { + Collection::times(fake()->randomDigitNotNull(), function () { AnimeResource::factory() ->for(Anime::factory()) ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) ->create(); }); + }); - $response = $this->get(route('api.animeresource.index', $parameters)); + $animeResources = AnimeResource::query()->where(BasePivot::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - $animeResources = AnimeResource::all(); + $response = get(route('api.animeresource.index', $parameters)); - $response->assertJson( - json_decode( - json_encode( - new AnimeResourceCollection($animeResources, new Query($parameters)) - ->response() - ->getData() - ), - true + $response->assertJson( + json_decode( + json_encode( + new AnimeResourceCollection($animeResources, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('resources by site', function () { + $siteFilter = Arr::random(ResourceSite::cases()); + + $parameters = [ + FilterParser::param() => [ + ExternalResource::ATTRIBUTE_SITE => $siteFilter->localize(), + ], + IncludeParser::param() => AnimeResource::RELATION_RESOURCE, + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeResource::factory() + ->for(Anime::factory()) + ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) + ->create(); + }); + + $response = get(route('api.animeresource.index', $parameters)); + + $animeResources = AnimeResource::with([ + AnimeResource::RELATION_RESOURCE => function (BelongsTo $query) use ($siteFilter) { + $query->where(ExternalResource::ATTRIBUTE_SITE, $siteFilter->value); + }, + ]) + ->get(); + + $response->assertJson( + json_decode( + json_encode( + new AnimeResourceCollection($animeResources, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by media format', function () { + $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), + ], + IncludeParser::param() => AnimeResource::RELATION_ANIME, + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeResource::factory() + ->for(Anime::factory()) + ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) + ->create(); + }); + + $response = get(route('api.animeresource.index', $parameters)); + + $animeResources = AnimeResource::with([ + AnimeResource::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { + $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); + }, + ]) + ->get(); + + $response->assertJson( + json_decode( + json_encode( + new AnimeResourceCollection($animeResources, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by season', function () { + $seasonFilter = Arr::random(AnimeSeason::cases()); + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), + ], + IncludeParser::param() => AnimeResource::RELATION_ANIME, + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeResource::factory() + ->for(Anime::factory()) + ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) + ->create(); + }); + + $response = get(route('api.animeresource.index', $parameters)); + + $animeResources = AnimeResource::with([ + AnimeResource::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { + $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); + }, + ]) + ->get(); + + $response->assertJson( + json_decode( + json_encode( + new AnimeResourceCollection($animeResources, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by year', function () { + $yearFilter = intval(fake()->year()); + $excludedYear = $yearFilter + 1; + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_YEAR => $yearFilter, + ], + IncludeParser::param() => AnimeResource::RELATION_ANIME, + ]; + + Collection::times(fake()->randomDigitNotNull(), function () use ($yearFilter, $excludedYear) { + AnimeResource::factory() + ->for( + Anime::factory() + ->state([ + Anime::ATTRIBUTE_YEAR => fake()->boolean() ? $yearFilter : $excludedYear, + ]) ) - ); - } + ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) + ->create(); + }); - /** - * The Anime Resource Index Endpoint shall support sorting resources. - */ - public function testSorts(): void - { - $schema = new AnimeResourceSchema(); + $response = get(route('api.animeresource.index', $parameters)); - /** @var Sort $sort */ - $sort = collect($schema->fields()) - ->filter(fn (Field $field) => $field instanceof SortableField) - ->map(fn (SortableField $field) => $field->getSort()) - ->random(); + $animeResources = AnimeResource::with([ + AnimeResource::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { + $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); + }, + ]) + ->get(); - $parameters = [ - SortParser::param() => $sort->format(Arr::random(Direction::cases())), - ]; - - $query = new Query($parameters); - - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeResource::factory() - ->for(Anime::factory()) - ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) - ->create(); - }); - - $response = $this->get(route('api.animeresource.index', $parameters)); - - $animeResources = $this->sort(AnimeResource::query(), $query, $schema)->get(); - - $response->assertJson( - json_decode( - json_encode( - new AnimeResourceCollection($animeResources, $query) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Resource Index Endpoint shall support filtering by created_at. - */ - public function testCreatedAtFilter(): void - { - $createdFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BasePivot::ATTRIBUTE_CREATED_AT => $createdFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($createdFilter, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeResource::factory() - ->for(Anime::factory()) - ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) - ->create(); - }); - }); - - Carbon::withTestNow($excludedDate, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeResource::factory() - ->for(Anime::factory()) - ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) - ->create(); - }); - }); - - $animeResources = AnimeResource::query()->where(BasePivot::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - - $response = $this->get(route('api.animeresource.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeResourceCollection($animeResources, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Resource Index Endpoint shall support filtering by updated_at. - */ - public function testUpdatedAtFilter(): void - { - $updatedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BasePivot::ATTRIBUTE_UPDATED_AT => $updatedFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($updatedFilter, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeResource::factory() - ->for(Anime::factory()) - ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) - ->create(); - }); - }); - - Carbon::withTestNow($excludedDate, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeResource::factory() - ->for(Anime::factory()) - ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) - ->create(); - }); - }); - - $animeResources = AnimeResource::query()->where(BasePivot::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - - $response = $this->get(route('api.animeresource.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeResourceCollection($animeResources, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Resource Index Endpoint shall support constrained eager loading of resources by site. - */ - public function testResourcesBySite(): void - { - $siteFilter = Arr::random(ResourceSite::cases()); - - $parameters = [ - FilterParser::param() => [ - ExternalResource::ATTRIBUTE_SITE => $siteFilter->localize(), - ], - IncludeParser::param() => AnimeResource::RELATION_RESOURCE, - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeResource::factory() - ->for(Anime::factory()) - ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) - ->create(); - }); - - $response = $this->get(route('api.animeresource.index', $parameters)); - - $animeResources = AnimeResource::with([ - AnimeResource::RELATION_RESOURCE => function (BelongsTo $query) use ($siteFilter) { - $query->where(ExternalResource::ATTRIBUTE_SITE, $siteFilter->value); - }, - ]) - ->get(); - - $response->assertJson( - json_decode( - json_encode( - new AnimeResourceCollection($animeResources, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Resource Show Endpoint shall support constrained eager loading of anime by media format. - */ - public function testAnimeByMediaFormat(): void - { - $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), - ], - IncludeParser::param() => AnimeResource::RELATION_ANIME, - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeResource::factory() - ->for(Anime::factory()) - ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) - ->create(); - }); - - $response = $this->get(route('api.animeresource.index', $parameters)); - - $animeResources = AnimeResource::with([ - AnimeResource::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { - $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); - }, - ]) - ->get(); - - $response->assertJson( - json_decode( - json_encode( - new AnimeResourceCollection($animeResources, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Resource Show Endpoint shall support constrained eager loading of anime by season. - */ - public function testAnimeBySeason(): void - { - $seasonFilter = Arr::random(AnimeSeason::cases()); - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), - ], - IncludeParser::param() => AnimeResource::RELATION_ANIME, - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeResource::factory() - ->for(Anime::factory()) - ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) - ->create(); - }); - - $response = $this->get(route('api.animeresource.index', $parameters)); - - $animeResources = AnimeResource::with([ - AnimeResource::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { - $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); - }, - ]) - ->get(); - - $response->assertJson( - json_decode( - json_encode( - new AnimeResourceCollection($animeResources, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Resource Show Endpoint shall support constrained eager loading of anime by year. - */ - public function testAnimeByYear(): void - { - $yearFilter = intval($this->faker->year()); - $excludedYear = $yearFilter + 1; - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_YEAR => $yearFilter, - ], - IncludeParser::param() => AnimeResource::RELATION_ANIME, - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () use ($yearFilter, $excludedYear) { - AnimeResource::factory() - ->for( - Anime::factory() - ->state([ - Anime::ATTRIBUTE_YEAR => $this->faker->boolean() ? $yearFilter : $excludedYear, - ]) - ) - ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) - ->create(); - }); - - $response = $this->get(route('api.animeresource.index', $parameters)); - - $animeResources = AnimeResource::with([ - AnimeResource::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { - $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); - }, - ]) - ->get(); - - $response->assertJson( - json_decode( - json_encode( - new AnimeResourceCollection($animeResources, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response->assertJson( + json_decode( + json_encode( + new AnimeResourceCollection($animeResources, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/AnimeResource/AnimeResourceShowTest.php b/tests/Feature/Http/Api/Pivot/Wiki/AnimeResource/AnimeResourceShowTest.php index 9d37079fc..42856f922 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/AnimeResource/AnimeResourceShowTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/AnimeResource/AnimeResourceShowTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\AnimeResource; - use App\Enums\Models\Wiki\AnimeMediaFormat; use App\Enums\Models\Wiki\AnimeSeason; use App\Enums\Models\Wiki\ResourceSite; @@ -19,288 +17,253 @@ use App\Models\Wiki\Anime; use App\Models\Wiki\ExternalResource; use App\Pivots\Wiki\AnimeResource; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; -use Tests\TestCase; -class AnimeResourceShowTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * The Anime Resource Show Endpoint shall return an error if the anime resource does not exist. - */ - public function testNotFound(): void - { - $anime = Anime::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response = $this->get(route('api.animeresource.show', ['anime' => $anime, 'resource' => $resource])); +test('not found', function () { + $anime = Anime::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - $response->assertNotFound(); - } + $response = get(route('api.animeresource.show', ['anime' => $anime, 'resource' => $resource])); - /** - * By default, the Anime Resource Show Endpoint shall return an Anime Resource Resource. - */ - public function testDefault(): void - { - $animeResource = AnimeResource::factory() - ->for(Anime::factory()) - ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) - ->createOne(); + $response->assertNotFound(); +}); - $response = $this->get(route('api.animeresource.show', ['anime' => $animeResource->anime, 'resource' => $animeResource->resource])); +test('default', function () { + $animeResource = AnimeResource::factory() + ->for(Anime::factory()) + ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) + ->createOne(); - $animeResource->unsetRelations(); + $response = get(route('api.animeresource.show', ['anime' => $animeResource->anime, 'resource' => $animeResource->resource])); - $response->assertJson( - json_decode( - json_encode( - new AnimeResourceResource($animeResource, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $animeResource->unsetRelations(); - /** - * The Anime Resource Show Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new AnimeResourceSchema(); + $response->assertJson( + json_decode( + json_encode( + new AnimeResourceResource($animeResource, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('allowed include paths', function () { + $schema = new AnimeResourceSchema(); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $allowedIncludes = collect($schema->allowedIncludes()); - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - $animeResource = AnimeResource::factory() - ->for(Anime::factory()) - ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) - ->createOne(); + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; - $response = $this->get(route('api.animeresource.show', ['anime' => $animeResource->anime, 'resource' => $animeResource->resource] + $parameters)); + $animeResource = AnimeResource::factory() + ->for(Anime::factory()) + ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) + ->createOne(); - $animeResource->unsetRelations()->load($includedPaths->all()); + $response = get(route('api.animeresource.show', ['anime' => $animeResource->anime, 'resource' => $animeResource->resource] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new AnimeResourceResource($animeResource, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $animeResource->unsetRelations()->load($includedPaths->all()); - /** - * The Anime Resource Show Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new AnimeResourceSchema(); + $response->assertJson( + json_decode( + json_encode( + new AnimeResourceResource($animeResource, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $fields = collect($schema->fields()); +test('sparse fieldsets', function () { + $schema = new AnimeResourceSchema(); - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); + $fields = collect($schema->fields()); - $parameters = [ - FieldParser::param() => [ - AnimeResourceResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); - $animeResource = AnimeResource::factory() - ->for(Anime::factory()) - ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) - ->createOne(); + $parameters = [ + FieldParser::param() => [ + AnimeResourceResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; - $response = $this->get(route('api.animeresource.show', ['anime' => $animeResource->anime, 'resource' => $animeResource->resource] + $parameters)); + $animeResource = AnimeResource::factory() + ->for(Anime::factory()) + ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) + ->createOne(); - $animeResource->unsetRelations(); + $response = get(route('api.animeresource.show', ['anime' => $animeResource->anime, 'resource' => $animeResource->resource] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new AnimeResourceResource($animeResource, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $animeResource->unsetRelations(); - /** - * The Anime Resource Show Endpoint shall support constrained eager loading of resources by site. - */ - public function testResourcesBySite(): void - { - $siteFilter = Arr::random(ResourceSite::cases()); + $response->assertJson( + json_decode( + json_encode( + new AnimeResourceResource($animeResource, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - ExternalResource::ATTRIBUTE_SITE => $siteFilter->localize(), - ], - IncludeParser::param() => AnimeResource::RELATION_RESOURCE, - ]; +test('resources by site', function () { + $siteFilter = Arr::random(ResourceSite::cases()); - $animeResource = AnimeResource::factory() - ->for(Anime::factory()) - ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + ExternalResource::ATTRIBUTE_SITE => $siteFilter->localize(), + ], + IncludeParser::param() => AnimeResource::RELATION_RESOURCE, + ]; - $response = $this->get(route('api.animeresource.show', ['anime' => $animeResource->anime, 'resource' => $animeResource->resource] + $parameters)); + $animeResource = AnimeResource::factory() + ->for(Anime::factory()) + ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) + ->createOne(); - $animeResource->unsetRelations()->load([ - AnimeResource::RELATION_RESOURCE => function (BelongsTo $query) use ($siteFilter) { - $query->where(ExternalResource::ATTRIBUTE_SITE, $siteFilter->value); - }, - ]); + $response = get(route('api.animeresource.show', ['anime' => $animeResource->anime, 'resource' => $animeResource->resource] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new AnimeResourceResource($animeResource, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $animeResource->unsetRelations()->load([ + AnimeResource::RELATION_RESOURCE => function (BelongsTo $query) use ($siteFilter) { + $query->where(ExternalResource::ATTRIBUTE_SITE, $siteFilter->value); + }, + ]); - /** - * The Anime Resource Show Endpoint shall support constrained eager loading of anime by media format. - */ - public function testAnimeByMediaFormat(): void - { - $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); + $response->assertJson( + json_decode( + json_encode( + new AnimeResourceResource($animeResource, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), - ], - IncludeParser::param() => AnimeResource::RELATION_ANIME, - ]; +test('anime by media format', function () { + $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); - $animeResource = AnimeResource::factory() - ->for(Anime::factory()) - ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), + ], + IncludeParser::param() => AnimeResource::RELATION_ANIME, + ]; - $response = $this->get(route('api.animeresource.show', ['anime' => $animeResource->anime, 'resource' => $animeResource->resource] + $parameters)); + $animeResource = AnimeResource::factory() + ->for(Anime::factory()) + ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) + ->createOne(); - $animeResource->unsetRelations()->load([ - AnimeResource::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { - $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); - }, - ]); + $response = get(route('api.animeresource.show', ['anime' => $animeResource->anime, 'resource' => $animeResource->resource] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new AnimeResourceResource($animeResource, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $animeResource->unsetRelations()->load([ + AnimeResource::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { + $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); + }, + ]); - /** - * The Anime Resource Show Endpoint shall support constrained eager loading of anime by season. - */ - public function testAnimeBySeason(): void - { - $seasonFilter = Arr::random(AnimeSeason::cases()); + $response->assertJson( + json_decode( + json_encode( + new AnimeResourceResource($animeResource, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), - ], - IncludeParser::param() => AnimeResource::RELATION_ANIME, - ]; +test('anime by season', function () { + $seasonFilter = Arr::random(AnimeSeason::cases()); - $animeResource = AnimeResource::factory() - ->for(Anime::factory()) - ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), + ], + IncludeParser::param() => AnimeResource::RELATION_ANIME, + ]; - $response = $this->get(route('api.animeresource.show', ['anime' => $animeResource->anime, 'resource' => $animeResource->resource] + $parameters)); + $animeResource = AnimeResource::factory() + ->for(Anime::factory()) + ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) + ->createOne(); - $animeResource->unsetRelations()->load([ - AnimeResource::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { - $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); - }, - ]); + $response = get(route('api.animeresource.show', ['anime' => $animeResource->anime, 'resource' => $animeResource->resource] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new AnimeResourceResource($animeResource, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $animeResource->unsetRelations()->load([ + AnimeResource::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { + $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); + }, + ]); - /** - * The Anime Resource Show Endpoint shall support constrained eager loading of anime by year. - */ - public function testAnimeByYear(): void - { - $yearFilter = intval($this->faker->year()); - $excludedYear = $yearFilter + 1; + $response->assertJson( + json_decode( + json_encode( + new AnimeResourceResource($animeResource, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_YEAR => $yearFilter, - ], - IncludeParser::param() => AnimeResource::RELATION_ANIME, - ]; +test('anime by year', function () { + $yearFilter = intval(fake()->year()); + $excludedYear = $yearFilter + 1; - $animeResource = AnimeResource::factory() - ->for( - Anime::factory() - ->state([ - Anime::ATTRIBUTE_YEAR => $this->faker->boolean() ? $yearFilter : $excludedYear, - ]) - ) - ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_YEAR => $yearFilter, + ], + IncludeParser::param() => AnimeResource::RELATION_ANIME, + ]; - $response = $this->get(route('api.animeresource.show', ['anime' => $animeResource->anime, 'resource' => $animeResource->resource] + $parameters)); + $animeResource = AnimeResource::factory() + ->for( + Anime::factory() + ->state([ + Anime::ATTRIBUTE_YEAR => fake()->boolean() ? $yearFilter : $excludedYear, + ]) + ) + ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) + ->createOne(); - $animeResource->unsetRelations()->load([ - AnimeResource::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { - $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); - }, - ]); + $response = get(route('api.animeresource.show', ['anime' => $animeResource->anime, 'resource' => $animeResource->resource] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new AnimeResourceResource($animeResource, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $animeResource->unsetRelations()->load([ + AnimeResource::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { + $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); + }, + ]); + + $response->assertJson( + json_decode( + json_encode( + new AnimeResourceResource($animeResource, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/AnimeResource/AnimeResourceStoreTest.php b/tests/Feature/Http/Api/Pivot/Wiki/AnimeResource/AnimeResourceStoreTest.php index cb88ee9b4..6dcc27295 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/AnimeResource/AnimeResourceStoreTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/AnimeResource/AnimeResourceStoreTest.php @@ -2,74 +2,58 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\AnimeResource; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Anime; use App\Models\Wiki\ExternalResource; use App\Pivots\Wiki\AnimeResource; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class AnimeResourceStoreTest extends TestCase -{ - /** - * The Anime Resource Store Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $anime = Anime::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); +use function Pest\Laravel\post; - $parameters = AnimeResource::factory()->raw(); +test('protected', function () { + $anime = Anime::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - $response = $this->post(route('api.animeresource.store', ['anime' => $anime, 'resource' => $resource] + $parameters)); + $parameters = AnimeResource::factory()->raw(); - $response->assertUnauthorized(); - } + $response = post(route('api.animeresource.store', ['anime' => $anime, 'resource' => $resource] + $parameters)); - /** - * The Anime Resource Store Endpoint shall forbid users without the create anime & create resource permissions. - */ - public function testForbidden(): void - { - $anime = Anime::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); + $response->assertUnauthorized(); +}); - $parameters = AnimeResource::factory()->raw(); +test('forbidden', function () { + $anime = Anime::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - $user = User::factory()->createOne(); + $parameters = AnimeResource::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->post(route('api.animeresource.store', ['anime' => $anime, 'resource' => $resource] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.animeresource.store', ['anime' => $anime, 'resource' => $resource] + $parameters)); - /** - * The Anime Resource Store Endpoint shall create an anime resource. - */ - public function testCreate(): void - { - $anime = Anime::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); + $response->assertForbidden(); +}); - $parameters = AnimeResource::factory()->raw(); +test('create', function () { + $anime = Anime::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - $user = User::factory() - ->withPermissions( - CrudPermission::CREATE->format(Anime::class), - CrudPermission::CREATE->format(ExternalResource::class) - ) - ->createOne(); + $parameters = AnimeResource::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::CREATE->format(Anime::class), + CrudPermission::CREATE->format(ExternalResource::class) + ) + ->createOne(); - $response = $this->post(route('api.animeresource.store', ['anime' => $anime, 'resource' => $resource] + $parameters)); + Sanctum::actingAs($user); - $response->assertCreated(); - static::assertDatabaseCount(AnimeResource::class, 1); - } -} + $response = post(route('api.animeresource.store', ['anime' => $anime, 'resource' => $resource] + $parameters)); + + $response->assertCreated(); + $this->assertDatabaseCount(AnimeResource::class, 1); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/AnimeResource/AnimeResourceUpdateTest.php b/tests/Feature/Http/Api/Pivot/Wiki/AnimeResource/AnimeResourceUpdateTest.php index a70bde64c..4b1d86ec3 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/AnimeResource/AnimeResourceUpdateTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/AnimeResource/AnimeResourceUpdateTest.php @@ -2,79 +2,63 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\AnimeResource; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Anime; use App\Models\Wiki\ExternalResource; use App\Pivots\Wiki\AnimeResource; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class AnimeResourceUpdateTest extends TestCase -{ - /** - * The Anime Resource Update Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $animeResource = AnimeResource::factory() - ->for(Anime::factory()) - ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) - ->createOne(); +use function Pest\Laravel\put; - $parameters = AnimeResource::factory()->raw(); +test('protected', function () { + $animeResource = AnimeResource::factory() + ->for(Anime::factory()) + ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) + ->createOne(); - $response = $this->put(route('api.animeresource.update', ['anime' => $animeResource->anime, 'resource' => $animeResource->resource] + $parameters)); + $parameters = AnimeResource::factory()->raw(); - $response->assertUnauthorized(); - } + $response = put(route('api.animeresource.update', ['anime' => $animeResource->anime, 'resource' => $animeResource->resource] + $parameters)); - /** - * The Anime Resource Update Endpoint shall forbid users without the update anime & update resource permissions. - */ - public function testForbidden(): void - { - $animeResource = AnimeResource::factory() - ->for(Anime::factory()) - ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) - ->createOne(); + $response->assertUnauthorized(); +}); - $parameters = AnimeResource::factory()->raw(); +test('forbidden', function () { + $animeResource = AnimeResource::factory() + ->for(Anime::factory()) + ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) + ->createOne(); - $user = User::factory()->createOne(); + $parameters = AnimeResource::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->put(route('api.animeresource.update', ['anime' => $animeResource->anime, 'resource' => $animeResource->resource] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.animeresource.update', ['anime' => $animeResource->anime, 'resource' => $animeResource->resource] + $parameters)); - /** - * The Anime Resource Update Endpoint shall update an anime resource. - */ - public function testUpdate(): void - { - $animeResource = AnimeResource::factory() - ->for(Anime::factory()) - ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) - ->createOne(); + $response->assertForbidden(); +}); - $parameters = AnimeResource::factory()->raw(); +test('update', function () { + $animeResource = AnimeResource::factory() + ->for(Anime::factory()) + ->for(ExternalResource::factory(), AnimeResource::RELATION_RESOURCE) + ->createOne(); - $user = User::factory() - ->withPermissions( - CrudPermission::UPDATE->format(Anime::class), - CrudPermission::UPDATE->format(ExternalResource::class) - ) - ->createOne(); + $parameters = AnimeResource::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::UPDATE->format(Anime::class), + CrudPermission::UPDATE->format(ExternalResource::class) + ) + ->createOne(); - $response = $this->put(route('api.animeresource.update', ['anime' => $animeResource->anime, 'resource' => $animeResource->resource] + $parameters)); + Sanctum::actingAs($user); - $response->assertOk(); - } -} + $response = put(route('api.animeresource.update', ['anime' => $animeResource->anime, 'resource' => $animeResource->resource] + $parameters)); + + $response->assertOk(); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/AnimeSeries/AnimeSeriesDestroyTest.php b/tests/Feature/Http/Api/Pivot/Wiki/AnimeSeries/AnimeSeriesDestroyTest.php index fa89be8b9..d20f19634 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/AnimeSeries/AnimeSeriesDestroyTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/AnimeSeries/AnimeSeriesDestroyTest.php @@ -2,96 +2,76 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\AnimeSeries; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Anime; use App\Models\Wiki\Series; use App\Pivots\Wiki\AnimeSeries; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class AnimeSeriesDestroyTest extends TestCase -{ - /** - * The Anime Series Destroy Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $animeSeries = AnimeSeries::factory() - ->for(Anime::factory()) - ->for(Series::factory()) - ->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.animeseries.destroy', ['anime' => $animeSeries->anime, 'series' => $animeSeries->series])); +test('protected', function () { + $animeSeries = AnimeSeries::factory() + ->for(Anime::factory()) + ->for(Series::factory()) + ->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.animeseries.destroy', ['anime' => $animeSeries->anime, 'series' => $animeSeries->series])); - /** - * The Anime Series Destroy Endpoint shall forbid users without the delete anime & delete series permissions. - */ - public function testForbidden(): void - { - $animeSeries = AnimeSeries::factory() - ->for(Anime::factory()) - ->for(Series::factory()) - ->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $animeSeries = AnimeSeries::factory() + ->for(Anime::factory()) + ->for(Series::factory()) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.animeseries.destroy', ['anime' => $animeSeries->anime, 'series' => $animeSeries->series])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.animeseries.destroy', ['anime' => $animeSeries->anime, 'series' => $animeSeries->series])); - /** - * The Anime Series Destroy Endpoint shall return an error if the anime series does not exist. - */ - public function testNotFound(): void - { - $anime = Anime::factory()->createOne(); - $series = Series::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory() - ->withPermissions( - CrudPermission::DELETE->format(Anime::class), - CrudPermission::DELETE->format(Series::class) - ) - ->createOne(); +test('not found', function () { + $anime = Anime::factory()->createOne(); + $series = Series::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::DELETE->format(Anime::class), + CrudPermission::DELETE->format(Series::class) + ) + ->createOne(); - $response = $this->delete(route('api.animeseries.destroy', ['anime' => $anime, 'series' => $series])); + Sanctum::actingAs($user); - $response->assertNotFound(); - } + $response = delete(route('api.animeseries.destroy', ['anime' => $anime, 'series' => $series])); - /** - * The Anime Series Destroy Endpoint shall delete the anime series. - */ - public function testDeleted(): void - { - $animeSeries = AnimeSeries::factory() - ->for(Anime::factory()) - ->for(Series::factory()) - ->createOne(); + $response->assertNotFound(); +}); - $user = User::factory() - ->withPermissions( - CrudPermission::DELETE->format(Anime::class), - CrudPermission::DELETE->format(Series::class) - ) - ->createOne(); +test('deleted', function () { + $animeSeries = AnimeSeries::factory() + ->for(Anime::factory()) + ->for(Series::factory()) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::DELETE->format(Anime::class), + CrudPermission::DELETE->format(Series::class) + ) + ->createOne(); - $response = $this->delete(route('api.animeseries.destroy', ['anime' => $animeSeries->anime, 'series' => $animeSeries->series])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertModelMissing($animeSeries); - } -} + $response = delete(route('api.animeseries.destroy', ['anime' => $animeSeries->anime, 'series' => $animeSeries->series])); + + $response->assertOk(); + $this->assertModelMissing($animeSeries); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/AnimeSeries/AnimeSeriesIndexTest.php b/tests/Feature/Http/Api/Pivot/Wiki/AnimeSeries/AnimeSeriesIndexTest.php index 0ce412299..459f77ddc 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/AnimeSeries/AnimeSeriesIndexTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/AnimeSeries/AnimeSeriesIndexTest.php @@ -2,9 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\AnimeSeries; - -use App\Concerns\Actions\Http\Api\SortsModels; use App\Contracts\Http\Api\Field\SortableField; use App\Enums\Http\Api\Sort\Direction; use App\Enums\Models\Wiki\AnimeMediaFormat; @@ -28,419 +25,377 @@ use App\Models\Wiki\Series; use App\Pivots\BasePivot; use App\Pivots\Wiki\AnimeSeries; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; use Illuminate\Support\Collection; -use Tests\TestCase; -class AnimeSeriesIndexTest extends TestCase -{ - use SortsModels; - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the Anime Series Index Endpoint shall return a collection of Anime Series Resources. - */ - public function testDefault(): void - { - Collection::times($this->faker->randomDigitNotNull(), function () { +uses(App\Concerns\Actions\Http\Api\SortsModels::class); + +uses(Illuminate\Foundation\Testing\WithFaker::class); + +test('default', function () { + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeSeries::factory() + ->for(Anime::factory()) + ->for(Series::factory()) + ->create(); + }); + + $animeSeries = AnimeSeries::all(); + + $response = get(route('api.animeseries.index')); + + $response->assertJson( + json_decode( + json_encode( + new AnimeSeriesCollection($animeSeries, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('paginated', function () { + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeSeries::factory() + ->for(Anime::factory()) + ->for(Series::factory()) + ->create(); + }); + + $response = get(route('api.animeseries.index')); + + $response->assertJsonStructure([ + AnimeSeriesCollection::$wrap, + 'links', + 'meta', + ]); +}); + +test('allowed include paths', function () { + $schema = new AnimeSeriesSchema(); + + $allowedIncludes = collect($schema->allowedIncludes()); + + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); + + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeSeries::factory() + ->for(Anime::factory()) + ->for(Series::factory()) + ->create(); + }); + + $response = get(route('api.animeseries.index', $parameters)); + + $animeSeries = AnimeSeries::with($includedPaths->all())->get(); + + $response->assertJson( + json_decode( + json_encode( + new AnimeSeriesCollection($animeSeries, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sparse fieldsets', function () { + $schema = new AnimeSeriesSchema(); + + $fields = collect($schema->fields()); + + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + AnimeSeriesResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeSeries::factory() + ->for(Anime::factory()) + ->for(Series::factory()) + ->create(); + }); + + $response = get(route('api.animeseries.index', $parameters)); + + $animeSeries = AnimeSeries::all(); + + $response->assertJson( + json_decode( + json_encode( + new AnimeSeriesCollection($animeSeries, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sorts', function () { + $schema = new AnimeSeriesSchema(); + + /** @var Sort $sort */ + $sort = collect($schema->fields()) + ->filter(fn (Field $field) => $field instanceof SortableField) + ->map(fn (SortableField $field) => $field->getSort()) + ->random(); + + $parameters = [ + SortParser::param() => $sort->format(Arr::random(Direction::cases())), + ]; + + $query = new Query($parameters); + + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeSeries::factory() + ->for(Anime::factory()) + ->for(Series::factory()) + ->create(); + }); + + $response = get(route('api.animeseries.index', $parameters)); + + $animeSeries = $this->sort(AnimeSeries::query(), $query, $schema)->get(); + + $response->assertJson( + json_decode( + json_encode( + new AnimeSeriesCollection($animeSeries, $query) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('created at filter', function () { + $createdFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BasePivot::ATTRIBUTE_CREATED_AT => $createdFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($createdFilter, function () { + Collection::times(fake()->randomDigitNotNull(), function () { AnimeSeries::factory() ->for(Anime::factory()) ->for(Series::factory()) ->create(); }); + }); - $animeSeries = AnimeSeries::all(); - - $response = $this->get(route('api.animeseries.index')); - - $response->assertJson( - json_decode( - json_encode( - new AnimeSeriesCollection($animeSeries, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Series Index Endpoint shall be paginated. - */ - public function testPaginated(): void - { - Collection::times($this->faker->randomDigitNotNull(), function () { + Carbon::withTestNow($excludedDate, function () { + Collection::times(fake()->randomDigitNotNull(), function () { AnimeSeries::factory() ->for(Anime::factory()) ->for(Series::factory()) ->create(); }); + }); - $response = $this->get(route('api.animeseries.index')); + $animeSeries = AnimeSeries::query()->where(BasePivot::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - $response->assertJsonStructure([ - AnimeSeriesCollection::$wrap, - 'links', - 'meta', - ]); - } + $response = get(route('api.animeseries.index', $parameters)); - /** - * The Anime Series Index Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new AnimeSeriesSchema(); + $response->assertJson( + json_decode( + json_encode( + new AnimeSeriesCollection($animeSeries, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('updated at filter', function () { + $updatedFilter = fake()->date(); + $excludedDate = fake()->date(); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $parameters = [ + FilterParser::param() => [ + BasePivot::ATTRIBUTE_UPDATED_AT => $updatedFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { + Carbon::withTestNow($updatedFilter, function () { + Collection::times(fake()->randomDigitNotNull(), function () { AnimeSeries::factory() ->for(Anime::factory()) ->for(Series::factory()) ->create(); }); + }); - $response = $this->get(route('api.animeseries.index', $parameters)); - - $animeSeries = AnimeSeries::with($includedPaths->all())->get(); - - $response->assertJson( - json_decode( - json_encode( - new AnimeSeriesCollection($animeSeries, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Series Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new AnimeSeriesSchema(); - - $fields = collect($schema->fields()); - - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); - - $parameters = [ - FieldParser::param() => [ - AnimeSeriesResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { + Carbon::withTestNow($excludedDate, function () { + Collection::times(fake()->randomDigitNotNull(), function () { AnimeSeries::factory() ->for(Anime::factory()) ->for(Series::factory()) ->create(); }); + }); - $response = $this->get(route('api.animeseries.index', $parameters)); + $animeSeries = AnimeSeries::query()->where(BasePivot::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - $animeSeries = AnimeSeries::all(); + $response = get(route('api.animeseries.index', $parameters)); - $response->assertJson( - json_decode( - json_encode( - new AnimeSeriesCollection($animeSeries, new Query($parameters)) - ->response() - ->getData() - ), - true + $response->assertJson( + json_decode( + json_encode( + new AnimeSeriesCollection($animeSeries, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by media format', function () { + $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), + ], + IncludeParser::param() => AnimeSeries::RELATION_ANIME, + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeSeries::factory() + ->for(Anime::factory()) + ->for(Series::factory()) + ->create(); + }); + + $response = get(route('api.animeseries.index', $parameters)); + + $animeSeries = AnimeSeries::with([ + AnimeSeries::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { + $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); + }, + ]) + ->get(); + + $response->assertJson( + json_decode( + json_encode( + new AnimeSeriesCollection($animeSeries, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by season', function () { + $seasonFilter = Arr::random(AnimeSeason::cases()); + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), + ], + IncludeParser::param() => AnimeSeries::RELATION_ANIME, + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeSeries::factory() + ->for(Anime::factory()) + ->for(Series::factory()) + ->create(); + }); + + $response = get(route('api.animeseries.index', $parameters)); + + $animeSeries = AnimeSeries::with([ + AnimeSeries::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { + $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); + }, + ]) + ->get(); + + $response->assertJson( + json_decode( + json_encode( + new AnimeSeriesCollection($animeSeries, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by year', function () { + $yearFilter = intval(fake()->year()); + $excludedYear = $yearFilter + 1; + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_YEAR => $yearFilter, + ], + IncludeParser::param() => AnimeSeries::RELATION_ANIME, + ]; + + Collection::times(fake()->randomDigitNotNull(), function () use ($yearFilter, $excludedYear) { + AnimeSeries::factory() + ->for( + Anime::factory() + ->state([ + Anime::ATTRIBUTE_YEAR => fake()->boolean() ? $yearFilter : $excludedYear, + ]) ) - ); - } + ->for(Series::factory()) + ->create(); + }); - /** - * The Anime Series Index Endpoint shall support sorting resources. - */ - public function testSorts(): void - { - $schema = new AnimeSeriesSchema(); + $response = get(route('api.animeseries.index', $parameters)); - /** @var Sort $sort */ - $sort = collect($schema->fields()) - ->filter(fn (Field $field) => $field instanceof SortableField) - ->map(fn (SortableField $field) => $field->getSort()) - ->random(); + $animeSeries = AnimeSeries::with([ + AnimeSeries::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { + $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); + }, + ]) + ->get(); - $parameters = [ - SortParser::param() => $sort->format(Arr::random(Direction::cases())), - ]; - - $query = new Query($parameters); - - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeSeries::factory() - ->for(Anime::factory()) - ->for(Series::factory()) - ->create(); - }); - - $response = $this->get(route('api.animeseries.index', $parameters)); - - $animeSeries = $this->sort(AnimeSeries::query(), $query, $schema)->get(); - - $response->assertJson( - json_decode( - json_encode( - new AnimeSeriesCollection($animeSeries, $query) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Series Index Endpoint shall support filtering by created_at. - */ - public function testCreatedAtFilter(): void - { - $createdFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BasePivot::ATTRIBUTE_CREATED_AT => $createdFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($createdFilter, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeSeries::factory() - ->for(Anime::factory()) - ->for(Series::factory()) - ->create(); - }); - }); - - Carbon::withTestNow($excludedDate, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeSeries::factory() - ->for(Anime::factory()) - ->for(Series::factory()) - ->create(); - }); - }); - - $animeSeries = AnimeSeries::query()->where(BasePivot::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - - $response = $this->get(route('api.animeseries.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeSeriesCollection($animeSeries, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Series Index Endpoint shall support filtering by updated_at. - */ - public function testUpdatedAtFilter(): void - { - $updatedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BasePivot::ATTRIBUTE_UPDATED_AT => $updatedFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($updatedFilter, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeSeries::factory() - ->for(Anime::factory()) - ->for(Series::factory()) - ->create(); - }); - }); - - Carbon::withTestNow($excludedDate, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeSeries::factory() - ->for(Anime::factory()) - ->for(Series::factory()) - ->create(); - }); - }); - - $animeSeries = AnimeSeries::query()->where(BasePivot::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - - $response = $this->get(route('api.animeseries.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeSeriesCollection($animeSeries, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Series Show Endpoint shall support constrained eager loading of anime by media format. - */ - public function testAnimeByMediaFormat(): void - { - $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), - ], - IncludeParser::param() => AnimeSeries::RELATION_ANIME, - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeSeries::factory() - ->for(Anime::factory()) - ->for(Series::factory()) - ->create(); - }); - - $response = $this->get(route('api.animeseries.index', $parameters)); - - $animeSeries = AnimeSeries::with([ - AnimeSeries::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { - $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); - }, - ]) - ->get(); - - $response->assertJson( - json_decode( - json_encode( - new AnimeSeriesCollection($animeSeries, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Series Show Endpoint shall support constrained eager loading of anime by season. - */ - public function testAnimeBySeason(): void - { - $seasonFilter = Arr::random(AnimeSeason::cases()); - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), - ], - IncludeParser::param() => AnimeSeries::RELATION_ANIME, - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeSeries::factory() - ->for(Anime::factory()) - ->for(Series::factory()) - ->create(); - }); - - $response = $this->get(route('api.animeseries.index', $parameters)); - - $animeSeries = AnimeSeries::with([ - AnimeSeries::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { - $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); - }, - ]) - ->get(); - - $response->assertJson( - json_decode( - json_encode( - new AnimeSeriesCollection($animeSeries, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Series Show Endpoint shall support constrained eager loading of anime by year. - */ - public function testAnimeByYear(): void - { - $yearFilter = intval($this->faker->year()); - $excludedYear = $yearFilter + 1; - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_YEAR => $yearFilter, - ], - IncludeParser::param() => AnimeSeries::RELATION_ANIME, - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () use ($yearFilter, $excludedYear) { - AnimeSeries::factory() - ->for( - Anime::factory() - ->state([ - Anime::ATTRIBUTE_YEAR => $this->faker->boolean() ? $yearFilter : $excludedYear, - ]) - ) - ->for(Series::factory()) - ->create(); - }); - - $response = $this->get(route('api.animeseries.index', $parameters)); - - $animeSeries = AnimeSeries::with([ - AnimeSeries::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { - $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); - }, - ]) - ->get(); - - $response->assertJson( - json_decode( - json_encode( - new AnimeSeriesCollection($animeSeries, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response->assertJson( + json_decode( + json_encode( + new AnimeSeriesCollection($animeSeries, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/AnimeSeries/AnimeSeriesShowTest.php b/tests/Feature/Http/Api/Pivot/Wiki/AnimeSeries/AnimeSeriesShowTest.php index bb852e590..9e60ad203 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/AnimeSeries/AnimeSeriesShowTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/AnimeSeries/AnimeSeriesShowTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\AnimeSeries; - use App\Enums\Models\Wiki\AnimeMediaFormat; use App\Enums\Models\Wiki\AnimeSeason; use App\Http\Api\Field\Field; @@ -18,249 +16,218 @@ use App\Models\Wiki\Anime; use App\Models\Wiki\Series; use App\Pivots\Wiki\AnimeSeries; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; -use Tests\TestCase; -class AnimeSeriesShowTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * The Anime Series Show Endpoint shall return an error if the anime series does not exist. - */ - public function testNotFound(): void - { - $anime = Anime::factory()->createOne(); - $series = Series::factory()->createOne(); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response = $this->get(route('api.animeseries.show', ['anime' => $anime, 'series' => $series])); +test('not found', function () { + $anime = Anime::factory()->createOne(); + $series = Series::factory()->createOne(); - $response->assertNotFound(); - } + $response = get(route('api.animeseries.show', ['anime' => $anime, 'series' => $series])); - /** - * By default, the Anime Series Show Endpoint shall return an Anime Series Resource. - */ - public function testDefault(): void - { - $animeSeries = AnimeSeries::factory() - ->for(Anime::factory()) - ->for(Series::factory()) - ->createOne(); + $response->assertNotFound(); +}); - $response = $this->get(route('api.animeseries.show', ['anime' => $animeSeries->anime, 'series' => $animeSeries->series])); +test('default', function () { + $animeSeries = AnimeSeries::factory() + ->for(Anime::factory()) + ->for(Series::factory()) + ->createOne(); - $animeSeries->unsetRelations(); + $response = get(route('api.animeseries.show', ['anime' => $animeSeries->anime, 'series' => $animeSeries->series])); - $response->assertJson( - json_decode( - json_encode( - new AnimeSeriesResource($animeSeries, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $animeSeries->unsetRelations(); - /** - * The Anime Series Show Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new AnimeSeriesSchema(); + $response->assertJson( + json_decode( + json_encode( + new AnimeSeriesResource($animeSeries, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('allowed include paths', function () { + $schema = new AnimeSeriesSchema(); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $allowedIncludes = collect($schema->allowedIncludes()); - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - $animeSeries = AnimeSeries::factory() - ->for(Anime::factory()) - ->for(Series::factory()) - ->createOne(); + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; - $response = $this->get(route('api.animeseries.show', ['anime' => $animeSeries->anime, 'series' => $animeSeries->series] + $parameters)); + $animeSeries = AnimeSeries::factory() + ->for(Anime::factory()) + ->for(Series::factory()) + ->createOne(); - $animeSeries->unsetRelations()->load($includedPaths->all()); + $response = get(route('api.animeseries.show', ['anime' => $animeSeries->anime, 'series' => $animeSeries->series] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new AnimeSeriesResource($animeSeries, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $animeSeries->unsetRelations()->load($includedPaths->all()); - /** - * The Anime Series Show Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new AnimeSeriesSchema(); + $response->assertJson( + json_decode( + json_encode( + new AnimeSeriesResource($animeSeries, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $fields = collect($schema->fields()); +test('sparse fieldsets', function () { + $schema = new AnimeSeriesSchema(); - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); + $fields = collect($schema->fields()); - $parameters = [ - FieldParser::param() => [ - AnimeSeriesResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); - $animeSeries = AnimeSeries::factory() - ->for(Anime::factory()) - ->for(Series::factory()) - ->createOne(); + $parameters = [ + FieldParser::param() => [ + AnimeSeriesResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; - $response = $this->get(route('api.animeseries.show', ['anime' => $animeSeries->anime, 'series' => $animeSeries->series] + $parameters)); + $animeSeries = AnimeSeries::factory() + ->for(Anime::factory()) + ->for(Series::factory()) + ->createOne(); - $animeSeries->unsetRelations(); + $response = get(route('api.animeseries.show', ['anime' => $animeSeries->anime, 'series' => $animeSeries->series] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new AnimeSeriesResource($animeSeries, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $animeSeries->unsetRelations(); - /** - * The Anime Series Show Endpoint shall support constrained eager loading of anime by media_format. - */ - public function testAnimeByMediaFormat(): void - { - $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); + $response->assertJson( + json_decode( + json_encode( + new AnimeSeriesResource($animeSeries, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), - ], - IncludeParser::param() => AnimeSeries::RELATION_ANIME, - ]; +test('anime by media format', function () { + $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); - $animeSeries = AnimeSeries::factory() - ->for(Anime::factory()) - ->for(Series::factory()) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), + ], + IncludeParser::param() => AnimeSeries::RELATION_ANIME, + ]; - $response = $this->get(route('api.animeseries.show', ['anime' => $animeSeries->anime, 'series' => $animeSeries->series] + $parameters)); + $animeSeries = AnimeSeries::factory() + ->for(Anime::factory()) + ->for(Series::factory()) + ->createOne(); - $animeSeries->unsetRelations()->load([ - AnimeSeries::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { - $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); - }, - ]); + $response = get(route('api.animeseries.show', ['anime' => $animeSeries->anime, 'series' => $animeSeries->series] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new AnimeSeriesResource($animeSeries, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $animeSeries->unsetRelations()->load([ + AnimeSeries::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { + $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); + }, + ]); - /** - * The Anime Series Show Endpoint shall support constrained eager loading of anime by season. - */ - public function testAnimeBySeason(): void - { - $seasonFilter = Arr::random(AnimeSeason::cases()); + $response->assertJson( + json_decode( + json_encode( + new AnimeSeriesResource($animeSeries, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), - ], - IncludeParser::param() => AnimeSeries::RELATION_ANIME, - ]; +test('anime by season', function () { + $seasonFilter = Arr::random(AnimeSeason::cases()); - $animeSeries = AnimeSeries::factory() - ->for(Anime::factory()) - ->for(Series::factory()) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), + ], + IncludeParser::param() => AnimeSeries::RELATION_ANIME, + ]; - $response = $this->get(route('api.animeseries.show', ['anime' => $animeSeries->anime, 'series' => $animeSeries->series] + $parameters)); + $animeSeries = AnimeSeries::factory() + ->for(Anime::factory()) + ->for(Series::factory()) + ->createOne(); - $animeSeries->unsetRelations()->load([ - AnimeSeries::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { - $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); - }, - ]); + $response = get(route('api.animeseries.show', ['anime' => $animeSeries->anime, 'series' => $animeSeries->series] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new AnimeSeriesResource($animeSeries, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $animeSeries->unsetRelations()->load([ + AnimeSeries::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { + $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); + }, + ]); - /** - * The Anime Series Show Endpoint shall support constrained eager loading of anime by year. - */ - public function testAnimeByYear(): void - { - $yearFilter = intval($this->faker->year()); - $excludedYear = $yearFilter + 1; + $response->assertJson( + json_decode( + json_encode( + new AnimeSeriesResource($animeSeries, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_YEAR => $yearFilter, - ], - IncludeParser::param() => AnimeSeries::RELATION_ANIME, - ]; +test('anime by year', function () { + $yearFilter = intval(fake()->year()); + $excludedYear = $yearFilter + 1; - $animeSeries = AnimeSeries::factory() - ->for( - Anime::factory() - ->state([ - Anime::ATTRIBUTE_YEAR => $this->faker->boolean() ? $yearFilter : $excludedYear, - ]) - ) - ->for(Series::factory()) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_YEAR => $yearFilter, + ], + IncludeParser::param() => AnimeSeries::RELATION_ANIME, + ]; - $response = $this->get(route('api.animeseries.show', ['anime' => $animeSeries->anime, 'series' => $animeSeries->series] + $parameters)); + $animeSeries = AnimeSeries::factory() + ->for( + Anime::factory() + ->state([ + Anime::ATTRIBUTE_YEAR => fake()->boolean() ? $yearFilter : $excludedYear, + ]) + ) + ->for(Series::factory()) + ->createOne(); - $animeSeries->unsetRelations()->load([ - AnimeSeries::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { - $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); - }, - ]); + $response = get(route('api.animeseries.show', ['anime' => $animeSeries->anime, 'series' => $animeSeries->series] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new AnimeSeriesResource($animeSeries, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $animeSeries->unsetRelations()->load([ + AnimeSeries::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { + $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); + }, + ]); + + $response->assertJson( + json_decode( + json_encode( + new AnimeSeriesResource($animeSeries, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/AnimeSeries/AnimeSeriesStoreTest.php b/tests/Feature/Http/Api/Pivot/Wiki/AnimeSeries/AnimeSeriesStoreTest.php index bcfbc4ab6..feca039d9 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/AnimeSeries/AnimeSeriesStoreTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/AnimeSeries/AnimeSeriesStoreTest.php @@ -2,68 +2,52 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\AnimeSeries; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Anime; use App\Models\Wiki\Series; use App\Pivots\Wiki\AnimeSeries; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class AnimeSeriesStoreTest extends TestCase -{ - /** - * The Anime Series Store Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $anime = Anime::factory()->createOne(); - $series = Series::factory()->createOne(); +use function Pest\Laravel\post; - $response = $this->post(route('api.animeseries.store', ['anime' => $anime, 'series' => $series])); +test('protected', function () { + $anime = Anime::factory()->createOne(); + $series = Series::factory()->createOne(); - $response->assertUnauthorized(); - } + $response = post(route('api.animeseries.store', ['anime' => $anime, 'series' => $series])); - /** - * The Anime Series Store Endpoint shall forbid users without the create anime & create series permissions. - */ - public function testForbidden(): void - { - $anime = Anime::factory()->createOne(); - $series = Series::factory()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $anime = Anime::factory()->createOne(); + $series = Series::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->post(route('api.animeseries.store', ['anime' => $anime, 'series' => $series])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.animeseries.store', ['anime' => $anime, 'series' => $series])); - /** - * The Anime Series Store Endpoint shall create an anime series. - */ - public function testCreate(): void - { - $anime = Anime::factory()->createOne(); - $series = Series::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory() - ->withPermissions( - CrudPermission::CREATE->format(Anime::class), - CrudPermission::CREATE->format(Series::class) - ) - ->createOne(); +test('create', function () { + $anime = Anime::factory()->createOne(); + $series = Series::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::CREATE->format(Anime::class), + CrudPermission::CREATE->format(Series::class) + ) + ->createOne(); - $response = $this->post(route('api.animeseries.store', ['anime' => $anime, 'series' => $series])); + Sanctum::actingAs($user); - $response->assertCreated(); - static::assertDatabaseCount(AnimeSeries::class, 1); - } -} + $response = post(route('api.animeseries.store', ['anime' => $anime, 'series' => $series])); + + $response->assertCreated(); + $this->assertDatabaseCount(AnimeSeries::class, 1); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/AnimeStudio/AnimeStudioDestroyTest.php b/tests/Feature/Http/Api/Pivot/Wiki/AnimeStudio/AnimeStudioDestroyTest.php index d19d0baf2..c41d76770 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/AnimeStudio/AnimeStudioDestroyTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/AnimeStudio/AnimeStudioDestroyTest.php @@ -2,96 +2,76 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\AnimeStudio; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Anime; use App\Models\Wiki\Studio; use App\Pivots\Wiki\AnimeStudio; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class AnimeStudioDestroyTest extends TestCase -{ - /** - * The Anime Studio Destroy Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $animeStudio = AnimeStudio::factory() - ->for(Anime::factory()) - ->for(Studio::factory()) - ->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.animestudio.destroy', ['anime' => $animeStudio->anime, 'studio' => $animeStudio->studio])); +test('protected', function () { + $animeStudio = AnimeStudio::factory() + ->for(Anime::factory()) + ->for(Studio::factory()) + ->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.animestudio.destroy', ['anime' => $animeStudio->anime, 'studio' => $animeStudio->studio])); - /** - * The Anime Studio Destroy Endpoint shall forbid users without the delete anime & delete studio permissions. - */ - public function testForbidden(): void - { - $animeStudio = AnimeStudio::factory() - ->for(Anime::factory()) - ->for(Studio::factory()) - ->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $animeStudio = AnimeStudio::factory() + ->for(Anime::factory()) + ->for(Studio::factory()) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.animestudio.destroy', ['anime' => $animeStudio->anime, 'studio' => $animeStudio->studio])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.animestudio.destroy', ['anime' => $animeStudio->anime, 'studio' => $animeStudio->studio])); - /** - * The Anime Studio Destroy Endpoint shall return an error if the anime studio does not exist. - */ - public function testNotFound(): void - { - $anime = Anime::factory()->createOne(); - $studio = Studio::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory() - ->withPermissions( - CrudPermission::DELETE->format(Anime::class), - CrudPermission::DELETE->format(Studio::class) - ) - ->createOne(); +test('not found', function () { + $anime = Anime::factory()->createOne(); + $studio = Studio::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::DELETE->format(Anime::class), + CrudPermission::DELETE->format(Studio::class) + ) + ->createOne(); - $response = $this->delete(route('api.animestudio.destroy', ['anime' => $anime, 'studio' => $studio])); + Sanctum::actingAs($user); - $response->assertNotFound(); - } + $response = delete(route('api.animestudio.destroy', ['anime' => $anime, 'studio' => $studio])); - /** - * The Anime Studio Destroy Endpoint shall delete the anime studio. - */ - public function testDeleted(): void - { - $animeStudio = AnimeStudio::factory() - ->for(Anime::factory()) - ->for(Studio::factory()) - ->createOne(); + $response->assertNotFound(); +}); - $user = User::factory() - ->withPermissions( - CrudPermission::DELETE->format(Anime::class), - CrudPermission::DELETE->format(Studio::class) - ) - ->createOne(); +test('deleted', function () { + $animeStudio = AnimeStudio::factory() + ->for(Anime::factory()) + ->for(Studio::factory()) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::DELETE->format(Anime::class), + CrudPermission::DELETE->format(Studio::class) + ) + ->createOne(); - $response = $this->delete(route('api.animestudio.destroy', ['anime' => $animeStudio->anime, 'studio' => $animeStudio->studio])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertModelMissing($animeStudio); - } -} + $response = delete(route('api.animestudio.destroy', ['anime' => $animeStudio->anime, 'studio' => $animeStudio->studio])); + + $response->assertOk(); + $this->assertModelMissing($animeStudio); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/AnimeStudio/AnimeStudioIndexTest.php b/tests/Feature/Http/Api/Pivot/Wiki/AnimeStudio/AnimeStudioIndexTest.php index 898feb696..09d591421 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/AnimeStudio/AnimeStudioIndexTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/AnimeStudio/AnimeStudioIndexTest.php @@ -2,9 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\AnimeStudio; - -use App\Concerns\Actions\Http\Api\SortsModels; use App\Contracts\Http\Api\Field\SortableField; use App\Enums\Http\Api\Sort\Direction; use App\Enums\Models\Wiki\AnimeMediaFormat; @@ -28,419 +25,377 @@ use App\Models\Wiki\Studio; use App\Pivots\BasePivot; use App\Pivots\Wiki\AnimeStudio; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; use Illuminate\Support\Collection; -use Tests\TestCase; -class AnimeStudioIndexTest extends TestCase -{ - use SortsModels; - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the Anime Studio Index Endpoint shall return a collection of Anime Studio Resources. - */ - public function testDefault(): void - { - Collection::times($this->faker->randomDigitNotNull(), function () { +uses(App\Concerns\Actions\Http\Api\SortsModels::class); + +uses(Illuminate\Foundation\Testing\WithFaker::class); + +test('default', function () { + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeStudio::factory() + ->for(Anime::factory()) + ->for(Studio::factory()) + ->create(); + }); + + $animeStudios = AnimeStudio::all(); + + $response = get(route('api.animestudio.index')); + + $response->assertJson( + json_decode( + json_encode( + new AnimeStudioCollection($animeStudios, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('paginated', function () { + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeStudio::factory() + ->for(Anime::factory()) + ->for(Studio::factory()) + ->create(); + }); + + $response = get(route('api.animestudio.index')); + + $response->assertJsonStructure([ + AnimeStudioCollection::$wrap, + 'links', + 'meta', + ]); +}); + +test('allowed include paths', function () { + $schema = new AnimeStudioSchema(); + + $allowedIncludes = collect($schema->allowedIncludes()); + + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); + + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeStudio::factory() + ->for(Anime::factory()) + ->for(Studio::factory()) + ->create(); + }); + + $response = get(route('api.animestudio.index', $parameters)); + + $animeStudios = AnimeStudio::with($includedPaths->all())->get(); + + $response->assertJson( + json_decode( + json_encode( + new AnimeStudioCollection($animeStudios, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sparse fieldsets', function () { + $schema = new AnimeStudioSchema(); + + $fields = collect($schema->fields()); + + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + AnimeStudioResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeStudio::factory() + ->for(Anime::factory()) + ->for(Studio::factory()) + ->create(); + }); + + $response = get(route('api.animestudio.index', $parameters)); + + $animeStudios = AnimeStudio::all(); + + $response->assertJson( + json_decode( + json_encode( + new AnimeStudioCollection($animeStudios, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sorts', function () { + $schema = new AnimeStudioSchema(); + + /** @var Sort $sort */ + $sort = collect($schema->fields()) + ->filter(fn (Field $field) => $field instanceof SortableField) + ->map(fn (SortableField $field) => $field->getSort()) + ->random(); + + $parameters = [ + SortParser::param() => $sort->format(Arr::random(Direction::cases())), + ]; + + $query = new Query($parameters); + + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeStudio::factory() + ->for(Anime::factory()) + ->for(Studio::factory()) + ->create(); + }); + + $response = get(route('api.animestudio.index', $parameters)); + + $animeStudios = $this->sort(AnimeStudio::query(), $query, $schema)->get(); + + $response->assertJson( + json_decode( + json_encode( + new AnimeStudioCollection($animeStudios, $query) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('created at filter', function () { + $createdFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BasePivot::ATTRIBUTE_CREATED_AT => $createdFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($createdFilter, function () { + Collection::times(fake()->randomDigitNotNull(), function () { AnimeStudio::factory() ->for(Anime::factory()) ->for(Studio::factory()) ->create(); }); + }); - $animeStudios = AnimeStudio::all(); - - $response = $this->get(route('api.animestudio.index')); - - $response->assertJson( - json_decode( - json_encode( - new AnimeStudioCollection($animeStudios, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Studio Index Endpoint shall be paginated. - */ - public function testPaginated(): void - { - Collection::times($this->faker->randomDigitNotNull(), function () { + Carbon::withTestNow($excludedDate, function () { + Collection::times(fake()->randomDigitNotNull(), function () { AnimeStudio::factory() ->for(Anime::factory()) ->for(Studio::factory()) ->create(); }); + }); - $response = $this->get(route('api.animestudio.index')); + $animeStudios = AnimeStudio::query()->where(BasePivot::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - $response->assertJsonStructure([ - AnimeStudioCollection::$wrap, - 'links', - 'meta', - ]); - } + $response = get(route('api.animestudio.index', $parameters)); - /** - * The Anime Studio Index Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new AnimeStudioSchema(); + $response->assertJson( + json_decode( + json_encode( + new AnimeStudioCollection($animeStudios, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('updated at filter', function () { + $updatedFilter = fake()->date(); + $excludedDate = fake()->date(); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $parameters = [ + FilterParser::param() => [ + BasePivot::ATTRIBUTE_UPDATED_AT => $updatedFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { + Carbon::withTestNow($updatedFilter, function () { + Collection::times(fake()->randomDigitNotNull(), function () { AnimeStudio::factory() ->for(Anime::factory()) ->for(Studio::factory()) ->create(); }); + }); - $response = $this->get(route('api.animestudio.index', $parameters)); - - $animeStudios = AnimeStudio::with($includedPaths->all())->get(); - - $response->assertJson( - json_decode( - json_encode( - new AnimeStudioCollection($animeStudios, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Studio Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new AnimeStudioSchema(); - - $fields = collect($schema->fields()); - - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); - - $parameters = [ - FieldParser::param() => [ - AnimeStudioResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { + Carbon::withTestNow($excludedDate, function () { + Collection::times(fake()->randomDigitNotNull(), function () { AnimeStudio::factory() ->for(Anime::factory()) ->for(Studio::factory()) ->create(); }); + }); - $response = $this->get(route('api.animestudio.index', $parameters)); + $animeStudios = AnimeStudio::query()->where(BasePivot::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - $animeStudios = AnimeStudio::all(); + $response = get(route('api.animestudio.index', $parameters)); - $response->assertJson( - json_decode( - json_encode( - new AnimeStudioCollection($animeStudios, new Query($parameters)) - ->response() - ->getData() - ), - true + $response->assertJson( + json_decode( + json_encode( + new AnimeStudioCollection($animeStudios, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by media format', function () { + $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), + ], + IncludeParser::param() => AnimeStudio::RELATION_ANIME, + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeStudio::factory() + ->for(Anime::factory()) + ->for(Studio::factory()) + ->create(); + }); + + $response = get(route('api.animestudio.index', $parameters)); + + $animeStudios = AnimeStudio::with([ + AnimeStudio::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { + $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); + }, + ]) + ->get(); + + $response->assertJson( + json_decode( + json_encode( + new AnimeStudioCollection($animeStudios, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by season', function () { + $seasonFilter = Arr::random(AnimeSeason::cases()); + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), + ], + IncludeParser::param() => AnimeStudio::RELATION_ANIME, + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeStudio::factory() + ->for(Anime::factory()) + ->for(Studio::factory()) + ->create(); + }); + + $response = get(route('api.animestudio.index', $parameters)); + + $animeStudios = AnimeStudio::with([ + AnimeStudio::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { + $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); + }, + ]) + ->get(); + + $response->assertJson( + json_decode( + json_encode( + new AnimeStudioCollection($animeStudios, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by year', function () { + $yearFilter = intval(fake()->year()); + $excludedYear = $yearFilter + 1; + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_YEAR => $yearFilter, + ], + IncludeParser::param() => AnimeStudio::RELATION_ANIME, + ]; + + Collection::times(fake()->randomDigitNotNull(), function () use ($yearFilter, $excludedYear) { + AnimeStudio::factory() + ->for( + Anime::factory() + ->state([ + Anime::ATTRIBUTE_YEAR => fake()->boolean() ? $yearFilter : $excludedYear, + ]) ) - ); - } + ->for(Studio::factory()) + ->create(); + }); - /** - * The Anime Studio Index Endpoint shall support sorting resources. - */ - public function testSorts(): void - { - $schema = new AnimeStudioSchema(); + $response = get(route('api.animestudio.index', $parameters)); - /** @var Sort $sort */ - $sort = collect($schema->fields()) - ->filter(fn (Field $field) => $field instanceof SortableField) - ->map(fn (SortableField $field) => $field->getSort()) - ->random(); + $animeStudios = AnimeStudio::with([ + AnimeStudio::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { + $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); + }, + ]) + ->get(); - $parameters = [ - SortParser::param() => $sort->format(Arr::random(Direction::cases())), - ]; - - $query = new Query($parameters); - - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeStudio::factory() - ->for(Anime::factory()) - ->for(Studio::factory()) - ->create(); - }); - - $response = $this->get(route('api.animestudio.index', $parameters)); - - $animeStudios = $this->sort(AnimeStudio::query(), $query, $schema)->get(); - - $response->assertJson( - json_decode( - json_encode( - new AnimeStudioCollection($animeStudios, $query) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Studio Index Endpoint shall support filtering by created_at. - */ - public function testCreatedAtFilter(): void - { - $createdFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BasePivot::ATTRIBUTE_CREATED_AT => $createdFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($createdFilter, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeStudio::factory() - ->for(Anime::factory()) - ->for(Studio::factory()) - ->create(); - }); - }); - - Carbon::withTestNow($excludedDate, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeStudio::factory() - ->for(Anime::factory()) - ->for(Studio::factory()) - ->create(); - }); - }); - - $animeStudios = AnimeStudio::query()->where(BasePivot::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - - $response = $this->get(route('api.animestudio.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeStudioCollection($animeStudios, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Studio Index Endpoint shall support filtering by updated_at. - */ - public function testUpdatedAtFilter(): void - { - $updatedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BasePivot::ATTRIBUTE_UPDATED_AT => $updatedFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($updatedFilter, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeStudio::factory() - ->for(Anime::factory()) - ->for(Studio::factory()) - ->create(); - }); - }); - - Carbon::withTestNow($excludedDate, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeStudio::factory() - ->for(Anime::factory()) - ->for(Studio::factory()) - ->create(); - }); - }); - - $animeStudios = AnimeStudio::query()->where(BasePivot::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - - $response = $this->get(route('api.animestudio.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeStudioCollection($animeStudios, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Studio Show Endpoint shall support constrained eager loading of anime by media format. - */ - public function testAnimeByMediaFormat(): void - { - $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), - ], - IncludeParser::param() => AnimeStudio::RELATION_ANIME, - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeStudio::factory() - ->for(Anime::factory()) - ->for(Studio::factory()) - ->create(); - }); - - $response = $this->get(route('api.animestudio.index', $parameters)); - - $animeStudios = AnimeStudio::with([ - AnimeStudio::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { - $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); - }, - ]) - ->get(); - - $response->assertJson( - json_decode( - json_encode( - new AnimeStudioCollection($animeStudios, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Studio Show Endpoint shall support constrained eager loading of anime by season. - */ - public function testAnimeBySeason(): void - { - $seasonFilter = Arr::random(AnimeSeason::cases()); - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), - ], - IncludeParser::param() => AnimeStudio::RELATION_ANIME, - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeStudio::factory() - ->for(Anime::factory()) - ->for(Studio::factory()) - ->create(); - }); - - $response = $this->get(route('api.animestudio.index', $parameters)); - - $animeStudios = AnimeStudio::with([ - AnimeStudio::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { - $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); - }, - ]) - ->get(); - - $response->assertJson( - json_decode( - json_encode( - new AnimeStudioCollection($animeStudios, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Studio Show Endpoint shall support constrained eager loading of anime by year. - */ - public function testAnimeByYear(): void - { - $yearFilter = intval($this->faker->year()); - $excludedYear = $yearFilter + 1; - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_YEAR => $yearFilter, - ], - IncludeParser::param() => AnimeStudio::RELATION_ANIME, - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () use ($yearFilter, $excludedYear) { - AnimeStudio::factory() - ->for( - Anime::factory() - ->state([ - Anime::ATTRIBUTE_YEAR => $this->faker->boolean() ? $yearFilter : $excludedYear, - ]) - ) - ->for(Studio::factory()) - ->create(); - }); - - $response = $this->get(route('api.animestudio.index', $parameters)); - - $animeStudios = AnimeStudio::with([ - AnimeStudio::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { - $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); - }, - ]) - ->get(); - - $response->assertJson( - json_decode( - json_encode( - new AnimeStudioCollection($animeStudios, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response->assertJson( + json_decode( + json_encode( + new AnimeStudioCollection($animeStudios, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/AnimeStudio/AnimeStudioShowTest.php b/tests/Feature/Http/Api/Pivot/Wiki/AnimeStudio/AnimeStudioShowTest.php index 3f927f332..ef65b5500 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/AnimeStudio/AnimeStudioShowTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/AnimeStudio/AnimeStudioShowTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\AnimeStudio; - use App\Enums\Models\Wiki\AnimeMediaFormat; use App\Enums\Models\Wiki\AnimeSeason; use App\Http\Api\Field\Field; @@ -18,249 +16,218 @@ use App\Models\Wiki\Anime; use App\Models\Wiki\Studio; use App\Pivots\Wiki\AnimeStudio; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; -use Tests\TestCase; -class AnimeStudioShowTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * The Anime Studio Show Endpoint shall return an error if the anime studio does not exist. - */ - public function testNotFound(): void - { - $anime = Anime::factory()->createOne(); - $studio = Studio::factory()->createOne(); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response = $this->get(route('api.animestudio.show', ['anime' => $anime, 'studio' => $studio])); +test('not found', function () { + $anime = Anime::factory()->createOne(); + $studio = Studio::factory()->createOne(); - $response->assertNotFound(); - } + $response = get(route('api.animestudio.show', ['anime' => $anime, 'studio' => $studio])); - /** - * By default, the Anime Studio Show Endpoint shall return an Anime Studio Resource. - */ - public function testDefault(): void - { - $animeStudio = AnimeStudio::factory() - ->for(Anime::factory()) - ->for(Studio::factory()) - ->createOne(); + $response->assertNotFound(); +}); - $response = $this->get(route('api.animestudio.show', ['anime' => $animeStudio->anime, 'studio' => $animeStudio->studio])); +test('default', function () { + $animeStudio = AnimeStudio::factory() + ->for(Anime::factory()) + ->for(Studio::factory()) + ->createOne(); - $animeStudio->unsetRelations(); + $response = get(route('api.animestudio.show', ['anime' => $animeStudio->anime, 'studio' => $animeStudio->studio])); - $response->assertJson( - json_decode( - json_encode( - new AnimeStudioResource($animeStudio, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $animeStudio->unsetRelations(); - /** - * The Anime Studio Show Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new AnimeStudioSchema(); + $response->assertJson( + json_decode( + json_encode( + new AnimeStudioResource($animeStudio, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('allowed include paths', function () { + $schema = new AnimeStudioSchema(); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $allowedIncludes = collect($schema->allowedIncludes()); - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - $animeStudio = AnimeStudio::factory() - ->for(Anime::factory()) - ->for(Studio::factory()) - ->createOne(); + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; - $response = $this->get(route('api.animestudio.show', ['anime' => $animeStudio->anime, 'studio' => $animeStudio->studio] + $parameters)); + $animeStudio = AnimeStudio::factory() + ->for(Anime::factory()) + ->for(Studio::factory()) + ->createOne(); - $animeStudio->unsetRelations()->load($includedPaths->all()); + $response = get(route('api.animestudio.show', ['anime' => $animeStudio->anime, 'studio' => $animeStudio->studio] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new AnimeStudioResource($animeStudio, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $animeStudio->unsetRelations()->load($includedPaths->all()); - /** - * The Anime Studio Show Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new AnimeStudioSchema(); + $response->assertJson( + json_decode( + json_encode( + new AnimeStudioResource($animeStudio, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $fields = collect($schema->fields()); +test('sparse fieldsets', function () { + $schema = new AnimeStudioSchema(); - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); + $fields = collect($schema->fields()); - $parameters = [ - FieldParser::param() => [ - AnimeStudioResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); - $animeStudio = AnimeStudio::factory() - ->for(Anime::factory()) - ->for(Studio::factory()) - ->createOne(); + $parameters = [ + FieldParser::param() => [ + AnimeStudioResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; - $response = $this->get(route('api.animestudio.show', ['anime' => $animeStudio->anime, 'studio' => $animeStudio->studio] + $parameters)); + $animeStudio = AnimeStudio::factory() + ->for(Anime::factory()) + ->for(Studio::factory()) + ->createOne(); - $animeStudio->unsetRelations(); + $response = get(route('api.animestudio.show', ['anime' => $animeStudio->anime, 'studio' => $animeStudio->studio] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new AnimeStudioResource($animeStudio, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $animeStudio->unsetRelations(); - /** - * The Anime Studio Show Endpoint shall support constrained eager loading of anime by media format. - */ - public function testAnimeByMediaFormat(): void - { - $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); + $response->assertJson( + json_decode( + json_encode( + new AnimeStudioResource($animeStudio, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), - ], - IncludeParser::param() => AnimeStudio::RELATION_ANIME, - ]; +test('anime by media format', function () { + $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); - $animeStudio = AnimeStudio::factory() - ->for(Anime::factory()) - ->for(Studio::factory()) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), + ], + IncludeParser::param() => AnimeStudio::RELATION_ANIME, + ]; - $response = $this->get(route('api.animestudio.show', ['anime' => $animeStudio->anime, 'studio' => $animeStudio->studio] + $parameters)); + $animeStudio = AnimeStudio::factory() + ->for(Anime::factory()) + ->for(Studio::factory()) + ->createOne(); - $animeStudio->unsetRelations()->load([ - AnimeStudio::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { - $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); - }, - ]); + $response = get(route('api.animestudio.show', ['anime' => $animeStudio->anime, 'studio' => $animeStudio->studio] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new AnimeStudioResource($animeStudio, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $animeStudio->unsetRelations()->load([ + AnimeStudio::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { + $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); + }, + ]); - /** - * The Anime Studio Show Endpoint shall support constrained eager loading of anime by season. - */ - public function testAnimeBySeason(): void - { - $seasonFilter = Arr::random(AnimeSeason::cases()); + $response->assertJson( + json_decode( + json_encode( + new AnimeStudioResource($animeStudio, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), - ], - IncludeParser::param() => AnimeStudio::RELATION_ANIME, - ]; +test('anime by season', function () { + $seasonFilter = Arr::random(AnimeSeason::cases()); - $animeStudio = AnimeStudio::factory() - ->for(Anime::factory()) - ->for(Studio::factory()) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), + ], + IncludeParser::param() => AnimeStudio::RELATION_ANIME, + ]; - $response = $this->get(route('api.animestudio.show', ['anime' => $animeStudio->anime, 'studio' => $animeStudio->studio] + $parameters)); + $animeStudio = AnimeStudio::factory() + ->for(Anime::factory()) + ->for(Studio::factory()) + ->createOne(); - $animeStudio->unsetRelations()->load([ - AnimeStudio::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { - $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); - }, - ]); + $response = get(route('api.animestudio.show', ['anime' => $animeStudio->anime, 'studio' => $animeStudio->studio] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new AnimeStudioResource($animeStudio, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $animeStudio->unsetRelations()->load([ + AnimeStudio::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { + $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); + }, + ]); - /** - * The Anime Studio Show Endpoint shall support constrained eager loading of anime by year. - */ - public function testAnimeByYear(): void - { - $yearFilter = intval($this->faker->year()); - $excludedYear = $yearFilter + 1; + $response->assertJson( + json_decode( + json_encode( + new AnimeStudioResource($animeStudio, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_YEAR => $yearFilter, - ], - IncludeParser::param() => AnimeStudio::RELATION_ANIME, - ]; +test('anime by year', function () { + $yearFilter = intval(fake()->year()); + $excludedYear = $yearFilter + 1; - $animeStudio = AnimeStudio::factory() - ->for( - Anime::factory() - ->state([ - Anime::ATTRIBUTE_YEAR => $this->faker->boolean() ? $yearFilter : $excludedYear, - ]) - ) - ->for(Studio::factory()) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_YEAR => $yearFilter, + ], + IncludeParser::param() => AnimeStudio::RELATION_ANIME, + ]; - $response = $this->get(route('api.animestudio.show', ['anime' => $animeStudio->anime, 'studio' => $animeStudio->studio] + $parameters)); + $animeStudio = AnimeStudio::factory() + ->for( + Anime::factory() + ->state([ + Anime::ATTRIBUTE_YEAR => fake()->boolean() ? $yearFilter : $excludedYear, + ]) + ) + ->for(Studio::factory()) + ->createOne(); - $animeStudio->unsetRelations()->load([ - AnimeStudio::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { - $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); - }, - ]); + $response = get(route('api.animestudio.show', ['anime' => $animeStudio->anime, 'studio' => $animeStudio->studio] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new AnimeStudioResource($animeStudio, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $animeStudio->unsetRelations()->load([ + AnimeStudio::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { + $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); + }, + ]); + + $response->assertJson( + json_decode( + json_encode( + new AnimeStudioResource($animeStudio, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/AnimeStudio/AnimeStudioStoreTest.php b/tests/Feature/Http/Api/Pivot/Wiki/AnimeStudio/AnimeStudioStoreTest.php index 83e9555d5..fe4151161 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/AnimeStudio/AnimeStudioStoreTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/AnimeStudio/AnimeStudioStoreTest.php @@ -2,68 +2,52 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\AnimeStudio; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Anime; use App\Models\Wiki\Studio; use App\Pivots\Wiki\AnimeStudio; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class AnimeStudioStoreTest extends TestCase -{ - /** - * The Anime Studio Store Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $anime = Anime::factory()->createOne(); - $studio = Studio::factory()->createOne(); +use function Pest\Laravel\post; - $response = $this->post(route('api.animestudio.store', ['anime' => $anime, 'studio' => $studio])); +test('protected', function () { + $anime = Anime::factory()->createOne(); + $studio = Studio::factory()->createOne(); - $response->assertUnauthorized(); - } + $response = post(route('api.animestudio.store', ['anime' => $anime, 'studio' => $studio])); - /** - * The Anime Studio Store Endpoint shall forbid users without the create anime & create studio permissions. - */ - public function testForbidden(): void - { - $anime = Anime::factory()->createOne(); - $studio = Studio::factory()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $anime = Anime::factory()->createOne(); + $studio = Studio::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->post(route('api.animestudio.store', ['anime' => $anime, 'studio' => $studio])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.animestudio.store', ['anime' => $anime, 'studio' => $studio])); - /** - * The Anime Studio Store Endpoint shall create an anime studio. - */ - public function testCreate(): void - { - $anime = Anime::factory()->createOne(); - $studio = Studio::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory() - ->withPermissions( - CrudPermission::CREATE->format(Anime::class), - CrudPermission::CREATE->format(Studio::class) - ) - ->createOne(); +test('create', function () { + $anime = Anime::factory()->createOne(); + $studio = Studio::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::CREATE->format(Anime::class), + CrudPermission::CREATE->format(Studio::class) + ) + ->createOne(); - $response = $this->post(route('api.animestudio.store', ['anime' => $anime, 'studio' => $studio])); + Sanctum::actingAs($user); - $response->assertCreated(); - static::assertDatabaseCount(AnimeStudio::class, 1); - } -} + $response = post(route('api.animestudio.store', ['anime' => $anime, 'studio' => $studio])); + + $response->assertCreated(); + $this->assertDatabaseCount(AnimeStudio::class, 1); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/AnimeThemeEntryVideo/AnimeThemeEntryVideoDestroyTest.php b/tests/Feature/Http/Api/Pivot/Wiki/AnimeThemeEntryVideo/AnimeThemeEntryVideoDestroyTest.php index 81a979e6f..26e5949e2 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/AnimeThemeEntryVideo/AnimeThemeEntryVideoDestroyTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/AnimeThemeEntryVideo/AnimeThemeEntryVideoDestroyTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\AnimeThemeEntryVideo; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Anime; @@ -12,91 +10,73 @@ use App\Models\Wiki\Anime\Theme\AnimeThemeEntry; use App\Models\Wiki\Video; use App\Pivots\Wiki\AnimeThemeEntryVideo; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class AnimeThemeEntryVideoDestroyTest extends TestCase -{ - /** - * The Anime Theme Entry Video Destroy Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $entryVideo = AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.animethemeentryvideo.destroy', ['animethemeentry' => $entryVideo->animethemeentry, 'video' => $entryVideo->video])); +test('protected', function () { + $entryVideo = AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.animethemeentryvideo.destroy', ['animethemeentry' => $entryVideo->animethemeentry, 'video' => $entryVideo->video])); - /** - * The Anime Theme Entry Video Destroy Endpoint shall forbid users without the delete anime theme entry & delete video permissions. - */ - public function testForbidden(): void - { - $entryVideo = AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $entryVideo = AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.animethemeentryvideo.destroy', ['animethemeentry' => $entryVideo->animethemeentry, 'video' => $entryVideo->video])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.animethemeentryvideo.destroy', ['animethemeentry' => $entryVideo->animethemeentry, 'video' => $entryVideo->video])); - /** - * The Anime Theme Entry Video Destroy Endpoint shall return an error if the anime theme entry video does not exist. - */ - public function testNotFound(): void - { - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->create(); + $response->assertForbidden(); +}); - $video = Video::factory()->createOne(); +test('not found', function () { + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->create(); - $user = User::factory() - ->withPermissions( - CrudPermission::DELETE->format(AnimeThemeEntry::class), - CrudPermission::DELETE->format(Video::class) - ) - ->createOne(); + $video = Video::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::DELETE->format(AnimeThemeEntry::class), + CrudPermission::DELETE->format(Video::class) + ) + ->createOne(); - $response = $this->delete(route('api.animethemeentryvideo.destroy', ['animethemeentry' => $entry, 'video' => $video])); + Sanctum::actingAs($user); - $response->assertNotFound(); - } + $response = delete(route('api.animethemeentryvideo.destroy', ['animethemeentry' => $entry, 'video' => $video])); - /** - * The Anime Theme Entry Video Destroy Endpoint shall delete the anime theme entry video. - */ - public function testDeleted(): void - { - $entryVideo = AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->createOne(); + $response->assertNotFound(); +}); - $user = User::factory() - ->withPermissions( - CrudPermission::DELETE->format(AnimeThemeEntry::class), - CrudPermission::DELETE->format(Video::class) - ) - ->createOne(); +test('deleted', function () { + $entryVideo = AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::DELETE->format(AnimeThemeEntry::class), + CrudPermission::DELETE->format(Video::class) + ) + ->createOne(); - $response = $this->delete(route('api.animethemeentryvideo.destroy', ['animethemeentry' => $entryVideo->animethemeentry, 'video' => $entryVideo->video])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertModelMissing($entryVideo); - } -} + $response = delete(route('api.animethemeentryvideo.destroy', ['animethemeentry' => $entryVideo->animethemeentry, 'video' => $entryVideo->video])); + + $response->assertOk(); + $this->assertModelMissing($entryVideo); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/AnimeThemeEntryVideo/AnimeThemeEntryVideoIndexTest.php b/tests/Feature/Http/Api/Pivot/Wiki/AnimeThemeEntryVideo/AnimeThemeEntryVideoIndexTest.php index c5d36f7a8..de477025c 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/AnimeThemeEntryVideo/AnimeThemeEntryVideoIndexTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/AnimeThemeEntryVideo/AnimeThemeEntryVideoIndexTest.php @@ -2,9 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\AnimeThemeEntryVideo; - -use App\Concerns\Actions\Http\Api\SortsModels; use App\Contracts\Http\Api\Field\SortableField; use App\Enums\Http\Api\Sort\Direction; use App\Enums\Models\Wiki\VideoOverlap; @@ -30,707 +27,637 @@ use App\Models\Wiki\Video; use App\Pivots\BasePivot; use App\Pivots\Wiki\AnimeThemeEntryVideo; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; use Illuminate\Support\Collection; -use Tests\TestCase; -class AnimeThemeEntryVideoIndexTest extends TestCase -{ - use SortsModels; - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the Anime Theme Entry Video Index Endpoint shall return a collection of Anime Theme Entry Video Resources. - */ - public function testDefault(): void - { - Collection::times($this->faker->randomDigitNotNull(), function () { +uses(App\Concerns\Actions\Http\Api\SortsModels::class); + +uses(Illuminate\Foundation\Testing\WithFaker::class); + +test('default', function () { + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->create(); + }); + + $entryVideos = AnimeThemeEntryVideo::all(); + + $response = get(route('api.animethemeentryvideo.index')); + + $response->assertJson( + json_decode( + json_encode( + new AnimeThemeEntryVideoCollection($entryVideos, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('paginated', function () { + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->create(); + }); + + $response = get(route('api.animethemeentryvideo.index')); + + $response->assertJsonStructure([ + AnimeThemeEntryVideoCollection::$wrap, + 'links', + 'meta', + ]); +}); + +test('allowed include paths', function () { + $schema = new AnimeThemeEntryVideoSchema(); + + $allowedIncludes = collect($schema->allowedIncludes()); + + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); + + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->create(); + }); + + $response = get(route('api.animethemeentryvideo.index', $parameters)); + + $entryVideos = AnimeThemeEntryVideo::with($includedPaths->all())->get(); + + $response->assertJson( + json_decode( + json_encode( + new AnimeThemeEntryVideoCollection($entryVideos, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sparse fieldsets', function () { + $schema = new AnimeThemeEntryVideoSchema(); + + $fields = collect($schema->fields()); + + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + AnimeThemeEntryVideoResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->create(); + }); + + $response = get(route('api.animethemeentryvideo.index', $parameters)); + + $entryVideos = AnimeThemeEntryVideo::all(); + + $response->assertJson( + json_decode( + json_encode( + new AnimeThemeEntryVideoCollection($entryVideos, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sorts', function () { + $schema = new AnimeThemeEntryVideoSchema(); + + /** @var Sort $sort */ + $sort = collect($schema->fields()) + ->filter(fn (Field $field) => $field instanceof SortableField) + ->map(fn (SortableField $field) => $field->getSort()) + ->random(); + + $parameters = [ + SortParser::param() => $sort->format(Arr::random(Direction::cases())), + ]; + + $query = new Query($parameters); + + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->create(); + }); + + $response = get(route('api.animethemeentryvideo.index', $parameters)); + + $entryVideos = $this->sort(AnimeThemeEntryVideo::query(), $query, $schema)->get(); + + $response->assertJson( + json_decode( + json_encode( + new AnimeThemeEntryVideoCollection($entryVideos, $query) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('created at filter', function () { + $createdFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BasePivot::ATTRIBUTE_CREATED_AT => $createdFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($createdFilter, function () { + Collection::times(fake()->randomDigitNotNull(), function () { AnimeThemeEntryVideo::factory() ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) ->for(Video::factory()) ->create(); }); + }); - $entryVideos = AnimeThemeEntryVideo::all(); - - $response = $this->get(route('api.animethemeentryvideo.index')); - - $response->assertJson( - json_decode( - json_encode( - new AnimeThemeEntryVideoCollection($entryVideos, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Theme Entry Video Index Endpoint shall be paginated. - */ - public function testPaginated(): void - { - Collection::times($this->faker->randomDigitNotNull(), function () { + Carbon::withTestNow($excludedDate, function () { + Collection::times(fake()->randomDigitNotNull(), function () { AnimeThemeEntryVideo::factory() ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) ->for(Video::factory()) ->create(); }); + }); - $response = $this->get(route('api.animethemeentryvideo.index')); + $entryVideos = AnimeThemeEntryVideo::query()->where(BasePivot::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - $response->assertJsonStructure([ - AnimeThemeEntryVideoCollection::$wrap, - 'links', - 'meta', - ]); - } + $response = get(route('api.animethemeentryvideo.index', $parameters)); - /** - * The Anime Theme Entry Video Index Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new AnimeThemeEntryVideoSchema(); + $response->assertJson( + json_decode( + json_encode( + new AnimeThemeEntryVideoCollection($entryVideos, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('updated at filter', function () { + $updatedFilter = fake()->date(); + $excludedDate = fake()->date(); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $parameters = [ + FilterParser::param() => [ + BasePivot::ATTRIBUTE_UPDATED_AT => $updatedFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { + Carbon::withTestNow($updatedFilter, function () { + Collection::times(fake()->randomDigitNotNull(), function () { AnimeThemeEntryVideo::factory() ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) ->for(Video::factory()) ->create(); }); + }); - $response = $this->get(route('api.animethemeentryvideo.index', $parameters)); - - $entryVideos = AnimeThemeEntryVideo::with($includedPaths->all())->get(); - - $response->assertJson( - json_decode( - json_encode( - new AnimeThemeEntryVideoCollection($entryVideos, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Theme Entry Video Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new AnimeThemeEntryVideoSchema(); - - $fields = collect($schema->fields()); - - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); - - $parameters = [ - FieldParser::param() => [ - AnimeThemeEntryVideoResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { + Carbon::withTestNow($excludedDate, function () { + Collection::times(fake()->randomDigitNotNull(), function () { AnimeThemeEntryVideo::factory() ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) ->for(Video::factory()) ->create(); }); - - $response = $this->get(route('api.animethemeentryvideo.index', $parameters)); - - $entryVideos = AnimeThemeEntryVideo::all(); - - $response->assertJson( - json_decode( - json_encode( - new AnimeThemeEntryVideoCollection($entryVideos, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Theme Entry Video Index Endpoint shall support sorting resources. - */ - public function testSorts(): void - { - $schema = new AnimeThemeEntryVideoSchema(); - - /** @var Sort $sort */ - $sort = collect($schema->fields()) - ->filter(fn (Field $field) => $field instanceof SortableField) - ->map(fn (SortableField $field) => $field->getSort()) - ->random(); - - $parameters = [ - SortParser::param() => $sort->format(Arr::random(Direction::cases())), - ]; - - $query = new Query($parameters); - - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->create(); - }); - - $response = $this->get(route('api.animethemeentryvideo.index', $parameters)); - - $entryVideos = $this->sort(AnimeThemeEntryVideo::query(), $query, $schema)->get(); - - $response->assertJson( - json_decode( - json_encode( - new AnimeThemeEntryVideoCollection($entryVideos, $query) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Theme Entry Video Index Endpoint shall support filtering by created_at. - */ - public function testCreatedAtFilter(): void - { - $createdFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BasePivot::ATTRIBUTE_CREATED_AT => $createdFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($createdFilter, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->create(); - }); - }); - - Carbon::withTestNow($excludedDate, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->create(); - }); - }); - - $entryVideos = AnimeThemeEntryVideo::query()->where(BasePivot::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - - $response = $this->get(route('api.animethemeentryvideo.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeThemeEntryVideoCollection($entryVideos, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Theme Entry Video Index Endpoint shall support filtering by updated_at. - */ - public function testUpdatedAtFilter(): void - { - $updatedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BasePivot::ATTRIBUTE_UPDATED_AT => $updatedFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($updatedFilter, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->create(); - }); - }); - - Carbon::withTestNow($excludedDate, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->create(); - }); - }); - - $entryVideos = AnimeThemeEntryVideo::query()->where(BasePivot::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - - $response = $this->get(route('api.animethemeentryvideo.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeThemeEntryVideoCollection($entryVideos, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Theme Entry Video Show Endpoint shall support constrained eager loading of entries by nsfw. - */ - public function testEntriesByNsfw(): void - { - $nsfwFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - AnimeThemeEntry::ATTRIBUTE_NSFW => $nsfwFilter, - ], - IncludeParser::param() => AnimeThemeEntryVideo::RELATION_ENTRY, - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->create(); - }); - - $response = $this->get(route('api.animethemeentryvideo.index', $parameters)); - - $entryVideos = AnimeThemeEntryVideo::with([ - AnimeThemeEntryVideo::RELATION_ENTRY => function (BelongsTo $query) use ($nsfwFilter) { - $query->where(AnimeThemeEntry::ATTRIBUTE_NSFW, $nsfwFilter); - }, - ]) - ->get(); - - $response->assertJson( - json_decode( - json_encode( - new AnimeThemeEntryVideoCollection($entryVideos, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Theme Entry Video Show Endpoint shall support constrained eager loading of entries by spoiler. - */ - public function testEntriesBySpoiler(): void - { - $spoilerFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - AnimeThemeEntry::ATTRIBUTE_SPOILER => $spoilerFilter, - ], - IncludeParser::param() => AnimeThemeEntryVideo::RELATION_ENTRY, - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->create(); - }); - - $response = $this->get(route('api.animethemeentryvideo.index', $parameters)); - - $entryVideos = AnimeThemeEntryVideo::with([ - AnimeThemeEntryVideo::RELATION_ENTRY => function (BelongsTo $query) use ($spoilerFilter) { - $query->where(AnimeThemeEntry::ATTRIBUTE_SPOILER, $spoilerFilter); - }, - ]) - ->get(); - - $response->assertJson( - json_decode( - json_encode( - new AnimeThemeEntryVideoCollection($entryVideos, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Theme Entry Video Show Endpoint shall support constrained eager loading of entries by version. - */ - public function testEntriesByVersion(): void - { - $versionFilter = $this->faker->randomDigitNotNull(); - - $parameters = [ - FilterParser::param() => [ - AnimeThemeEntry::ATTRIBUTE_VERSION => $versionFilter, - ], - IncludeParser::param() => AnimeThemeEntryVideo::RELATION_ENTRY, - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->create(); - }); - - $response = $this->get(route('api.animethemeentryvideo.index', $parameters)); - - $entryVideos = AnimeThemeEntryVideo::with([ - AnimeThemeEntryVideo::RELATION_ENTRY => function (BelongsTo $query) use ($versionFilter) { - $query->where(AnimeThemeEntry::ATTRIBUTE_VERSION, $versionFilter); - }, - ]) - ->get(); - - $response->assertJson( - json_decode( - json_encode( - new AnimeThemeEntryVideoCollection($entryVideos, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Theme Entry Video Show Endpoint shall support constrained eager loading of videos by lyrics. - */ - public function testVideosByLyrics(): void - { - $lyricsFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_LYRICS => $lyricsFilter, - ], - IncludeParser::param() => AnimeThemeEntryVideo::RELATION_VIDEO, - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->create(); - }); - - $response = $this->get(route('api.animethemeentryvideo.index', $parameters)); - - $entryVideos = AnimeThemeEntryVideo::with([ - AnimeThemeEntryVideo::RELATION_VIDEO => function (BelongsTo $query) use ($lyricsFilter) { - $query->where(Video::ATTRIBUTE_LYRICS, $lyricsFilter); - }, - ]) - ->get(); - - $response->assertJson( - json_decode( - json_encode( - new AnimeThemeEntryVideoCollection($entryVideos, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Theme Entry Video Show Endpoint shall support constrained eager loading of videos by nc. - */ - public function testVideosByNc(): void - { - $ncFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_NC => $ncFilter, - ], - IncludeParser::param() => AnimeThemeEntryVideo::RELATION_VIDEO, - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->create(); - }); - - $response = $this->get(route('api.animethemeentryvideo.index', $parameters)); - - $entryVideos = AnimeThemeEntryVideo::with([ - AnimeThemeEntryVideo::RELATION_VIDEO => function (BelongsTo $query) use ($ncFilter) { - $query->where(Video::ATTRIBUTE_NC, $ncFilter); - }, - ]) - ->get(); - - $response->assertJson( - json_decode( - json_encode( - new AnimeThemeEntryVideoCollection($entryVideos, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Theme Entry Video Show Endpoint shall support constrained eager loading of videos by overlap. - */ - public function testVideosByOverlap(): void - { - $overlapFilter = Arr::random(VideoOverlap::cases()); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_OVERLAP => $overlapFilter->localize(), - ], - IncludeParser::param() => AnimeThemeEntryVideo::RELATION_VIDEO, - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->create(); - }); - - $response = $this->get(route('api.animethemeentryvideo.index', $parameters)); - - $entryVideos = AnimeThemeEntryVideo::with([ - AnimeThemeEntryVideo::RELATION_VIDEO => function (BelongsTo $query) use ($overlapFilter) { - $query->where(Video::ATTRIBUTE_OVERLAP, $overlapFilter->value); - }, - ]) - ->get(); - - $response->assertJson( - json_decode( - json_encode( - new AnimeThemeEntryVideoCollection($entryVideos, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Theme Entry Video Show Endpoint shall support constrained eager loading of videos by resolution. - */ - public function testVideosByResolution(): void - { - $resolutionFilter = $this->faker->randomNumber(); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_RESOLUTION => $resolutionFilter, - ], - IncludeParser::param() => AnimeThemeEntryVideo::RELATION_VIDEO, - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->create(); - }); - - $response = $this->get(route('api.animethemeentryvideo.index', $parameters)); - - $entryVideos = AnimeThemeEntryVideo::with([ - AnimeThemeEntryVideo::RELATION_VIDEO => function (BelongsTo $query) use ($resolutionFilter) { - $query->where(Video::ATTRIBUTE_RESOLUTION, $resolutionFilter); - }, - ]) - ->get(); - - $response->assertJson( - json_decode( - json_encode( - new AnimeThemeEntryVideoCollection($entryVideos, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Theme Entry Video Show Endpoint shall support constrained eager loading of videos by source. - */ - public function testVideosBySource(): void - { - $sourceFilter = Arr::random(VideoSource::cases()); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_SOURCE => $sourceFilter->localize(), - ], - IncludeParser::param() => AnimeThemeEntryVideo::RELATION_VIDEO, - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->create(); - }); - - $response = $this->get(route('api.animethemeentryvideo.index', $parameters)); - - $entryVideos = AnimeThemeEntryVideo::with([ - AnimeThemeEntryVideo::RELATION_VIDEO => function (BelongsTo $query) use ($sourceFilter) { - $query->where(Video::ATTRIBUTE_SOURCE, $sourceFilter->value); - }, - ]) - ->get(); - - $response->assertJson( - json_decode( - json_encode( - new AnimeThemeEntryVideoCollection($entryVideos, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Theme Entry Video Show Endpoint shall support constrained eager loading of videos by subbed. - */ - public function testVideosBySubbed(): void - { - $subbedFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_SUBBED => $subbedFilter, - ], - IncludeParser::param() => AnimeThemeEntryVideo::RELATION_VIDEO, - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->create(); - }); - - $response = $this->get(route('api.animethemeentryvideo.index', $parameters)); - - $entryVideos = AnimeThemeEntryVideo::with([ - AnimeThemeEntryVideo::RELATION_VIDEO => function (BelongsTo $query) use ($subbedFilter) { - $query->where(Video::ATTRIBUTE_SUBBED, $subbedFilter); - }, - ]) - ->get(); - - $response->assertJson( - json_decode( - json_encode( - new AnimeThemeEntryVideoCollection($entryVideos, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Theme Entry Video Show Endpoint shall support constrained eager loading of videos by uncen. - */ - public function testVideosByUncen(): void - { - $uncenFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_UNCEN => $uncenFilter, - ], - IncludeParser::param() => AnimeThemeEntryVideo::RELATION_VIDEO, - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { - AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->create(); - }); - - $response = $this->get(route('api.animethemeentryvideo.index', $parameters)); - - $entryVideos = AnimeThemeEntryVideo::with([ - AnimeThemeEntryVideo::RELATION_VIDEO => function (BelongsTo $query) use ($uncenFilter) { - $query->where(Video::ATTRIBUTE_UNCEN, $uncenFilter); - }, - ]) - ->get(); - - $response->assertJson( - json_decode( - json_encode( - new AnimeThemeEntryVideoCollection($entryVideos, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + }); + + $entryVideos = AnimeThemeEntryVideo::query()->where(BasePivot::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); + + $response = get(route('api.animethemeentryvideo.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnimeThemeEntryVideoCollection($entryVideos, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('entries by nsfw', function () { + $nsfwFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + AnimeThemeEntry::ATTRIBUTE_NSFW => $nsfwFilter, + ], + IncludeParser::param() => AnimeThemeEntryVideo::RELATION_ENTRY, + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->create(); + }); + + $response = get(route('api.animethemeentryvideo.index', $parameters)); + + $entryVideos = AnimeThemeEntryVideo::with([ + AnimeThemeEntryVideo::RELATION_ENTRY => function (BelongsTo $query) use ($nsfwFilter) { + $query->where(AnimeThemeEntry::ATTRIBUTE_NSFW, $nsfwFilter); + }, + ]) + ->get(); + + $response->assertJson( + json_decode( + json_encode( + new AnimeThemeEntryVideoCollection($entryVideos, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('entries by spoiler', function () { + $spoilerFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + AnimeThemeEntry::ATTRIBUTE_SPOILER => $spoilerFilter, + ], + IncludeParser::param() => AnimeThemeEntryVideo::RELATION_ENTRY, + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->create(); + }); + + $response = get(route('api.animethemeentryvideo.index', $parameters)); + + $entryVideos = AnimeThemeEntryVideo::with([ + AnimeThemeEntryVideo::RELATION_ENTRY => function (BelongsTo $query) use ($spoilerFilter) { + $query->where(AnimeThemeEntry::ATTRIBUTE_SPOILER, $spoilerFilter); + }, + ]) + ->get(); + + $response->assertJson( + json_decode( + json_encode( + new AnimeThemeEntryVideoCollection($entryVideos, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('entries by version', function () { + $versionFilter = fake()->randomDigitNotNull(); + + $parameters = [ + FilterParser::param() => [ + AnimeThemeEntry::ATTRIBUTE_VERSION => $versionFilter, + ], + IncludeParser::param() => AnimeThemeEntryVideo::RELATION_ENTRY, + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->create(); + }); + + $response = get(route('api.animethemeentryvideo.index', $parameters)); + + $entryVideos = AnimeThemeEntryVideo::with([ + AnimeThemeEntryVideo::RELATION_ENTRY => function (BelongsTo $query) use ($versionFilter) { + $query->where(AnimeThemeEntry::ATTRIBUTE_VERSION, $versionFilter); + }, + ]) + ->get(); + + $response->assertJson( + json_decode( + json_encode( + new AnimeThemeEntryVideoCollection($entryVideos, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by lyrics', function () { + $lyricsFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_LYRICS => $lyricsFilter, + ], + IncludeParser::param() => AnimeThemeEntryVideo::RELATION_VIDEO, + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->create(); + }); + + $response = get(route('api.animethemeentryvideo.index', $parameters)); + + $entryVideos = AnimeThemeEntryVideo::with([ + AnimeThemeEntryVideo::RELATION_VIDEO => function (BelongsTo $query) use ($lyricsFilter) { + $query->where(Video::ATTRIBUTE_LYRICS, $lyricsFilter); + }, + ]) + ->get(); + + $response->assertJson( + json_decode( + json_encode( + new AnimeThemeEntryVideoCollection($entryVideos, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by nc', function () { + $ncFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_NC => $ncFilter, + ], + IncludeParser::param() => AnimeThemeEntryVideo::RELATION_VIDEO, + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->create(); + }); + + $response = get(route('api.animethemeentryvideo.index', $parameters)); + + $entryVideos = AnimeThemeEntryVideo::with([ + AnimeThemeEntryVideo::RELATION_VIDEO => function (BelongsTo $query) use ($ncFilter) { + $query->where(Video::ATTRIBUTE_NC, $ncFilter); + }, + ]) + ->get(); + + $response->assertJson( + json_decode( + json_encode( + new AnimeThemeEntryVideoCollection($entryVideos, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by overlap', function () { + $overlapFilter = Arr::random(VideoOverlap::cases()); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_OVERLAP => $overlapFilter->localize(), + ], + IncludeParser::param() => AnimeThemeEntryVideo::RELATION_VIDEO, + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->create(); + }); + + $response = get(route('api.animethemeentryvideo.index', $parameters)); + + $entryVideos = AnimeThemeEntryVideo::with([ + AnimeThemeEntryVideo::RELATION_VIDEO => function (BelongsTo $query) use ($overlapFilter) { + $query->where(Video::ATTRIBUTE_OVERLAP, $overlapFilter->value); + }, + ]) + ->get(); + + $response->assertJson( + json_decode( + json_encode( + new AnimeThemeEntryVideoCollection($entryVideos, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by resolution', function () { + $resolutionFilter = fake()->randomNumber(); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_RESOLUTION => $resolutionFilter, + ], + IncludeParser::param() => AnimeThemeEntryVideo::RELATION_VIDEO, + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->create(); + }); + + $response = get(route('api.animethemeentryvideo.index', $parameters)); + + $entryVideos = AnimeThemeEntryVideo::with([ + AnimeThemeEntryVideo::RELATION_VIDEO => function (BelongsTo $query) use ($resolutionFilter) { + $query->where(Video::ATTRIBUTE_RESOLUTION, $resolutionFilter); + }, + ]) + ->get(); + + $response->assertJson( + json_decode( + json_encode( + new AnimeThemeEntryVideoCollection($entryVideos, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by source', function () { + $sourceFilter = Arr::random(VideoSource::cases()); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_SOURCE => $sourceFilter->localize(), + ], + IncludeParser::param() => AnimeThemeEntryVideo::RELATION_VIDEO, + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->create(); + }); + + $response = get(route('api.animethemeentryvideo.index', $parameters)); + + $entryVideos = AnimeThemeEntryVideo::with([ + AnimeThemeEntryVideo::RELATION_VIDEO => function (BelongsTo $query) use ($sourceFilter) { + $query->where(Video::ATTRIBUTE_SOURCE, $sourceFilter->value); + }, + ]) + ->get(); + + $response->assertJson( + json_decode( + json_encode( + new AnimeThemeEntryVideoCollection($entryVideos, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by subbed', function () { + $subbedFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_SUBBED => $subbedFilter, + ], + IncludeParser::param() => AnimeThemeEntryVideo::RELATION_VIDEO, + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->create(); + }); + + $response = get(route('api.animethemeentryvideo.index', $parameters)); + + $entryVideos = AnimeThemeEntryVideo::with([ + AnimeThemeEntryVideo::RELATION_VIDEO => function (BelongsTo $query) use ($subbedFilter) { + $query->where(Video::ATTRIBUTE_SUBBED, $subbedFilter); + }, + ]) + ->get(); + + $response->assertJson( + json_decode( + json_encode( + new AnimeThemeEntryVideoCollection($entryVideos, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by uncen', function () { + $uncenFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_UNCEN => $uncenFilter, + ], + IncludeParser::param() => AnimeThemeEntryVideo::RELATION_VIDEO, + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->create(); + }); + + $response = get(route('api.animethemeentryvideo.index', $parameters)); + + $entryVideos = AnimeThemeEntryVideo::with([ + AnimeThemeEntryVideo::RELATION_VIDEO => function (BelongsTo $query) use ($uncenFilter) { + $query->where(Video::ATTRIBUTE_UNCEN, $uncenFilter); + }, + ]) + ->get(); + + $response->assertJson( + json_decode( + json_encode( + new AnimeThemeEntryVideoCollection($entryVideos, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/AnimeThemeEntryVideo/AnimeThemeEntryVideoShowTest.php b/tests/Feature/Http/Api/Pivot/Wiki/AnimeThemeEntryVideo/AnimeThemeEntryVideoShowTest.php index 2a98e03a5..229c714a8 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/AnimeThemeEntryVideo/AnimeThemeEntryVideoShowTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/AnimeThemeEntryVideo/AnimeThemeEntryVideoShowTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\AnimeThemeEntryVideo; - use App\Enums\Models\Wiki\VideoOverlap; use App\Enums\Models\Wiki\VideoSource; use App\Http\Api\Field\Field; @@ -20,519 +18,460 @@ use App\Models\Wiki\Anime\Theme\AnimeThemeEntry; use App\Models\Wiki\Video; use App\Pivots\Wiki\AnimeThemeEntryVideo; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; -use Tests\TestCase; - -class AnimeThemeEntryVideoShowTest extends TestCase -{ - use WithFaker; - - /** - * The Anime Theme Entry Video Show Endpoint shall return an error if the anime video does not exist. - */ - public function testNotFound(): void - { - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->create(); - - $video = Video::factory()->createOne(); - - $response = $this->get(route('api.animethemeentryvideo.show', ['animethemeentry' => $entry, 'video' => $video])); - - $response->assertNotFound(); - } - - /** - * By default, the Anime Theme Entry Video Show Endpoint shall return an Anime Theme Entry Video Resource. - */ - public function testDefault(): void - { - $entryVideo = AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->createOne(); - - $response = $this->get(route('api.animethemeentryvideo.show', ['animethemeentry' => $entryVideo->animethemeentry, 'video' => $entryVideo->video])); - - $entryVideo->unsetRelations(); - - $response->assertJson( - json_decode( - json_encode( - new AnimeThemeEntryVideoResource($entryVideo, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Theme Entry Video Show Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new AnimeThemeEntryVideoSchema(); - - $allowedIncludes = collect($schema->allowedIncludes()); - - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); - - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; - - $entryVideo = AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->createOne(); - - $response = $this->get(route('api.animethemeentryvideo.show', ['animethemeentry' => $entryVideo->animethemeentry, 'video' => $entryVideo->video] + $parameters)); - - $entryVideo->unsetRelations()->load($includedPaths->all()); - - $response->assertJson( - json_decode( - json_encode( - new AnimeThemeEntryVideoResource($entryVideo, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Theme Entry Video Show Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new AnimeThemeEntryVideoSchema(); - - $fields = collect($schema->fields()); - - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); - - $parameters = [ - FieldParser::param() => [ - AnimeThemeEntryVideoResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; - - $entryVideo = AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->createOne(); - - $response = $this->get(route('api.animethemeentryvideo.show', ['animethemeentry' => $entryVideo->animethemeentry, 'video' => $entryVideo->video] + $parameters)); - - $entryVideo->unsetRelations(); - - $response->assertJson( - json_decode( - json_encode( - new AnimeThemeEntryVideoResource($entryVideo, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Theme Entry Video Show Endpoint shall support constrained eager loading of entries by nsfw. - */ - public function testEntryByNsfw(): void - { - $nsfwFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - AnimeThemeEntry::ATTRIBUTE_NSFW => $nsfwFilter, - ], - IncludeParser::param() => AnimeThemeEntryVideo::RELATION_ENTRY, - ]; - - $entryVideo = AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->createOne(); - - $response = $this->get(route('api.animethemeentryvideo.show', ['animethemeentry' => $entryVideo->animethemeentry, 'video' => $entryVideo->video] + $parameters)); - - $entryVideo->unsetRelations()->load([ - AnimeThemeEntryVideo::RELATION_ENTRY => function (BelongsTo $query) use ($nsfwFilter) { - $query->where(AnimeThemeEntry::ATTRIBUTE_NSFW, $nsfwFilter); - }, - ]); - - $response->assertJson( - json_decode( - json_encode( - new AnimeThemeEntryVideoResource($entryVideo, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Theme Entry Video Show Endpoint shall support constrained eager loading of entries by spoiler. - */ - public function testEntryBySpoiler(): void - { - $spoilerFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - AnimeThemeEntry::ATTRIBUTE_SPOILER => $spoilerFilter, - ], - IncludeParser::param() => AnimeThemeEntryVideo::RELATION_ENTRY, - ]; - - $entryVideo = AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->createOne(); - - $response = $this->get(route('api.animethemeentryvideo.show', ['animethemeentry' => $entryVideo->animethemeentry, 'video' => $entryVideo->video] + $parameters)); - - $entryVideo->unsetRelations()->load([ - AnimeThemeEntryVideo::RELATION_ENTRY => function (BelongsTo $query) use ($spoilerFilter) { - $query->where(AnimeThemeEntry::ATTRIBUTE_SPOILER, $spoilerFilter); - }, - ]); - - $response->assertJson( - json_decode( - json_encode( - new AnimeThemeEntryVideoResource($entryVideo, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Theme Entry Video Show Endpoint shall support constrained eager loading of entries by version. - */ - public function testEntryByVersion(): void - { - $versionFilter = $this->faker->randomDigitNotNull(); - - $parameters = [ - FilterParser::param() => [ - AnimeThemeEntry::ATTRIBUTE_VERSION => $versionFilter, - ], - IncludeParser::param() => AnimeThemeEntryVideo::RELATION_ENTRY, - ]; - - $entryVideo = AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->createOne(); - - $response = $this->get(route('api.animethemeentryvideo.show', ['animethemeentry' => $entryVideo->animethemeentry, 'video' => $entryVideo->video] + $parameters)); - - $entryVideo->unsetRelations()->load([ - AnimeThemeEntryVideo::RELATION_ENTRY => function (BelongsTo $query) use ($versionFilter) { - $query->where(AnimeThemeEntry::ATTRIBUTE_VERSION, $versionFilter); - }, - ]); - - $response->assertJson( - json_decode( - json_encode( - new AnimeThemeEntryVideoResource($entryVideo, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Theme Entry Video Show Endpoint shall support constrained eager loading of videos by lyrics. - */ - public function testVideoByLyrics(): void - { - $lyricsFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_LYRICS => $lyricsFilter, - ], - IncludeParser::param() => AnimeThemeEntryVideo::RELATION_VIDEO, - ]; - - $entryVideo = AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->createOne(); - - $response = $this->get(route('api.animethemeentryvideo.show', ['animethemeentry' => $entryVideo->animethemeentry, 'video' => $entryVideo->video] + $parameters)); - - $entryVideo->unsetRelations()->load([ - AnimeThemeEntryVideo::RELATION_VIDEO => function (BelongsTo $query) use ($lyricsFilter) { - $query->where(Video::ATTRIBUTE_LYRICS, $lyricsFilter); - }, - ]); - - $response->assertJson( - json_decode( - json_encode( - new AnimeThemeEntryVideoResource($entryVideo, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Theme Entry Video Show Endpoint shall support constrained eager loading of videos by nc. - */ - public function testVideoByNc(): void - { - $ncFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_NC => $ncFilter, - ], - IncludeParser::param() => AnimeThemeEntryVideo::RELATION_VIDEO, - ]; - - $entryVideo = AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->createOne(); - - $response = $this->get(route('api.animethemeentryvideo.show', ['animethemeentry' => $entryVideo->animethemeentry, 'video' => $entryVideo->video] + $parameters)); - - $entryVideo->unsetRelations()->load([ - AnimeThemeEntryVideo::RELATION_VIDEO => function (BelongsTo $query) use ($ncFilter) { - $query->where(Video::ATTRIBUTE_NC, $ncFilter); - }, - ]); - - $response->assertJson( - json_decode( - json_encode( - new AnimeThemeEntryVideoResource($entryVideo, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Theme Entry Video Show Endpoint shall support constrained eager loading of videos by overlap. - */ - public function testVideoByOverlap(): void - { - $overlapFilter = Arr::random(VideoOverlap::cases()); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_OVERLAP => $overlapFilter->localize(), - ], - IncludeParser::param() => AnimeThemeEntryVideo::RELATION_VIDEO, - ]; - - $entryVideo = AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->createOne(); - - $response = $this->get(route('api.animethemeentryvideo.show', ['animethemeentry' => $entryVideo->animethemeentry, 'video' => $entryVideo->video] + $parameters)); - - $entryVideo->unsetRelations()->load([ - AnimeThemeEntryVideo::RELATION_VIDEO => function (BelongsTo $query) use ($overlapFilter) { - $query->where(Video::ATTRIBUTE_OVERLAP, $overlapFilter->value); - }, - ]); - - $response->assertJson( - json_decode( - json_encode( - new AnimeThemeEntryVideoResource($entryVideo, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Theme Entry Video Show Endpoint shall support constrained eager loading of videos by resolution. - */ - public function testVideoByResolution(): void - { - $resolutionFilter = $this->faker->randomNumber(); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_RESOLUTION => $resolutionFilter, - ], - IncludeParser::param() => AnimeThemeEntryVideo::RELATION_VIDEO, - ]; - - $entryVideo = AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->createOne(); - - $response = $this->get(route('api.animethemeentryvideo.show', ['animethemeentry' => $entryVideo->animethemeentry, 'video' => $entryVideo->video] + $parameters)); - - $entryVideo->unsetRelations()->load([ - AnimeThemeEntryVideo::RELATION_VIDEO => function (BelongsTo $query) use ($resolutionFilter) { - $query->where(Video::ATTRIBUTE_RESOLUTION, $resolutionFilter); - }, - ]); - - $response->assertJson( - json_decode( - json_encode( - new AnimeThemeEntryVideoResource($entryVideo, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Theme Entry Video Show Endpoint shall support constrained eager loading of videos by source. - */ - public function testVideoBySource(): void - { - $sourceFilter = Arr::random(VideoSource::cases()); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_SOURCE => $sourceFilter->localize(), - ], - IncludeParser::param() => AnimeThemeEntryVideo::RELATION_VIDEO, - ]; - - $entryVideo = AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->createOne(); - - $response = $this->get(route('api.animethemeentryvideo.show', ['animethemeentry' => $entryVideo->animethemeentry, 'video' => $entryVideo->video] + $parameters)); - - $entryVideo->unsetRelations()->load([ - AnimeThemeEntryVideo::RELATION_VIDEO => function (BelongsTo $query) use ($sourceFilter) { - $query->where(Video::ATTRIBUTE_SOURCE, $sourceFilter->value); - }, - ]); - - $response->assertJson( - json_decode( - json_encode( - new AnimeThemeEntryVideoResource($entryVideo, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Theme Entry Video Show Endpoint shall support constrained eager loading of videos by subbed. - */ - public function testVideoBySubbed(): void - { - $subbedFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_SUBBED => $subbedFilter, - ], - IncludeParser::param() => AnimeThemeEntryVideo::RELATION_VIDEO, - ]; - - $entryVideo = AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->createOne(); - - $response = $this->get(route('api.animethemeentryvideo.show', ['animethemeentry' => $entryVideo->animethemeentry, 'video' => $entryVideo->video] + $parameters)); - - $entryVideo->unsetRelations()->load([ - AnimeThemeEntryVideo::RELATION_VIDEO => function (BelongsTo $query) use ($subbedFilter) { - $query->where(Video::ATTRIBUTE_SUBBED, $subbedFilter); - }, - ]); - - $response->assertJson( - json_decode( - json_encode( - new AnimeThemeEntryVideoResource($entryVideo, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Theme Entry Video Show Endpoint shall support constrained eager loading of videos by uncen. - */ - public function testVideoByUncen(): void - { - $uncenFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_UNCEN => $uncenFilter, - ], - IncludeParser::param() => AnimeThemeEntryVideo::RELATION_VIDEO, - ]; - - $entryVideo = AnimeThemeEntryVideo::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->for(Video::factory()) - ->createOne(); - - $response = $this->get(route('api.animethemeentryvideo.show', ['animethemeentry' => $entryVideo->animethemeentry, 'video' => $entryVideo->video] + $parameters)); - - $entryVideo->unsetRelations()->load([ - AnimeThemeEntryVideo::RELATION_VIDEO => function (BelongsTo $query) use ($uncenFilter) { - $query->where(Video::ATTRIBUTE_UNCEN, $uncenFilter); - }, - ]); - - $response->assertJson( - json_decode( - json_encode( - new AnimeThemeEntryVideoResource($entryVideo, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + +use function Pest\Laravel\get; + +uses(Illuminate\Foundation\Testing\WithFaker::class); + +test('not found', function () { + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->create(); + + $video = Video::factory()->createOne(); + + $response = get(route('api.animethemeentryvideo.show', ['animethemeentry' => $entry, 'video' => $video])); + + $response->assertNotFound(); +}); + +test('default', function () { + $entryVideo = AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->createOne(); + + $response = get(route('api.animethemeentryvideo.show', ['animethemeentry' => $entryVideo->animethemeentry, 'video' => $entryVideo->video])); + + $entryVideo->unsetRelations(); + + $response->assertJson( + json_decode( + json_encode( + new AnimeThemeEntryVideoResource($entryVideo, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('allowed include paths', function () { + $schema = new AnimeThemeEntryVideoSchema(); + + $allowedIncludes = collect($schema->allowedIncludes()); + + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); + + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; + + $entryVideo = AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->createOne(); + + $response = get(route('api.animethemeentryvideo.show', ['animethemeentry' => $entryVideo->animethemeentry, 'video' => $entryVideo->video] + $parameters)); + + $entryVideo->unsetRelations()->load($includedPaths->all()); + + $response->assertJson( + json_decode( + json_encode( + new AnimeThemeEntryVideoResource($entryVideo, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sparse fieldsets', function () { + $schema = new AnimeThemeEntryVideoSchema(); + + $fields = collect($schema->fields()); + + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + AnimeThemeEntryVideoResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + $entryVideo = AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->createOne(); + + $response = get(route('api.animethemeentryvideo.show', ['animethemeentry' => $entryVideo->animethemeentry, 'video' => $entryVideo->video] + $parameters)); + + $entryVideo->unsetRelations(); + + $response->assertJson( + json_decode( + json_encode( + new AnimeThemeEntryVideoResource($entryVideo, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('entry by nsfw', function () { + $nsfwFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + AnimeThemeEntry::ATTRIBUTE_NSFW => $nsfwFilter, + ], + IncludeParser::param() => AnimeThemeEntryVideo::RELATION_ENTRY, + ]; + + $entryVideo = AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->createOne(); + + $response = get(route('api.animethemeentryvideo.show', ['animethemeentry' => $entryVideo->animethemeentry, 'video' => $entryVideo->video] + $parameters)); + + $entryVideo->unsetRelations()->load([ + AnimeThemeEntryVideo::RELATION_ENTRY => function (BelongsTo $query) use ($nsfwFilter) { + $query->where(AnimeThemeEntry::ATTRIBUTE_NSFW, $nsfwFilter); + }, + ]); + + $response->assertJson( + json_decode( + json_encode( + new AnimeThemeEntryVideoResource($entryVideo, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('entry by spoiler', function () { + $spoilerFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + AnimeThemeEntry::ATTRIBUTE_SPOILER => $spoilerFilter, + ], + IncludeParser::param() => AnimeThemeEntryVideo::RELATION_ENTRY, + ]; + + $entryVideo = AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->createOne(); + + $response = get(route('api.animethemeentryvideo.show', ['animethemeentry' => $entryVideo->animethemeentry, 'video' => $entryVideo->video] + $parameters)); + + $entryVideo->unsetRelations()->load([ + AnimeThemeEntryVideo::RELATION_ENTRY => function (BelongsTo $query) use ($spoilerFilter) { + $query->where(AnimeThemeEntry::ATTRIBUTE_SPOILER, $spoilerFilter); + }, + ]); + + $response->assertJson( + json_decode( + json_encode( + new AnimeThemeEntryVideoResource($entryVideo, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('entry by version', function () { + $versionFilter = fake()->randomDigitNotNull(); + + $parameters = [ + FilterParser::param() => [ + AnimeThemeEntry::ATTRIBUTE_VERSION => $versionFilter, + ], + IncludeParser::param() => AnimeThemeEntryVideo::RELATION_ENTRY, + ]; + + $entryVideo = AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->createOne(); + + $response = get(route('api.animethemeentryvideo.show', ['animethemeentry' => $entryVideo->animethemeentry, 'video' => $entryVideo->video] + $parameters)); + + $entryVideo->unsetRelations()->load([ + AnimeThemeEntryVideo::RELATION_ENTRY => function (BelongsTo $query) use ($versionFilter) { + $query->where(AnimeThemeEntry::ATTRIBUTE_VERSION, $versionFilter); + }, + ]); + + $response->assertJson( + json_decode( + json_encode( + new AnimeThemeEntryVideoResource($entryVideo, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('video by lyrics', function () { + $lyricsFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_LYRICS => $lyricsFilter, + ], + IncludeParser::param() => AnimeThemeEntryVideo::RELATION_VIDEO, + ]; + + $entryVideo = AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->createOne(); + + $response = get(route('api.animethemeentryvideo.show', ['animethemeentry' => $entryVideo->animethemeentry, 'video' => $entryVideo->video] + $parameters)); + + $entryVideo->unsetRelations()->load([ + AnimeThemeEntryVideo::RELATION_VIDEO => function (BelongsTo $query) use ($lyricsFilter) { + $query->where(Video::ATTRIBUTE_LYRICS, $lyricsFilter); + }, + ]); + + $response->assertJson( + json_decode( + json_encode( + new AnimeThemeEntryVideoResource($entryVideo, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('video by nc', function () { + $ncFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_NC => $ncFilter, + ], + IncludeParser::param() => AnimeThemeEntryVideo::RELATION_VIDEO, + ]; + + $entryVideo = AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->createOne(); + + $response = get(route('api.animethemeentryvideo.show', ['animethemeentry' => $entryVideo->animethemeentry, 'video' => $entryVideo->video] + $parameters)); + + $entryVideo->unsetRelations()->load([ + AnimeThemeEntryVideo::RELATION_VIDEO => function (BelongsTo $query) use ($ncFilter) { + $query->where(Video::ATTRIBUTE_NC, $ncFilter); + }, + ]); + + $response->assertJson( + json_decode( + json_encode( + new AnimeThemeEntryVideoResource($entryVideo, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('video by overlap', function () { + $overlapFilter = Arr::random(VideoOverlap::cases()); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_OVERLAP => $overlapFilter->localize(), + ], + IncludeParser::param() => AnimeThemeEntryVideo::RELATION_VIDEO, + ]; + + $entryVideo = AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->createOne(); + + $response = get(route('api.animethemeentryvideo.show', ['animethemeentry' => $entryVideo->animethemeentry, 'video' => $entryVideo->video] + $parameters)); + + $entryVideo->unsetRelations()->load([ + AnimeThemeEntryVideo::RELATION_VIDEO => function (BelongsTo $query) use ($overlapFilter) { + $query->where(Video::ATTRIBUTE_OVERLAP, $overlapFilter->value); + }, + ]); + + $response->assertJson( + json_decode( + json_encode( + new AnimeThemeEntryVideoResource($entryVideo, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('video by resolution', function () { + $resolutionFilter = fake()->randomNumber(); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_RESOLUTION => $resolutionFilter, + ], + IncludeParser::param() => AnimeThemeEntryVideo::RELATION_VIDEO, + ]; + + $entryVideo = AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->createOne(); + + $response = get(route('api.animethemeentryvideo.show', ['animethemeentry' => $entryVideo->animethemeentry, 'video' => $entryVideo->video] + $parameters)); + + $entryVideo->unsetRelations()->load([ + AnimeThemeEntryVideo::RELATION_VIDEO => function (BelongsTo $query) use ($resolutionFilter) { + $query->where(Video::ATTRIBUTE_RESOLUTION, $resolutionFilter); + }, + ]); + + $response->assertJson( + json_decode( + json_encode( + new AnimeThemeEntryVideoResource($entryVideo, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('video by source', function () { + $sourceFilter = Arr::random(VideoSource::cases()); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_SOURCE => $sourceFilter->localize(), + ], + IncludeParser::param() => AnimeThemeEntryVideo::RELATION_VIDEO, + ]; + + $entryVideo = AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->createOne(); + + $response = get(route('api.animethemeentryvideo.show', ['animethemeentry' => $entryVideo->animethemeentry, 'video' => $entryVideo->video] + $parameters)); + + $entryVideo->unsetRelations()->load([ + AnimeThemeEntryVideo::RELATION_VIDEO => function (BelongsTo $query) use ($sourceFilter) { + $query->where(Video::ATTRIBUTE_SOURCE, $sourceFilter->value); + }, + ]); + + $response->assertJson( + json_decode( + json_encode( + new AnimeThemeEntryVideoResource($entryVideo, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('video by subbed', function () { + $subbedFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_SUBBED => $subbedFilter, + ], + IncludeParser::param() => AnimeThemeEntryVideo::RELATION_VIDEO, + ]; + + $entryVideo = AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->createOne(); + + $response = get(route('api.animethemeentryvideo.show', ['animethemeentry' => $entryVideo->animethemeentry, 'video' => $entryVideo->video] + $parameters)); + + $entryVideo->unsetRelations()->load([ + AnimeThemeEntryVideo::RELATION_VIDEO => function (BelongsTo $query) use ($subbedFilter) { + $query->where(Video::ATTRIBUTE_SUBBED, $subbedFilter); + }, + ]); + + $response->assertJson( + json_decode( + json_encode( + new AnimeThemeEntryVideoResource($entryVideo, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('video by uncen', function () { + $uncenFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_UNCEN => $uncenFilter, + ], + IncludeParser::param() => AnimeThemeEntryVideo::RELATION_VIDEO, + ]; + + $entryVideo = AnimeThemeEntryVideo::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->for(Video::factory()) + ->createOne(); + + $response = get(route('api.animethemeentryvideo.show', ['animethemeentry' => $entryVideo->animethemeentry, 'video' => $entryVideo->video] + $parameters)); + + $entryVideo->unsetRelations()->load([ + AnimeThemeEntryVideo::RELATION_VIDEO => function (BelongsTo $query) use ($uncenFilter) { + $query->where(Video::ATTRIBUTE_UNCEN, $uncenFilter); + }, + ]); + + $response->assertJson( + json_decode( + json_encode( + new AnimeThemeEntryVideoResource($entryVideo, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/AnimeThemeEntryVideo/AnimeThemeEntryVideoStoreTest.php b/tests/Feature/Http/Api/Pivot/Wiki/AnimeThemeEntryVideo/AnimeThemeEntryVideoStoreTest.php index 45c680ca5..a24860620 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/AnimeThemeEntryVideo/AnimeThemeEntryVideoStoreTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/AnimeThemeEntryVideo/AnimeThemeEntryVideoStoreTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\AnimeThemeEntryVideo; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Anime; @@ -12,69 +10,55 @@ use App\Models\Wiki\Anime\Theme\AnimeThemeEntry; use App\Models\Wiki\Video; use App\Pivots\Wiki\AnimeThemeEntryVideo; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class AnimeThemeEntryVideoStoreTest extends TestCase -{ - /** - * The Anime Theme Entry Video Store Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->create(); +use function Pest\Laravel\post; - $video = Video::factory()->createOne(); +test('protected', function () { + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->create(); - $response = $this->post(route('api.animethemeentryvideo.store', ['animethemeentry' => $entry, 'video' => $video])); + $video = Video::factory()->createOne(); - $response->assertUnauthorized(); - } + $response = post(route('api.animethemeentryvideo.store', ['animethemeentry' => $entry, 'video' => $video])); - /** - * The Anime Theme Entry Video Store Endpoint shall forbid users without the create anime theme entry & create video permissions. - */ - public function testForbidden(): void - { - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->create(); + $response->assertUnauthorized(); +}); - $video = Video::factory()->createOne(); +test('forbidden', function () { + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->create(); - $user = User::factory()->createOne(); + $video = Video::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->post(route('api.animethemeentryvideo.store', ['animethemeentry' => $entry, 'video' => $video])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.animethemeentryvideo.store', ['animethemeentry' => $entry, 'video' => $video])); - /** - * The Anime Theme Entry Video Store Endpoint shall create an Anime Theme Entry Video. - */ - public function testCreate(): void - { - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->create(); + $response->assertForbidden(); +}); - $video = Video::factory()->createOne(); +test('create', function () { + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->create(); - $user = User::factory() - ->withPermissions( - CrudPermission::CREATE->format(AnimeThemeEntry::class), - CrudPermission::CREATE->format(Video::class) - ) - ->createOne(); + $video = Video::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::CREATE->format(AnimeThemeEntry::class), + CrudPermission::CREATE->format(Video::class) + ) + ->createOne(); - $response = $this->post(route('api.animethemeentryvideo.store', ['animethemeentry' => $entry, 'video' => $video])); + Sanctum::actingAs($user); - $response->assertCreated(); - static::assertDatabaseCount(AnimeThemeEntryVideo::class, 1); - } -} + $response = post(route('api.animethemeentryvideo.store', ['animethemeentry' => $entry, 'video' => $video])); + + $response->assertCreated(); + $this->assertDatabaseCount(AnimeThemeEntryVideo::class, 1); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/ArtistImage/ArtistImageDestroyTest.php b/tests/Feature/Http/Api/Pivot/Wiki/ArtistImage/ArtistImageDestroyTest.php index 3395d4273..f75867bf5 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/ArtistImage/ArtistImageDestroyTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/ArtistImage/ArtistImageDestroyTest.php @@ -2,96 +2,76 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\ArtistImage; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Artist; use App\Models\Wiki\Image; use App\Pivots\Wiki\ArtistImage; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ArtistImageDestroyTest extends TestCase -{ - /** - * The Artist Image Destroy Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $artistImage = ArtistImage::factory() - ->for(Artist::factory()) - ->for(Image::factory()) - ->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.artistimage.destroy', ['artist' => $artistImage->artist, 'image' => $artistImage->image])); +test('protected', function () { + $artistImage = ArtistImage::factory() + ->for(Artist::factory()) + ->for(Image::factory()) + ->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.artistimage.destroy', ['artist' => $artistImage->artist, 'image' => $artistImage->image])); - /** - * The Artist Image Destroy Endpoint shall forbid users without the delete artist & delete image permissions. - */ - public function testForbidden(): void - { - $artistImage = ArtistImage::factory() - ->for(Artist::factory()) - ->for(Image::factory()) - ->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $artistImage = ArtistImage::factory() + ->for(Artist::factory()) + ->for(Image::factory()) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.artistimage.destroy', ['artist' => $artistImage->artist, 'image' => $artistImage->image])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.artistimage.destroy', ['artist' => $artistImage->artist, 'image' => $artistImage->image])); - /** - * The Artist Image Destroy Endpoint shall return an error if the artist image does not exist. - */ - public function testNotFound(): void - { - $artist = Artist::factory()->createOne(); - $image = Image::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory() - ->withPermissions( - CrudPermission::DELETE->format(Artist::class), - CrudPermission::DELETE->format(Image::class) - ) - ->createOne(); +test('not found', function () { + $artist = Artist::factory()->createOne(); + $image = Image::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::DELETE->format(Artist::class), + CrudPermission::DELETE->format(Image::class) + ) + ->createOne(); - $response = $this->delete(route('api.artistimage.destroy', ['artist' => $artist, 'image' => $image])); + Sanctum::actingAs($user); - $response->assertNotFound(); - } + $response = delete(route('api.artistimage.destroy', ['artist' => $artist, 'image' => $image])); - /** - * The Artist Image Destroy Endpoint shall delete the artist image. - */ - public function testDeleted(): void - { - $artistImage = ArtistImage::factory() - ->for(Artist::factory()) - ->for(Image::factory()) - ->createOne(); + $response->assertNotFound(); +}); - $user = User::factory() - ->withPermissions( - CrudPermission::DELETE->format(Artist::class), - CrudPermission::DELETE->format(Image::class) - ) - ->createOne(); +test('deleted', function () { + $artistImage = ArtistImage::factory() + ->for(Artist::factory()) + ->for(Image::factory()) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::DELETE->format(Artist::class), + CrudPermission::DELETE->format(Image::class) + ) + ->createOne(); - $response = $this->delete(route('api.artistimage.destroy', ['artist' => $artistImage->artist, 'image' => $artistImage->image])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertModelMissing($artistImage); - } -} + $response = delete(route('api.artistimage.destroy', ['artist' => $artistImage->artist, 'image' => $artistImage->image])); + + $response->assertOk(); + $this->assertModelMissing($artistImage); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/ArtistImage/ArtistImageIndexTest.php b/tests/Feature/Http/Api/Pivot/Wiki/ArtistImage/ArtistImageIndexTest.php index e0bdb0224..ec26f2337 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/ArtistImage/ArtistImageIndexTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/ArtistImage/ArtistImageIndexTest.php @@ -2,9 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\ArtistImage; - -use App\Concerns\Actions\Http\Api\SortsModels; use App\Contracts\Http\Api\Field\SortableField; use App\Enums\Http\Api\Sort\Direction; use App\Enums\Models\Wiki\ImageFacet; @@ -27,329 +24,295 @@ use App\Models\Wiki\Image; use App\Pivots\BasePivot; use App\Pivots\Wiki\ArtistImage; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; use Illuminate\Support\Collection; -use Tests\TestCase; -class ArtistImageIndexTest extends TestCase -{ - use SortsModels; - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the Artist Image Index Endpoint shall return a collection of Artist Image Resources. - */ - public function testDefault(): void - { - Collection::times($this->faker->randomDigitNotNull(), function () { +uses(App\Concerns\Actions\Http\Api\SortsModels::class); + +uses(Illuminate\Foundation\Testing\WithFaker::class); + +test('default', function () { + Collection::times(fake()->randomDigitNotNull(), function () { + ArtistImage::factory() + ->for(Artist::factory()) + ->for(Image::factory()) + ->create(); + }); + + $artistImages = ArtistImage::all(); + + $response = get(route('api.artistimage.index')); + + $response->assertJson( + json_decode( + json_encode( + new ArtistImageCollection($artistImages, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('paginated', function () { + Collection::times(fake()->randomDigitNotNull(), function () { + ArtistImage::factory() + ->for(Artist::factory()) + ->for(Image::factory()) + ->create(); + }); + + $response = get(route('api.artistimage.index')); + + $response->assertJsonStructure([ + ArtistImageCollection::$wrap, + 'links', + 'meta', + ]); +}); + +test('allowed include paths', function () { + $schema = new ArtistImageSchema(); + + $allowedIncludes = collect($schema->allowedIncludes()); + + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); + + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + ArtistImage::factory() + ->for(Artist::factory()) + ->for(Image::factory()) + ->create(); + }); + + $response = get(route('api.artistimage.index', $parameters)); + + $artistImages = ArtistImage::with($includedPaths->all())->get(); + + $response->assertJson( + json_decode( + json_encode( + new ArtistImageCollection($artistImages, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sparse fieldsets', function () { + $schema = new ArtistImageSchema(); + + $fields = collect($schema->fields()); + + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + ArtistImageResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + ArtistImage::factory() + ->for(Artist::factory()) + ->for(Image::factory()) + ->create(); + }); + + $response = get(route('api.artistimage.index', $parameters)); + + $artistImages = ArtistImage::all(); + + $response->assertJson( + json_decode( + json_encode( + new ArtistImageCollection($artistImages, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sorts', function () { + $schema = new ArtistImageSchema(); + + /** @var Sort $sort */ + $sort = collect($schema->fields()) + ->filter(fn (Field $field) => $field instanceof SortableField) + ->map(fn (SortableField $field) => $field->getSort()) + ->random(); + + $parameters = [ + SortParser::param() => $sort->format(Arr::random(Direction::cases())), + ]; + + $query = new Query($parameters); + + Collection::times(fake()->randomDigitNotNull(), function () { + ArtistImage::factory() + ->for(Artist::factory()) + ->for(Image::factory()) + ->create(); + }); + + $response = get(route('api.artistimage.index', $parameters)); + + $artistImages = $this->sort(ArtistImage::query(), $query, $schema)->get(); + + $response->assertJson( + json_decode( + json_encode( + new ArtistImageCollection($artistImages, $query) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('created at filter', function () { + $createdFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BasePivot::ATTRIBUTE_CREATED_AT => $createdFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($createdFilter, function () { + Collection::times(fake()->randomDigitNotNull(), function () { ArtistImage::factory() ->for(Artist::factory()) ->for(Image::factory()) ->create(); }); + }); - $artistImages = ArtistImage::all(); - - $response = $this->get(route('api.artistimage.index')); - - $response->assertJson( - json_decode( - json_encode( - new ArtistImageCollection($artistImages, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Image Index Endpoint shall be paginated. - */ - public function testPaginated(): void - { - Collection::times($this->faker->randomDigitNotNull(), function () { + Carbon::withTestNow($excludedDate, function () { + Collection::times(fake()->randomDigitNotNull(), function () { ArtistImage::factory() ->for(Artist::factory()) ->for(Image::factory()) ->create(); }); + }); - $response = $this->get(route('api.artistimage.index')); + $artistImages = ArtistImage::query()->where(BasePivot::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - $response->assertJsonStructure([ - ArtistImageCollection::$wrap, - 'links', - 'meta', - ]); - } + $response = get(route('api.artistimage.index', $parameters)); - /** - * The Artist Image Index Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new ArtistImageSchema(); + $response->assertJson( + json_decode( + json_encode( + new ArtistImageCollection($artistImages, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('updated at filter', function () { + $updatedFilter = fake()->date(); + $excludedDate = fake()->date(); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $parameters = [ + FilterParser::param() => [ + BasePivot::ATTRIBUTE_UPDATED_AT => $updatedFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { + Carbon::withTestNow($updatedFilter, function () { + Collection::times(fake()->randomDigitNotNull(), function () { ArtistImage::factory() ->for(Artist::factory()) ->for(Image::factory()) ->create(); }); + }); - $response = $this->get(route('api.artistimage.index', $parameters)); - - $artistImages = ArtistImage::with($includedPaths->all())->get(); - - $response->assertJson( - json_decode( - json_encode( - new ArtistImageCollection($artistImages, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Image Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new ArtistImageSchema(); - - $fields = collect($schema->fields()); - - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); - - $parameters = [ - FieldParser::param() => [ - ArtistImageResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { + Carbon::withTestNow($excludedDate, function () { + Collection::times(fake()->randomDigitNotNull(), function () { ArtistImage::factory() ->for(Artist::factory()) ->for(Image::factory()) ->create(); }); + }); - $response = $this->get(route('api.artistimage.index', $parameters)); + $artistImages = ArtistImage::query()->where(BasePivot::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - $artistImages = ArtistImage::all(); + $response = get(route('api.artistimage.index', $parameters)); - $response->assertJson( - json_decode( - json_encode( - new ArtistImageCollection($artistImages, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response->assertJson( + json_decode( + json_encode( + new ArtistImageCollection($artistImages, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - /** - * The Artist Image Index Endpoint shall support sorting resources. - */ - public function testSorts(): void - { - $schema = new ArtistImageSchema(); +test('images by facet', function () { + $facetFilter = Arr::random(ImageFacet::cases()); - /** @var Sort $sort */ - $sort = collect($schema->fields()) - ->filter(fn (Field $field) => $field instanceof SortableField) - ->map(fn (SortableField $field) => $field->getSort()) - ->random(); + $parameters = [ + FilterParser::param() => [ + Image::ATTRIBUTE_FACET => $facetFilter->localize(), + ], + IncludeParser::param() => ArtistImage::RELATION_IMAGE, + ]; - $parameters = [ - SortParser::param() => $sort->format(Arr::random(Direction::cases())), - ]; + Collection::times(fake()->randomDigitNotNull(), function () { + ArtistImage::factory() + ->for(Artist::factory()) + ->for(Image::factory()) + ->create(); + }); - $query = new Query($parameters); + $response = get(route('api.artistimage.index', $parameters)); - Collection::times($this->faker->randomDigitNotNull(), function () { - ArtistImage::factory() - ->for(Artist::factory()) - ->for(Image::factory()) - ->create(); - }); + $artistImages = ArtistImage::with([ + ArtistImage::RELATION_IMAGE => function (BelongsTo $query) use ($facetFilter) { + $query->where(Image::ATTRIBUTE_FACET, $facetFilter->value); + }, + ]) + ->get(); - $response = $this->get(route('api.artistimage.index', $parameters)); - - $artistImages = $this->sort(ArtistImage::query(), $query, $schema)->get(); - - $response->assertJson( - json_decode( - json_encode( - new ArtistImageCollection($artistImages, $query) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Image Index Endpoint shall support filtering by created_at. - */ - public function testCreatedAtFilter(): void - { - $createdFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BasePivot::ATTRIBUTE_CREATED_AT => $createdFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($createdFilter, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - ArtistImage::factory() - ->for(Artist::factory()) - ->for(Image::factory()) - ->create(); - }); - }); - - Carbon::withTestNow($excludedDate, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - ArtistImage::factory() - ->for(Artist::factory()) - ->for(Image::factory()) - ->create(); - }); - }); - - $artistImages = ArtistImage::query()->where(BasePivot::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - - $response = $this->get(route('api.artistimage.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ArtistImageCollection($artistImages, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Image Index Endpoint shall support filtering by updated_at. - */ - public function testUpdatedAtFilter(): void - { - $updatedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BasePivot::ATTRIBUTE_UPDATED_AT => $updatedFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($updatedFilter, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - ArtistImage::factory() - ->for(Artist::factory()) - ->for(Image::factory()) - ->create(); - }); - }); - - Carbon::withTestNow($excludedDate, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - ArtistImage::factory() - ->for(Artist::factory()) - ->for(Image::factory()) - ->create(); - }); - }); - - $artistImages = ArtistImage::query()->where(BasePivot::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - - $response = $this->get(route('api.artistimage.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ArtistImageCollection($artistImages, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Image Index Endpoint shall support constrained eager loading of images by facet. - */ - public function testImagesByFacet(): void - { - $facetFilter = Arr::random(ImageFacet::cases()); - - $parameters = [ - FilterParser::param() => [ - Image::ATTRIBUTE_FACET => $facetFilter->localize(), - ], - IncludeParser::param() => ArtistImage::RELATION_IMAGE, - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { - ArtistImage::factory() - ->for(Artist::factory()) - ->for(Image::factory()) - ->create(); - }); - - $response = $this->get(route('api.artistimage.index', $parameters)); - - $artistImages = ArtistImage::with([ - ArtistImage::RELATION_IMAGE => function (BelongsTo $query) use ($facetFilter) { - $query->where(Image::ATTRIBUTE_FACET, $facetFilter->value); - }, - ]) - ->get(); - - $response->assertJson( - json_decode( - json_encode( - new ArtistImageCollection($artistImages, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response->assertJson( + json_decode( + json_encode( + new ArtistImageCollection($artistImages, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/ArtistImage/ArtistImageShowTest.php b/tests/Feature/Http/Api/Pivot/Wiki/ArtistImage/ArtistImageShowTest.php index 2812016f9..6a7efdbfb 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/ArtistImage/ArtistImageShowTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/ArtistImage/ArtistImageShowTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\ArtistImage; - use App\Enums\Models\Wiki\ImageFacet; use App\Http\Api\Field\Field; use App\Http\Api\Include\AllowedInclude; @@ -17,165 +15,142 @@ use App\Models\Wiki\Artist; use App\Models\Wiki\Image; use App\Pivots\Wiki\ArtistImage; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; -use Tests\TestCase; -class ArtistImageShowTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * The Artist Image Show Endpoint shall return an error if the artist image does not exist. - */ - public function testNotFound(): void - { - $artist = Artist::factory()->createOne(); - $image = Image::factory()->createOne(); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response = $this->get(route('api.artistimage.show', ['artist' => $artist, 'image' => $image])); +test('not found', function () { + $artist = Artist::factory()->createOne(); + $image = Image::factory()->createOne(); - $response->assertNotFound(); - } + $response = get(route('api.artistimage.show', ['artist' => $artist, 'image' => $image])); - /** - * By default, the Artist Image Show Endpoint shall return an Artist Image Resource. - */ - public function testDefault(): void - { - $artistImage = ArtistImage::factory() - ->for(Artist::factory()) - ->for(Image::factory()) - ->createOne(); + $response->assertNotFound(); +}); - $response = $this->get(route('api.artistimage.show', ['artist' => $artistImage->artist, 'image' => $artistImage->image])); +test('default', function () { + $artistImage = ArtistImage::factory() + ->for(Artist::factory()) + ->for(Image::factory()) + ->createOne(); - $artistImage->unsetRelations(); + $response = get(route('api.artistimage.show', ['artist' => $artistImage->artist, 'image' => $artistImage->image])); - $response->assertJson( - json_decode( - json_encode( - new ArtistImageResource($artistImage, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $artistImage->unsetRelations(); - /** - * The Artist Image Show Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new ArtistImageSchema(); + $response->assertJson( + json_decode( + json_encode( + new ArtistImageResource($artistImage, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('allowed include paths', function () { + $schema = new ArtistImageSchema(); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $allowedIncludes = collect($schema->allowedIncludes()); - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - $artistImage = ArtistImage::factory() - ->for(Artist::factory()) - ->for(Image::factory()) - ->createOne(); + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; - $response = $this->get(route('api.artistimage.show', ['artist' => $artistImage->artist, 'image' => $artistImage->image] + $parameters)); + $artistImage = ArtistImage::factory() + ->for(Artist::factory()) + ->for(Image::factory()) + ->createOne(); - $artistImage->unsetRelations()->load($includedPaths->all()); + $response = get(route('api.artistimage.show', ['artist' => $artistImage->artist, 'image' => $artistImage->image] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new ArtistImageResource($artistImage, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $artistImage->unsetRelations()->load($includedPaths->all()); - /** - * The Artist Image Show Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new ArtistImageSchema(); + $response->assertJson( + json_decode( + json_encode( + new ArtistImageResource($artistImage, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $fields = collect($schema->fields()); +test('sparse fieldsets', function () { + $schema = new ArtistImageSchema(); - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); + $fields = collect($schema->fields()); - $parameters = [ - FieldParser::param() => [ - ArtistImageResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); - $artistImage = ArtistImage::factory() - ->for(Artist::factory()) - ->for(Image::factory()) - ->createOne(); + $parameters = [ + FieldParser::param() => [ + ArtistImageResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; - $response = $this->get(route('api.artistimage.show', ['artist' => $artistImage->artist, 'image' => $artistImage->image] + $parameters)); + $artistImage = ArtistImage::factory() + ->for(Artist::factory()) + ->for(Image::factory()) + ->createOne(); - $artistImage->unsetRelations(); + $response = get(route('api.artistimage.show', ['artist' => $artistImage->artist, 'image' => $artistImage->image] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new ArtistImageResource($artistImage, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $artistImage->unsetRelations(); - /** - * The Artist Image Show Endpoint shall support constrained eager loading of images by facet. - */ - public function testImagesByFacet(): void - { - $facetFilter = Arr::random(ImageFacet::cases()); + $response->assertJson( + json_decode( + json_encode( + new ArtistImageResource($artistImage, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Image::ATTRIBUTE_FACET => $facetFilter->localize(), - ], - IncludeParser::param() => ArtistImage::RELATION_IMAGE, - ]; +test('images by facet', function () { + $facetFilter = Arr::random(ImageFacet::cases()); - $artistImage = ArtistImage::factory() - ->for(Artist::factory()) - ->for(Image::factory()) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + Image::ATTRIBUTE_FACET => $facetFilter->localize(), + ], + IncludeParser::param() => ArtistImage::RELATION_IMAGE, + ]; - $response = $this->get(route('api.artistimage.show', ['artist' => $artistImage->artist, 'image' => $artistImage->image] + $parameters)); + $artistImage = ArtistImage::factory() + ->for(Artist::factory()) + ->for(Image::factory()) + ->createOne(); - $artistImage->unsetRelations()->load([ - ArtistImage::RELATION_IMAGE => function (BelongsTo $query) use ($facetFilter) { - $query->where(Image::ATTRIBUTE_FACET, $facetFilter->value); - }, - ]); + $response = get(route('api.artistimage.show', ['artist' => $artistImage->artist, 'image' => $artistImage->image] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new ArtistImageResource($artistImage, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $artistImage->unsetRelations()->load([ + ArtistImage::RELATION_IMAGE => function (BelongsTo $query) use ($facetFilter) { + $query->where(Image::ATTRIBUTE_FACET, $facetFilter->value); + }, + ]); + + $response->assertJson( + json_decode( + json_encode( + new ArtistImageResource($artistImage, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/ArtistImage/ArtistImageStoreTest.php b/tests/Feature/Http/Api/Pivot/Wiki/ArtistImage/ArtistImageStoreTest.php index 48e21cafa..98de5fa30 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/ArtistImage/ArtistImageStoreTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/ArtistImage/ArtistImageStoreTest.php @@ -2,68 +2,52 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\ArtistImage; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Artist; use App\Models\Wiki\Image; use App\Pivots\Wiki\ArtistImage; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ArtistImageStoreTest extends TestCase -{ - /** - * The Artist Image Store Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $artist = Artist::factory()->createOne(); - $image = Image::factory()->createOne(); +use function Pest\Laravel\post; - $response = $this->post(route('api.artistimage.store', ['artist' => $artist, 'image' => $image])); +test('protected', function () { + $artist = Artist::factory()->createOne(); + $image = Image::factory()->createOne(); - $response->assertUnauthorized(); - } + $response = post(route('api.artistimage.store', ['artist' => $artist, 'image' => $image])); - /** - * The Artist Image Store Endpoint shall forbid users without the create artist & create image permissions. - */ - public function testForbidden(): void - { - $artist = Artist::factory()->createOne(); - $image = Image::factory()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $artist = Artist::factory()->createOne(); + $image = Image::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->post(route('api.artistimage.store', ['artist' => $artist, 'image' => $image])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.artistimage.store', ['artist' => $artist, 'image' => $image])); - /** - * The Artist Image Store Endpoint shall create an artist image. - */ - public function testCreate(): void - { - $artist = Artist::factory()->createOne(); - $image = Image::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory() - ->withPermissions( - CrudPermission::CREATE->format(Artist::class), - CrudPermission::CREATE->format(Image::class) - ) - ->createOne(); +test('create', function () { + $artist = Artist::factory()->createOne(); + $image = Image::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::CREATE->format(Artist::class), + CrudPermission::CREATE->format(Image::class) + ) + ->createOne(); - $response = $this->post(route('api.artistimage.store', ['artist' => $artist, 'image' => $image])); + Sanctum::actingAs($user); - $response->assertCreated(); - static::assertDatabaseCount(ArtistImage::class, 1); - } -} + $response = post(route('api.artistimage.store', ['artist' => $artist, 'image' => $image])); + + $response->assertCreated(); + $this->assertDatabaseCount(ArtistImage::class, 1); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/ArtistMember/ArtistMemberDestroyTest.php b/tests/Feature/Http/Api/Pivot/Wiki/ArtistMember/ArtistMemberDestroyTest.php index 65c13e925..9870d12fd 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/ArtistMember/ArtistMemberDestroyTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/ArtistMember/ArtistMemberDestroyTest.php @@ -2,85 +2,65 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\ArtistMember; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Artist; use App\Pivots\Wiki\ArtistMember; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ArtistMemberDestroyTest extends TestCase -{ - /** - * The Artist Member Destroy Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $artistMember = ArtistMember::factory() - ->for(Artist::factory(), ArtistMember::RELATION_ARTIST) - ->for(Artist::factory(), ArtistMember::RELATION_MEMBER) - ->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.artistmember.destroy', ['artist' => $artistMember->artist, 'member' => $artistMember->member])); +test('protected', function () { + $artistMember = ArtistMember::factory() + ->for(Artist::factory(), ArtistMember::RELATION_ARTIST) + ->for(Artist::factory(), ArtistMember::RELATION_MEMBER) + ->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.artistmember.destroy', ['artist' => $artistMember->artist, 'member' => $artistMember->member])); - /** - * The Artist Member Destroy Endpoint shall forbid users without the delete artist permission. - */ - public function testForbidden(): void - { - $artistMember = ArtistMember::factory() - ->for(Artist::factory(), ArtistMember::RELATION_ARTIST) - ->for(Artist::factory(), ArtistMember::RELATION_MEMBER) - ->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $artistMember = ArtistMember::factory() + ->for(Artist::factory(), ArtistMember::RELATION_ARTIST) + ->for(Artist::factory(), ArtistMember::RELATION_MEMBER) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.artistmember.destroy', ['artist' => $artistMember->artist, 'member' => $artistMember->member])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.artistmember.destroy', ['artist' => $artistMember->artist, 'member' => $artistMember->member])); - /** - * The Artist Member Destroy Endpoint shall return an error if the artist member does not exist. - */ - public function testNotFound(): void - { - $artist = Artist::factory()->createOne(); - $member = Artist::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Artist::class))->createOne(); +test('not found', function () { + $artist = Artist::factory()->createOne(); + $member = Artist::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Artist::class))->createOne(); - $response = $this->delete(route('api.artistmember.destroy', ['artist' => $artist, 'member' => $member])); + Sanctum::actingAs($user); - $response->assertNotFound(); - } + $response = delete(route('api.artistmember.destroy', ['artist' => $artist, 'member' => $member])); - /** - * The Artist Member Destroy Endpoint shall delete the artist member. - */ - public function testDeleted(): void - { - $artistMember = ArtistMember::factory() - ->for(Artist::factory(), ArtistMember::RELATION_ARTIST) - ->for(Artist::factory(), ArtistMember::RELATION_MEMBER) - ->createOne(); + $response->assertNotFound(); +}); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Artist::class))->createOne(); +test('deleted', function () { + $artistMember = ArtistMember::factory() + ->for(Artist::factory(), ArtistMember::RELATION_ARTIST) + ->for(Artist::factory(), ArtistMember::RELATION_MEMBER) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Artist::class))->createOne(); - $response = $this->delete(route('api.artistmember.destroy', ['artist' => $artistMember->artist, 'member' => $artistMember->member])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertModelMissing($artistMember); - } -} + $response = delete(route('api.artistmember.destroy', ['artist' => $artistMember->artist, 'member' => $artistMember->member])); + + $response->assertOk(); + $this->assertModelMissing($artistMember); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/ArtistMember/ArtistMemberIndexTest.php b/tests/Feature/Http/Api/Pivot/Wiki/ArtistMember/ArtistMemberIndexTest.php index 69d6a5a39..83e73b769 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/ArtistMember/ArtistMemberIndexTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/ArtistMember/ArtistMemberIndexTest.php @@ -2,9 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\ArtistMember; - -use App\Concerns\Actions\Http\Api\SortsModels; use App\Contracts\Http\Api\Field\SortableField; use App\Enums\Http\Api\Sort\Direction; use App\Http\Api\Criteria\Paging\Criteria; @@ -24,287 +21,257 @@ use App\Http\Resources\Pivot\Wiki\Resource\ArtistMemberResource; use App\Models\Wiki\Artist; use App\Pivots\BasePivot; use App\Pivots\Wiki\ArtistMember; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; use Illuminate\Support\Collection; -use Tests\TestCase; -class ArtistMemberIndexTest extends TestCase -{ - use SortsModels; - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the Artist Member Index Endpoint shall return a collection of Artist Member Resources. - */ - public function testDefault(): void - { - Collection::times($this->faker->randomDigitNotNull(), function () { +uses(App\Concerns\Actions\Http\Api\SortsModels::class); + +uses(Illuminate\Foundation\Testing\WithFaker::class); + +test('default', function () { + Collection::times(fake()->randomDigitNotNull(), function () { + ArtistMember::factory() + ->for(Artist::factory(), ArtistMember::RELATION_ARTIST) + ->for(Artist::factory(), ArtistMember::RELATION_MEMBER) + ->create(); + }); + + $artistMembers = ArtistMember::all(); + + $response = get(route('api.artistmember.index')); + + $response->assertJson( + json_decode( + json_encode( + new ArtistMemberCollection($artistMembers, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('paginated', function () { + Collection::times(fake()->randomDigitNotNull(), function () { + ArtistMember::factory() + ->for(Artist::factory(), ArtistMember::RELATION_ARTIST) + ->for(Artist::factory(), ArtistMember::RELATION_MEMBER) + ->create(); + }); + + $response = get(route('api.artistmember.index')); + + $response->assertJsonStructure([ + ArtistMemberCollection::$wrap, + 'links', + 'meta', + ]); +}); + +test('allowed include paths', function () { + $schema = new ArtistMemberSchema(); + + $allowedIncludes = collect($schema->allowedIncludes()); + + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); + + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + ArtistMember::factory() + ->for(Artist::factory(), ArtistMember::RELATION_ARTIST) + ->for(Artist::factory(), ArtistMember::RELATION_MEMBER) + ->create(); + }); + + $response = get(route('api.artistmember.index', $parameters)); + + $artistMembers = ArtistMember::with($includedPaths->all())->get(); + + $response->assertJson( + json_decode( + json_encode( + new ArtistMemberCollection($artistMembers, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sparse fieldsets', function () { + $schema = new ArtistMemberSchema(); + + $fields = collect($schema->fields()); + + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + ArtistMemberResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + ArtistMember::factory() + ->for(Artist::factory(), ArtistMember::RELATION_ARTIST) + ->for(Artist::factory(), ArtistMember::RELATION_MEMBER) + ->create(); + }); + + $response = get(route('api.artistmember.index', $parameters)); + + $artistMembers = ArtistMember::all(); + + $response->assertJson( + json_decode( + json_encode( + new ArtistMemberCollection($artistMembers, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sorts', function () { + $schema = new ArtistMemberSchema(); + + /** @var Sort $sort */ + $sort = collect($schema->fields()) + ->filter(fn (Field $field) => $field instanceof SortableField) + ->map(fn (SortableField $field) => $field->getSort()) + ->random(); + + $parameters = [ + SortParser::param() => $sort->format(Arr::random(Direction::cases())), + ]; + + $query = new Query($parameters); + + Collection::times(fake()->randomDigitNotNull(), function () { + ArtistMember::factory() + ->for(Artist::factory(), ArtistMember::RELATION_ARTIST) + ->for(Artist::factory(), ArtistMember::RELATION_MEMBER) + ->create(); + }); + + $response = get(route('api.artistmember.index', $parameters)); + + $artistMembers = $this->sort(ArtistMember::query(), $query, $schema)->get(); + + $response->assertJson( + json_decode( + json_encode( + new ArtistMemberCollection($artistMembers, $query) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('created at filter', function () { + $createdFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BasePivot::ATTRIBUTE_CREATED_AT => $createdFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($createdFilter, function () { + Collection::times(fake()->randomDigitNotNull(), function () { ArtistMember::factory() ->for(Artist::factory(), ArtistMember::RELATION_ARTIST) ->for(Artist::factory(), ArtistMember::RELATION_MEMBER) ->create(); }); + }); - $artistMembers = ArtistMember::all(); - - $response = $this->get(route('api.artistmember.index')); - - $response->assertJson( - json_decode( - json_encode( - new ArtistMemberCollection($artistMembers, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Member Index Endpoint shall be paginated. - */ - public function testPaginated(): void - { - Collection::times($this->faker->randomDigitNotNull(), function () { + Carbon::withTestNow($excludedDate, function () { + Collection::times(fake()->randomDigitNotNull(), function () { ArtistMember::factory() ->for(Artist::factory(), ArtistMember::RELATION_ARTIST) ->for(Artist::factory(), ArtistMember::RELATION_MEMBER) ->create(); }); + }); - $response = $this->get(route('api.artistmember.index')); + $artistMembers = ArtistMember::query()->where(BasePivot::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - $response->assertJsonStructure([ - ArtistMemberCollection::$wrap, - 'links', - 'meta', - ]); - } + $response = get(route('api.artistmember.index', $parameters)); - /** - * The Artist Member Index Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new ArtistMemberSchema(); + $response->assertJson( + json_decode( + json_encode( + new ArtistMemberCollection($artistMembers, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('updated at filter', function () { + $updatedFilter = fake()->date(); + $excludedDate = fake()->date(); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $parameters = [ + FilterParser::param() => [ + BasePivot::ATTRIBUTE_UPDATED_AT => $updatedFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { + Carbon::withTestNow($updatedFilter, function () { + Collection::times(fake()->randomDigitNotNull(), function () { ArtistMember::factory() ->for(Artist::factory(), ArtistMember::RELATION_ARTIST) ->for(Artist::factory(), ArtistMember::RELATION_MEMBER) ->create(); }); + }); - $response = $this->get(route('api.artistmember.index', $parameters)); - - $artistMembers = ArtistMember::with($includedPaths->all())->get(); - - $response->assertJson( - json_decode( - json_encode( - new ArtistMemberCollection($artistMembers, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Member Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new ArtistMemberSchema(); - - $fields = collect($schema->fields()); - - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); - - $parameters = [ - FieldParser::param() => [ - ArtistMemberResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { + Carbon::withTestNow($excludedDate, function () { + Collection::times(fake()->randomDigitNotNull(), function () { ArtistMember::factory() ->for(Artist::factory(), ArtistMember::RELATION_ARTIST) ->for(Artist::factory(), ArtistMember::RELATION_MEMBER) ->create(); }); + }); - $response = $this->get(route('api.artistmember.index', $parameters)); + $artistMembers = ArtistMember::query()->where(BasePivot::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - $artistMembers = ArtistMember::all(); + $response = get(route('api.artistmember.index', $parameters)); - $response->assertJson( - json_decode( - json_encode( - new ArtistMemberCollection($artistMembers, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Member Index Endpoint shall support sorting resources. - */ - public function testSorts(): void - { - $schema = new ArtistMemberSchema(); - - /** @var Sort $sort */ - $sort = collect($schema->fields()) - ->filter(fn (Field $field) => $field instanceof SortableField) - ->map(fn (SortableField $field) => $field->getSort()) - ->random(); - - $parameters = [ - SortParser::param() => $sort->format(Arr::random(Direction::cases())), - ]; - - $query = new Query($parameters); - - Collection::times($this->faker->randomDigitNotNull(), function () { - ArtistMember::factory() - ->for(Artist::factory(), ArtistMember::RELATION_ARTIST) - ->for(Artist::factory(), ArtistMember::RELATION_MEMBER) - ->create(); - }); - - $response = $this->get(route('api.artistmember.index', $parameters)); - - $artistMembers = $this->sort(ArtistMember::query(), $query, $schema)->get(); - - $response->assertJson( - json_decode( - json_encode( - new ArtistMemberCollection($artistMembers, $query) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Member Index Endpoint shall support filtering by created_at. - */ - public function testCreatedAtFilter(): void - { - $createdFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BasePivot::ATTRIBUTE_CREATED_AT => $createdFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($createdFilter, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - ArtistMember::factory() - ->for(Artist::factory(), ArtistMember::RELATION_ARTIST) - ->for(Artist::factory(), ArtistMember::RELATION_MEMBER) - ->create(); - }); - }); - - Carbon::withTestNow($excludedDate, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - ArtistMember::factory() - ->for(Artist::factory(), ArtistMember::RELATION_ARTIST) - ->for(Artist::factory(), ArtistMember::RELATION_MEMBER) - ->create(); - }); - }); - - $artistMembers = ArtistMember::query()->where(BasePivot::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - - $response = $this->get(route('api.artistmember.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ArtistMemberCollection($artistMembers, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Member Index Endpoint shall support filtering by updated_at. - */ - public function testUpdatedAtFilter(): void - { - $updatedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BasePivot::ATTRIBUTE_UPDATED_AT => $updatedFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($updatedFilter, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - ArtistMember::factory() - ->for(Artist::factory(), ArtistMember::RELATION_ARTIST) - ->for(Artist::factory(), ArtistMember::RELATION_MEMBER) - ->create(); - }); - }); - - Carbon::withTestNow($excludedDate, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - ArtistMember::factory() - ->for(Artist::factory(), ArtistMember::RELATION_ARTIST) - ->for(Artist::factory(), ArtistMember::RELATION_MEMBER) - ->create(); - }); - }); - - $artistMembers = ArtistMember::query()->where(BasePivot::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - - $response = $this->get(route('api.artistmember.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ArtistMemberCollection($artistMembers, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response->assertJson( + json_decode( + json_encode( + new ArtistMemberCollection($artistMembers, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/ArtistMember/ArtistMemberShowTest.php b/tests/Feature/Http/Api/Pivot/Wiki/ArtistMember/ArtistMemberShowTest.php index 2b5babaf4..6f113d341 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/ArtistMember/ArtistMemberShowTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/ArtistMember/ArtistMemberShowTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\ArtistMember; - use App\Http\Api\Field\Field; use App\Http\Api\Include\AllowedInclude; use App\Http\Api\Parser\FieldParser; @@ -13,125 +11,106 @@ use App\Http\Api\Schema\Pivot\Wiki\ArtistMemberSchema; use App\Http\Resources\Pivot\Wiki\Resource\ArtistMemberResource; use App\Models\Wiki\Artist; use App\Pivots\Wiki\ArtistMember; -use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; -class ArtistMemberShowTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * The Artist Member Show Endpoint shall return an error if the artist member does not exist. - */ - public function testNotFound(): void - { - $artist = Artist::factory()->createOne(); - $member = Artist::factory()->createOne(); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response = $this->get(route('api.artistmember.show', ['artist' => $artist, 'member' => $member])); +test('not found', function () { + $artist = Artist::factory()->createOne(); + $member = Artist::factory()->createOne(); - $response->assertNotFound(); - } + $response = get(route('api.artistmember.show', ['artist' => $artist, 'member' => $member])); - /** - * By default, the Artist Member Show Endpoint shall return an Artist Member Resource. - */ - public function testDefault(): void - { - $artistMember = ArtistMember::factory() - ->for(Artist::factory(), ArtistMember::RELATION_ARTIST) - ->for(Artist::factory(), ArtistMember::RELATION_MEMBER) - ->createOne(); + $response->assertNotFound(); +}); - $response = $this->get(route('api.artistmember.show', ['artist' => $artistMember->artist, 'member' => $artistMember->member])); +test('default', function () { + $artistMember = ArtistMember::factory() + ->for(Artist::factory(), ArtistMember::RELATION_ARTIST) + ->for(Artist::factory(), ArtistMember::RELATION_MEMBER) + ->createOne(); - $artistMember->unsetRelations(); + $response = get(route('api.artistmember.show', ['artist' => $artistMember->artist, 'member' => $artistMember->member])); - $response->assertJson( - json_decode( - json_encode( - new ArtistMemberResource($artistMember, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $artistMember->unsetRelations(); - /** - * The Artist Member Show Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new ArtistMemberSchema(); + $response->assertJson( + json_decode( + json_encode( + new ArtistMemberResource($artistMember, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('allowed include paths', function () { + $schema = new ArtistMemberSchema(); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $allowedIncludes = collect($schema->allowedIncludes()); - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - $artistMember = ArtistMember::factory() - ->for(Artist::factory(), ArtistMember::RELATION_ARTIST) - ->for(Artist::factory(), ArtistMember::RELATION_MEMBER) - ->createOne(); + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; - $response = $this->get(route('api.artistmember.show', ['artist' => $artistMember->artist, 'member' => $artistMember->member] + $parameters)); + $artistMember = ArtistMember::factory() + ->for(Artist::factory(), ArtistMember::RELATION_ARTIST) + ->for(Artist::factory(), ArtistMember::RELATION_MEMBER) + ->createOne(); - $artistMember->unsetRelations()->load($includedPaths->all()); + $response = get(route('api.artistmember.show', ['artist' => $artistMember->artist, 'member' => $artistMember->member] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new ArtistMemberResource($artistMember, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $artistMember->unsetRelations()->load($includedPaths->all()); - /** - * The Artist Member Show Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new ArtistMemberSchema(); + $response->assertJson( + json_decode( + json_encode( + new ArtistMemberResource($artistMember, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $fields = collect($schema->fields()); +test('sparse fieldsets', function () { + $schema = new ArtistMemberSchema(); - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); + $fields = collect($schema->fields()); - $parameters = [ - FieldParser::param() => [ - ArtistMemberResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); - $artistMember = ArtistMember::factory() - ->for(Artist::factory(), ArtistMember::RELATION_ARTIST) - ->for(Artist::factory(), ArtistMember::RELATION_MEMBER) - ->createOne(); + $parameters = [ + FieldParser::param() => [ + ArtistMemberResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; - $response = $this->get(route('api.artistmember.show', ['artist' => $artistMember->artist, 'member' => $artistMember->member] + $parameters)); + $artistMember = ArtistMember::factory() + ->for(Artist::factory(), ArtistMember::RELATION_ARTIST) + ->for(Artist::factory(), ArtistMember::RELATION_MEMBER) + ->createOne(); - $artistMember->unsetRelations(); + $response = get(route('api.artistmember.show', ['artist' => $artistMember->artist, 'member' => $artistMember->member] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new ArtistMemberResource($artistMember, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $artistMember->unsetRelations(); + + $response->assertJson( + json_decode( + json_encode( + new ArtistMemberResource($artistMember, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/ArtistMember/ArtistMemberStoreTest.php b/tests/Feature/Http/Api/Pivot/Wiki/ArtistMember/ArtistMemberStoreTest.php index 52443efed..af60203f5 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/ArtistMember/ArtistMemberStoreTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/ArtistMember/ArtistMemberStoreTest.php @@ -2,68 +2,52 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\ArtistMember; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Artist; use App\Pivots\Wiki\ArtistMember; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ArtistMemberStoreTest extends TestCase -{ - /** - * The Artist Member Store Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $artist = Artist::factory()->createOne(); - $member = Artist::factory()->createOne(); +use function Pest\Laravel\post; - $parameters = ArtistMember::factory()->raw(); +test('protected', function () { + $artist = Artist::factory()->createOne(); + $member = Artist::factory()->createOne(); - $response = $this->post(route('api.artistmember.store', ['artist' => $artist, 'member' => $member] + $parameters)); + $parameters = ArtistMember::factory()->raw(); - $response->assertUnauthorized(); - } + $response = post(route('api.artistmember.store', ['artist' => $artist, 'member' => $member] + $parameters)); - /** - * The Artist Member Store Endpoint shall forbid users without the create artist permission. - */ - public function testForbidden(): void - { - $artist = Artist::factory()->createOne(); - $member = Artist::factory()->createOne(); + $response->assertUnauthorized(); +}); - $parameters = ArtistMember::factory()->raw(); +test('forbidden', function () { + $artist = Artist::factory()->createOne(); + $member = Artist::factory()->createOne(); - $user = User::factory()->createOne(); + $parameters = ArtistMember::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->post(route('api.artistmember.store', ['artist' => $artist, 'member' => $member] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.artistmember.store', ['artist' => $artist, 'member' => $member] + $parameters)); - /** - * The Artist Member Store Endpoint shall create an artist member. - */ - public function testCreate(): void - { - $artist = Artist::factory()->createOne(); - $member = Artist::factory()->createOne(); + $response->assertForbidden(); +}); - $parameters = ArtistMember::factory()->raw(); +test('create', function () { + $artist = Artist::factory()->createOne(); + $member = Artist::factory()->createOne(); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Artist::class))->createOne(); + $parameters = ArtistMember::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Artist::class))->createOne(); - $response = $this->post(route('api.artistmember.store', ['artist' => $artist, 'member' => $member] + $parameters)); + Sanctum::actingAs($user); - $response->assertCreated(); - static::assertDatabaseCount(ArtistMember::class, 1); - } -} + $response = post(route('api.artistmember.store', ['artist' => $artist, 'member' => $member] + $parameters)); + + $response->assertCreated(); + $this->assertDatabaseCount(ArtistMember::class, 1); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/ArtistMember/ArtistMemberUpdateTest.php b/tests/Feature/Http/Api/Pivot/Wiki/ArtistMember/ArtistMemberUpdateTest.php index 0557f20cc..cda778186 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/ArtistMember/ArtistMemberUpdateTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/ArtistMember/ArtistMemberUpdateTest.php @@ -2,73 +2,57 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\ArtistMember; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Artist; use App\Pivots\Wiki\ArtistMember; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ArtistMemberUpdateTest extends TestCase -{ - /** - * The Artist Member Update Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $artistMember = ArtistMember::factory() - ->for(Artist::factory(), ArtistMember::RELATION_ARTIST) - ->for(Artist::factory(), ArtistMember::RELATION_MEMBER) - ->createOne(); +use function Pest\Laravel\put; - $parameters = ArtistMember::factory()->raw(); +test('protected', function () { + $artistMember = ArtistMember::factory() + ->for(Artist::factory(), ArtistMember::RELATION_ARTIST) + ->for(Artist::factory(), ArtistMember::RELATION_MEMBER) + ->createOne(); - $response = $this->put(route('api.artistmember.update', ['artist' => $artistMember->artist, 'member' => $artistMember->member] + $parameters)); + $parameters = ArtistMember::factory()->raw(); - $response->assertUnauthorized(); - } + $response = put(route('api.artistmember.update', ['artist' => $artistMember->artist, 'member' => $artistMember->member] + $parameters)); - /** - * The Artist Member Update Endpoint shall forbid users without the update artist permission. - */ - public function testForbidden(): void - { - $artistMember = ArtistMember::factory() - ->for(Artist::factory(), ArtistMember::RELATION_ARTIST) - ->for(Artist::factory(), ArtistMember::RELATION_MEMBER) - ->createOne(); + $response->assertUnauthorized(); +}); - $parameters = ArtistMember::factory()->raw(); +test('forbidden', function () { + $artistMember = ArtistMember::factory() + ->for(Artist::factory(), ArtistMember::RELATION_ARTIST) + ->for(Artist::factory(), ArtistMember::RELATION_MEMBER) + ->createOne(); - $user = User::factory()->createOne(); + $parameters = ArtistMember::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->put(route('api.artistmember.update', ['artist' => $artistMember->artist, 'member' => $artistMember->member] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.artistmember.update', ['artist' => $artistMember->artist, 'member' => $artistMember->member] + $parameters)); - /** - * The Artist Member Update Endpoint shall update an artist member. - */ - public function testUpdate(): void - { - $artistMember = ArtistMember::factory() - ->for(Artist::factory(), ArtistMember::RELATION_ARTIST) - ->for(Artist::factory(), ArtistMember::RELATION_MEMBER) - ->createOne(); + $response->assertForbidden(); +}); - $parameters = ArtistMember::factory()->raw(); +test('update', function () { + $artistMember = ArtistMember::factory() + ->for(Artist::factory(), ArtistMember::RELATION_ARTIST) + ->for(Artist::factory(), ArtistMember::RELATION_MEMBER) + ->createOne(); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Artist::class))->createOne(); + $parameters = ArtistMember::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Artist::class))->createOne(); - $response = $this->put(route('api.artistmember.update', ['artist' => $artistMember->artist, 'member' => $artistMember->member] + $parameters)); + Sanctum::actingAs($user); - $response->assertOk(); - } -} + $response = put(route('api.artistmember.update', ['artist' => $artistMember->artist, 'member' => $artistMember->member] + $parameters)); + + $response->assertOk(); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/ArtistResource/ArtistResourceDestroyTest.php b/tests/Feature/Http/Api/Pivot/Wiki/ArtistResource/ArtistResourceDestroyTest.php index 0e70a140b..08bfd2336 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/ArtistResource/ArtistResourceDestroyTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/ArtistResource/ArtistResourceDestroyTest.php @@ -2,96 +2,76 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\ArtistResource; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Artist; use App\Models\Wiki\ExternalResource; use App\Pivots\Wiki\ArtistResource; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ArtistResourceDestroyTest extends TestCase -{ - /** - * The Artist Resource Destroy Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $artistResource = ArtistResource::factory() - ->for(Artist::factory()) - ->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE) - ->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.artistresource.destroy', ['artist' => $artistResource->artist, 'resource' => $artistResource->resource])); +test('protected', function () { + $artistResource = ArtistResource::factory() + ->for(Artist::factory()) + ->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE) + ->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.artistresource.destroy', ['artist' => $artistResource->artist, 'resource' => $artistResource->resource])); - /** - * The Artist Resource Destroy Endpoint shall forbid users without the delete artist & delete resource permissions. - */ - public function testForbidden(): void - { - $artistResource = ArtistResource::factory() - ->for(Artist::factory()) - ->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE) - ->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $artistResource = ArtistResource::factory() + ->for(Artist::factory()) + ->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.artistresource.destroy', ['artist' => $artistResource->artist, 'resource' => $artistResource->resource])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.artistresource.destroy', ['artist' => $artistResource->artist, 'resource' => $artistResource->resource])); - /** - * The Artist Resource Destroy Endpoint shall return an error if the artist resource does not exist. - */ - public function testNotFound(): void - { - $artist = Artist::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory() - ->withPermissions( - CrudPermission::DELETE->format(Artist::class), - CrudPermission::DELETE->format(ExternalResource::class) - ) - ->createOne(); +test('not found', function () { + $artist = Artist::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::DELETE->format(Artist::class), + CrudPermission::DELETE->format(ExternalResource::class) + ) + ->createOne(); - $response = $this->delete(route('api.artistresource.destroy', ['artist' => $artist, 'resource' => $resource])); + Sanctum::actingAs($user); - $response->assertNotFound(); - } + $response = delete(route('api.artistresource.destroy', ['artist' => $artist, 'resource' => $resource])); - /** - * The Artist Resource Destroy Endpoint shall delete the artist resource. - */ - public function testDeleted(): void - { - $artistResource = ArtistResource::factory() - ->for(Artist::factory()) - ->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE) - ->createOne(); + $response->assertNotFound(); +}); - $user = User::factory() - ->withPermissions( - CrudPermission::DELETE->format(Artist::class), - CrudPermission::DELETE->format(ExternalResource::class) - ) - ->createOne(); +test('deleted', function () { + $artistResource = ArtistResource::factory() + ->for(Artist::factory()) + ->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::DELETE->format(Artist::class), + CrudPermission::DELETE->format(ExternalResource::class) + ) + ->createOne(); - $response = $this->delete(route('api.artistresource.destroy', ['artist' => $artistResource->artist, 'resource' => $artistResource->resource])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertModelMissing($artistResource); - } -} + $response = delete(route('api.artistresource.destroy', ['artist' => $artistResource->artist, 'resource' => $artistResource->resource])); + + $response->assertOk(); + $this->assertModelMissing($artistResource); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/ArtistResource/ArtistResourceIndexTest.php b/tests/Feature/Http/Api/Pivot/Wiki/ArtistResource/ArtistResourceIndexTest.php index b0aa0c9df..5a7556423 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/ArtistResource/ArtistResourceIndexTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/ArtistResource/ArtistResourceIndexTest.php @@ -2,9 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\ArtistResource; - -use App\Concerns\Actions\Http\Api\SortsModels; use App\Contracts\Http\Api\Field\SortableField; use App\Enums\Http\Api\Sort\Direction; use App\Enums\Models\Wiki\ResourceSite; @@ -27,329 +24,295 @@ use App\Models\Wiki\ExternalResource; use App\Pivots\BasePivot; use App\Pivots\Wiki\ArtistResource; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; use Illuminate\Support\Collection; -use Tests\TestCase; -class ArtistResourceIndexTest extends TestCase -{ - use SortsModels; - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the Artist Resource Index Endpoint shall return a collection of Artist Resource Resources. - */ - public function testDefault(): void - { - Collection::times($this->faker->randomDigitNotNull(), function () { +uses(App\Concerns\Actions\Http\Api\SortsModels::class); + +uses(Illuminate\Foundation\Testing\WithFaker::class); + +test('default', function () { + Collection::times(fake()->randomDigitNotNull(), function () { + ArtistResource::factory() + ->for(Artist::factory()) + ->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE) + ->create(); + }); + + $artistResources = ArtistResource::all(); + + $response = get(route('api.artistresource.index')); + + $response->assertJson( + json_decode( + json_encode( + new ArtistResourceCollection($artistResources, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('paginated', function () { + Collection::times(fake()->randomDigitNotNull(), function () { + ArtistResource::factory() + ->for(Artist::factory()) + ->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE) + ->create(); + }); + + $response = get(route('api.artistresource.index')); + + $response->assertJsonStructure([ + ArtistResourceCollection::$wrap, + 'links', + 'meta', + ]); +}); + +test('allowed include paths', function () { + $schema = new ArtistResourceSchema(); + + $allowedIncludes = collect($schema->allowedIncludes()); + + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); + + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + ArtistResource::factory() + ->for(Artist::factory()) + ->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE) + ->create(); + }); + + $response = get(route('api.artistresource.index', $parameters)); + + $artistResources = ArtistResource::with($includedPaths->all())->get(); + + $response->assertJson( + json_decode( + json_encode( + new ArtistResourceCollection($artistResources, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sparse fieldsets', function () { + $schema = new ArtistResourceSchema(); + + $fields = collect($schema->fields()); + + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + ArtistResourceResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + ArtistResource::factory() + ->for(Artist::factory()) + ->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE) + ->create(); + }); + + $response = get(route('api.artistresource.index', $parameters)); + + $artistResources = ArtistResource::all(); + + $response->assertJson( + json_decode( + json_encode( + new ArtistResourceCollection($artistResources, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sorts', function () { + $schema = new ArtistResourceSchema(); + + /** @var Sort $sort */ + $sort = collect($schema->fields()) + ->filter(fn (Field $field) => $field instanceof SortableField) + ->map(fn (SortableField $field) => $field->getSort()) + ->random(); + + $parameters = [ + SortParser::param() => $sort->format(Arr::random(Direction::cases())), + ]; + + $query = new Query($parameters); + + Collection::times(fake()->randomDigitNotNull(), function () { + ArtistResource::factory() + ->for(Artist::factory()) + ->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE) + ->create(); + }); + + $response = get(route('api.artistresource.index', $parameters)); + + $artistResources = $this->sort(ArtistResource::query(), $query, $schema)->get(); + + $response->assertJson( + json_decode( + json_encode( + new ArtistResourceCollection($artistResources, $query) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('created at filter', function () { + $createdFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BasePivot::ATTRIBUTE_CREATED_AT => $createdFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($createdFilter, function () { + Collection::times(fake()->randomDigitNotNull(), function () { ArtistResource::factory() ->for(Artist::factory()) ->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE) ->create(); }); + }); - $artistResources = ArtistResource::all(); - - $response = $this->get(route('api.artistresource.index')); - - $response->assertJson( - json_decode( - json_encode( - new ArtistResourceCollection($artistResources, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Resource Index Endpoint shall be paginated. - */ - public function testPaginated(): void - { - Collection::times($this->faker->randomDigitNotNull(), function () { + Carbon::withTestNow($excludedDate, function () { + Collection::times(fake()->randomDigitNotNull(), function () { ArtistResource::factory() ->for(Artist::factory()) ->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE) ->create(); }); + }); - $response = $this->get(route('api.artistresource.index')); + $artistResources = ArtistResource::query()->where(BasePivot::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - $response->assertJsonStructure([ - ArtistResourceCollection::$wrap, - 'links', - 'meta', - ]); - } + $response = get(route('api.artistresource.index', $parameters)); - /** - * The Artist Resource Index Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new ArtistResourceSchema(); + $response->assertJson( + json_decode( + json_encode( + new ArtistResourceCollection($artistResources, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('updated at filter', function () { + $updatedFilter = fake()->date(); + $excludedDate = fake()->date(); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $parameters = [ + FilterParser::param() => [ + BasePivot::ATTRIBUTE_UPDATED_AT => $updatedFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { + Carbon::withTestNow($updatedFilter, function () { + Collection::times(fake()->randomDigitNotNull(), function () { ArtistResource::factory() ->for(Artist::factory()) ->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE) ->create(); }); + }); - $response = $this->get(route('api.artistresource.index', $parameters)); - - $artistResources = ArtistResource::with($includedPaths->all())->get(); - - $response->assertJson( - json_decode( - json_encode( - new ArtistResourceCollection($artistResources, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Resource Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new ArtistResourceSchema(); - - $fields = collect($schema->fields()); - - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); - - $parameters = [ - FieldParser::param() => [ - ArtistResourceResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { + Carbon::withTestNow($excludedDate, function () { + Collection::times(fake()->randomDigitNotNull(), function () { ArtistResource::factory() ->for(Artist::factory()) ->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE) ->create(); }); + }); - $response = $this->get(route('api.artistresource.index', $parameters)); + $artistResources = ArtistResource::query()->where(BasePivot::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - $artistResources = ArtistResource::all(); + $response = get(route('api.artistresource.index', $parameters)); - $response->assertJson( - json_decode( - json_encode( - new ArtistResourceCollection($artistResources, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response->assertJson( + json_decode( + json_encode( + new ArtistResourceCollection($artistResources, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - /** - * The Artist Resource Index Endpoint shall support sorting resources. - */ - public function testSorts(): void - { - $schema = new ArtistResourceSchema(); +test('resources by site', function () { + $siteFilter = Arr::random(ResourceSite::cases()); - /** @var Sort $sort */ - $sort = collect($schema->fields()) - ->filter(fn (Field $field) => $field instanceof SortableField) - ->map(fn (SortableField $field) => $field->getSort()) - ->random(); + $parameters = [ + FilterParser::param() => [ + ExternalResource::ATTRIBUTE_SITE => $siteFilter->localize(), + ], + IncludeParser::param() => ArtistResource::RELATION_RESOURCE, + ]; - $parameters = [ - SortParser::param() => $sort->format(Arr::random(Direction::cases())), - ]; + Collection::times(fake()->randomDigitNotNull(), function () { + ArtistResource::factory() + ->for(Artist::factory()) + ->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE) + ->create(); + }); - $query = new Query($parameters); + $response = get(route('api.artistresource.index', $parameters)); - Collection::times($this->faker->randomDigitNotNull(), function () { - ArtistResource::factory() - ->for(Artist::factory()) - ->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE) - ->create(); - }); + $artistResources = ArtistResource::with([ + ArtistResource::RELATION_RESOURCE => function (BelongsTo $query) use ($siteFilter) { + $query->where(ExternalResource::ATTRIBUTE_SITE, $siteFilter->value); + }, + ]) + ->get(); - $response = $this->get(route('api.artistresource.index', $parameters)); - - $artistResources = $this->sort(ArtistResource::query(), $query, $schema)->get(); - - $response->assertJson( - json_decode( - json_encode( - new ArtistResourceCollection($artistResources, $query) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Resource Index Endpoint shall support filtering by created_at. - */ - public function testCreatedAtFilter(): void - { - $createdFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BasePivot::ATTRIBUTE_CREATED_AT => $createdFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($createdFilter, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - ArtistResource::factory() - ->for(Artist::factory()) - ->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE) - ->create(); - }); - }); - - Carbon::withTestNow($excludedDate, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - ArtistResource::factory() - ->for(Artist::factory()) - ->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE) - ->create(); - }); - }); - - $artistResources = ArtistResource::query()->where(BasePivot::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - - $response = $this->get(route('api.artistresource.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ArtistResourceCollection($artistResources, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Resource Index Endpoint shall support filtering by updated_at. - */ - public function testUpdatedAtFilter(): void - { - $updatedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BasePivot::ATTRIBUTE_UPDATED_AT => $updatedFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($updatedFilter, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - ArtistResource::factory() - ->for(Artist::factory()) - ->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE) - ->create(); - }); - }); - - Carbon::withTestNow($excludedDate, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - ArtistResource::factory() - ->for(Artist::factory()) - ->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE) - ->create(); - }); - }); - - $artistResources = ArtistResource::query()->where(BasePivot::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - - $response = $this->get(route('api.artistresource.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ArtistResourceCollection($artistResources, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Resource Index Endpoint shall support constrained eager loading of resources by site. - */ - public function testResourcesBySite(): void - { - $siteFilter = Arr::random(ResourceSite::cases()); - - $parameters = [ - FilterParser::param() => [ - ExternalResource::ATTRIBUTE_SITE => $siteFilter->localize(), - ], - IncludeParser::param() => ArtistResource::RELATION_RESOURCE, - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { - ArtistResource::factory() - ->for(Artist::factory()) - ->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE) - ->create(); - }); - - $response = $this->get(route('api.artistresource.index', $parameters)); - - $artistResources = ArtistResource::with([ - ArtistResource::RELATION_RESOURCE => function (BelongsTo $query) use ($siteFilter) { - $query->where(ExternalResource::ATTRIBUTE_SITE, $siteFilter->value); - }, - ]) - ->get(); - - $response->assertJson( - json_decode( - json_encode( - new ArtistResourceCollection($artistResources, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response->assertJson( + json_decode( + json_encode( + new ArtistResourceCollection($artistResources, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/ArtistResource/ArtistResourceShowTest.php b/tests/Feature/Http/Api/Pivot/Wiki/ArtistResource/ArtistResourceShowTest.php index b9555f7aa..bcb60eb02 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/ArtistResource/ArtistResourceShowTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/ArtistResource/ArtistResourceShowTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\ArtistResource; - use App\Enums\Models\Wiki\ResourceSite; use App\Http\Api\Field\Field; use App\Http\Api\Include\AllowedInclude; @@ -17,165 +15,142 @@ use App\Models\Wiki\Artist; use App\Models\Wiki\ExternalResource; use App\Pivots\Wiki\ArtistResource; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; -use Tests\TestCase; -class ArtistResourceShowTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * The Artist Resource Show Endpoint shall return an error if the artist resource does not exist. - */ - public function testNotFound(): void - { - $artist = Artist::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response = $this->get(route('api.artistresource.show', ['artist' => $artist, 'resource' => $resource])); +test('not found', function () { + $artist = Artist::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - $response->assertNotFound(); - } + $response = get(route('api.artistresource.show', ['artist' => $artist, 'resource' => $resource])); - /** - * By default, the Artist Resource Show Endpoint shall return an Artist Resource Resource. - */ - public function testDefault(): void - { - $artistResource = ArtistResource::factory() - ->for(Artist::factory()) - ->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE) - ->createOne(); + $response->assertNotFound(); +}); - $response = $this->get(route('api.artistresource.show', ['artist' => $artistResource->artist, 'resource' => $artistResource->resource])); +test('default', function () { + $artistResource = ArtistResource::factory() + ->for(Artist::factory()) + ->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE) + ->createOne(); - $artistResource->unsetRelations(); + $response = get(route('api.artistresource.show', ['artist' => $artistResource->artist, 'resource' => $artistResource->resource])); - $response->assertJson( - json_decode( - json_encode( - new ArtistResourceResource($artistResource, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $artistResource->unsetRelations(); - /** - * The Artist Resource Show Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new ArtistResourceSchema(); + $response->assertJson( + json_decode( + json_encode( + new ArtistResourceResource($artistResource, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('allowed include paths', function () { + $schema = new ArtistResourceSchema(); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $allowedIncludes = collect($schema->allowedIncludes()); - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - $artistResource = ArtistResource::factory() - ->for(Artist::factory()) - ->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE) - ->createOne(); + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; - $response = $this->get(route('api.artistresource.show', ['artist' => $artistResource->artist, 'resource' => $artistResource->resource] + $parameters)); + $artistResource = ArtistResource::factory() + ->for(Artist::factory()) + ->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE) + ->createOne(); - $artistResource->unsetRelations()->load($includedPaths->all()); + $response = get(route('api.artistresource.show', ['artist' => $artistResource->artist, 'resource' => $artistResource->resource] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new ArtistResourceResource($artistResource, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $artistResource->unsetRelations()->load($includedPaths->all()); - /** - * The Artist Resource Show Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new ArtistResourceSchema(); + $response->assertJson( + json_decode( + json_encode( + new ArtistResourceResource($artistResource, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $fields = collect($schema->fields()); +test('sparse fieldsets', function () { + $schema = new ArtistResourceSchema(); - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); + $fields = collect($schema->fields()); - $parameters = [ - FieldParser::param() => [ - ArtistResourceResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); - $artistResource = ArtistResource::factory() - ->for(Artist::factory()) - ->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE) - ->createOne(); + $parameters = [ + FieldParser::param() => [ + ArtistResourceResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; - $response = $this->get(route('api.artistresource.show', ['artist' => $artistResource->artist, 'resource' => $artistResource->resource] + $parameters)); + $artistResource = ArtistResource::factory() + ->for(Artist::factory()) + ->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE) + ->createOne(); - $artistResource->unsetRelations(); + $response = get(route('api.artistresource.show', ['artist' => $artistResource->artist, 'resource' => $artistResource->resource] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new ArtistResourceResource($artistResource, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $artistResource->unsetRelations(); - /** - * The Artist Resource Show Endpoint shall support constrained eager loading of resources by site. - */ - public function testResourcesBySite(): void - { - $siteFilter = Arr::random(ResourceSite::cases()); + $response->assertJson( + json_decode( + json_encode( + new ArtistResourceResource($artistResource, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - ExternalResource::ATTRIBUTE_SITE => $siteFilter->localize(), - ], - IncludeParser::param() => ArtistResource::RELATION_RESOURCE, - ]; +test('resources by site', function () { + $siteFilter = Arr::random(ResourceSite::cases()); - $artistResource = ArtistResource::factory() - ->for(Artist::factory()) - ->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + ExternalResource::ATTRIBUTE_SITE => $siteFilter->localize(), + ], + IncludeParser::param() => ArtistResource::RELATION_RESOURCE, + ]; - $response = $this->get(route('api.artistresource.show', ['artist' => $artistResource->artist, 'resource' => $artistResource->resource] + $parameters)); + $artistResource = ArtistResource::factory() + ->for(Artist::factory()) + ->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE) + ->createOne(); - $artistResource->unsetRelations()->load([ - ArtistResource::RELATION_RESOURCE => function (BelongsTo $query) use ($siteFilter) { - $query->where(ExternalResource::ATTRIBUTE_SITE, $siteFilter->value); - }, - ]); + $response = get(route('api.artistresource.show', ['artist' => $artistResource->artist, 'resource' => $artistResource->resource] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new ArtistResourceResource($artistResource, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $artistResource->unsetRelations()->load([ + ArtistResource::RELATION_RESOURCE => function (BelongsTo $query) use ($siteFilter) { + $query->where(ExternalResource::ATTRIBUTE_SITE, $siteFilter->value); + }, + ]); + + $response->assertJson( + json_decode( + json_encode( + new ArtistResourceResource($artistResource, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/ArtistResource/ArtistResourceStoreTest.php b/tests/Feature/Http/Api/Pivot/Wiki/ArtistResource/ArtistResourceStoreTest.php index 6ad8cde9d..6fea7b2ab 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/ArtistResource/ArtistResourceStoreTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/ArtistResource/ArtistResourceStoreTest.php @@ -2,74 +2,58 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\ArtistResource; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Artist; use App\Models\Wiki\ExternalResource; use App\Pivots\Wiki\ArtistResource; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ArtistResourceStoreTest extends TestCase -{ - /** - * The Artist Resource Store Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $artist = Artist::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); +use function Pest\Laravel\post; - $parameters = ArtistResource::factory()->raw(); +test('protected', function () { + $artist = Artist::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - $response = $this->post(route('api.artistresource.store', ['artist' => $artist, 'resource' => $resource] + $parameters)); + $parameters = ArtistResource::factory()->raw(); - $response->assertUnauthorized(); - } + $response = post(route('api.artistresource.store', ['artist' => $artist, 'resource' => $resource] + $parameters)); - /** - * The Artist Resource Store Endpoint shall forbid users without the create artist & create resource permissions. - */ - public function testForbidden(): void - { - $artist = Artist::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); + $response->assertUnauthorized(); +}); - $parameters = ArtistResource::factory()->raw(); +test('forbidden', function () { + $artist = Artist::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - $user = User::factory()->createOne(); + $parameters = ArtistResource::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->post(route('api.artistresource.store', ['artist' => $artist, 'resource' => $resource] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.artistresource.store', ['artist' => $artist, 'resource' => $resource] + $parameters)); - /** - * The Artist Resource Store Endpoint shall create an artist resource. - */ - public function testCreate(): void - { - $artist = Artist::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); + $response->assertForbidden(); +}); - $parameters = ArtistResource::factory()->raw(); +test('create', function () { + $artist = Artist::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - $user = User::factory() - ->withPermissions( - CrudPermission::CREATE->format(Artist::class), - CrudPermission::CREATE->format(ExternalResource::class) - ) - ->createOne(); + $parameters = ArtistResource::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::CREATE->format(Artist::class), + CrudPermission::CREATE->format(ExternalResource::class) + ) + ->createOne(); - $response = $this->post(route('api.artistresource.store', ['artist' => $artist, 'resource' => $resource] + $parameters)); + Sanctum::actingAs($user); - $response->assertCreated(); - static::assertDatabaseCount(ArtistResource::class, 1); - } -} + $response = post(route('api.artistresource.store', ['artist' => $artist, 'resource' => $resource] + $parameters)); + + $response->assertCreated(); + $this->assertDatabaseCount(ArtistResource::class, 1); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/ArtistResource/ArtistResourceUpdateTest.php b/tests/Feature/Http/Api/Pivot/Wiki/ArtistResource/ArtistResourceUpdateTest.php index 117707429..8e111b874 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/ArtistResource/ArtistResourceUpdateTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/ArtistResource/ArtistResourceUpdateTest.php @@ -2,79 +2,63 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\ArtistResource; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Artist; use App\Models\Wiki\ExternalResource; use App\Pivots\Wiki\ArtistResource; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ArtistResourceUpdateTest extends TestCase -{ - /** - * The Artist Resource Update Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $artistResource = ArtistResource::factory() - ->for(Artist::factory()) - ->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE) - ->createOne(); +use function Pest\Laravel\put; - $parameters = ArtistResource::factory()->raw(); +test('protected', function () { + $artistResource = ArtistResource::factory() + ->for(Artist::factory()) + ->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE) + ->createOne(); - $response = $this->put(route('api.artistresource.update', ['artist' => $artistResource->artist, 'resource' => $artistResource->resource] + $parameters)); + $parameters = ArtistResource::factory()->raw(); - $response->assertUnauthorized(); - } + $response = put(route('api.artistresource.update', ['artist' => $artistResource->artist, 'resource' => $artistResource->resource] + $parameters)); - /** - * The Artist Resource Update Endpoint shall forbid users without the update artist & update resource permissions. - */ - public function testForbidden(): void - { - $artistResource = ArtistResource::factory() - ->for(Artist::factory()) - ->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE) - ->createOne(); + $response->assertUnauthorized(); +}); - $parameters = ArtistResource::factory()->raw(); +test('forbidden', function () { + $artistResource = ArtistResource::factory() + ->for(Artist::factory()) + ->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE) + ->createOne(); - $user = User::factory()->createOne(); + $parameters = ArtistResource::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->put(route('api.artistresource.update', ['artist' => $artistResource->artist, 'resource' => $artistResource->resource] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.artistresource.update', ['artist' => $artistResource->artist, 'resource' => $artistResource->resource] + $parameters)); - /** - * The Artist Resource Update Endpoint shall update an artist resource. - */ - public function testUpdate(): void - { - $artistResource = ArtistResource::factory() - ->for(Artist::factory()) - ->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE) - ->createOne(); + $response->assertForbidden(); +}); - $parameters = ArtistResource::factory()->raw(); +test('update', function () { + $artistResource = ArtistResource::factory() + ->for(Artist::factory()) + ->for(ExternalResource::factory(), ArtistResource::RELATION_RESOURCE) + ->createOne(); - $user = User::factory() - ->withPermissions( - CrudPermission::UPDATE->format(Artist::class), - CrudPermission::UPDATE->format(ExternalResource::class) - ) - ->createOne(); + $parameters = ArtistResource::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::UPDATE->format(Artist::class), + CrudPermission::UPDATE->format(ExternalResource::class) + ) + ->createOne(); - $response = $this->put(route('api.artistresource.update', ['artist' => $artistResource->artist, 'resource' => $artistResource->resource] + $parameters)); + Sanctum::actingAs($user); - $response->assertOk(); - } -} + $response = put(route('api.artistresource.update', ['artist' => $artistResource->artist, 'resource' => $artistResource->resource] + $parameters)); + + $response->assertOk(); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/ArtistSong/ArtistSongDestroyTest.php b/tests/Feature/Http/Api/Pivot/Wiki/ArtistSong/ArtistSongDestroyTest.php index 711728cdb..5a170da86 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/ArtistSong/ArtistSongDestroyTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/ArtistSong/ArtistSongDestroyTest.php @@ -2,96 +2,76 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\ArtistSong; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Artist; use App\Models\Wiki\Song; use App\Pivots\Wiki\ArtistSong; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ArtistSongDestroyTest extends TestCase -{ - /** - * The Artist Song Destroy Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $artistSong = ArtistSong::factory() - ->for(Artist::factory()) - ->for(Song::factory()) - ->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.artistsong.destroy', ['artist' => $artistSong->artist, 'song' => $artistSong->song])); +test('protected', function () { + $artistSong = ArtistSong::factory() + ->for(Artist::factory()) + ->for(Song::factory()) + ->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.artistsong.destroy', ['artist' => $artistSong->artist, 'song' => $artistSong->song])); - /** - * The Artist Song Destroy Endpoint shall forbid users without the delete artist & delete song permissions. - */ - public function testForbidden(): void - { - $artistSong = ArtistSong::factory() - ->for(Artist::factory()) - ->for(Song::factory()) - ->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $artistSong = ArtistSong::factory() + ->for(Artist::factory()) + ->for(Song::factory()) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.artistsong.destroy', ['artist' => $artistSong->artist, 'song' => $artistSong->song])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.artistsong.destroy', ['artist' => $artistSong->artist, 'song' => $artistSong->song])); - /** - * The Artist Song Destroy Endpoint shall return an error if the artist song does not exist. - */ - public function testNotFound(): void - { - $artist = Artist::factory()->createOne(); - $song = Song::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory() - ->withPermissions( - CrudPermission::DELETE->format(Artist::class), - CrudPermission::DELETE->format(Song::class) - ) - ->createOne(); +test('not found', function () { + $artist = Artist::factory()->createOne(); + $song = Song::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::DELETE->format(Artist::class), + CrudPermission::DELETE->format(Song::class) + ) + ->createOne(); - $response = $this->delete(route('api.artistsong.destroy', ['artist' => $artist, 'song' => $song])); + Sanctum::actingAs($user); - $response->assertNotFound(); - } + $response = delete(route('api.artistsong.destroy', ['artist' => $artist, 'song' => $song])); - /** - * The Artist Song Destroy Endpoint shall delete the artist song. - */ - public function testDeleted(): void - { - $artistSong = ArtistSong::factory() - ->for(Artist::factory()) - ->for(Song::factory()) - ->createOne(); + $response->assertNotFound(); +}); - $user = User::factory() - ->withPermissions( - CrudPermission::DELETE->format(Artist::class), - CrudPermission::DELETE->format(Song::class) - ) - ->createOne(); +test('deleted', function () { + $artistSong = ArtistSong::factory() + ->for(Artist::factory()) + ->for(Song::factory()) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::DELETE->format(Artist::class), + CrudPermission::DELETE->format(Song::class) + ) + ->createOne(); - $response = $this->delete(route('api.artistsong.destroy', ['artist' => $artistSong->artist, 'song' => $artistSong->song])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertModelMissing($artistSong); - } -} + $response = delete(route('api.artistsong.destroy', ['artist' => $artistSong->artist, 'song' => $artistSong->song])); + + $response->assertOk(); + $this->assertModelMissing($artistSong); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/ArtistSong/ArtistSongIndexTest.php b/tests/Feature/Http/Api/Pivot/Wiki/ArtistSong/ArtistSongIndexTest.php index 3e12fac1d..74e5cc67d 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/ArtistSong/ArtistSongIndexTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/ArtistSong/ArtistSongIndexTest.php @@ -2,9 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\ArtistSong; - -use App\Concerns\Actions\Http\Api\SortsModels; use App\Contracts\Http\Api\Field\SortableField; use App\Enums\Http\Api\Sort\Direction; use App\Http\Api\Criteria\Paging\Criteria; @@ -25,287 +22,257 @@ use App\Models\Wiki\Artist; use App\Models\Wiki\Song; use App\Pivots\BasePivot; use App\Pivots\Wiki\ArtistSong; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; use Illuminate\Support\Collection; -use Tests\TestCase; -class ArtistSongIndexTest extends TestCase -{ - use SortsModels; - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the Artist Song Index Endpoint shall return a collection of Artist Song Resources. - */ - public function testDefault(): void - { - Collection::times($this->faker->randomDigitNotNull(), function () { +uses(App\Concerns\Actions\Http\Api\SortsModels::class); + +uses(Illuminate\Foundation\Testing\WithFaker::class); + +test('default', function () { + Collection::times(fake()->randomDigitNotNull(), function () { + ArtistSong::factory() + ->for(Artist::factory()) + ->for(Song::factory()) + ->create(); + }); + + $artistSongs = ArtistSong::all(); + + $response = get(route('api.artistsong.index')); + + $response->assertJson( + json_decode( + json_encode( + new ArtistSongCollection($artistSongs, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('paginated', function () { + Collection::times(fake()->randomDigitNotNull(), function () { + ArtistSong::factory() + ->for(Artist::factory()) + ->for(Song::factory()) + ->create(); + }); + + $response = get(route('api.artistsong.index')); + + $response->assertJsonStructure([ + ArtistSongCollection::$wrap, + 'links', + 'meta', + ]); +}); + +test('allowed include paths', function () { + $schema = new ArtistSongSchema(); + + $allowedIncludes = collect($schema->allowedIncludes()); + + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); + + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + ArtistSong::factory() + ->for(Artist::factory()) + ->for(Song::factory()) + ->create(); + }); + + $response = get(route('api.artistsong.index', $parameters)); + + $artistSongs = ArtistSong::with($includedPaths->all())->get(); + + $response->assertJson( + json_decode( + json_encode( + new ArtistSongCollection($artistSongs, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sparse fieldsets', function () { + $schema = new ArtistSongSchema(); + + $fields = collect($schema->fields()); + + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + ArtistSongResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + ArtistSong::factory() + ->for(Artist::factory()) + ->for(Song::factory()) + ->create(); + }); + + $response = get(route('api.artistsong.index', $parameters)); + + $artistSongs = ArtistSong::all(); + + $response->assertJson( + json_decode( + json_encode( + new ArtistSongCollection($artistSongs, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sorts', function () { + $schema = new ArtistSongSchema(); + + /** @var Sort $sort */ + $sort = collect($schema->fields()) + ->filter(fn (Field $field) => $field instanceof SortableField) + ->map(fn (SortableField $field) => $field->getSort()) + ->random(); + + $parameters = [ + SortParser::param() => $sort->format(Arr::random(Direction::cases())), + ]; + + $query = new Query($parameters); + + Collection::times(fake()->randomDigitNotNull(), function () { + ArtistSong::factory() + ->for(Artist::factory()) + ->for(Song::factory()) + ->create(); + }); + + $response = get(route('api.artistsong.index', $parameters)); + + $artistSongs = $this->sort(ArtistSong::query(), $query, $schema)->get(); + + $response->assertJson( + json_decode( + json_encode( + new ArtistSongCollection($artistSongs, $query) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('created at filter', function () { + $createdFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BasePivot::ATTRIBUTE_CREATED_AT => $createdFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($createdFilter, function () { + Collection::times(fake()->randomDigitNotNull(), function () { ArtistSong::factory() ->for(Artist::factory()) ->for(Song::factory()) ->create(); }); + }); - $artistSongs = ArtistSong::all(); - - $response = $this->get(route('api.artistsong.index')); - - $response->assertJson( - json_decode( - json_encode( - new ArtistSongCollection($artistSongs, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Song Index Endpoint shall be paginated. - */ - public function testPaginated(): void - { - Collection::times($this->faker->randomDigitNotNull(), function () { + Carbon::withTestNow($excludedDate, function () { + Collection::times(fake()->randomDigitNotNull(), function () { ArtistSong::factory() ->for(Artist::factory()) ->for(Song::factory()) ->create(); }); + }); - $response = $this->get(route('api.artistsong.index')); + $artistSongs = ArtistSong::query()->where(BasePivot::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - $response->assertJsonStructure([ - ArtistSongCollection::$wrap, - 'links', - 'meta', - ]); - } + $response = get(route('api.artistsong.index', $parameters)); - /** - * The Artist Song Index Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new ArtistSongSchema(); + $response->assertJson( + json_decode( + json_encode( + new ArtistSongCollection($artistSongs, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('updated at filter', function () { + $updatedFilter = fake()->date(); + $excludedDate = fake()->date(); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $parameters = [ + FilterParser::param() => [ + BasePivot::ATTRIBUTE_UPDATED_AT => $updatedFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { + Carbon::withTestNow($updatedFilter, function () { + Collection::times(fake()->randomDigitNotNull(), function () { ArtistSong::factory() ->for(Artist::factory()) ->for(Song::factory()) ->create(); }); + }); - $response = $this->get(route('api.artistsong.index', $parameters)); - - $artistSongs = ArtistSong::with($includedPaths->all())->get(); - - $response->assertJson( - json_decode( - json_encode( - new ArtistSongCollection($artistSongs, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Song Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new ArtistSongSchema(); - - $fields = collect($schema->fields()); - - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); - - $parameters = [ - FieldParser::param() => [ - ArtistSongResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { + Carbon::withTestNow($excludedDate, function () { + Collection::times(fake()->randomDigitNotNull(), function () { ArtistSong::factory() ->for(Artist::factory()) ->for(Song::factory()) ->create(); }); + }); - $response = $this->get(route('api.artistsong.index', $parameters)); + $artistSongs = ArtistSong::query()->where(BasePivot::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - $artistSongs = ArtistSong::all(); + $response = get(route('api.artistsong.index', $parameters)); - $response->assertJson( - json_decode( - json_encode( - new ArtistSongCollection($artistSongs, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Song Index Endpoint shall support sorting resources. - */ - public function testSorts(): void - { - $schema = new ArtistSongSchema(); - - /** @var Sort $sort */ - $sort = collect($schema->fields()) - ->filter(fn (Field $field) => $field instanceof SortableField) - ->map(fn (SortableField $field) => $field->getSort()) - ->random(); - - $parameters = [ - SortParser::param() => $sort->format(Arr::random(Direction::cases())), - ]; - - $query = new Query($parameters); - - Collection::times($this->faker->randomDigitNotNull(), function () { - ArtistSong::factory() - ->for(Artist::factory()) - ->for(Song::factory()) - ->create(); - }); - - $response = $this->get(route('api.artistsong.index', $parameters)); - - $artistSongs = $this->sort(ArtistSong::query(), $query, $schema)->get(); - - $response->assertJson( - json_decode( - json_encode( - new ArtistSongCollection($artistSongs, $query) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Song Index Endpoint shall support filtering by created_at. - */ - public function testCreatedAtFilter(): void - { - $createdFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BasePivot::ATTRIBUTE_CREATED_AT => $createdFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($createdFilter, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - ArtistSong::factory() - ->for(Artist::factory()) - ->for(Song::factory()) - ->create(); - }); - }); - - Carbon::withTestNow($excludedDate, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - ArtistSong::factory() - ->for(Artist::factory()) - ->for(Song::factory()) - ->create(); - }); - }); - - $artistSongs = ArtistSong::query()->where(BasePivot::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - - $response = $this->get(route('api.artistsong.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ArtistSongCollection($artistSongs, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Song Index Endpoint shall support filtering by updated_at. - */ - public function testUpdatedAtFilter(): void - { - $updatedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BasePivot::ATTRIBUTE_UPDATED_AT => $updatedFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($updatedFilter, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - ArtistSong::factory() - ->for(Artist::factory()) - ->for(Song::factory()) - ->create(); - }); - }); - - Carbon::withTestNow($excludedDate, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - ArtistSong::factory() - ->for(Artist::factory()) - ->for(Song::factory()) - ->create(); - }); - }); - - $artistSongs = ArtistSong::query()->where(BasePivot::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - - $response = $this->get(route('api.artistsong.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ArtistSongCollection($artistSongs, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response->assertJson( + json_decode( + json_encode( + new ArtistSongCollection($artistSongs, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/ArtistSong/ArtistSongShowTest.php b/tests/Feature/Http/Api/Pivot/Wiki/ArtistSong/ArtistSongShowTest.php index 88d0adfbc..942a10272 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/ArtistSong/ArtistSongShowTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/ArtistSong/ArtistSongShowTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\ArtistSong; - use App\Http\Api\Field\Field; use App\Http\Api\Include\AllowedInclude; use App\Http\Api\Parser\FieldParser; @@ -14,125 +12,106 @@ use App\Http\Resources\Pivot\Wiki\Resource\ArtistSongResource; use App\Models\Wiki\Artist; use App\Models\Wiki\Song; use App\Pivots\Wiki\ArtistSong; -use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; -class ArtistSongShowTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * The Artist Song Show Endpoint shall return an error if the artist song does not exist. - */ - public function testNotFound(): void - { - $artist = Artist::factory()->createOne(); - $song = Song::factory()->createOne(); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response = $this->get(route('api.artistsong.show', ['artist' => $artist, 'song' => $song])); +test('not found', function () { + $artist = Artist::factory()->createOne(); + $song = Song::factory()->createOne(); - $response->assertNotFound(); - } + $response = get(route('api.artistsong.show', ['artist' => $artist, 'song' => $song])); - /** - * By default, the Artist Song Show Endpoint shall return an Artist Song Resource. - */ - public function testDefault(): void - { - $artistSong = ArtistSong::factory() - ->for(Artist::factory()) - ->for(Song::factory()) - ->createOne(); + $response->assertNotFound(); +}); - $response = $this->get(route('api.artistsong.show', ['artist' => $artistSong->artist, 'song' => $artistSong->song])); +test('default', function () { + $artistSong = ArtistSong::factory() + ->for(Artist::factory()) + ->for(Song::factory()) + ->createOne(); - $artistSong->unsetRelations(); + $response = get(route('api.artistsong.show', ['artist' => $artistSong->artist, 'song' => $artistSong->song])); - $response->assertJson( - json_decode( - json_encode( - new ArtistSongResource($artistSong, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $artistSong->unsetRelations(); - /** - * The Artist Song Show Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new ArtistSongSchema(); + $response->assertJson( + json_decode( + json_encode( + new ArtistSongResource($artistSong, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('allowed include paths', function () { + $schema = new ArtistSongSchema(); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $allowedIncludes = collect($schema->allowedIncludes()); - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - $artistSong = ArtistSong::factory() - ->for(Artist::factory()) - ->for(Song::factory()) - ->createOne(); + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; - $response = $this->get(route('api.artistsong.show', ['artist' => $artistSong->artist, 'song' => $artistSong->song] + $parameters)); + $artistSong = ArtistSong::factory() + ->for(Artist::factory()) + ->for(Song::factory()) + ->createOne(); - $artistSong->unsetRelations()->load($includedPaths->all()); + $response = get(route('api.artistsong.show', ['artist' => $artistSong->artist, 'song' => $artistSong->song] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new ArtistSongResource($artistSong, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $artistSong->unsetRelations()->load($includedPaths->all()); - /** - * The Artist Song Show Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new ArtistSongSchema(); + $response->assertJson( + json_decode( + json_encode( + new ArtistSongResource($artistSong, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $fields = collect($schema->fields()); +test('sparse fieldsets', function () { + $schema = new ArtistSongSchema(); - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); + $fields = collect($schema->fields()); - $parameters = [ - FieldParser::param() => [ - ArtistSongResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); - $artistSong = ArtistSong::factory() - ->for(Artist::factory()) - ->for(Song::factory()) - ->createOne(); + $parameters = [ + FieldParser::param() => [ + ArtistSongResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; - $response = $this->get(route('api.artistsong.show', ['artist' => $artistSong->artist, 'song' => $artistSong->song] + $parameters)); + $artistSong = ArtistSong::factory() + ->for(Artist::factory()) + ->for(Song::factory()) + ->createOne(); - $artistSong->unsetRelations(); + $response = get(route('api.artistsong.show', ['artist' => $artistSong->artist, 'song' => $artistSong->song] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new ArtistSongResource($artistSong, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $artistSong->unsetRelations(); + + $response->assertJson( + json_decode( + json_encode( + new ArtistSongResource($artistSong, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/ArtistSong/ArtistSongStoreTest.php b/tests/Feature/Http/Api/Pivot/Wiki/ArtistSong/ArtistSongStoreTest.php index 483ae40b0..24f049eac 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/ArtistSong/ArtistSongStoreTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/ArtistSong/ArtistSongStoreTest.php @@ -2,74 +2,58 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\ArtistSong; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Artist; use App\Models\Wiki\Song; use App\Pivots\Wiki\ArtistSong; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ArtistSongStoreTest extends TestCase -{ - /** - * The Artist Song Store Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $artist = Artist::factory()->createOne(); - $song = Song::factory()->createOne(); +use function Pest\Laravel\post; - $parameters = ArtistSong::factory()->raw(); +test('protected', function () { + $artist = Artist::factory()->createOne(); + $song = Song::factory()->createOne(); - $response = $this->post(route('api.artistsong.store', ['artist' => $artist, 'song' => $song] + $parameters)); + $parameters = ArtistSong::factory()->raw(); - $response->assertUnauthorized(); - } + $response = post(route('api.artistsong.store', ['artist' => $artist, 'song' => $song] + $parameters)); - /** - * The Artist Song Store Endpoint shall forbid users without the create artist & create song permissions. - */ - public function testForbidden(): void - { - $artist = Artist::factory()->createOne(); - $song = Song::factory()->createOne(); + $response->assertUnauthorized(); +}); - $parameters = ArtistSong::factory()->raw(); +test('forbidden', function () { + $artist = Artist::factory()->createOne(); + $song = Song::factory()->createOne(); - $user = User::factory()->createOne(); + $parameters = ArtistSong::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->post(route('api.artistsong.store', ['artist' => $artist, 'song' => $song] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.artistsong.store', ['artist' => $artist, 'song' => $song] + $parameters)); - /** - * The Artist Song Store Endpoint shall create an artist song. - */ - public function testCreate(): void - { - $artist = Artist::factory()->createOne(); - $song = Song::factory()->createOne(); + $response->assertForbidden(); +}); - $parameters = ArtistSong::factory()->raw(); +test('create', function () { + $artist = Artist::factory()->createOne(); + $song = Song::factory()->createOne(); - $user = User::factory() - ->withPermissions( - CrudPermission::CREATE->format(Artist::class), - CrudPermission::CREATE->format(Song::class) - ) - ->createOne(); + $parameters = ArtistSong::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::CREATE->format(Artist::class), + CrudPermission::CREATE->format(Song::class) + ) + ->createOne(); - $response = $this->post(route('api.artistsong.store', ['artist' => $artist, 'song' => $song] + $parameters)); + Sanctum::actingAs($user); - $response->assertCreated(); - static::assertDatabaseCount(ArtistSong::class, 1); - } -} + $response = post(route('api.artistsong.store', ['artist' => $artist, 'song' => $song] + $parameters)); + + $response->assertCreated(); + $this->assertDatabaseCount(ArtistSong::class, 1); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/ArtistSong/ArtistSongUpdateTest.php b/tests/Feature/Http/Api/Pivot/Wiki/ArtistSong/ArtistSongUpdateTest.php index 2c613ab70..ede84b377 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/ArtistSong/ArtistSongUpdateTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/ArtistSong/ArtistSongUpdateTest.php @@ -2,79 +2,63 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\ArtistSong; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Artist; use App\Models\Wiki\Song; use App\Pivots\Wiki\ArtistSong; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ArtistSongUpdateTest extends TestCase -{ - /** - * The Artist Resource Update Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $artistSong = ArtistSong::factory() - ->for(Artist::factory()) - ->for(Song::factory()) - ->createOne(); +use function Pest\Laravel\put; - $parameters = ArtistSong::factory()->raw(); +test('protected', function () { + $artistSong = ArtistSong::factory() + ->for(Artist::factory()) + ->for(Song::factory()) + ->createOne(); - $response = $this->put(route('api.artistsong.update', ['artist' => $artistSong->artist, 'song' => $artistSong->song] + $parameters)); + $parameters = ArtistSong::factory()->raw(); - $response->assertUnauthorized(); - } + $response = put(route('api.artistsong.update', ['artist' => $artistSong->artist, 'song' => $artistSong->song] + $parameters)); - /** - * The Artist Resource Update Endpoint shall forbid users without the update artist & update song permissions. - */ - public function testForbidden(): void - { - $artistSong = ArtistSong::factory() - ->for(Artist::factory()) - ->for(Song::factory()) - ->createOne(); + $response->assertUnauthorized(); +}); - $parameters = ArtistSong::factory()->raw(); +test('forbidden', function () { + $artistSong = ArtistSong::factory() + ->for(Artist::factory()) + ->for(Song::factory()) + ->createOne(); - $user = User::factory()->createOne(); + $parameters = ArtistSong::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->put(route('api.artistsong.update', ['artist' => $artistSong->artist, 'song' => $artistSong->song] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.artistsong.update', ['artist' => $artistSong->artist, 'song' => $artistSong->song] + $parameters)); - /** - * The Artist Resource Update Endpoint shall update an artist song. - */ - public function testUpdate(): void - { - $artistSong = ArtistSong::factory() - ->for(Artist::factory()) - ->for(Song::factory()) - ->createOne(); + $response->assertForbidden(); +}); - $parameters = ArtistSong::factory()->raw(); +test('update', function () { + $artistSong = ArtistSong::factory() + ->for(Artist::factory()) + ->for(Song::factory()) + ->createOne(); - $user = User::factory() - ->withPermissions( - CrudPermission::UPDATE->format(Artist::class), - CrudPermission::UPDATE->format(Song::class) - ) - ->createOne(); + $parameters = ArtistSong::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::UPDATE->format(Artist::class), + CrudPermission::UPDATE->format(Song::class) + ) + ->createOne(); - $response = $this->put(route('api.artistsong.update', ['artist' => $artistSong->artist, 'song' => $artistSong->song] + $parameters)); + Sanctum::actingAs($user); - $response->assertOk(); - } -} + $response = put(route('api.artistsong.update', ['artist' => $artistSong->artist, 'song' => $artistSong->song] + $parameters)); + + $response->assertOk(); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/SongResource/SongResourceDestroyTest.php b/tests/Feature/Http/Api/Pivot/Wiki/SongResource/SongResourceDestroyTest.php index 7fd4a6553..509d3f0c9 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/SongResource/SongResourceDestroyTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/SongResource/SongResourceDestroyTest.php @@ -2,96 +2,76 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\SongResource; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\ExternalResource; use App\Models\Wiki\Song; use App\Pivots\Wiki\SongResource; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class SongResourceDestroyTest extends TestCase -{ - /** - * The Song Resource Destroy Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $songResource = SongResource::factory() - ->for(Song::factory()) - ->for(ExternalResource::factory(), SongResource::RELATION_RESOURCE) - ->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.songresource.destroy', ['song' => $songResource->song, 'resource' => $songResource->resource])); +test('protected', function () { + $songResource = SongResource::factory() + ->for(Song::factory()) + ->for(ExternalResource::factory(), SongResource::RELATION_RESOURCE) + ->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.songresource.destroy', ['song' => $songResource->song, 'resource' => $songResource->resource])); - /** - * The Song Resource Destroy Endpoint shall forbid users without the delete song & delete resource permissions. - */ - public function testForbidden(): void - { - $songResource = SongResource::factory() - ->for(Song::factory()) - ->for(ExternalResource::factory(), SongResource::RELATION_RESOURCE) - ->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $songResource = SongResource::factory() + ->for(Song::factory()) + ->for(ExternalResource::factory(), SongResource::RELATION_RESOURCE) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.songresource.destroy', ['song' => $songResource->song, 'resource' => $songResource->resource])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.songresource.destroy', ['song' => $songResource->song, 'resource' => $songResource->resource])); - /** - * The Song Resource Destroy Endpoint shall return an error if the song resource does not exist. - */ - public function testNotFound(): void - { - $song = Song::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory() - ->withPermissions( - CrudPermission::DELETE->format(Song::class), - CrudPermission::DELETE->format(ExternalResource::class) - ) - ->createOne(); +test('not found', function () { + $song = Song::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::DELETE->format(Song::class), + CrudPermission::DELETE->format(ExternalResource::class) + ) + ->createOne(); - $response = $this->delete(route('api.songresource.destroy', ['song' => $song, 'resource' => $resource])); + Sanctum::actingAs($user); - $response->assertNotFound(); - } + $response = delete(route('api.songresource.destroy', ['song' => $song, 'resource' => $resource])); - /** - * The Song Resource Destroy Endpoint shall delete the song resource. - */ - public function testDeleted(): void - { - $songResource = SongResource::factory() - ->for(Song::factory()) - ->for(ExternalResource::factory(), SongResource::RELATION_RESOURCE) - ->createOne(); + $response->assertNotFound(); +}); - $user = User::factory() - ->withPermissions( - CrudPermission::DELETE->format(Song::class), - CrudPermission::DELETE->format(ExternalResource::class) - ) - ->createOne(); +test('deleted', function () { + $songResource = SongResource::factory() + ->for(Song::factory()) + ->for(ExternalResource::factory(), SongResource::RELATION_RESOURCE) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::DELETE->format(Song::class), + CrudPermission::DELETE->format(ExternalResource::class) + ) + ->createOne(); - $response = $this->delete(route('api.songresource.destroy', ['song' => $songResource->song, 'resource' => $songResource->resource])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertModelMissing($songResource); - } -} + $response = delete(route('api.songresource.destroy', ['song' => $songResource->song, 'resource' => $songResource->resource])); + + $response->assertOk(); + $this->assertModelMissing($songResource); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/SongResource/SongResourceIndexTest.php b/tests/Feature/Http/Api/Pivot/Wiki/SongResource/SongResourceIndexTest.php index 710be1cd4..5aed758b0 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/SongResource/SongResourceIndexTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/SongResource/SongResourceIndexTest.php @@ -2,9 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\SongResource; - -use App\Concerns\Actions\Http\Api\SortsModels; use App\Contracts\Http\Api\Field\SortableField; use App\Enums\Http\Api\Sort\Direction; use App\Enums\Models\Wiki\ResourceSite; @@ -27,329 +24,295 @@ use App\Models\Wiki\Song; use App\Pivots\BasePivot; use App\Pivots\Wiki\SongResource; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; use Illuminate\Support\Collection; -use Tests\TestCase; -class SongResourceIndexTest extends TestCase -{ - use SortsModels; - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the Song Resource Index Endpoint shall return a collection of Song Resource Resources. - */ - public function testDefault(): void - { - Collection::times($this->faker->randomDigitNotNull(), function () { +uses(App\Concerns\Actions\Http\Api\SortsModels::class); + +uses(Illuminate\Foundation\Testing\WithFaker::class); + +test('default', function () { + Collection::times(fake()->randomDigitNotNull(), function () { + SongResource::factory() + ->for(Song::factory()) + ->for(ExternalResource::factory(), SongResource::RELATION_RESOURCE) + ->create(); + }); + + $songResources = SongResource::all(); + + $response = get(route('api.songresource.index')); + + $response->assertJson( + json_decode( + json_encode( + new SongResourceCollection($songResources, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('paginated', function () { + Collection::times(fake()->randomDigitNotNull(), function () { + SongResource::factory() + ->for(Song::factory()) + ->for(ExternalResource::factory(), SongResource::RELATION_RESOURCE) + ->create(); + }); + + $response = get(route('api.songresource.index')); + + $response->assertJsonStructure([ + SongResourceCollection::$wrap, + 'links', + 'meta', + ]); +}); + +test('allowed include paths', function () { + $schema = new SongResourceSchema(); + + $allowedIncludes = collect($schema->allowedIncludes()); + + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); + + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + SongResource::factory() + ->for(Song::factory()) + ->for(ExternalResource::factory(), SongResource::RELATION_RESOURCE) + ->create(); + }); + + $response = get(route('api.songresource.index', $parameters)); + + $songResources = SongResource::with($includedPaths->all())->get(); + + $response->assertJson( + json_decode( + json_encode( + new SongResourceCollection($songResources, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sparse fieldsets', function () { + $schema = new SongResourceSchema(); + + $fields = collect($schema->fields()); + + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + SongResourceResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + SongResource::factory() + ->for(Song::factory()) + ->for(ExternalResource::factory(), SongResource::RELATION_RESOURCE) + ->create(); + }); + + $response = get(route('api.songresource.index', $parameters)); + + $songResources = SongResource::all(); + + $response->assertJson( + json_decode( + json_encode( + new SongResourceCollection($songResources, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sorts', function () { + $schema = new SongResourceSchema(); + + /** @var Sort $sort */ + $sort = collect($schema->fields()) + ->filter(fn (Field $field) => $field instanceof SortableField) + ->map(fn (SortableField $field) => $field->getSort()) + ->random(); + + $parameters = [ + SortParser::param() => $sort->format(Arr::random(Direction::cases())), + ]; + + $query = new Query($parameters); + + Collection::times(fake()->randomDigitNotNull(), function () { + SongResource::factory() + ->for(Song::factory()) + ->for(ExternalResource::factory(), SongResource::RELATION_RESOURCE) + ->create(); + }); + + $response = get(route('api.songresource.index', $parameters)); + + $songResources = $this->sort(SongResource::query(), $query, $schema)->get(); + + $response->assertJson( + json_decode( + json_encode( + new SongResourceCollection($songResources, $query) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('created at filter', function () { + $createdFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BasePivot::ATTRIBUTE_CREATED_AT => $createdFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($createdFilter, function () { + Collection::times(fake()->randomDigitNotNull(), function () { SongResource::factory() ->for(Song::factory()) ->for(ExternalResource::factory(), SongResource::RELATION_RESOURCE) ->create(); }); + }); - $songResources = SongResource::all(); - - $response = $this->get(route('api.songresource.index')); - - $response->assertJson( - json_decode( - json_encode( - new SongResourceCollection($songResources, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Song Resource Index Endpoint shall be paginated. - */ - public function testPaginated(): void - { - Collection::times($this->faker->randomDigitNotNull(), function () { + Carbon::withTestNow($excludedDate, function () { + Collection::times(fake()->randomDigitNotNull(), function () { SongResource::factory() ->for(Song::factory()) ->for(ExternalResource::factory(), SongResource::RELATION_RESOURCE) ->create(); }); + }); - $response = $this->get(route('api.songresource.index')); + $songResources = SongResource::query()->where(BasePivot::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - $response->assertJsonStructure([ - SongResourceCollection::$wrap, - 'links', - 'meta', - ]); - } + $response = get(route('api.songresource.index', $parameters)); - /** - * The Song Resource Index Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new SongResourceSchema(); + $response->assertJson( + json_decode( + json_encode( + new SongResourceCollection($songResources, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('updated at filter', function () { + $updatedFilter = fake()->date(); + $excludedDate = fake()->date(); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $parameters = [ + FilterParser::param() => [ + BasePivot::ATTRIBUTE_UPDATED_AT => $updatedFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { + Carbon::withTestNow($updatedFilter, function () { + Collection::times(fake()->randomDigitNotNull(), function () { SongResource::factory() ->for(Song::factory()) ->for(ExternalResource::factory(), SongResource::RELATION_RESOURCE) ->create(); }); + }); - $response = $this->get(route('api.songresource.index', $parameters)); - - $songResources = SongResource::with($includedPaths->all())->get(); - - $response->assertJson( - json_decode( - json_encode( - new SongResourceCollection($songResources, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Song Resource Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new SongResourceSchema(); - - $fields = collect($schema->fields()); - - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); - - $parameters = [ - FieldParser::param() => [ - SongResourceResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { + Carbon::withTestNow($excludedDate, function () { + Collection::times(fake()->randomDigitNotNull(), function () { SongResource::factory() ->for(Song::factory()) ->for(ExternalResource::factory(), SongResource::RELATION_RESOURCE) ->create(); }); + }); - $response = $this->get(route('api.songresource.index', $parameters)); + $songResources = SongResource::query()->where(BasePivot::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - $songResources = SongResource::all(); + $response = get(route('api.songresource.index', $parameters)); - $response->assertJson( - json_decode( - json_encode( - new SongResourceCollection($songResources, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response->assertJson( + json_decode( + json_encode( + new SongResourceCollection($songResources, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - /** - * The Song Resource Index Endpoint shall support sorting resources. - */ - public function testSorts(): void - { - $schema = new SongResourceSchema(); +test('resources by site', function () { + $siteFilter = Arr::random(ResourceSite::cases()); - /** @var Sort $sort */ - $sort = collect($schema->fields()) - ->filter(fn (Field $field) => $field instanceof SortableField) - ->map(fn (SortableField $field) => $field->getSort()) - ->random(); + $parameters = [ + FilterParser::param() => [ + ExternalResource::ATTRIBUTE_SITE => $siteFilter->localize(), + ], + IncludeParser::param() => SongResource::RELATION_RESOURCE, + ]; - $parameters = [ - SortParser::param() => $sort->format(Arr::random(Direction::cases())), - ]; + Collection::times(fake()->randomDigitNotNull(), function () { + SongResource::factory() + ->for(Song::factory()) + ->for(ExternalResource::factory(), SongResource::RELATION_RESOURCE) + ->create(); + }); - $query = new Query($parameters); + $response = get(route('api.songresource.index', $parameters)); - Collection::times($this->faker->randomDigitNotNull(), function () { - SongResource::factory() - ->for(Song::factory()) - ->for(ExternalResource::factory(), SongResource::RELATION_RESOURCE) - ->create(); - }); + $songResources = SongResource::with([ + SongResource::RELATION_RESOURCE => function (BelongsTo $query) use ($siteFilter) { + $query->where(ExternalResource::ATTRIBUTE_SITE, $siteFilter->value); + }, + ]) + ->get(); - $response = $this->get(route('api.songresource.index', $parameters)); - - $songResources = $this->sort(SongResource::query(), $query, $schema)->get(); - - $response->assertJson( - json_decode( - json_encode( - new SongResourceCollection($songResources, $query) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Song Resource Index Endpoint shall support filtering by created_at. - */ - public function testCreatedAtFilter(): void - { - $createdFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BasePivot::ATTRIBUTE_CREATED_AT => $createdFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($createdFilter, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - SongResource::factory() - ->for(Song::factory()) - ->for(ExternalResource::factory(), SongResource::RELATION_RESOURCE) - ->create(); - }); - }); - - Carbon::withTestNow($excludedDate, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - SongResource::factory() - ->for(Song::factory()) - ->for(ExternalResource::factory(), SongResource::RELATION_RESOURCE) - ->create(); - }); - }); - - $songResources = SongResource::query()->where(BasePivot::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - - $response = $this->get(route('api.songresource.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new SongResourceCollection($songResources, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Song Resource Index Endpoint shall support filtering by updated_at. - */ - public function testUpdatedAtFilter(): void - { - $updatedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BasePivot::ATTRIBUTE_UPDATED_AT => $updatedFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($updatedFilter, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - SongResource::factory() - ->for(Song::factory()) - ->for(ExternalResource::factory(), SongResource::RELATION_RESOURCE) - ->create(); - }); - }); - - Carbon::withTestNow($excludedDate, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - SongResource::factory() - ->for(Song::factory()) - ->for(ExternalResource::factory(), SongResource::RELATION_RESOURCE) - ->create(); - }); - }); - - $songResources = SongResource::query()->where(BasePivot::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - - $response = $this->get(route('api.songresource.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new SongResourceCollection($songResources, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Song Resource Index Endpoint shall support constrained eager loading of resources by site. - */ - public function testResourcesBySite(): void - { - $siteFilter = Arr::random(ResourceSite::cases()); - - $parameters = [ - FilterParser::param() => [ - ExternalResource::ATTRIBUTE_SITE => $siteFilter->localize(), - ], - IncludeParser::param() => SongResource::RELATION_RESOURCE, - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { - SongResource::factory() - ->for(Song::factory()) - ->for(ExternalResource::factory(), SongResource::RELATION_RESOURCE) - ->create(); - }); - - $response = $this->get(route('api.songresource.index', $parameters)); - - $songResources = SongResource::with([ - SongResource::RELATION_RESOURCE => function (BelongsTo $query) use ($siteFilter) { - $query->where(ExternalResource::ATTRIBUTE_SITE, $siteFilter->value); - }, - ]) - ->get(); - - $response->assertJson( - json_decode( - json_encode( - new SongResourceCollection($songResources, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response->assertJson( + json_decode( + json_encode( + new SongResourceCollection($songResources, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/SongResource/SongResourceShowTest.php b/tests/Feature/Http/Api/Pivot/Wiki/SongResource/SongResourceShowTest.php index f6617854a..84a4dee6a 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/SongResource/SongResourceShowTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/SongResource/SongResourceShowTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\SongResource; - use App\Enums\Models\Wiki\ResourceSite; use App\Http\Api\Field\Field; use App\Http\Api\Include\AllowedInclude; @@ -17,165 +15,142 @@ use App\Models\Wiki\ExternalResource; use App\Models\Wiki\Song; use App\Pivots\Wiki\SongResource; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; -use Tests\TestCase; -class SongResourceShowTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * The Song Resource Show Endpoint shall return an error if the song resource does not exist. - */ - public function testNotFound(): void - { - $song = Song::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response = $this->get(route('api.songresource.show', ['song' => $song, 'resource' => $resource])); +test('not found', function () { + $song = Song::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - $response->assertNotFound(); - } + $response = get(route('api.songresource.show', ['song' => $song, 'resource' => $resource])); - /** - * By default, the Song Resource Show Endpoint shall return an Song Resource Resource. - */ - public function testDefault(): void - { - $songResource = SongResource::factory() - ->for(Song::factory()) - ->for(ExternalResource::factory(), SongResource::RELATION_RESOURCE) - ->createOne(); + $response->assertNotFound(); +}); - $response = $this->get(route('api.songresource.show', ['song' => $songResource->song, 'resource' => $songResource->resource])); +test('default', function () { + $songResource = SongResource::factory() + ->for(Song::factory()) + ->for(ExternalResource::factory(), SongResource::RELATION_RESOURCE) + ->createOne(); - $songResource->unsetRelations(); + $response = get(route('api.songresource.show', ['song' => $songResource->song, 'resource' => $songResource->resource])); - $response->assertJson( - json_decode( - json_encode( - new SongResourceResource($songResource, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $songResource->unsetRelations(); - /** - * The Song Resource Show Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new SongResourceSchema(); + $response->assertJson( + json_decode( + json_encode( + new SongResourceResource($songResource, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('allowed include paths', function () { + $schema = new SongResourceSchema(); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $allowedIncludes = collect($schema->allowedIncludes()); - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - $songResource = SongResource::factory() - ->for(Song::factory()) - ->for(ExternalResource::factory(), SongResource::RELATION_RESOURCE) - ->createOne(); + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; - $response = $this->get(route('api.songresource.show', ['song' => $songResource->song, 'resource' => $songResource->resource] + $parameters)); + $songResource = SongResource::factory() + ->for(Song::factory()) + ->for(ExternalResource::factory(), SongResource::RELATION_RESOURCE) + ->createOne(); - $songResource->unsetRelations()->load($includedPaths->all()); + $response = get(route('api.songresource.show', ['song' => $songResource->song, 'resource' => $songResource->resource] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new SongResourceResource($songResource, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $songResource->unsetRelations()->load($includedPaths->all()); - /** - * The Song Resource Show Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new SongResourceSchema(); + $response->assertJson( + json_decode( + json_encode( + new SongResourceResource($songResource, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $fields = collect($schema->fields()); +test('sparse fieldsets', function () { + $schema = new SongResourceSchema(); - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); + $fields = collect($schema->fields()); - $parameters = [ - FieldParser::param() => [ - SongResourceResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); - $songResource = SongResource::factory() - ->for(Song::factory()) - ->for(ExternalResource::factory(), SongResource::RELATION_RESOURCE) - ->createOne(); + $parameters = [ + FieldParser::param() => [ + SongResourceResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; - $response = $this->get(route('api.songresource.show', ['song' => $songResource->song, 'resource' => $songResource->resource] + $parameters)); + $songResource = SongResource::factory() + ->for(Song::factory()) + ->for(ExternalResource::factory(), SongResource::RELATION_RESOURCE) + ->createOne(); - $songResource->unsetRelations(); + $response = get(route('api.songresource.show', ['song' => $songResource->song, 'resource' => $songResource->resource] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new SongResourceResource($songResource, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $songResource->unsetRelations(); - /** - * The Song Resource Show Endpoint shall support constrained eager loading of resources by site. - */ - public function testResourcesBySite(): void - { - $siteFilter = Arr::random(ResourceSite::cases()); + $response->assertJson( + json_decode( + json_encode( + new SongResourceResource($songResource, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - ExternalResource::ATTRIBUTE_SITE => $siteFilter->localize(), - ], - IncludeParser::param() => SongResource::RELATION_RESOURCE, - ]; +test('resources by site', function () { + $siteFilter = Arr::random(ResourceSite::cases()); - $songResource = SongResource::factory() - ->for(Song::factory()) - ->for(ExternalResource::factory(), SongResource::RELATION_RESOURCE) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + ExternalResource::ATTRIBUTE_SITE => $siteFilter->localize(), + ], + IncludeParser::param() => SongResource::RELATION_RESOURCE, + ]; - $response = $this->get(route('api.songresource.show', ['song' => $songResource->song, 'resource' => $songResource->resource] + $parameters)); + $songResource = SongResource::factory() + ->for(Song::factory()) + ->for(ExternalResource::factory(), SongResource::RELATION_RESOURCE) + ->createOne(); - $songResource->unsetRelations()->load([ - SongResource::RELATION_RESOURCE => function (BelongsTo $query) use ($siteFilter) { - $query->where(ExternalResource::ATTRIBUTE_SITE, $siteFilter->value); - }, - ]); + $response = get(route('api.songresource.show', ['song' => $songResource->song, 'resource' => $songResource->resource] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new SongResourceResource($songResource, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $songResource->unsetRelations()->load([ + SongResource::RELATION_RESOURCE => function (BelongsTo $query) use ($siteFilter) { + $query->where(ExternalResource::ATTRIBUTE_SITE, $siteFilter->value); + }, + ]); + + $response->assertJson( + json_decode( + json_encode( + new SongResourceResource($songResource, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/SongResource/SongResourceStoreTest.php b/tests/Feature/Http/Api/Pivot/Wiki/SongResource/SongResourceStoreTest.php index 5d8b7a74b..c6d9b7738 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/SongResource/SongResourceStoreTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/SongResource/SongResourceStoreTest.php @@ -2,74 +2,58 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\SongResource; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\ExternalResource; use App\Models\Wiki\Song; use App\Pivots\Wiki\SongResource; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class SongResourceStoreTest extends TestCase -{ - /** - * The Song Resource Store Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $song = Song::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); +use function Pest\Laravel\post; - $parameters = SongResource::factory()->raw(); +test('protected', function () { + $song = Song::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - $response = $this->post(route('api.songresource.store', ['song' => $song, 'resource' => $resource] + $parameters)); + $parameters = SongResource::factory()->raw(); - $response->assertUnauthorized(); - } + $response = post(route('api.songresource.store', ['song' => $song, 'resource' => $resource] + $parameters)); - /** - * The Song Resource Store Endpoint shall forbid users without the create song & create resource permissions. - */ - public function testForbidden(): void - { - $song = Song::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); + $response->assertUnauthorized(); +}); - $parameters = SongResource::factory()->raw(); +test('forbidden', function () { + $song = Song::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - $user = User::factory()->createOne(); + $parameters = SongResource::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->post(route('api.songresource.store', ['song' => $song, 'resource' => $resource] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.songresource.store', ['song' => $song, 'resource' => $resource] + $parameters)); - /** - * The Song Resource Store Endpoint shall create an song resource. - */ - public function testCreate(): void - { - $song = Song::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); + $response->assertForbidden(); +}); - $parameters = SongResource::factory()->raw(); +test('create', function () { + $song = Song::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - $user = User::factory() - ->withPermissions( - CrudPermission::CREATE->format(Song::class), - CrudPermission::CREATE->format(ExternalResource::class) - ) - ->createOne(); + $parameters = SongResource::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::CREATE->format(Song::class), + CrudPermission::CREATE->format(ExternalResource::class) + ) + ->createOne(); - $response = $this->post(route('api.songresource.store', ['song' => $song, 'resource' => $resource] + $parameters)); + Sanctum::actingAs($user); - $response->assertCreated(); - static::assertDatabaseCount(SongResource::class, 1); - } -} + $response = post(route('api.songresource.store', ['song' => $song, 'resource' => $resource] + $parameters)); + + $response->assertCreated(); + $this->assertDatabaseCount(SongResource::class, 1); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/SongResource/SongResourceUpdateTest.php b/tests/Feature/Http/Api/Pivot/Wiki/SongResource/SongResourceUpdateTest.php index 5a1c56b03..e9c2280d7 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/SongResource/SongResourceUpdateTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/SongResource/SongResourceUpdateTest.php @@ -2,79 +2,63 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\SongResource; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\ExternalResource; use App\Models\Wiki\Song; use App\Pivots\Wiki\SongResource; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class SongResourceUpdateTest extends TestCase -{ - /** - * The Song Resource Update Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $songResource = SongResource::factory() - ->for(Song::factory()) - ->for(ExternalResource::factory(), SongResource::RELATION_RESOURCE) - ->createOne(); +use function Pest\Laravel\put; - $parameters = SongResource::factory()->raw(); +test('protected', function () { + $songResource = SongResource::factory() + ->for(Song::factory()) + ->for(ExternalResource::factory(), SongResource::RELATION_RESOURCE) + ->createOne(); - $response = $this->put(route('api.songresource.update', ['song' => $songResource->song, 'resource' => $songResource->resource] + $parameters)); + $parameters = SongResource::factory()->raw(); - $response->assertUnauthorized(); - } + $response = put(route('api.songresource.update', ['song' => $songResource->song, 'resource' => $songResource->resource] + $parameters)); - /** - * The Song Resource Update Endpoint shall forbid users without the update song & update resource permissions. - */ - public function testForbidden(): void - { - $songResource = SongResource::factory() - ->for(Song::factory()) - ->for(ExternalResource::factory(), SongResource::RELATION_RESOURCE) - ->createOne(); + $response->assertUnauthorized(); +}); - $parameters = SongResource::factory()->raw(); +test('forbidden', function () { + $songResource = SongResource::factory() + ->for(Song::factory()) + ->for(ExternalResource::factory(), SongResource::RELATION_RESOURCE) + ->createOne(); - $user = User::factory()->createOne(); + $parameters = SongResource::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->put(route('api.songresource.update', ['song' => $songResource->song, 'resource' => $songResource->resource] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.songresource.update', ['song' => $songResource->song, 'resource' => $songResource->resource] + $parameters)); - /** - * The Song Resource Update Endpoint shall update an song resource. - */ - public function testUpdate(): void - { - $songResource = SongResource::factory() - ->for(Song::factory()) - ->for(ExternalResource::factory(), SongResource::RELATION_RESOURCE) - ->createOne(); + $response->assertForbidden(); +}); - $parameters = SongResource::factory()->raw(); +test('update', function () { + $songResource = SongResource::factory() + ->for(Song::factory()) + ->for(ExternalResource::factory(), SongResource::RELATION_RESOURCE) + ->createOne(); - $user = User::factory() - ->withPermissions( - CrudPermission::UPDATE->format(Song::class), - CrudPermission::UPDATE->format(ExternalResource::class) - ) - ->createOne(); + $parameters = SongResource::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::UPDATE->format(Song::class), + CrudPermission::UPDATE->format(ExternalResource::class) + ) + ->createOne(); - $response = $this->put(route('api.songresource.update', ['song' => $songResource->song, 'resource' => $songResource->resource] + $parameters)); + Sanctum::actingAs($user); - $response->assertOk(); - } -} + $response = put(route('api.songresource.update', ['song' => $songResource->song, 'resource' => $songResource->resource] + $parameters)); + + $response->assertOk(); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/StudioImage/StudioImageDestroyTest.php b/tests/Feature/Http/Api/Pivot/Wiki/StudioImage/StudioImageDestroyTest.php index ae2ace36b..ef02cacab 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/StudioImage/StudioImageDestroyTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/StudioImage/StudioImageDestroyTest.php @@ -2,96 +2,76 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\StudioImage; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Image; use App\Models\Wiki\Studio; use App\Pivots\Wiki\StudioImage; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class StudioImageDestroyTest extends TestCase -{ - /** - * The Studio Image Destroy Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $studioImage = StudioImage::factory() - ->for(Studio::factory()) - ->for(Image::factory()) - ->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.studioimage.destroy', ['studio' => $studioImage->studio, 'image' => $studioImage->image])); +test('protected', function () { + $studioImage = StudioImage::factory() + ->for(Studio::factory()) + ->for(Image::factory()) + ->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.studioimage.destroy', ['studio' => $studioImage->studio, 'image' => $studioImage->image])); - /** - * The Studio Image Destroy Endpoint shall forbid users without the delete studio & delete image permissions. - */ - public function testForbidden(): void - { - $studioImage = StudioImage::factory() - ->for(Studio::factory()) - ->for(Image::factory()) - ->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $studioImage = StudioImage::factory() + ->for(Studio::factory()) + ->for(Image::factory()) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.studioimage.destroy', ['studio' => $studioImage->studio, 'image' => $studioImage->image])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.studioimage.destroy', ['studio' => $studioImage->studio, 'image' => $studioImage->image])); - /** - * The Studio Image Destroy Endpoint shall return an error if the studio image does not exist. - */ - public function testNotFound(): void - { - $studio = Studio::factory()->createOne(); - $image = Image::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory() - ->withPermissions( - CrudPermission::DELETE->format(Studio::class), - CrudPermission::DELETE->format(Image::class) - ) - ->createOne(); +test('not found', function () { + $studio = Studio::factory()->createOne(); + $image = Image::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::DELETE->format(Studio::class), + CrudPermission::DELETE->format(Image::class) + ) + ->createOne(); - $response = $this->delete(route('api.studioimage.destroy', ['studio' => $studio, 'image' => $image])); + Sanctum::actingAs($user); - $response->assertNotFound(); - } + $response = delete(route('api.studioimage.destroy', ['studio' => $studio, 'image' => $image])); - /** - * The Studio Image Destroy Endpoint shall delete the studio image. - */ - public function testDeleted(): void - { - $studioImage = StudioImage::factory() - ->for(Studio::factory()) - ->for(Image::factory()) - ->createOne(); + $response->assertNotFound(); +}); - $user = User::factory() - ->withPermissions( - CrudPermission::DELETE->format(Studio::class), - CrudPermission::DELETE->format(Image::class) - ) - ->createOne(); +test('deleted', function () { + $studioImage = StudioImage::factory() + ->for(Studio::factory()) + ->for(Image::factory()) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::DELETE->format(Studio::class), + CrudPermission::DELETE->format(Image::class) + ) + ->createOne(); - $response = $this->delete(route('api.studioimage.destroy', ['studio' => $studioImage->studio, 'image' => $studioImage->image])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertModelMissing($studioImage); - } -} + $response = delete(route('api.studioimage.destroy', ['studio' => $studioImage->studio, 'image' => $studioImage->image])); + + $response->assertOk(); + $this->assertModelMissing($studioImage); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/StudioImage/StudioImageIndexTest.php b/tests/Feature/Http/Api/Pivot/Wiki/StudioImage/StudioImageIndexTest.php index e1c5dea03..ef3b64dc9 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/StudioImage/StudioImageIndexTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/StudioImage/StudioImageIndexTest.php @@ -2,9 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\StudioImage; - -use App\Concerns\Actions\Http\Api\SortsModels; use App\Contracts\Http\Api\Field\SortableField; use App\Enums\Http\Api\Sort\Direction; use App\Enums\Models\Wiki\ImageFacet; @@ -27,329 +24,295 @@ use App\Models\Wiki\Studio; use App\Pivots\BasePivot; use App\Pivots\Wiki\StudioImage; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; use Illuminate\Support\Collection; -use Tests\TestCase; -class StudioImageIndexTest extends TestCase -{ - use SortsModels; - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the Studio Image Index Endpoint shall return a collection of Studio Image Resources. - */ - public function testDefault(): void - { - Collection::times($this->faker->randomDigitNotNull(), function () { +uses(App\Concerns\Actions\Http\Api\SortsModels::class); + +uses(Illuminate\Foundation\Testing\WithFaker::class); + +test('default', function () { + Collection::times(fake()->randomDigitNotNull(), function () { + StudioImage::factory() + ->for(Studio::factory()) + ->for(Image::factory()) + ->create(); + }); + + $studioImages = StudioImage::all(); + + $response = get(route('api.studioimage.index')); + + $response->assertJson( + json_decode( + json_encode( + new StudioImageCollection($studioImages, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('paginated', function () { + Collection::times(fake()->randomDigitNotNull(), function () { + StudioImage::factory() + ->for(Studio::factory()) + ->for(Image::factory()) + ->create(); + }); + + $response = get(route('api.studioimage.index')); + + $response->assertJsonStructure([ + StudioImageCollection::$wrap, + 'links', + 'meta', + ]); +}); + +test('allowed include paths', function () { + $schema = new StudioImageSchema(); + + $allowedIncludes = collect($schema->allowedIncludes()); + + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); + + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + StudioImage::factory() + ->for(Studio::factory()) + ->for(Image::factory()) + ->create(); + }); + + $response = get(route('api.studioimage.index', $parameters)); + + $studioImages = StudioImage::with($includedPaths->all())->get(); + + $response->assertJson( + json_decode( + json_encode( + new StudioImageCollection($studioImages, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sparse fieldsets', function () { + $schema = new StudioImageSchema(); + + $fields = collect($schema->fields()); + + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + StudioImageResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + StudioImage::factory() + ->for(Studio::factory()) + ->for(Image::factory()) + ->create(); + }); + + $response = get(route('api.studioimage.index', $parameters)); + + $studioImages = StudioImage::all(); + + $response->assertJson( + json_decode( + json_encode( + new StudioImageCollection($studioImages, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sorts', function () { + $schema = new StudioImageSchema(); + + /** @var Sort $sort */ + $sort = collect($schema->fields()) + ->filter(fn (Field $field) => $field instanceof SortableField) + ->map(fn (SortableField $field) => $field->getSort()) + ->random(); + + $parameters = [ + SortParser::param() => $sort->format(Arr::random(Direction::cases())), + ]; + + $query = new Query($parameters); + + Collection::times(fake()->randomDigitNotNull(), function () { + StudioImage::factory() + ->for(Studio::factory()) + ->for(Image::factory()) + ->create(); + }); + + $response = get(route('api.studioimage.index', $parameters)); + + $studioImages = $this->sort(StudioImage::query(), $query, $schema)->get(); + + $response->assertJson( + json_decode( + json_encode( + new StudioImageCollection($studioImages, $query) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('created at filter', function () { + $createdFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BasePivot::ATTRIBUTE_CREATED_AT => $createdFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($createdFilter, function () { + Collection::times(fake()->randomDigitNotNull(), function () { StudioImage::factory() ->for(Studio::factory()) ->for(Image::factory()) ->create(); }); + }); - $studioImages = StudioImage::all(); - - $response = $this->get(route('api.studioimage.index')); - - $response->assertJson( - json_decode( - json_encode( - new StudioImageCollection($studioImages, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Studio Image Index Endpoint shall be paginated. - */ - public function testPaginated(): void - { - Collection::times($this->faker->randomDigitNotNull(), function () { + Carbon::withTestNow($excludedDate, function () { + Collection::times(fake()->randomDigitNotNull(), function () { StudioImage::factory() ->for(Studio::factory()) ->for(Image::factory()) ->create(); }); + }); - $response = $this->get(route('api.studioimage.index')); + $studioImages = StudioImage::query()->where(BasePivot::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - $response->assertJsonStructure([ - StudioImageCollection::$wrap, - 'links', - 'meta', - ]); - } + $response = get(route('api.studioimage.index', $parameters)); - /** - * The Studio Image Index Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new StudioImageSchema(); + $response->assertJson( + json_decode( + json_encode( + new StudioImageCollection($studioImages, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('updated at filter', function () { + $updatedFilter = fake()->date(); + $excludedDate = fake()->date(); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $parameters = [ + FilterParser::param() => [ + BasePivot::ATTRIBUTE_UPDATED_AT => $updatedFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { + Carbon::withTestNow($updatedFilter, function () { + Collection::times(fake()->randomDigitNotNull(), function () { StudioImage::factory() ->for(Studio::factory()) ->for(Image::factory()) ->create(); }); + }); - $response = $this->get(route('api.studioimage.index', $parameters)); - - $studioImages = StudioImage::with($includedPaths->all())->get(); - - $response->assertJson( - json_decode( - json_encode( - new StudioImageCollection($studioImages, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Studio Image Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new StudioImageSchema(); - - $fields = collect($schema->fields()); - - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); - - $parameters = [ - FieldParser::param() => [ - StudioImageResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { + Carbon::withTestNow($excludedDate, function () { + Collection::times(fake()->randomDigitNotNull(), function () { StudioImage::factory() ->for(Studio::factory()) ->for(Image::factory()) ->create(); }); + }); - $response = $this->get(route('api.studioimage.index', $parameters)); + $studioImages = StudioImage::query()->where(BasePivot::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - $studioImages = StudioImage::all(); + $response = get(route('api.studioimage.index', $parameters)); - $response->assertJson( - json_decode( - json_encode( - new StudioImageCollection($studioImages, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response->assertJson( + json_decode( + json_encode( + new StudioImageCollection($studioImages, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - /** - * The Studio Image Index Endpoint shall support sorting resources. - */ - public function testSorts(): void - { - $schema = new StudioImageSchema(); +test('images by facet', function () { + $facetFilter = Arr::random(ImageFacet::cases()); - /** @var Sort $sort */ - $sort = collect($schema->fields()) - ->filter(fn (Field $field) => $field instanceof SortableField) - ->map(fn (SortableField $field) => $field->getSort()) - ->random(); + $parameters = [ + FilterParser::param() => [ + Image::ATTRIBUTE_FACET => $facetFilter->localize(), + ], + IncludeParser::param() => StudioImage::RELATION_IMAGE, + ]; - $parameters = [ - SortParser::param() => $sort->format(Arr::random(Direction::cases())), - ]; + Collection::times(fake()->randomDigitNotNull(), function () { + StudioImage::factory() + ->for(Studio::factory()) + ->for(Image::factory()) + ->create(); + }); - $query = new Query($parameters); + $response = get(route('api.studioimage.index', $parameters)); - Collection::times($this->faker->randomDigitNotNull(), function () { - StudioImage::factory() - ->for(Studio::factory()) - ->for(Image::factory()) - ->create(); - }); + $studioImages = StudioImage::with([ + StudioImage::RELATION_IMAGE => function (BelongsTo $query) use ($facetFilter) { + $query->where(Image::ATTRIBUTE_FACET, $facetFilter->value); + }, + ]) + ->get(); - $response = $this->get(route('api.studioimage.index', $parameters)); - - $studioImages = $this->sort(StudioImage::query(), $query, $schema)->get(); - - $response->assertJson( - json_decode( - json_encode( - new StudioImageCollection($studioImages, $query) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Studio Image Index Endpoint shall support filtering by created_at. - */ - public function testCreatedAtFilter(): void - { - $createdFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BasePivot::ATTRIBUTE_CREATED_AT => $createdFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($createdFilter, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - StudioImage::factory() - ->for(Studio::factory()) - ->for(Image::factory()) - ->create(); - }); - }); - - Carbon::withTestNow($excludedDate, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - StudioImage::factory() - ->for(Studio::factory()) - ->for(Image::factory()) - ->create(); - }); - }); - - $studioImages = StudioImage::query()->where(BasePivot::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - - $response = $this->get(route('api.studioimage.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new StudioImageCollection($studioImages, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Studio Image Index Endpoint shall support filtering by updated_at. - */ - public function testUpdatedAtFilter(): void - { - $updatedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BasePivot::ATTRIBUTE_UPDATED_AT => $updatedFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($updatedFilter, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - StudioImage::factory() - ->for(Studio::factory()) - ->for(Image::factory()) - ->create(); - }); - }); - - Carbon::withTestNow($excludedDate, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - StudioImage::factory() - ->for(Studio::factory()) - ->for(Image::factory()) - ->create(); - }); - }); - - $studioImages = StudioImage::query()->where(BasePivot::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - - $response = $this->get(route('api.studioimage.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new StudioImageCollection($studioImages, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Studio Image Index Endpoint shall support constrained eager loading of images by facet. - */ - public function testImagesByFacet(): void - { - $facetFilter = Arr::random(ImageFacet::cases()); - - $parameters = [ - FilterParser::param() => [ - Image::ATTRIBUTE_FACET => $facetFilter->localize(), - ], - IncludeParser::param() => StudioImage::RELATION_IMAGE, - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { - StudioImage::factory() - ->for(Studio::factory()) - ->for(Image::factory()) - ->create(); - }); - - $response = $this->get(route('api.studioimage.index', $parameters)); - - $studioImages = StudioImage::with([ - StudioImage::RELATION_IMAGE => function (BelongsTo $query) use ($facetFilter) { - $query->where(Image::ATTRIBUTE_FACET, $facetFilter->value); - }, - ]) - ->get(); - - $response->assertJson( - json_decode( - json_encode( - new StudioImageCollection($studioImages, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response->assertJson( + json_decode( + json_encode( + new StudioImageCollection($studioImages, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/StudioImage/StudioImageShowTest.php b/tests/Feature/Http/Api/Pivot/Wiki/StudioImage/StudioImageShowTest.php index 87399282c..bd5ccf95d 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/StudioImage/StudioImageShowTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/StudioImage/StudioImageShowTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\StudioImage; - use App\Enums\Models\Wiki\ImageFacet; use App\Http\Api\Field\Field; use App\Http\Api\Include\AllowedInclude; @@ -17,165 +15,142 @@ use App\Models\Wiki\Image; use App\Models\Wiki\Studio; use App\Pivots\Wiki\StudioImage; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; -use Tests\TestCase; -class StudioImageShowTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * The Studio Image Show Endpoint shall return an error if the studio image does not exist. - */ - public function testNotFound(): void - { - $studio = Studio::factory()->createOne(); - $image = Image::factory()->createOne(); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response = $this->get(route('api.studioimage.show', ['studio' => $studio, 'image' => $image])); +test('not found', function () { + $studio = Studio::factory()->createOne(); + $image = Image::factory()->createOne(); - $response->assertNotFound(); - } + $response = get(route('api.studioimage.show', ['studio' => $studio, 'image' => $image])); - /** - * By default, the Studio Image Show Endpoint shall return an Studio Image Resource. - */ - public function testDefault(): void - { - $studioImage = StudioImage::factory() - ->for(Studio::factory()) - ->for(Image::factory()) - ->createOne(); + $response->assertNotFound(); +}); - $response = $this->get(route('api.studioimage.show', ['studio' => $studioImage->studio, 'image' => $studioImage->image])); +test('default', function () { + $studioImage = StudioImage::factory() + ->for(Studio::factory()) + ->for(Image::factory()) + ->createOne(); - $studioImage->unsetRelations(); + $response = get(route('api.studioimage.show', ['studio' => $studioImage->studio, 'image' => $studioImage->image])); - $response->assertJson( - json_decode( - json_encode( - new StudioImageResource($studioImage, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $studioImage->unsetRelations(); - /** - * The Studio Image Show Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new StudioImageSchema(); + $response->assertJson( + json_decode( + json_encode( + new StudioImageResource($studioImage, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('allowed include paths', function () { + $schema = new StudioImageSchema(); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $allowedIncludes = collect($schema->allowedIncludes()); - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - $studioImage = StudioImage::factory() - ->for(Studio::factory()) - ->for(Image::factory()) - ->createOne(); + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; - $response = $this->get(route('api.studioimage.show', ['studio' => $studioImage->studio, 'image' => $studioImage->image] + $parameters)); + $studioImage = StudioImage::factory() + ->for(Studio::factory()) + ->for(Image::factory()) + ->createOne(); - $studioImage->unsetRelations()->load($includedPaths->all()); + $response = get(route('api.studioimage.show', ['studio' => $studioImage->studio, 'image' => $studioImage->image] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new StudioImageResource($studioImage, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $studioImage->unsetRelations()->load($includedPaths->all()); - /** - * The Studio Image Show Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new StudioImageSchema(); + $response->assertJson( + json_decode( + json_encode( + new StudioImageResource($studioImage, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $fields = collect($schema->fields()); +test('sparse fieldsets', function () { + $schema = new StudioImageSchema(); - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); + $fields = collect($schema->fields()); - $parameters = [ - FieldParser::param() => [ - StudioImageResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); - $studioImage = StudioImage::factory() - ->for(Studio::factory()) - ->for(Image::factory()) - ->createOne(); + $parameters = [ + FieldParser::param() => [ + StudioImageResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; - $response = $this->get(route('api.studioimage.show', ['studio' => $studioImage->studio, 'image' => $studioImage->image] + $parameters)); + $studioImage = StudioImage::factory() + ->for(Studio::factory()) + ->for(Image::factory()) + ->createOne(); - $studioImage->unsetRelations(); + $response = get(route('api.studioimage.show', ['studio' => $studioImage->studio, 'image' => $studioImage->image] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new StudioImageResource($studioImage, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $studioImage->unsetRelations(); - /** - * The Studio Image Show Endpoint shall support constrained eager loading of images by facet. - */ - public function testImagesByFacet(): void - { - $facetFilter = Arr::random(ImageFacet::cases()); + $response->assertJson( + json_decode( + json_encode( + new StudioImageResource($studioImage, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Image::ATTRIBUTE_FACET => $facetFilter->localize(), - ], - IncludeParser::param() => StudioImage::RELATION_IMAGE, - ]; +test('images by facet', function () { + $facetFilter = Arr::random(ImageFacet::cases()); - $studioImage = StudioImage::factory() - ->for(Studio::factory()) - ->for(Image::factory()) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + Image::ATTRIBUTE_FACET => $facetFilter->localize(), + ], + IncludeParser::param() => StudioImage::RELATION_IMAGE, + ]; - $response = $this->get(route('api.studioimage.show', ['studio' => $studioImage->studio, 'image' => $studioImage->image] + $parameters)); + $studioImage = StudioImage::factory() + ->for(Studio::factory()) + ->for(Image::factory()) + ->createOne(); - $studioImage->unsetRelations()->load([ - StudioImage::RELATION_IMAGE => function (BelongsTo $query) use ($facetFilter) { - $query->where(Image::ATTRIBUTE_FACET, $facetFilter->value); - }, - ]); + $response = get(route('api.studioimage.show', ['studio' => $studioImage->studio, 'image' => $studioImage->image] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new StudioImageResource($studioImage, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $studioImage->unsetRelations()->load([ + StudioImage::RELATION_IMAGE => function (BelongsTo $query) use ($facetFilter) { + $query->where(Image::ATTRIBUTE_FACET, $facetFilter->value); + }, + ]); + + $response->assertJson( + json_decode( + json_encode( + new StudioImageResource($studioImage, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/StudioImage/StudioImageStoreTest.php b/tests/Feature/Http/Api/Pivot/Wiki/StudioImage/StudioImageStoreTest.php index 75d477ebe..3549f0d69 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/StudioImage/StudioImageStoreTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/StudioImage/StudioImageStoreTest.php @@ -2,68 +2,52 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\StudioImage; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Image; use App\Models\Wiki\Studio; use App\Pivots\Wiki\StudioImage; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class StudioImageStoreTest extends TestCase -{ - /** - * The Studio Image Store Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $studio = Studio::factory()->createOne(); - $image = Image::factory()->createOne(); +use function Pest\Laravel\post; - $response = $this->post(route('api.studioimage.store', ['studio' => $studio, 'image' => $image])); +test('protected', function () { + $studio = Studio::factory()->createOne(); + $image = Image::factory()->createOne(); - $response->assertUnauthorized(); - } + $response = post(route('api.studioimage.store', ['studio' => $studio, 'image' => $image])); - /** - * The Studio Image Store Endpoint shall forbid users without the create studio & create image permissions. - */ - public function testForbidden(): void - { - $studio = Studio::factory()->createOne(); - $image = Image::factory()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $studio = Studio::factory()->createOne(); + $image = Image::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->post(route('api.studioimage.store', ['studio' => $studio, 'image' => $image])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.studioimage.store', ['studio' => $studio, 'image' => $image])); - /** - * The Studio Image Store Endpoint shall create an studio image. - */ - public function testCreate(): void - { - $studio = Studio::factory()->createOne(); - $image = Image::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory() - ->withPermissions( - CrudPermission::CREATE->format(Studio::class), - CrudPermission::CREATE->format(Image::class) - ) - ->createOne(); +test('create', function () { + $studio = Studio::factory()->createOne(); + $image = Image::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::CREATE->format(Studio::class), + CrudPermission::CREATE->format(Image::class) + ) + ->createOne(); - $response = $this->post(route('api.studioimage.store', ['studio' => $studio, 'image' => $image])); + Sanctum::actingAs($user); - $response->assertCreated(); - static::assertDatabaseCount(StudioImage::class, 1); - } -} + $response = post(route('api.studioimage.store', ['studio' => $studio, 'image' => $image])); + + $response->assertCreated(); + $this->assertDatabaseCount(StudioImage::class, 1); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/StudioResource/StudioResourceDestroyTest.php b/tests/Feature/Http/Api/Pivot/Wiki/StudioResource/StudioResourceDestroyTest.php index 45d4247cd..8d9d089b8 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/StudioResource/StudioResourceDestroyTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/StudioResource/StudioResourceDestroyTest.php @@ -2,96 +2,76 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\StudioResource; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\ExternalResource; use App\Models\Wiki\Studio; use App\Pivots\Wiki\StudioResource; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class StudioResourceDestroyTest extends TestCase -{ - /** - * The Studio Resource Destroy Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $studioResource = StudioResource::factory() - ->for(Studio::factory()) - ->for(ExternalResource::factory(), StudioResource::RELATION_RESOURCE) - ->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.studioresource.destroy', ['studio' => $studioResource->studio, 'resource' => $studioResource->resource])); +test('protected', function () { + $studioResource = StudioResource::factory() + ->for(Studio::factory()) + ->for(ExternalResource::factory(), StudioResource::RELATION_RESOURCE) + ->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.studioresource.destroy', ['studio' => $studioResource->studio, 'resource' => $studioResource->resource])); - /** - * The Studio Resource Destroy Endpoint shall forbid users without the delete studio & delete resource permissions. - */ - public function testForbidden(): void - { - $studioResource = StudioResource::factory() - ->for(Studio::factory()) - ->for(ExternalResource::factory(), StudioResource::RELATION_RESOURCE) - ->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $studioResource = StudioResource::factory() + ->for(Studio::factory()) + ->for(ExternalResource::factory(), StudioResource::RELATION_RESOURCE) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.studioresource.destroy', ['studio' => $studioResource->studio, 'resource' => $studioResource->resource])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.studioresource.destroy', ['studio' => $studioResource->studio, 'resource' => $studioResource->resource])); - /** - * The Studio Resource Destroy Endpoint shall return an error if the studio resource does not exist. - */ - public function testNotFound(): void - { - $studio = Studio::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory() - ->withPermissions( - CrudPermission::DELETE->format(Studio::class), - CrudPermission::DELETE->format(ExternalResource::class) - ) - ->createOne(); +test('not found', function () { + $studio = Studio::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::DELETE->format(Studio::class), + CrudPermission::DELETE->format(ExternalResource::class) + ) + ->createOne(); - $response = $this->delete(route('api.studioresource.destroy', ['studio' => $studio, 'resource' => $resource])); + Sanctum::actingAs($user); - $response->assertNotFound(); - } + $response = delete(route('api.studioresource.destroy', ['studio' => $studio, 'resource' => $resource])); - /** - * The Studio Resource Destroy Endpoint shall delete the studio resource. - */ - public function testDeleted(): void - { - $studioResource = StudioResource::factory() - ->for(Studio::factory()) - ->for(ExternalResource::factory(), StudioResource::RELATION_RESOURCE) - ->createOne(); + $response->assertNotFound(); +}); - $user = User::factory() - ->withPermissions( - CrudPermission::DELETE->format(Studio::class), - CrudPermission::DELETE->format(ExternalResource::class) - ) - ->createOne(); +test('deleted', function () { + $studioResource = StudioResource::factory() + ->for(Studio::factory()) + ->for(ExternalResource::factory(), StudioResource::RELATION_RESOURCE) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::DELETE->format(Studio::class), + CrudPermission::DELETE->format(ExternalResource::class) + ) + ->createOne(); - $response = $this->delete(route('api.studioresource.destroy', ['studio' => $studioResource->studio, 'resource' => $studioResource->resource])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertModelMissing($studioResource); - } -} + $response = delete(route('api.studioresource.destroy', ['studio' => $studioResource->studio, 'resource' => $studioResource->resource])); + + $response->assertOk(); + $this->assertModelMissing($studioResource); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/StudioResource/StudioResourceIndexTest.php b/tests/Feature/Http/Api/Pivot/Wiki/StudioResource/StudioResourceIndexTest.php index 219108669..0abdc0bcb 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/StudioResource/StudioResourceIndexTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/StudioResource/StudioResourceIndexTest.php @@ -2,9 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\StudioResource; - -use App\Concerns\Actions\Http\Api\SortsModels; use App\Contracts\Http\Api\Field\SortableField; use App\Enums\Http\Api\Sort\Direction; use App\Enums\Models\Wiki\ResourceSite; @@ -27,329 +24,295 @@ use App\Models\Wiki\Studio; use App\Pivots\BasePivot; use App\Pivots\Wiki\StudioResource; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; use Illuminate\Support\Collection; -use Tests\TestCase; -class StudioResourceIndexTest extends TestCase -{ - use SortsModels; - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the Studio Resource Index Endpoint shall return a collection of Studio Resource Resources. - */ - public function testDefault(): void - { - Collection::times($this->faker->randomDigitNotNull(), function () { +uses(App\Concerns\Actions\Http\Api\SortsModels::class); + +uses(Illuminate\Foundation\Testing\WithFaker::class); + +test('default', function () { + Collection::times(fake()->randomDigitNotNull(), function () { + StudioResource::factory() + ->for(Studio::factory()) + ->for(ExternalResource::factory(), StudioResource::RELATION_RESOURCE) + ->create(); + }); + + $studioResources = StudioResource::all(); + + $response = get(route('api.studioresource.index')); + + $response->assertJson( + json_decode( + json_encode( + new StudioResourceCollection($studioResources, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('paginated', function () { + Collection::times(fake()->randomDigitNotNull(), function () { + StudioResource::factory() + ->for(Studio::factory()) + ->for(ExternalResource::factory(), StudioResource::RELATION_RESOURCE) + ->create(); + }); + + $response = get(route('api.studioresource.index')); + + $response->assertJsonStructure([ + StudioResourceCollection::$wrap, + 'links', + 'meta', + ]); +}); + +test('allowed include paths', function () { + $schema = new StudioResourceSchema(); + + $allowedIncludes = collect($schema->allowedIncludes()); + + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); + + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + StudioResource::factory() + ->for(Studio::factory()) + ->for(ExternalResource::factory(), StudioResource::RELATION_RESOURCE) + ->create(); + }); + + $response = get(route('api.studioresource.index', $parameters)); + + $studioResources = StudioResource::with($includedPaths->all())->get(); + + $response->assertJson( + json_decode( + json_encode( + new StudioResourceCollection($studioResources, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sparse fieldsets', function () { + $schema = new StudioResourceSchema(); + + $fields = collect($schema->fields()); + + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + StudioResourceResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + Collection::times(fake()->randomDigitNotNull(), function () { + StudioResource::factory() + ->for(Studio::factory()) + ->for(ExternalResource::factory(), StudioResource::RELATION_RESOURCE) + ->create(); + }); + + $response = get(route('api.studioresource.index', $parameters)); + + $studioResources = StudioResource::all(); + + $response->assertJson( + json_decode( + json_encode( + new StudioResourceCollection($studioResources, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sorts', function () { + $schema = new StudioResourceSchema(); + + /** @var Sort $sort */ + $sort = collect($schema->fields()) + ->filter(fn (Field $field) => $field instanceof SortableField) + ->map(fn (SortableField $field) => $field->getSort()) + ->random(); + + $parameters = [ + SortParser::param() => $sort->format(Arr::random(Direction::cases())), + ]; + + $query = new Query($parameters); + + Collection::times(fake()->randomDigitNotNull(), function () { + StudioResource::factory() + ->for(Studio::factory()) + ->for(ExternalResource::factory(), StudioResource::RELATION_RESOURCE) + ->create(); + }); + + $response = get(route('api.studioresource.index', $parameters)); + + $studioResources = $this->sort(StudioResource::query(), $query, $schema)->get(); + + $response->assertJson( + json_decode( + json_encode( + new StudioResourceCollection($studioResources, $query) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('created at filter', function () { + $createdFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BasePivot::ATTRIBUTE_CREATED_AT => $createdFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($createdFilter, function () { + Collection::times(fake()->randomDigitNotNull(), function () { StudioResource::factory() ->for(Studio::factory()) ->for(ExternalResource::factory(), StudioResource::RELATION_RESOURCE) ->create(); }); + }); - $studioResources = StudioResource::all(); - - $response = $this->get(route('api.studioresource.index')); - - $response->assertJson( - json_decode( - json_encode( - new StudioResourceCollection($studioResources, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Studio Resource Index Endpoint shall be paginated. - */ - public function testPaginated(): void - { - Collection::times($this->faker->randomDigitNotNull(), function () { + Carbon::withTestNow($excludedDate, function () { + Collection::times(fake()->randomDigitNotNull(), function () { StudioResource::factory() ->for(Studio::factory()) ->for(ExternalResource::factory(), StudioResource::RELATION_RESOURCE) ->create(); }); + }); - $response = $this->get(route('api.studioresource.index')); + $studioResources = StudioResource::query()->where(BasePivot::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - $response->assertJsonStructure([ - StudioResourceCollection::$wrap, - 'links', - 'meta', - ]); - } + $response = get(route('api.studioresource.index', $parameters)); - /** - * The Studio Resource Index Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new StudioResourceSchema(); + $response->assertJson( + json_decode( + json_encode( + new StudioResourceCollection($studioResources, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('updated at filter', function () { + $updatedFilter = fake()->date(); + $excludedDate = fake()->date(); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $parameters = [ + FilterParser::param() => [ + BasePivot::ATTRIBUTE_UPDATED_AT => $updatedFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { + Carbon::withTestNow($updatedFilter, function () { + Collection::times(fake()->randomDigitNotNull(), function () { StudioResource::factory() ->for(Studio::factory()) ->for(ExternalResource::factory(), StudioResource::RELATION_RESOURCE) ->create(); }); + }); - $response = $this->get(route('api.studioresource.index', $parameters)); - - $studioResources = StudioResource::with($includedPaths->all())->get(); - - $response->assertJson( - json_decode( - json_encode( - new StudioResourceCollection($studioResources, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Studio Resource Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new StudioResourceSchema(); - - $fields = collect($schema->fields()); - - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); - - $parameters = [ - FieldParser::param() => [ - StudioResourceResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { + Carbon::withTestNow($excludedDate, function () { + Collection::times(fake()->randomDigitNotNull(), function () { StudioResource::factory() ->for(Studio::factory()) ->for(ExternalResource::factory(), StudioResource::RELATION_RESOURCE) ->create(); }); + }); - $response = $this->get(route('api.studioresource.index', $parameters)); + $studioResources = StudioResource::query()->where(BasePivot::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - $studioResources = StudioResource::all(); + $response = get(route('api.studioresource.index', $parameters)); - $response->assertJson( - json_decode( - json_encode( - new StudioResourceCollection($studioResources, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response->assertJson( + json_decode( + json_encode( + new StudioResourceCollection($studioResources, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - /** - * The Studio Resource Index Endpoint shall support sorting resources. - */ - public function testSorts(): void - { - $schema = new StudioResourceSchema(); +test('resources by site', function () { + $siteFilter = Arr::random(ResourceSite::cases()); - /** @var Sort $sort */ - $sort = collect($schema->fields()) - ->filter(fn (Field $field) => $field instanceof SortableField) - ->map(fn (SortableField $field) => $field->getSort()) - ->random(); + $parameters = [ + FilterParser::param() => [ + ExternalResource::ATTRIBUTE_SITE => $siteFilter->localize(), + ], + IncludeParser::param() => StudioResource::RELATION_RESOURCE, + ]; - $parameters = [ - SortParser::param() => $sort->format(Arr::random(Direction::cases())), - ]; + Collection::times(fake()->randomDigitNotNull(), function () { + StudioResource::factory() + ->for(Studio::factory()) + ->for(ExternalResource::factory(), StudioResource::RELATION_RESOURCE) + ->create(); + }); - $query = new Query($parameters); + $response = get(route('api.studioresource.index', $parameters)); - Collection::times($this->faker->randomDigitNotNull(), function () { - StudioResource::factory() - ->for(Studio::factory()) - ->for(ExternalResource::factory(), StudioResource::RELATION_RESOURCE) - ->create(); - }); + $studioResources = StudioResource::with([ + StudioResource::RELATION_RESOURCE => function (BelongsTo $query) use ($siteFilter) { + $query->where(ExternalResource::ATTRIBUTE_SITE, $siteFilter->value); + }, + ]) + ->get(); - $response = $this->get(route('api.studioresource.index', $parameters)); - - $studioResources = $this->sort(StudioResource::query(), $query, $schema)->get(); - - $response->assertJson( - json_decode( - json_encode( - new StudioResourceCollection($studioResources, $query) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Studio Resource Index Endpoint shall support filtering by created_at. - */ - public function testCreatedAtFilter(): void - { - $createdFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BasePivot::ATTRIBUTE_CREATED_AT => $createdFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($createdFilter, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - StudioResource::factory() - ->for(Studio::factory()) - ->for(ExternalResource::factory(), StudioResource::RELATION_RESOURCE) - ->create(); - }); - }); - - Carbon::withTestNow($excludedDate, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - StudioResource::factory() - ->for(Studio::factory()) - ->for(ExternalResource::factory(), StudioResource::RELATION_RESOURCE) - ->create(); - }); - }); - - $studioResources = StudioResource::query()->where(BasePivot::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - - $response = $this->get(route('api.studioresource.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new StudioResourceCollection($studioResources, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Studio Resource Index Endpoint shall support filtering by updated_at. - */ - public function testUpdatedAtFilter(): void - { - $updatedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BasePivot::ATTRIBUTE_UPDATED_AT => $updatedFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($updatedFilter, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - StudioResource::factory() - ->for(Studio::factory()) - ->for(ExternalResource::factory(), StudioResource::RELATION_RESOURCE) - ->create(); - }); - }); - - Carbon::withTestNow($excludedDate, function () { - Collection::times($this->faker->randomDigitNotNull(), function () { - StudioResource::factory() - ->for(Studio::factory()) - ->for(ExternalResource::factory(), StudioResource::RELATION_RESOURCE) - ->create(); - }); - }); - - $studioResources = StudioResource::query()->where(BasePivot::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - - $response = $this->get(route('api.studioresource.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new StudioResourceCollection($studioResources, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Studio Resource Index Endpoint shall support constrained eager loading of resources by site. - */ - public function testResourcesBySite(): void - { - $siteFilter = Arr::random(ResourceSite::cases()); - - $parameters = [ - FilterParser::param() => [ - ExternalResource::ATTRIBUTE_SITE => $siteFilter->localize(), - ], - IncludeParser::param() => StudioResource::RELATION_RESOURCE, - ]; - - Collection::times($this->faker->randomDigitNotNull(), function () { - StudioResource::factory() - ->for(Studio::factory()) - ->for(ExternalResource::factory(), StudioResource::RELATION_RESOURCE) - ->create(); - }); - - $response = $this->get(route('api.studioresource.index', $parameters)); - - $studioResources = StudioResource::with([ - StudioResource::RELATION_RESOURCE => function (BelongsTo $query) use ($siteFilter) { - $query->where(ExternalResource::ATTRIBUTE_SITE, $siteFilter->value); - }, - ]) - ->get(); - - $response->assertJson( - json_decode( - json_encode( - new StudioResourceCollection($studioResources, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response->assertJson( + json_decode( + json_encode( + new StudioResourceCollection($studioResources, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/StudioResource/StudioResourceShowTest.php b/tests/Feature/Http/Api/Pivot/Wiki/StudioResource/StudioResourceShowTest.php index ea520747c..038b73e68 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/StudioResource/StudioResourceShowTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/StudioResource/StudioResourceShowTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\StudioResource; - use App\Enums\Models\Wiki\ResourceSite; use App\Http\Api\Field\Field; use App\Http\Api\Include\AllowedInclude; @@ -17,165 +15,142 @@ use App\Models\Wiki\ExternalResource; use App\Models\Wiki\Studio; use App\Pivots\Wiki\StudioResource; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; -use Tests\TestCase; -class StudioResourceShowTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * The Studio Resource Show Endpoint shall return an error if the studio resource does not exist. - */ - public function testNotFound(): void - { - $studio = Studio::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response = $this->get(route('api.studioresource.show', ['studio' => $studio, 'resource' => $resource])); +test('not found', function () { + $studio = Studio::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - $response->assertNotFound(); - } + $response = get(route('api.studioresource.show', ['studio' => $studio, 'resource' => $resource])); - /** - * By default, the Studio Resource Show Endpoint shall return a Studio Resource Resource. - */ - public function testDefault(): void - { - $studioResource = StudioResource::factory() - ->for(Studio::factory()) - ->for(ExternalResource::factory(), StudioResource::RELATION_RESOURCE) - ->createOne(); + $response->assertNotFound(); +}); - $response = $this->get(route('api.studioresource.show', ['studio' => $studioResource->studio, 'resource' => $studioResource->resource])); +test('default', function () { + $studioResource = StudioResource::factory() + ->for(Studio::factory()) + ->for(ExternalResource::factory(), StudioResource::RELATION_RESOURCE) + ->createOne(); - $studioResource->unsetRelations(); + $response = get(route('api.studioresource.show', ['studio' => $studioResource->studio, 'resource' => $studioResource->resource])); - $response->assertJson( - json_decode( - json_encode( - new StudioResourceResource($studioResource, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $studioResource->unsetRelations(); - /** - * The Studio Resource Show Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new StudioResourceSchema(); + $response->assertJson( + json_decode( + json_encode( + new StudioResourceResource($studioResource, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('allowed include paths', function () { + $schema = new StudioResourceSchema(); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $allowedIncludes = collect($schema->allowedIncludes()); - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - $studioResource = StudioResource::factory() - ->for(Studio::factory()) - ->for(ExternalResource::factory(), StudioResource::RELATION_RESOURCE) - ->createOne(); + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; - $response = $this->get(route('api.studioresource.show', ['studio' => $studioResource->studio, 'resource' => $studioResource->resource] + $parameters)); + $studioResource = StudioResource::factory() + ->for(Studio::factory()) + ->for(ExternalResource::factory(), StudioResource::RELATION_RESOURCE) + ->createOne(); - $studioResource->unsetRelations()->load($includedPaths->all()); + $response = get(route('api.studioresource.show', ['studio' => $studioResource->studio, 'resource' => $studioResource->resource] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new StudioResourceResource($studioResource, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $studioResource->unsetRelations()->load($includedPaths->all()); - /** - * The Studio Resource Show Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new StudioResourceSchema(); + $response->assertJson( + json_decode( + json_encode( + new StudioResourceResource($studioResource, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $fields = collect($schema->fields()); +test('sparse fieldsets', function () { + $schema = new StudioResourceSchema(); - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); + $fields = collect($schema->fields()); - $parameters = [ - FieldParser::param() => [ - StudioResourceResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); - $studioResource = StudioResource::factory() - ->for(Studio::factory()) - ->for(ExternalResource::factory(), StudioResource::RELATION_RESOURCE) - ->createOne(); + $parameters = [ + FieldParser::param() => [ + StudioResourceResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; - $response = $this->get(route('api.studioresource.show', ['studio' => $studioResource->studio, 'resource' => $studioResource->resource] + $parameters)); + $studioResource = StudioResource::factory() + ->for(Studio::factory()) + ->for(ExternalResource::factory(), StudioResource::RELATION_RESOURCE) + ->createOne(); - $studioResource->unsetRelations(); + $response = get(route('api.studioresource.show', ['studio' => $studioResource->studio, 'resource' => $studioResource->resource] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new StudioResourceResource($studioResource, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $studioResource->unsetRelations(); - /** - * The Studio Resource Show Endpoint shall support constrained eager loading of resources by site. - */ - public function testResourcesBySite(): void - { - $siteFilter = Arr::random(ResourceSite::cases()); + $response->assertJson( + json_decode( + json_encode( + new StudioResourceResource($studioResource, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - ExternalResource::ATTRIBUTE_SITE => $siteFilter->localize(), - ], - IncludeParser::param() => StudioResource::RELATION_RESOURCE, - ]; +test('resources by site', function () { + $siteFilter = Arr::random(ResourceSite::cases()); - $studioResource = StudioResource::factory() - ->for(Studio::factory()) - ->for(ExternalResource::factory(), StudioResource::RELATION_RESOURCE) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + ExternalResource::ATTRIBUTE_SITE => $siteFilter->localize(), + ], + IncludeParser::param() => StudioResource::RELATION_RESOURCE, + ]; - $response = $this->get(route('api.studioresource.show', ['studio' => $studioResource->studio, 'resource' => $studioResource->resource] + $parameters)); + $studioResource = StudioResource::factory() + ->for(Studio::factory()) + ->for(ExternalResource::factory(), StudioResource::RELATION_RESOURCE) + ->createOne(); - $studioResource->unsetRelations()->load([ - StudioResource::RELATION_RESOURCE => function (BelongsTo $query) use ($siteFilter) { - $query->where(ExternalResource::ATTRIBUTE_SITE, $siteFilter->value); - }, - ]); + $response = get(route('api.studioresource.show', ['studio' => $studioResource->studio, 'resource' => $studioResource->resource] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new StudioResourceResource($studioResource, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $studioResource->unsetRelations()->load([ + StudioResource::RELATION_RESOURCE => function (BelongsTo $query) use ($siteFilter) { + $query->where(ExternalResource::ATTRIBUTE_SITE, $siteFilter->value); + }, + ]); + + $response->assertJson( + json_decode( + json_encode( + new StudioResourceResource($studioResource, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/StudioResource/StudioResourceStoreTest.php b/tests/Feature/Http/Api/Pivot/Wiki/StudioResource/StudioResourceStoreTest.php index 740a961e0..99eee1c12 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/StudioResource/StudioResourceStoreTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/StudioResource/StudioResourceStoreTest.php @@ -2,74 +2,58 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\StudioResource; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\ExternalResource; use App\Models\Wiki\Studio; use App\Pivots\Wiki\StudioResource; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class StudioResourceStoreTest extends TestCase -{ - /** - * The Studio Resource Store Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $studio = Studio::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); +use function Pest\Laravel\post; - $parameters = StudioResource::factory()->raw(); +test('protected', function () { + $studio = Studio::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - $response = $this->post(route('api.studioresource.store', ['studio' => $studio, 'resource' => $resource] + $parameters)); + $parameters = StudioResource::factory()->raw(); - $response->assertUnauthorized(); - } + $response = post(route('api.studioresource.store', ['studio' => $studio, 'resource' => $resource] + $parameters)); - /** - * The Studio Resource Store Endpoint shall forbid users without the create studio & create resource permissions. - */ - public function testForbidden(): void - { - $studio = Studio::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); + $response->assertUnauthorized(); +}); - $parameters = StudioResource::factory()->raw(); +test('forbidden', function () { + $studio = Studio::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - $user = User::factory()->createOne(); + $parameters = StudioResource::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->post(route('api.studioresource.store', ['studio' => $studio, 'resource' => $resource] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.studioresource.store', ['studio' => $studio, 'resource' => $resource] + $parameters)); - /** - * The Studio Resource Store Endpoint shall create a studio resource. - */ - public function testCreate(): void - { - $studio = Studio::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); + $response->assertForbidden(); +}); - $parameters = StudioResource::factory()->raw(); +test('create', function () { + $studio = Studio::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - $user = User::factory() - ->withPermissions( - CrudPermission::CREATE->format(Studio::class), - CrudPermission::CREATE->format(ExternalResource::class) - ) - ->createOne(); + $parameters = StudioResource::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::CREATE->format(Studio::class), + CrudPermission::CREATE->format(ExternalResource::class) + ) + ->createOne(); - $response = $this->post(route('api.studioresource.store', ['studio' => $studio, 'resource' => $resource] + $parameters)); + Sanctum::actingAs($user); - $response->assertCreated(); - static::assertDatabaseCount(StudioResource::class, 1); - } -} + $response = post(route('api.studioresource.store', ['studio' => $studio, 'resource' => $resource] + $parameters)); + + $response->assertCreated(); + $this->assertDatabaseCount(StudioResource::class, 1); +}); diff --git a/tests/Feature/Http/Api/Pivot/Wiki/StudioResource/StudioResourceUpdateTest.php b/tests/Feature/Http/Api/Pivot/Wiki/StudioResource/StudioResourceUpdateTest.php index 297f11f0e..d8f5cb882 100644 --- a/tests/Feature/Http/Api/Pivot/Wiki/StudioResource/StudioResourceUpdateTest.php +++ b/tests/Feature/Http/Api/Pivot/Wiki/StudioResource/StudioResourceUpdateTest.php @@ -2,79 +2,63 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Pivot\Wiki\StudioResource; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\ExternalResource; use App\Models\Wiki\Studio; use App\Pivots\Wiki\StudioResource; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class StudioResourceUpdateTest extends TestCase -{ - /** - * The Studio Resource Update Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $studioResource = StudioResource::factory() - ->for(Studio::factory()) - ->for(ExternalResource::factory(), StudioResource::RELATION_RESOURCE) - ->createOne(); +use function Pest\Laravel\put; - $parameters = StudioResource::factory()->raw(); +test('protected', function () { + $studioResource = StudioResource::factory() + ->for(Studio::factory()) + ->for(ExternalResource::factory(), StudioResource::RELATION_RESOURCE) + ->createOne(); - $response = $this->put(route('api.studioresource.update', ['studio' => $studioResource->studio, 'resource' => $studioResource->resource] + $parameters)); + $parameters = StudioResource::factory()->raw(); - $response->assertUnauthorized(); - } + $response = put(route('api.studioresource.update', ['studio' => $studioResource->studio, 'resource' => $studioResource->resource] + $parameters)); - /** - * The Studio Resource Update Endpoint shall forbid users without the update studio & update resource permissions. - */ - public function testForbidden(): void - { - $studioResource = StudioResource::factory() - ->for(Studio::factory()) - ->for(ExternalResource::factory(), StudioResource::RELATION_RESOURCE) - ->createOne(); + $response->assertUnauthorized(); +}); - $parameters = StudioResource::factory()->raw(); +test('forbidden', function () { + $studioResource = StudioResource::factory() + ->for(Studio::factory()) + ->for(ExternalResource::factory(), StudioResource::RELATION_RESOURCE) + ->createOne(); - $user = User::factory()->createOne(); + $parameters = StudioResource::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->put(route('api.studioresource.update', ['studio' => $studioResource->studio, 'resource' => $studioResource->resource] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.studioresource.update', ['studio' => $studioResource->studio, 'resource' => $studioResource->resource] + $parameters)); - /** - * The Studio Resource Update Endpoint shall update a studio resource. - */ - public function testUpdate(): void - { - $studioResource = StudioResource::factory() - ->for(Studio::factory()) - ->for(ExternalResource::factory(), StudioResource::RELATION_RESOURCE) - ->createOne(); + $response->assertForbidden(); +}); - $parameters = StudioResource::factory()->raw(); +test('update', function () { + $studioResource = StudioResource::factory() + ->for(Studio::factory()) + ->for(ExternalResource::factory(), StudioResource::RELATION_RESOURCE) + ->createOne(); - $user = User::factory() - ->withPermissions( - CrudPermission::UPDATE->format(Studio::class), - CrudPermission::UPDATE->format(ExternalResource::class) - ) - ->createOne(); + $parameters = StudioResource::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory() + ->withPermissions( + CrudPermission::UPDATE->format(Studio::class), + CrudPermission::UPDATE->format(ExternalResource::class) + ) + ->createOne(); - $response = $this->put(route('api.studioresource.update', ['studio' => $studioResource->studio, 'resource' => $studioResource->resource] + $parameters)); + Sanctum::actingAs($user); - $response->assertOk(); - } -} + $response = put(route('api.studioresource.update', ['studio' => $studioResource->studio, 'resource' => $studioResource->resource] + $parameters)); + + $response->assertOk(); +}); diff --git a/tests/Feature/Http/Api/SearchTest.php b/tests/Feature/Http/Api/SearchTest.php index a431c6603..1a373cab1 100644 --- a/tests/Feature/Http/Api/SearchTest.php +++ b/tests/Feature/Http/Api/SearchTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api; - use App\Http\Api\Parser\FieldParser; use App\Http\Api\Parser\SearchParser; use App\Http\Resources\List\Collection\PlaylistCollection; @@ -15,93 +13,78 @@ use App\Http\Resources\Wiki\Collection\SeriesCollection; use App\Http\Resources\Wiki\Collection\SongCollection; use App\Http\Resources\Wiki\Collection\StudioCollection; use App\Http\Resources\Wiki\Collection\VideoCollection; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Config; -use Tests\TestCase; -class SearchTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * The Search Endpoint shall require a search term. - */ - public function testNoSearchTerm(): void - { - $response = $this->get(route('api.search.show')); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response->assertJsonValidationErrors(SearchParser::param()); +test('no search term', function () { + $response = get(route('api.search.show')); + + $response->assertJsonValidationErrors(SearchParser::param()); +}); + +test('search attributes', function () { + $driver = Config::get('scout.driver'); + if (empty($driver)) { + $this->markTestSkipped('A driver must be configured for this test'); } - /** - * The Search Endpoint shall display the Search attributes. - */ - public function testSearchAttributes(): void - { - $driver = Config::get('scout.driver'); - if (empty($driver)) { - static::markTestSkipped('A driver must be configured for this test'); - } + $q = fake()->word(); - $q = $this->faker->word(); + $parameters = [ + SearchParser::param() => $q, + ]; - $parameters = [ - SearchParser::param() => $q, - ]; + $response = get(route('api.search.show', $parameters)); - $response = $this->get(route('api.search.show', $parameters)); + $response->assertJson([ + SearchResource::$wrap => [ + AnimeCollection::$wrap => [], + ThemeCollection::$wrap => [], + ArtistCollection::$wrap => [], + PlaylistCollection::$wrap => [], + SeriesCollection::$wrap => [], + SongCollection::$wrap => [], + StudioCollection::$wrap => [], + VideoCollection::$wrap => [], + ], + ]); +}); - $response->assertJson([ - SearchResource::$wrap => [ - AnimeCollection::$wrap => [], - ThemeCollection::$wrap => [], - ArtistCollection::$wrap => [], - PlaylistCollection::$wrap => [], - SeriesCollection::$wrap => [], - SongCollection::$wrap => [], - StudioCollection::$wrap => [], - VideoCollection::$wrap => [], - ], - ]); +test('search sparse fieldsets', function () { + $driver = Config::get('scout.driver'); + if (empty($driver)) { + $this->markTestSkipped('A driver must be configured for this test'); } - /** - * The Search Endpoint shall allow each resource to be included/excluded in a sparse fieldset. - */ - public function testSearchSparseFieldsets(): void - { - $driver = Config::get('scout.driver'); - if (empty($driver)) { - static::markTestSkipped('A driver must be configured for this test'); - } + $fields = [ + AnimeCollection::$wrap, + ThemeCollection::$wrap, + ArtistCollection::$wrap, + PlaylistCollection::$wrap, + SeriesCollection::$wrap, + SongCollection::$wrap, + StudioCollection::$wrap, + VideoCollection::$wrap, + ]; - $fields = [ - AnimeCollection::$wrap, - ThemeCollection::$wrap, - ArtistCollection::$wrap, - PlaylistCollection::$wrap, - SeriesCollection::$wrap, - SongCollection::$wrap, - StudioCollection::$wrap, - VideoCollection::$wrap, - ]; + $includedFields = Arr::random($fields, fake()->numberBetween(1, count($fields))); - $includedFields = Arr::random($fields, $this->faker->numberBetween(1, count($fields))); + $q = fake()->word(); - $q = $this->faker->word(); + $parameters = [ + SearchParser::param() => $q, + FieldParser::param() => [ + SearchResource::$wrap => implode(',', $includedFields), + ], + ]; - $parameters = [ - SearchParser::param() => $q, - FieldParser::param() => [ - SearchResource::$wrap => implode(',', $includedFields), - ], - ]; + $response = get(route('api.search.show', $parameters)); - $response = $this->get(route('api.search.show', $parameters)); - - $response->assertJsonStructure([ - SearchResource::$wrap => $includedFields, - ]); - } -} + $response->assertJsonStructure([ + SearchResource::$wrap => $includedFields, + ]); +}); diff --git a/tests/Feature/Http/Api/ThrottleTest.php b/tests/Feature/Http/Api/ThrottleTest.php index 4bec09fcd..ef0ed2b5d 100644 --- a/tests/Feature/Http/Api/ThrottleTest.php +++ b/tests/Feature/Http/Api/ThrottleTest.php @@ -2,49 +2,33 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api; - use App\Enums\Auth\SpecialPermission; use App\Models\Auth\User; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ThrottleTest extends TestCase -{ - /** - * Client with forwarded ip shall be rate limited. - */ - public function testForwardedIpRateLimited(): void - { - $response = $this->withHeader('x-forwarded-ip', fake()->ipv4())->get(route('api.anime.index')); +use function Pest\Laravel\get; - $response->assertHeader('X-RateLimit-Limit'); - $response->assertHeader('X-RateLimit-Remaining'); - } +test('forwarded ip rate limited', function () { + $response = $this->withHeader('x-forwarded-ip', fake()->ipv4())->get(route('api.anime.index')); - /** - * Client with no forwarded ip shall not be rate limited. - */ - public function testClientNoForwardedIpNotRateLimited(): void - { - $response = $this->get(route('api.anime.index')); + $response->assertHeader('X-RateLimit-Limit'); + $response->assertHeader('X-RateLimit-Remaining'); +}); - $response->assertHeaderMissing('X-RateLimit-Limit'); - $response->assertHeaderMissing('X-RateLimit-Remaining'); - } +test('client no forwarded ip not rate limited', function () { + $response = get(route('api.anime.index')); - /** - * Users with the 'bypass api rate limiter' permission shall not be rate limited. - */ - public function testUserNotRateLimited(): void - { - $user = User::factory()->withPermissions(SpecialPermission::BYPASS_API_RATE_LIMITER->value)->createOne(); + $response->assertHeaderMissing('X-RateLimit-Limit'); + $response->assertHeaderMissing('X-RateLimit-Remaining'); +}); - Sanctum::actingAs($user); +test('user not rate limited', function () { + $user = User::factory()->withPermissions(SpecialPermission::BYPASS_API_RATE_LIMITER->value)->createOne(); - $response = $this->get(route('api.anime.index')); + Sanctum::actingAs($user); - $response->assertHeaderMissing('X-RateLimit-Limit'); - $response->assertHeaderMissing('X-RateLimit-Remaining'); - } -} + $response = get(route('api.anime.index')); + + $response->assertHeaderMissing('X-RateLimit-Limit'); + $response->assertHeaderMissing('X-RateLimit-Remaining'); +}); diff --git a/tests/Feature/Http/Api/Wiki/Anime/AnimeDestroyTest.php b/tests/Feature/Http/Api/Wiki/Anime/AnimeDestroyTest.php index 285be3705..6b44320a0 100644 --- a/tests/Feature/Http/Api/Wiki/Anime/AnimeDestroyTest.php +++ b/tests/Feature/Http/Api/Wiki/Anime/AnimeDestroyTest.php @@ -2,74 +2,54 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Anime; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Anime; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class AnimeDestroyTest extends TestCase -{ - /** - * The Anime Destroy Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $anime = Anime::factory()->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.anime.destroy', ['anime' => $anime])); +test('protected', function () { + $anime = Anime::factory()->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.anime.destroy', ['anime' => $anime])); - /** - * The Anime Destroy Endpoint shall forbid users without the delete anime permission. - */ - public function testForbidden(): void - { - $anime = Anime::factory()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $anime = Anime::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.anime.destroy', ['anime' => $anime])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.anime.destroy', ['anime' => $anime])); - /** - * The Anime Destroy Endpoint shall forbid users from updating an anime that is trashed. - */ - public function testTrashed(): void - { - $anime = Anime::factory()->trashed()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Anime::class))->createOne(); +test('trashed', function () { + $anime = Anime::factory()->trashed()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Anime::class))->createOne(); - $response = $this->delete(route('api.anime.destroy', ['anime' => $anime])); + Sanctum::actingAs($user); - $response->assertNotFound(); - } + $response = delete(route('api.anime.destroy', ['anime' => $anime])); - /** - * The Anime Destroy Endpoint shall delete the anime. - */ - public function testDeleted(): void - { - $anime = Anime::factory()->createOne(); + $response->assertNotFound(); +}); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Anime::class))->createOne(); +test('deleted', function () { + $anime = Anime::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Anime::class))->createOne(); - $response = $this->delete(route('api.anime.destroy', ['anime' => $anime])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertSoftDeleted($anime); - } -} + $response = delete(route('api.anime.destroy', ['anime' => $anime])); + + $response->assertOk(); + $this->assertSoftDeleted($anime); +}); diff --git a/tests/Feature/Http/Api/Wiki/Anime/AnimeForceDeleteTest.php b/tests/Feature/Http/Api/Wiki/Anime/AnimeForceDeleteTest.php index fba700d99..5a95dbf7d 100644 --- a/tests/Feature/Http/Api/Wiki/Anime/AnimeForceDeleteTest.php +++ b/tests/Feature/Http/Api/Wiki/Anime/AnimeForceDeleteTest.php @@ -2,58 +2,42 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Anime; - use App\Enums\Auth\ExtendedCrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Anime; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class AnimeForceDeleteTest extends TestCase -{ - /** - * The Anime Force Delete Endpoint shall require authorization. - */ - public function testAuthorized(): void - { - $anime = Anime::factory()->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.anime.forceDelete', ['anime' => $anime])); +test('authorized', function () { + $anime = Anime::factory()->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.anime.forceDelete', ['anime' => $anime])); - /** - * The Anime Force Delete Endpoint shall forbid users without the force delete anime permission. - */ - public function testForbidden(): void - { - $anime = Anime::factory()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $anime = Anime::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.anime.forceDelete', ['anime' => $anime])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.anime.forceDelete', ['anime' => $anime])); - /** - * The Anime Force Delete Endpoint shall force delete the anime. - */ - public function testDeleted(): void - { - $anime = Anime::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::FORCE_DELETE->format(Anime::class))->createOne(); +test('deleted', function () { + $anime = Anime::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::FORCE_DELETE->format(Anime::class))->createOne(); - $response = $this->delete(route('api.anime.forceDelete', ['anime' => $anime])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertModelMissing($anime); - } -} + $response = delete(route('api.anime.forceDelete', ['anime' => $anime])); + + $response->assertOk(); + $this->assertModelMissing($anime); +}); diff --git a/tests/Feature/Http/Api/Wiki/Anime/AnimeIndexTest.php b/tests/Feature/Http/Api/Wiki/Anime/AnimeIndexTest.php index 5323a00f3..3609afd4b 100644 --- a/tests/Feature/Http/Api/Wiki/Anime/AnimeIndexTest.php +++ b/tests/Feature/Http/Api/Wiki/Anime/AnimeIndexTest.php @@ -2,9 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Anime; - -use App\Concerns\Actions\Http\Api\SortsModels; use App\Constants\ModelConstants; use App\Contracts\Http\Api\Field\SortableField; use App\Enums\Http\Api\Filter\TrashedStatus; @@ -45,1108 +42,990 @@ use App\Models\Wiki\Video; use Illuminate\Database\Eloquent\Factories\Sequence; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\HasMany; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; -use Tests\TestCase; -class AnimeIndexTest extends TestCase -{ - use SortsModels; - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the Anime Index Endpoint shall return a collection of Anime Resources. - */ - public function testDefault(): void - { - $anime = Anime::factory()->count($this->faker->numberBetween(1, 3))->create(); +uses(App\Concerns\Actions\Http\Api\SortsModels::class); - $response = $this->get(route('api.anime.index')); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response->assertJson( - json_decode( - json_encode( - new AnimeCollection($anime, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } +test('default', function () { + $anime = Anime::factory()->count(fake()->numberBetween(1, 3))->create(); - /** - * The Anime Index Endpoint shall be paginated. - */ - public function testPaginated(): void - { - Anime::factory()->count($this->faker->randomDigitNotNull())->create(); + $response = get(route('api.anime.index')); - $response = $this->get(route('api.anime.index')); + $response->assertJson( + json_decode( + json_encode( + new AnimeCollection($anime, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $response->assertJsonStructure([ - AnimeCollection::$wrap, - 'links', - 'meta', - ]); - } +test('paginated', function () { + Anime::factory()->count(fake()->randomDigitNotNull())->create(); - /** - * The Anime Index Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new AnimeSchema(); + $response = get(route('api.anime.index')); - $allowedIncludes = collect($schema->allowedIncludes()); + $response->assertJsonStructure([ + AnimeCollection::$wrap, + 'links', + 'meta', + ]); +}); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); +test('allowed include paths', function () { + $schema = new AnimeSchema(); - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + $allowedIncludes = collect($schema->allowedIncludes()); - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); - Anime::factory()->jsonApiResource()->count($this->faker->numberBetween(1, 3))->create(); - $anime = Anime::with($includedPaths->all())->get(); + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - $response = $this->get(route('api.anime.index', $parameters)); + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; - $response->assertJson( - json_decode( - json_encode( - new AnimeCollection($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + Anime::factory()->jsonApiResource()->count(fake()->numberBetween(1, 3))->create(); + $anime = Anime::with($includedPaths->all())->get(); - /** - * The Anime Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new AnimeSchema(); + $response = get(route('api.anime.index', $parameters)); - $fields = collect($schema->fields()); + $response->assertJson( + json_decode( + json_encode( + new AnimeCollection($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); +test('sparse fieldsets', function () { + $schema = new AnimeSchema(); - $parameters = [ - FieldParser::param() => [ - AnimeResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + $fields = collect($schema->fields()); + + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + AnimeResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + $anime = Anime::factory()->count(fake()->randomDigitNotNull())->create(); + + $response = get(route('api.anime.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnimeCollection($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sorts', function () { + $schema = new AnimeSchema(); + + /** @var Sort $sort */ + $sort = collect($schema->fields()) + ->filter(fn (Field $field) => $field instanceof SortableField) + ->map(fn (SortableField $field) => $field->getSort()) + ->random(); + + $parameters = [ + SortParser::param() => $sort->format(Arr::random(Direction::cases())), + ]; + + $query = new Query($parameters); + + Anime::factory()->count(fake()->randomDigitNotNull())->create(); + + $response = get(route('api.anime.index', $parameters)); + + $anime = $this->sort(Anime::query(), $query, $schema)->get(); + + $response->assertJson( + json_decode( + json_encode( + new AnimeCollection($anime, $query) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('season filter', function () { + $seasonFilter = Arr::random(AnimeSeason::cases()); + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), + ], + ]; + + Anime::factory()->count(fake()->randomDigitNotNull())->create(); + $anime = Anime::query()->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value)->get(); + + $response = get(route('api.anime.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnimeCollection($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('media format filter', function () { + $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), + ], + ]; + + Anime::factory()->count(fake()->randomDigitNotNull())->create(); + $anime = Anime::query()->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value)->get(); + + $response = get(route('api.anime.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnimeCollection($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('year filter', function () { + $yearFilter = fake()->numberBetween(2000, 2002); + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_YEAR => $yearFilter, + ], + ]; + + Anime::factory() + ->count(fake()->randomDigitNotNull()) + ->state(new Sequence( + [Anime::ATTRIBUTE_YEAR => 2000], + [Anime::ATTRIBUTE_YEAR => 2001], + [Anime::ATTRIBUTE_YEAR => 2002], + )) + ->create(); + + $anime = Anime::query()->where(Anime::ATTRIBUTE_YEAR, $yearFilter)->get(); + + $response = get(route('api.anime.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnimeCollection($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('created at filter', function () { + $createdFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($createdFilter, function () { + Anime::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + Carbon::withTestNow($excludedDate, function () { + Anime::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + $anime = Anime::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); + + $response = get(route('api.anime.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnimeCollection($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('updated at filter', function () { + $updatedFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($updatedFilter, function () { + Anime::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + Carbon::withTestNow($excludedDate, function () { + Anime::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + $anime = Anime::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); + + $response = get(route('api.anime.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnimeCollection($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('without trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITHOUT->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Anime::factory()->count(fake()->randomDigitNotNull())->create(); + + Anime::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + + $anime = Anime::withoutTrashed()->get(); + + $response = get(route('api.anime.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnimeCollection($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('with trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Anime::factory()->count(fake()->randomDigitNotNull())->create(); + + Anime::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + + $anime = Anime::withTrashed()->get(); + + $response = get(route('api.anime.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnimeCollection($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('only trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::ONLY->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Anime::factory()->count(fake()->randomDigitNotNull())->create(); + + Anime::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + + $anime = Anime::onlyTrashed()->get(); + + $response = get(route('api.anime.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnimeCollection($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('deleted at filter', function () { + $deletedFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + ModelConstants::ATTRIBUTE_DELETED_AT => $deletedFilter, + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($deletedFilter, function () { + Anime::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + }); + + Carbon::withTestNow($excludedDate, function () { + Anime::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + }); + + $anime = Anime::withTrashed()->where(ModelConstants::ATTRIBUTE_DELETED_AT, $deletedFilter)->get(); + + $response = get(route('api.anime.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnimeCollection($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('synonyms by type', function () { + $typeFilter = Arr::random(AnimeSynonymType::cases()); + + $parameters = [ + FilterParser::param() => [ + SynonymResource::$wrap => [ + AnimeSynonym::ATTRIBUTE_TYPE => $typeFilter->localize(), ], - ]; + ], + IncludeParser::param() => Anime::RELATION_SYNONYMS, + ]; - $anime = Anime::factory()->count($this->faker->randomDigitNotNull())->create(); + Anime::factory() + ->has(AnimeSynonym::factory()->count(fake()->randomDigitNotNull())) + ->count(fake()->randomDigitNotNull()) + ->create(); - $response = $this->get(route('api.anime.index', $parameters)); + $anime = Anime::with([ + Anime::RELATION_SYNONYMS => function (HasMany $query) use ($typeFilter) { + $query->where(AnimeSynonym::ATTRIBUTE_TYPE, $typeFilter->value); + }, + ]) + ->get(); - $response->assertJson( - json_decode( - json_encode( - new AnimeCollection($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.anime.index', $parameters)); - /** - * The Anime Index Endpoint shall support sorting resources. - */ - public function testSorts(): void - { - $schema = new AnimeSchema(); + $response->assertJson( + json_decode( + json_encode( + new AnimeCollection($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - /** @var Sort $sort */ - $sort = collect($schema->fields()) - ->filter(fn (Field $field) => $field instanceof SortableField) - ->map(fn (SortableField $field) => $field->getSort()) - ->random(); +test('themes by sequence', function () { + $sequenceFilter = fake()->randomDigitNotNull(); + $excludedSequence = $sequenceFilter + 1; - $parameters = [ - SortParser::param() => $sort->format(Arr::random(Direction::cases())), - ]; + $parameters = [ + FilterParser::param() => [ + AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter, + ], + IncludeParser::param() => Anime::RELATION_THEMES, + ]; - $query = new Query($parameters); + Anime::factory() + ->has( + AnimeTheme::factory() + ->count(fake()->randomDigitNotNull()) + ->state(new Sequence( + [AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter], + [AnimeTheme::ATTRIBUTE_SEQUENCE => $excludedSequence], + )) + ) + ->count(fake()->randomDigitNotNull()) + ->create(); - Anime::factory()->count($this->faker->randomDigitNotNull())->create(); + $anime = Anime::with([ + Anime::RELATION_THEMES => function (HasMany $query) use ($sequenceFilter) { + $query->where(AnimeTheme::ATTRIBUTE_SEQUENCE, $sequenceFilter); + }, + ]) + ->get(); - $response = $this->get(route('api.anime.index', $parameters)); + $response = get(route('api.anime.index', $parameters)); - $anime = $this->sort(Anime::query(), $query, $schema)->get(); + $response->assertJson( + json_decode( + json_encode( + new AnimeCollection($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $response->assertJson( - json_decode( - json_encode( - new AnimeCollection($anime, $query) - ->response() - ->getData() - ), - true - ) - ); - } +test('themes by type', function () { + $typeFilter = Arr::random(ThemeType::cases()); - /** - * The Anime Index Endpoint shall support filtering by season. - */ - public function testSeasonFilter(): void - { - $seasonFilter = Arr::random(AnimeSeason::cases()); - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), + $parameters = [ + FilterParser::param() => [ + ThemeResource::$wrap => [ + AnimeTheme::ATTRIBUTE_TYPE => $typeFilter->localize(), ], - ]; - - Anime::factory()->count($this->faker->randomDigitNotNull())->create(); - $anime = Anime::query()->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value)->get(); - - $response = $this->get(route('api.anime.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeCollection($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Index Endpoint shall support filtering by media_format. - */ - public function testMediaFormatFilter(): void - { - $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), - ], - ]; - - Anime::factory()->count($this->faker->randomDigitNotNull())->create(); - $anime = Anime::query()->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value)->get(); - - $response = $this->get(route('api.anime.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeCollection($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Index Endpoint shall support filtering by season. - */ - public function testYearFilter(): void - { - $yearFilter = $this->faker->numberBetween(2000, 2002); - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_YEAR => $yearFilter, - ], - ]; - - Anime::factory() - ->count($this->faker->randomDigitNotNull()) - ->state(new Sequence( - [Anime::ATTRIBUTE_YEAR => 2000], - [Anime::ATTRIBUTE_YEAR => 2001], - [Anime::ATTRIBUTE_YEAR => 2002], - )) - ->create(); - - $anime = Anime::query()->where(Anime::ATTRIBUTE_YEAR, $yearFilter)->get(); - - $response = $this->get(route('api.anime.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeCollection($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Index Endpoint shall support filtering by created_at. - */ - public function testCreatedAtFilter(): void - { - $createdFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($createdFilter, function () { - Anime::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - Carbon::withTestNow($excludedDate, function () { - Anime::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - $anime = Anime::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - - $response = $this->get(route('api.anime.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeCollection($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Index Endpoint shall support filtering by updated_at. - */ - public function testUpdatedAtFilter(): void - { - $updatedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($updatedFilter, function () { - Anime::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - Carbon::withTestNow($excludedDate, function () { - Anime::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - $anime = Anime::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - - $response = $this->get(route('api.anime.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeCollection($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Index Endpoint shall support filtering by trashed. - */ - public function testWithoutTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITHOUT->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Anime::factory()->count($this->faker->randomDigitNotNull())->create(); - - Anime::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - - $anime = Anime::withoutTrashed()->get(); - - $response = $this->get(route('api.anime.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeCollection($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Index Endpoint shall support filtering by trashed. - */ - public function testWithTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Anime::factory()->count($this->faker->randomDigitNotNull())->create(); - - Anime::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - - $anime = Anime::withTrashed()->get(); - - $response = $this->get(route('api.anime.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeCollection($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Index Endpoint shall support filtering by trashed. - */ - public function testOnlyTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::ONLY->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Anime::factory()->count($this->faker->randomDigitNotNull())->create(); - - Anime::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - - $anime = Anime::onlyTrashed()->get(); - - $response = $this->get(route('api.anime.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeCollection($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Index Endpoint shall support filtering by deleted_at. - */ - public function testDeletedAtFilter(): void - { - $deletedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - ModelConstants::ATTRIBUTE_DELETED_AT => $deletedFilter, - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($deletedFilter, function () { - Anime::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - }); - - Carbon::withTestNow($excludedDate, function () { - Anime::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - }); - - $anime = Anime::withTrashed()->where(ModelConstants::ATTRIBUTE_DELETED_AT, $deletedFilter)->get(); - - $response = $this->get(route('api.anime.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeCollection($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Index Endpoint shall support constrained eager loading of synonyms by type. - */ - public function testSynonymsByType(): void - { - $typeFilter = Arr::random(AnimeSynonymType::cases()); - - $parameters = [ - FilterParser::param() => [ - SynonymResource::$wrap => [ - AnimeSynonym::ATTRIBUTE_TYPE => $typeFilter->localize(), - ], - ], - IncludeParser::param() => Anime::RELATION_SYNONYMS, - ]; - - Anime::factory() - ->has(AnimeSynonym::factory()->count($this->faker->randomDigitNotNull())) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $anime = Anime::with([ - Anime::RELATION_SYNONYMS => function (HasMany $query) use ($typeFilter) { - $query->where(AnimeSynonym::ATTRIBUTE_TYPE, $typeFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.anime.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeCollection($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Index Endpoint shall support constrained eager loading of themes by sequence. - */ - public function testThemesBySequence(): void - { - $sequenceFilter = $this->faker->randomDigitNotNull(); - $excludedSequence = $sequenceFilter + 1; - - $parameters = [ - FilterParser::param() => [ - AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter, - ], - IncludeParser::param() => Anime::RELATION_THEMES, - ]; - - Anime::factory() - ->has( - AnimeTheme::factory() - ->count($this->faker->randomDigitNotNull()) - ->state(new Sequence( - [AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter], - [AnimeTheme::ATTRIBUTE_SEQUENCE => $excludedSequence], - )) - ) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $anime = Anime::with([ - Anime::RELATION_THEMES => function (HasMany $query) use ($sequenceFilter) { - $query->where(AnimeTheme::ATTRIBUTE_SEQUENCE, $sequenceFilter); - }, - ]) - ->get(); - - $response = $this->get(route('api.anime.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeCollection($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Index Endpoint shall support constrained eager loading of themes by type. - */ - public function testThemesByType(): void - { - $typeFilter = Arr::random(ThemeType::cases()); - - $parameters = [ - FilterParser::param() => [ - ThemeResource::$wrap => [ - AnimeTheme::ATTRIBUTE_TYPE => $typeFilter->localize(), - ], - ], - IncludeParser::param() => Anime::RELATION_THEMES, - ]; - - Anime::factory() - ->has(AnimeTheme::factory()->count($this->faker->randomDigitNotNull())) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $anime = Anime::with([ - Anime::RELATION_THEMES => function (HasMany $query) use ($typeFilter) { - $query->where(AnimeTheme::ATTRIBUTE_TYPE, $typeFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.anime.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeCollection($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Index Endpoint shall support constrained eager loading of entries by nsfw. - */ - public function testEntriesByNsfw(): void - { - $nsfwFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - AnimeThemeEntry::ATTRIBUTE_NSFW => $nsfwFilter, - ], - IncludeParser::param() => Anime::RELATION_ENTRIES, - ]; - - Anime::factory() - ->has( - AnimeTheme::factory() - ->has(AnimeThemeEntry::factory()->count($this->faker->numberBetween(1, 3))) - ->count($this->faker->numberBetween(1, 3)) - ) - ->count($this->faker->numberBetween(1, 3)) - ->create(); - - $anime = Anime::with([ - Anime::RELATION_ENTRIES => function (HasMany $query) use ($nsfwFilter) { - $query->where(AnimeThemeEntry::ATTRIBUTE_NSFW, $nsfwFilter); - }, - ]) - ->get(); - - $response = $this->get(route('api.anime.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeCollection($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Index Endpoint shall support constrained eager loading of entries by spoiler. - */ - public function testEntriesBySpoiler(): void - { - $spoilerFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - AnimeThemeEntry::ATTRIBUTE_SPOILER => $spoilerFilter, - ], - IncludeParser::param() => Anime::RELATION_ENTRIES, - ]; - - Anime::factory() - ->has( - AnimeTheme::factory() - ->has(AnimeThemeEntry::factory()->count($this->faker->numberBetween(1, 3))) - ->count($this->faker->numberBetween(1, 3)) - ) - ->count($this->faker->numberBetween(1, 3)) - ->create(); - - $anime = Anime::with([ - Anime::RELATION_ENTRIES => function (HasMany $query) use ($spoilerFilter) { - $query->where(AnimeThemeEntry::ATTRIBUTE_SPOILER, $spoilerFilter); - }, - ]) - ->get(); - - $response = $this->get(route('api.anime.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeCollection($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Index Endpoint shall support constrained eager loading of entries by version. - */ - public function testEntriesByVersion(): void - { - $versionFilter = $this->faker->numberBetween(1, 3); - $excludedVersion = $versionFilter + 1; - - $parameters = [ - FilterParser::param() => [ - AnimeThemeEntry::ATTRIBUTE_VERSION => $versionFilter, - ], - IncludeParser::param() => Anime::RELATION_ENTRIES, - ]; - - Anime::factory() - ->count($this->faker->numberBetween(1, 3)) - ->has( - AnimeTheme::factory() - ->count($this->faker->numberBetween(1, 3)) - ->has( - AnimeThemeEntry::factory() - ->count($this->faker->numberBetween(1, 3)) - ->state(new Sequence( - [AnimeThemeEntry::ATTRIBUTE_VERSION => $versionFilter], - [AnimeThemeEntry::ATTRIBUTE_VERSION => $excludedVersion], - )) - ) - ) - ->create(); - - $anime = Anime::with([ - Anime::RELATION_ENTRIES => function (HasMany $query) use ($versionFilter) { - $query->where(AnimeThemeEntry::ATTRIBUTE_VERSION, $versionFilter); - }, - ]) - ->get(); - - $response = $this->get(route('api.anime.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeCollection($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Index Endpoint shall support constrained eager loading of resources by site. - */ - public function testResourcesBySite(): void - { - $siteFilter = Arr::random(ResourceSite::cases()); - - $parameters = [ - FilterParser::param() => [ - ExternalResource::ATTRIBUTE_SITE => $siteFilter->localize(), - ], - IncludeParser::param() => Anime::RELATION_RESOURCES, - ]; - - Anime::factory() - ->has(ExternalResource::factory()->count($this->faker->randomDigitNotNull()), Anime::RELATION_RESOURCES) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $anime = Anime::with([ - Anime::RELATION_RESOURCES => function (BelongsToMany $query) use ($siteFilter) { - $query->where(ExternalResource::ATTRIBUTE_SITE, $siteFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.anime.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeCollection($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Index Endpoint shall support constrained eager loading of images by facet. - */ - public function testImagesByFacet(): void - { - $facetFilter = Arr::random(ImageFacet::cases()); - - $parameters = [ - FilterParser::param() => [ - Image::ATTRIBUTE_FACET => $facetFilter->localize(), - ], - IncludeParser::param() => Anime::RELATION_IMAGES, - ]; - - Anime::factory() - ->has(Image::factory()->count($this->faker->randomDigitNotNull())) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $anime = Anime::with([ - Anime::RELATION_IMAGES => function (BelongsToMany $query) use ($facetFilter) { - $query->where(Image::ATTRIBUTE_FACET, $facetFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.anime.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeCollection($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Index Endpoint shall support constrained eager loading of videos by lyrics. - */ - public function testVideosByLyrics(): void - { - $lyricsFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_LYRICS => $lyricsFilter, - ], - IncludeParser::param() => Anime::RELATION_VIDEOS, - ]; - - Anime::factory()->jsonApiResource()->count($this->faker->numberBetween(1, 3))->create(); - - $anime = Anime::with([ - Anime::RELATION_VIDEOS => function (BelongsToMany $query) use ($lyricsFilter) { - $query->where(Video::ATTRIBUTE_LYRICS, $lyricsFilter); - }, - ]) - ->get(); - - $response = $this->get(route('api.anime.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeCollection($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Index Endpoint shall support constrained eager loading of videos by nc. - */ - public function testVideosByNc(): void - { - $ncFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_NC => $ncFilter, - ], - IncludeParser::param() => Anime::RELATION_VIDEOS, - ]; - - Anime::factory()->jsonApiResource()->count($this->faker->numberBetween(1, 3))->create(); - - $anime = Anime::with([ - Anime::RELATION_VIDEOS => function (BelongsToMany $query) use ($ncFilter) { - $query->where(Video::ATTRIBUTE_NC, $ncFilter); - }, - ]) - ->get(); - - $response = $this->get(route('api.anime.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeCollection($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Index Endpoint shall support constrained eager loading of videos by overlap. - */ - public function testVideosByOverlap(): void - { - $overlapFilter = Arr::random(VideoOverlap::cases()); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_OVERLAP => $overlapFilter->localize(), - ], - IncludeParser::param() => Anime::RELATION_VIDEOS, - ]; - - Anime::factory()->jsonApiResource()->count($this->faker->numberBetween(1, 3))->create(); - - $anime = Anime::with([ - Anime::RELATION_VIDEOS => function (BelongsToMany $query) use ($overlapFilter) { - $query->where(Video::ATTRIBUTE_OVERLAP, $overlapFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.anime.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeCollection($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Index Endpoint shall support constrained eager loading of videos by resolution. - */ - public function testVideosByResolution(): void - { - $resolutionFilter = $this->faker->randomNumber(); - $excludedResolution = $resolutionFilter + 1; - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_RESOLUTION => $resolutionFilter, - ], - IncludeParser::param() => Anime::RELATION_VIDEOS, - ]; - - Anime::factory() - ->count($this->faker->numberBetween(1, 3)) - ->has( - AnimeTheme::factory() - ->count($this->faker->numberBetween(1, 3)) - ->has( - AnimeThemeEntry::factory() - ->count($this->faker->numberBetween(1, 3)) - ->has( - Video::factory() - ->count($this->faker->numberBetween(1, 3)) - ->state(new Sequence( - [Video::ATTRIBUTE_RESOLUTION => $resolutionFilter], - [Video::ATTRIBUTE_RESOLUTION => $excludedResolution], - )) - ) - ) - ) - ->create(); - - $anime = Anime::with([ - Anime::RELATION_VIDEOS => function (BelongsToMany $query) use ($resolutionFilter) { - $query->where(Video::ATTRIBUTE_RESOLUTION, $resolutionFilter); - }, - ]) - ->get(); - - $response = $this->get(route('api.anime.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeCollection($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Index Endpoint shall support constrained eager loading of videos by source. - */ - public function testVideosBySource(): void - { - $sourceFilter = Arr::random(VideoSource::cases()); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_SOURCE => $sourceFilter->localize(), - ], - IncludeParser::param() => Anime::RELATION_VIDEOS, - ]; - - Anime::factory()->jsonApiResource()->count($this->faker->numberBetween(1, 3))->create(); - - $anime = Anime::with([ - Anime::RELATION_VIDEOS => function (BelongsToMany $query) use ($sourceFilter) { - $query->where(Video::ATTRIBUTE_SOURCE, $sourceFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.anime.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeCollection($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Index Endpoint shall support constrained eager loading of videos by subbed. - */ - public function testVideosBySubbed(): void - { - $subbedFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_SUBBED => $subbedFilter, - ], - IncludeParser::param() => Anime::RELATION_VIDEOS, - ]; - - Anime::factory()->jsonApiResource()->count($this->faker->numberBetween(1, 3))->create(); - - $anime = Anime::with([ - Anime::RELATION_VIDEOS => function (BelongsToMany $query) use ($subbedFilter) { - $query->where(Video::ATTRIBUTE_SUBBED, $subbedFilter); - }, - ]) - ->get(); - - $response = $this->get(route('api.anime.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeCollection($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Index Endpoint shall support constrained eager loading of videos by uncen. - */ - public function testVideosByUncen(): void - { - $uncenFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_UNCEN => $uncenFilter, - ], - IncludeParser::param() => Anime::RELATION_VIDEOS, - ]; - - Anime::factory()->jsonApiResource()->count($this->faker->numberBetween(1, 3))->create(); - - $anime = Anime::with([ - Anime::RELATION_VIDEOS => function (BelongsToMany $query) use ($uncenFilter) { - $query->where(Video::ATTRIBUTE_UNCEN, $uncenFilter); - }, - ]) - ->get(); - - $response = $this->get(route('api.anime.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeCollection($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + ], + IncludeParser::param() => Anime::RELATION_THEMES, + ]; + + Anime::factory() + ->has(AnimeTheme::factory()->count(fake()->randomDigitNotNull())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $anime = Anime::with([ + Anime::RELATION_THEMES => function (HasMany $query) use ($typeFilter) { + $query->where(AnimeTheme::ATTRIBUTE_TYPE, $typeFilter->value); + }, + ]) + ->get(); + + $response = get(route('api.anime.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnimeCollection($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('entries by nsfw', function () { + $nsfwFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + AnimeThemeEntry::ATTRIBUTE_NSFW => $nsfwFilter, + ], + IncludeParser::param() => Anime::RELATION_ENTRIES, + ]; + + Anime::factory() + ->has( + AnimeTheme::factory() + ->has(AnimeThemeEntry::factory()->count(fake()->numberBetween(1, 3))) + ->count(fake()->numberBetween(1, 3)) + ) + ->count(fake()->numberBetween(1, 3)) + ->create(); + + $anime = Anime::with([ + Anime::RELATION_ENTRIES => function (HasMany $query) use ($nsfwFilter) { + $query->where(AnimeThemeEntry::ATTRIBUTE_NSFW, $nsfwFilter); + }, + ]) + ->get(); + + $response = get(route('api.anime.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnimeCollection($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('entries by spoiler', function () { + $spoilerFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + AnimeThemeEntry::ATTRIBUTE_SPOILER => $spoilerFilter, + ], + IncludeParser::param() => Anime::RELATION_ENTRIES, + ]; + + Anime::factory() + ->has( + AnimeTheme::factory() + ->has(AnimeThemeEntry::factory()->count(fake()->numberBetween(1, 3))) + ->count(fake()->numberBetween(1, 3)) + ) + ->count(fake()->numberBetween(1, 3)) + ->create(); + + $anime = Anime::with([ + Anime::RELATION_ENTRIES => function (HasMany $query) use ($spoilerFilter) { + $query->where(AnimeThemeEntry::ATTRIBUTE_SPOILER, $spoilerFilter); + }, + ]) + ->get(); + + $response = get(route('api.anime.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnimeCollection($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('entries by version', function () { + $versionFilter = fake()->numberBetween(1, 3); + $excludedVersion = $versionFilter + 1; + + $parameters = [ + FilterParser::param() => [ + AnimeThemeEntry::ATTRIBUTE_VERSION => $versionFilter, + ], + IncludeParser::param() => Anime::RELATION_ENTRIES, + ]; + + Anime::factory() + ->count(fake()->numberBetween(1, 3)) + ->has( + AnimeTheme::factory() + ->count(fake()->numberBetween(1, 3)) + ->has( + AnimeThemeEntry::factory() + ->count(fake()->numberBetween(1, 3)) + ->state(new Sequence( + [AnimeThemeEntry::ATTRIBUTE_VERSION => $versionFilter], + [AnimeThemeEntry::ATTRIBUTE_VERSION => $excludedVersion], + )) + ) + ) + ->create(); + + $anime = Anime::with([ + Anime::RELATION_ENTRIES => function (HasMany $query) use ($versionFilter) { + $query->where(AnimeThemeEntry::ATTRIBUTE_VERSION, $versionFilter); + }, + ]) + ->get(); + + $response = get(route('api.anime.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnimeCollection($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('resources by site', function () { + $siteFilter = Arr::random(ResourceSite::cases()); + + $parameters = [ + FilterParser::param() => [ + ExternalResource::ATTRIBUTE_SITE => $siteFilter->localize(), + ], + IncludeParser::param() => Anime::RELATION_RESOURCES, + ]; + + Anime::factory() + ->has(ExternalResource::factory()->count(fake()->randomDigitNotNull()), Anime::RELATION_RESOURCES) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $anime = Anime::with([ + Anime::RELATION_RESOURCES => function (BelongsToMany $query) use ($siteFilter) { + $query->where(ExternalResource::ATTRIBUTE_SITE, $siteFilter->value); + }, + ]) + ->get(); + + $response = get(route('api.anime.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnimeCollection($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('images by facet', function () { + $facetFilter = Arr::random(ImageFacet::cases()); + + $parameters = [ + FilterParser::param() => [ + Image::ATTRIBUTE_FACET => $facetFilter->localize(), + ], + IncludeParser::param() => Anime::RELATION_IMAGES, + ]; + + Anime::factory() + ->has(Image::factory()->count(fake()->randomDigitNotNull())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $anime = Anime::with([ + Anime::RELATION_IMAGES => function (BelongsToMany $query) use ($facetFilter) { + $query->where(Image::ATTRIBUTE_FACET, $facetFilter->value); + }, + ]) + ->get(); + + $response = get(route('api.anime.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnimeCollection($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by lyrics', function () { + $lyricsFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_LYRICS => $lyricsFilter, + ], + IncludeParser::param() => Anime::RELATION_VIDEOS, + ]; + + Anime::factory()->jsonApiResource()->count(fake()->numberBetween(1, 3))->create(); + + $anime = Anime::with([ + Anime::RELATION_VIDEOS => function (BelongsToMany $query) use ($lyricsFilter) { + $query->where(Video::ATTRIBUTE_LYRICS, $lyricsFilter); + }, + ]) + ->get(); + + $response = get(route('api.anime.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnimeCollection($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by nc', function () { + $ncFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_NC => $ncFilter, + ], + IncludeParser::param() => Anime::RELATION_VIDEOS, + ]; + + Anime::factory()->jsonApiResource()->count(fake()->numberBetween(1, 3))->create(); + + $anime = Anime::with([ + Anime::RELATION_VIDEOS => function (BelongsToMany $query) use ($ncFilter) { + $query->where(Video::ATTRIBUTE_NC, $ncFilter); + }, + ]) + ->get(); + + $response = get(route('api.anime.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnimeCollection($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by overlap', function () { + $overlapFilter = Arr::random(VideoOverlap::cases()); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_OVERLAP => $overlapFilter->localize(), + ], + IncludeParser::param() => Anime::RELATION_VIDEOS, + ]; + + Anime::factory()->jsonApiResource()->count(fake()->numberBetween(1, 3))->create(); + + $anime = Anime::with([ + Anime::RELATION_VIDEOS => function (BelongsToMany $query) use ($overlapFilter) { + $query->where(Video::ATTRIBUTE_OVERLAP, $overlapFilter->value); + }, + ]) + ->get(); + + $response = get(route('api.anime.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnimeCollection($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by resolution', function () { + $resolutionFilter = fake()->randomNumber(); + $excludedResolution = $resolutionFilter + 1; + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_RESOLUTION => $resolutionFilter, + ], + IncludeParser::param() => Anime::RELATION_VIDEOS, + ]; + + Anime::factory() + ->count(fake()->numberBetween(1, 3)) + ->has( + AnimeTheme::factory() + ->count(fake()->numberBetween(1, 3)) + ->has( + AnimeThemeEntry::factory() + ->count(fake()->numberBetween(1, 3)) + ->has( + Video::factory() + ->count(fake()->numberBetween(1, 3)) + ->state(new Sequence( + [Video::ATTRIBUTE_RESOLUTION => $resolutionFilter], + [Video::ATTRIBUTE_RESOLUTION => $excludedResolution], + )) + ) + ) + ) + ->create(); + + $anime = Anime::with([ + Anime::RELATION_VIDEOS => function (BelongsToMany $query) use ($resolutionFilter) { + $query->where(Video::ATTRIBUTE_RESOLUTION, $resolutionFilter); + }, + ]) + ->get(); + + $response = get(route('api.anime.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnimeCollection($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by source', function () { + $sourceFilter = Arr::random(VideoSource::cases()); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_SOURCE => $sourceFilter->localize(), + ], + IncludeParser::param() => Anime::RELATION_VIDEOS, + ]; + + Anime::factory()->jsonApiResource()->count(fake()->numberBetween(1, 3))->create(); + + $anime = Anime::with([ + Anime::RELATION_VIDEOS => function (BelongsToMany $query) use ($sourceFilter) { + $query->where(Video::ATTRIBUTE_SOURCE, $sourceFilter->value); + }, + ]) + ->get(); + + $response = get(route('api.anime.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnimeCollection($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by subbed', function () { + $subbedFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_SUBBED => $subbedFilter, + ], + IncludeParser::param() => Anime::RELATION_VIDEOS, + ]; + + Anime::factory()->jsonApiResource()->count(fake()->numberBetween(1, 3))->create(); + + $anime = Anime::with([ + Anime::RELATION_VIDEOS => function (BelongsToMany $query) use ($subbedFilter) { + $query->where(Video::ATTRIBUTE_SUBBED, $subbedFilter); + }, + ]) + ->get(); + + $response = get(route('api.anime.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnimeCollection($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by uncen', function () { + $uncenFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_UNCEN => $uncenFilter, + ], + IncludeParser::param() => Anime::RELATION_VIDEOS, + ]; + + Anime::factory()->jsonApiResource()->count(fake()->numberBetween(1, 3))->create(); + + $anime = Anime::with([ + Anime::RELATION_VIDEOS => function (BelongsToMany $query) use ($uncenFilter) { + $query->where(Video::ATTRIBUTE_UNCEN, $uncenFilter); + }, + ]) + ->get(); + + $response = get(route('api.anime.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnimeCollection($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Wiki/Anime/AnimeRestoreTest.php b/tests/Feature/Http/Api/Wiki/Anime/AnimeRestoreTest.php index 8bf9913dd..27c232289 100644 --- a/tests/Feature/Http/Api/Wiki/Anime/AnimeRestoreTest.php +++ b/tests/Feature/Http/Api/Wiki/Anime/AnimeRestoreTest.php @@ -2,74 +2,54 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Anime; - use App\Enums\Auth\ExtendedCrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Anime; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class AnimeRestoreTest extends TestCase -{ - /** - * The Anime Restore Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $anime = Anime::factory()->trashed()->createOne(); +use function Pest\Laravel\patch; - $response = $this->patch(route('api.anime.restore', ['anime' => $anime])); +test('protected', function () { + $anime = Anime::factory()->trashed()->createOne(); - $response->assertUnauthorized(); - } + $response = patch(route('api.anime.restore', ['anime' => $anime])); - /** - * The Anime Restore Endpoint shall forbid users without the restore anime permission. - */ - public function testForbidden(): void - { - $anime = Anime::factory()->trashed()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $anime = Anime::factory()->trashed()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->patch(route('api.anime.restore', ['anime' => $anime])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = patch(route('api.anime.restore', ['anime' => $anime])); - /** - * The Anime Restore Endpoint shall forbid users from restoring an anime that isn't trashed. - */ - public function testTrashed(): void - { - $anime = Anime::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(Anime::class))->createOne(); +test('trashed', function () { + $anime = Anime::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(Anime::class))->createOne(); - $response = $this->patch(route('api.anime.restore', ['anime' => $anime])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = patch(route('api.anime.restore', ['anime' => $anime])); - /** - * The Anime Restore Endpoint shall restore the anime. - */ - public function testRestored(): void - { - $anime = Anime::factory()->trashed()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(Anime::class))->createOne(); +test('restored', function () { + $anime = Anime::factory()->trashed()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(Anime::class))->createOne(); - $response = $this->patch(route('api.anime.restore', ['anime' => $anime])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertNotSoftDeleted($anime); - } -} + $response = patch(route('api.anime.restore', ['anime' => $anime])); + + $response->assertOk(); + $this->assertNotSoftDeleted($anime); +}); diff --git a/tests/Feature/Http/Api/Wiki/Anime/AnimeShowTest.php b/tests/Feature/Http/Api/Wiki/Anime/AnimeShowTest.php index 3c056450f..5785b1443 100644 --- a/tests/Feature/Http/Api/Wiki/Anime/AnimeShowTest.php +++ b/tests/Feature/Http/Api/Wiki/Anime/AnimeShowTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Anime; - use App\Enums\Models\Wiki\AnimeSynonymType; use App\Enums\Models\Wiki\ImageFacet; use App\Enums\Models\Wiki\ResourceSite; @@ -30,727 +28,648 @@ use App\Models\Wiki\Video; use Illuminate\Database\Eloquent\Factories\Sequence; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\HasMany; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; -use Tests\TestCase; -class AnimeShowTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the Anime Show Endpoint shall return an Anime Resource. - */ - public function testDefault(): void - { - $anime = Anime::factory()->create(); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response = $this->get(route('api.anime.show', ['anime' => $anime])); +test('default', function () { + $anime = Anime::factory()->create(); - $response->assertJson( - json_decode( - json_encode( - new AnimeResource($anime, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.anime.show', ['anime' => $anime])); - /** - * The Anime Show Endpoint shall return an Anime Resource for soft deleted anime. - */ - public function testSoftDelete(): void - { - $anime = Anime::factory()->trashed()->createOne(); + $response->assertJson( + json_decode( + json_encode( + new AnimeResource($anime, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $anime->unsetRelations(); +test('soft delete', function () { + $anime = Anime::factory()->trashed()->createOne(); - $response = $this->get(route('api.anime.show', ['anime' => $anime])); + $anime->unsetRelations(); - $response->assertJson( - json_decode( - json_encode( - new AnimeResource($anime, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.anime.show', ['anime' => $anime])); - /** - * The Anime Show Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new AnimeSchema(); + $response->assertJson( + json_decode( + json_encode( + new AnimeResource($anime, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('allowed include paths', function () { + $schema = new AnimeSchema(); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $allowedIncludes = collect($schema->allowedIncludes()); - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - $anime = Anime::factory()->jsonApiResource()->createOne(); + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; - $response = $this->get(route('api.anime.show', ['anime' => $anime] + $parameters)); + $anime = Anime::factory()->jsonApiResource()->createOne(); - $response->assertJson( - json_decode( - json_encode( - new AnimeResource($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.anime.show', ['anime' => $anime] + $parameters)); - /** - * The Anime Show Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new AnimeSchema(); + $response->assertJson( + json_decode( + json_encode( + new AnimeResource($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $fields = collect($schema->fields()); +test('sparse fieldsets', function () { + $schema = new AnimeSchema(); - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); + $fields = collect($schema->fields()); - $parameters = [ - FieldParser::param() => [ - AnimeResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + AnimeResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + $anime = Anime::factory()->create(); + + $response = get(route('api.anime.show', ['anime' => $anime] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnimeResource($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('synonyms by type', function () { + $typeFilter = Arr::random(AnimeSynonymType::cases()); + + $parameters = [ + FilterParser::param() => [ + SynonymResource::$wrap => [ + AnimeSynonym::ATTRIBUTE_TYPE => $typeFilter->localize(), ], - ]; + ], + IncludeParser::param() => Anime::RELATION_SYNONYMS, + ]; - $anime = Anime::factory()->create(); + $anime = Anime::factory() + ->has(AnimeSynonym::factory()->count(fake()->randomDigitNotNull())) + ->createOne(); - $response = $this->get(route('api.anime.show', ['anime' => $anime] + $parameters)); + $anime->unsetRelations()->load([ + Anime::RELATION_SYNONYMS => function (HasMany $query) use ($typeFilter) { + $query->where(AnimeSynonym::ATTRIBUTE_TYPE, $typeFilter->value); + }, + ]); - $response->assertJson( - json_decode( - json_encode( - new AnimeResource($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.anime.show', ['anime' => $anime] + $parameters)); - /** - * The Anime Show Endpoint shall support constrained eager loading of synonyms by type. - */ - public function testSynonymsByType(): void - { - $typeFilter = Arr::random(AnimeSynonymType::cases()); + $response->assertJson( + json_decode( + json_encode( + new AnimeResource($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - SynonymResource::$wrap => [ - AnimeSynonym::ATTRIBUTE_TYPE => $typeFilter->localize(), - ], +test('themes by sequence', function () { + $sequenceFilter = fake()->randomDigitNotNull(); + $excludedSequence = $sequenceFilter + 1; + + $parameters = [ + FilterParser::param() => [ + AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter, + ], + IncludeParser::param() => Anime::RELATION_THEMES, + ]; + + $anime = Anime::factory() + ->has( + AnimeTheme::factory() + ->count(fake()->randomDigitNotNull()) + ->state(new Sequence( + [AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter], + [AnimeTheme::ATTRIBUTE_SEQUENCE => $excludedSequence], + )) + ) + ->createOne(); + + $anime->unsetRelations()->load([ + Anime::RELATION_THEMES => function (HasMany $query) use ($sequenceFilter) { + $query->where(AnimeTheme::ATTRIBUTE_SEQUENCE, $sequenceFilter); + }, + ]); + + $response = get(route('api.anime.show', ['anime' => $anime] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnimeResource($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('themes by type', function () { + $typeFilter = Arr::random(ThemeType::cases()); + + $parameters = [ + FilterParser::param() => [ + ThemeResource::$wrap => [ + AnimeTheme::ATTRIBUTE_TYPE => $typeFilter->localize(), ], - IncludeParser::param() => Anime::RELATION_SYNONYMS, - ]; - - $anime = Anime::factory() - ->has(AnimeSynonym::factory()->count($this->faker->randomDigitNotNull())) - ->createOne(); - - $anime->unsetRelations()->load([ - Anime::RELATION_SYNONYMS => function (HasMany $query) use ($typeFilter) { - $query->where(AnimeSynonym::ATTRIBUTE_TYPE, $typeFilter->value); - }, - ]); - - $response = $this->get(route('api.anime.show', ['anime' => $anime] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeResource($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Show Endpoint shall support constrained eager loading of themes by sequence. - */ - public function testThemesBySequence(): void - { - $sequenceFilter = $this->faker->randomDigitNotNull(); - $excludedSequence = $sequenceFilter + 1; - - $parameters = [ - FilterParser::param() => [ - AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter, - ], - IncludeParser::param() => Anime::RELATION_THEMES, - ]; - - $anime = Anime::factory() - ->has( - AnimeTheme::factory() - ->count($this->faker->randomDigitNotNull()) - ->state(new Sequence( - [AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter], - [AnimeTheme::ATTRIBUTE_SEQUENCE => $excludedSequence], - )) - ) - ->createOne(); - - $anime->unsetRelations()->load([ - Anime::RELATION_THEMES => function (HasMany $query) use ($sequenceFilter) { - $query->where(AnimeTheme::ATTRIBUTE_SEQUENCE, $sequenceFilter); - }, - ]); - - $response = $this->get(route('api.anime.show', ['anime' => $anime] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeResource($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Show Endpoint shall support constrained eager loading of themes by type. - */ - public function testThemesByType(): void - { - $typeFilter = Arr::random(ThemeType::cases()); - - $parameters = [ - FilterParser::param() => [ - ThemeResource::$wrap => [ - AnimeTheme::ATTRIBUTE_TYPE => $typeFilter->localize(), - ], - ], - IncludeParser::param() => Anime::RELATION_THEMES, - ]; - - $anime = Anime::factory() - ->has(AnimeTheme::factory()->count($this->faker->randomDigitNotNull())) - ->createOne(); - - $anime->unsetRelations()->load([ - Anime::RELATION_THEMES => function (HasMany $query) use ($typeFilter) { - $query->where(AnimeTheme::ATTRIBUTE_TYPE, $typeFilter->value); - }, - ]); - - $response = $this->get(route('api.anime.show', ['anime' => $anime] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeResource($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Show Endpoint shall support constrained eager loading of entries by nsfw. - */ - public function testEntriesByNsfw(): void - { - $nsfwFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - AnimeThemeEntry::ATTRIBUTE_NSFW => $nsfwFilter, - ], - IncludeParser::param() => Anime::RELATION_ENTRIES, - ]; - - $anime = Anime::factory() - ->has( - AnimeTheme::factory() - ->has(AnimeThemeEntry::factory()->count($this->faker->numberBetween(1, 3))) - ->count($this->faker->numberBetween(1, 3)) - ) - ->createOne(); - - $anime->unsetRelations()->load([ - Anime::RELATION_ENTRIES => function (HasMany $query) use ($nsfwFilter) { - $query->where(AnimeThemeEntry::ATTRIBUTE_NSFW, $nsfwFilter); - }, - ]); - - $response = $this->get(route('api.anime.show', ['anime' => $anime] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeResource($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Show Endpoint shall support constrained eager loading of entries by spoiler. - */ - public function testEntriesBySpoiler(): void - { - $spoilerFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - AnimeThemeEntry::ATTRIBUTE_SPOILER => $spoilerFilter, - ], - IncludeParser::param() => Anime::RELATION_ENTRIES, - ]; - - $anime = Anime::factory() - ->has( - AnimeTheme::factory() - ->has(AnimeThemeEntry::factory()->count($this->faker->numberBetween(1, 3))) - ->count($this->faker->numberBetween(1, 3)) - ) - ->createOne(); - - $anime->unsetRelations()->load([ - Anime::RELATION_ENTRIES => function (HasMany $query) use ($spoilerFilter) { - $query->where(AnimeThemeEntry::ATTRIBUTE_SPOILER, $spoilerFilter); - }, - ]); - - $response = $this->get(route('api.anime.show', ['anime' => $anime] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeResource($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Show Endpoint shall support constrained eager loading of entries by version. - */ - public function testEntriesByVersion(): void - { - $versionFilter = $this->faker->numberBetween(1, 3); - $excludedVersion = $versionFilter + 1; - - $parameters = [ - FilterParser::param() => [ - AnimeThemeEntry::ATTRIBUTE_VERSION => $versionFilter, - ], - IncludeParser::param() => Anime::RELATION_ENTRIES, - ]; - - $anime = Anime::factory() - ->has( - AnimeTheme::factory() - ->count($this->faker->numberBetween(1, 3)) - ->has( - AnimeThemeEntry::factory() - ->count($this->faker->numberBetween(1, 3)) - ->state(new Sequence( - [AnimeThemeEntry::ATTRIBUTE_VERSION => $versionFilter], - [AnimeThemeEntry::ATTRIBUTE_VERSION => $excludedVersion], - )) - ) - ) - ->createOne(); - - $anime->unsetRelations()->load([ - Anime::RELATION_ENTRIES => function (HasMany $query) use ($versionFilter) { - $query->where(AnimeThemeEntry::ATTRIBUTE_VERSION, $versionFilter); - }, - ]); - - $response = $this->get(route('api.anime.show', ['anime' => $anime] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeResource($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Show Endpoint shall support constrained eager loading of resources by site. - */ - public function testResourcesBySite(): void - { - $siteFilter = Arr::random(ResourceSite::cases()); - - $parameters = [ - FilterParser::param() => [ - ExternalResource::ATTRIBUTE_SITE => $siteFilter->localize(), - ], - IncludeParser::param() => Anime::RELATION_RESOURCES, - ]; - - $anime = Anime::factory() - ->has(ExternalResource::factory()->count($this->faker->randomDigitNotNull()), Anime::RELATION_RESOURCES) - ->createOne(); - - $anime->unsetRelations()->load([ - Anime::RELATION_RESOURCES => function (BelongsToMany $query) use ($siteFilter) { - $query->where(ExternalResource::ATTRIBUTE_SITE, $siteFilter->value); - }, - ]); - - $response = $this->get(route('api.anime.show', ['anime' => $anime] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeResource($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Show Endpoint shall support constrained eager loading of images by facet. - */ - public function testImagesByFacet(): void - { - $facetFilter = Arr::random(ImageFacet::cases()); - - $parameters = [ - FilterParser::param() => [ - Image::ATTRIBUTE_FACET => $facetFilter->localize(), - ], - IncludeParser::param() => Anime::RELATION_IMAGES, - ]; - - $anime = Anime::factory() - ->has(Image::factory()->count($this->faker->randomDigitNotNull())) - ->createOne(); - - $anime->unsetRelations()->load([ - Anime::RELATION_IMAGES => function (BelongsToMany $query) use ($facetFilter) { - $query->where(Image::ATTRIBUTE_FACET, $facetFilter->value); - }, - ]); - - $response = $this->get(route('api.anime.show', ['anime' => $anime] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeResource($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Show Endpoint shall support constrained eager loading of videos by lyrics. - */ - public function testVideosByLyrics(): void - { - $lyricsFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_LYRICS => $lyricsFilter, - ], - IncludeParser::param() => Anime::RELATION_VIDEOS, - ]; - - $anime = Anime::factory()->jsonApiResource()->createOne(); - - $anime->unsetRelations()->load([ - Anime::RELATION_VIDEOS => function (BelongsToMany $query) use ($lyricsFilter) { - $query->where(Video::ATTRIBUTE_LYRICS, $lyricsFilter); - }, - ]); - - $response = $this->get(route('api.anime.show', ['anime' => $anime] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeResource($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Show Endpoint shall support constrained eager loading of videos by nc. - */ - public function testVideosByNc(): void - { - $ncFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_NC => $ncFilter, - ], - IncludeParser::param() => Anime::RELATION_VIDEOS, - ]; - - $anime = Anime::factory()->jsonApiResource()->createOne(); - - $anime->unsetRelations()->load([ - Anime::RELATION_VIDEOS => function (BelongsToMany $query) use ($ncFilter) { - $query->where(Video::ATTRIBUTE_NC, $ncFilter); - }, - ]); - - $response = $this->get(route('api.anime.show', ['anime' => $anime] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeResource($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Show Endpoint shall support constrained eager loading of videos by overlap. - */ - public function testVideosByOverlap(): void - { - $overlapFilter = Arr::random(VideoOverlap::cases()); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_OVERLAP => $overlapFilter->localize(), - ], - IncludeParser::param() => Anime::RELATION_VIDEOS, - ]; - - $anime = Anime::factory()->jsonApiResource()->createOne(); - - $anime->unsetRelations()->load([ - Anime::RELATION_VIDEOS => function (BelongsToMany $query) use ($overlapFilter) { - $query->where(Video::ATTRIBUTE_OVERLAP, $overlapFilter->value); - }, - ]); - - $response = $this->get(route('api.anime.show', ['anime' => $anime] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeResource($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Show Endpoint shall support constrained eager loading of videos by resolution. - */ - public function testVideosByResolution(): void - { - $resolutionFilter = $this->faker->randomNumber(); - $excludedResolution = $resolutionFilter + 1; - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_RESOLUTION => $resolutionFilter, - ], - IncludeParser::param() => Anime::RELATION_VIDEOS, - ]; - - $anime = Anime::factory() - ->has( - AnimeTheme::factory() - ->count($this->faker->numberBetween(1, 3)) - ->has( - AnimeThemeEntry::factory() - ->count($this->faker->numberBetween(1, 3)) - ->has( - Video::factory() - ->count($this->faker->numberBetween(1, 3)) - ->state(new Sequence( - [Video::ATTRIBUTE_RESOLUTION => $resolutionFilter], - [Video::ATTRIBUTE_RESOLUTION => $excludedResolution], - )) - ) - ) - ) - ->create(); - - $anime->unsetRelations()->load([ - Anime::RELATION_VIDEOS => function (BelongsToMany $query) use ($resolutionFilter) { - $query->where(Video::ATTRIBUTE_RESOLUTION, $resolutionFilter); - }, - ]); - - $response = $this->get(route('api.anime.show', ['anime' => $anime] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeResource($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Show Endpoint shall support constrained eager loading of videos by source. - */ - public function testVideosBySource(): void - { - $sourceFilter = Arr::random(VideoSource::cases()); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_SOURCE => $sourceFilter->localize(), - ], - IncludeParser::param() => Anime::RELATION_VIDEOS, - ]; - - $anime = Anime::factory()->jsonApiResource()->createOne(); - - $anime->unsetRelations()->load([ - Anime::RELATION_VIDEOS => function (BelongsToMany $query) use ($sourceFilter) { - $query->where(Video::ATTRIBUTE_SOURCE, $sourceFilter->value); - }, - ]); - - $response = $this->get(route('api.anime.show', ['anime' => $anime] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeResource($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Show Endpoint shall support constrained eager loading of videos by subbed. - */ - public function testVideosBySubbed(): void - { - $subbedFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_SUBBED => $subbedFilter, - ], - IncludeParser::param() => Anime::RELATION_VIDEOS, - ]; - - $anime = Anime::factory()->jsonApiResource()->createOne(); - - $anime->unsetRelations()->load([ - Anime::RELATION_VIDEOS => function (BelongsToMany $query) use ($subbedFilter) { - $query->where(Video::ATTRIBUTE_SUBBED, $subbedFilter); - }, - ]); - - $response = $this->get(route('api.anime.show', ['anime' => $anime] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeResource($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Show Endpoint shall support constrained eager loading of videos by uncen. - */ - public function testVideosByUncen(): void - { - $uncenFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_UNCEN => $uncenFilter, - ], - IncludeParser::param() => Anime::RELATION_VIDEOS, - ]; - - $anime = Anime::factory()->jsonApiResource()->createOne(); - - $anime->unsetRelations()->load([ - Anime::RELATION_VIDEOS => function (BelongsToMany $query) use ($uncenFilter) { - $query->where(Video::ATTRIBUTE_UNCEN, $uncenFilter); - }, - ]); - - $response = $this->get(route('api.anime.show', ['anime' => $anime] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AnimeResource($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + ], + IncludeParser::param() => Anime::RELATION_THEMES, + ]; + + $anime = Anime::factory() + ->has(AnimeTheme::factory()->count(fake()->randomDigitNotNull())) + ->createOne(); + + $anime->unsetRelations()->load([ + Anime::RELATION_THEMES => function (HasMany $query) use ($typeFilter) { + $query->where(AnimeTheme::ATTRIBUTE_TYPE, $typeFilter->value); + }, + ]); + + $response = get(route('api.anime.show', ['anime' => $anime] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnimeResource($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('entries by nsfw', function () { + $nsfwFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + AnimeThemeEntry::ATTRIBUTE_NSFW => $nsfwFilter, + ], + IncludeParser::param() => Anime::RELATION_ENTRIES, + ]; + + $anime = Anime::factory() + ->has( + AnimeTheme::factory() + ->has(AnimeThemeEntry::factory()->count(fake()->numberBetween(1, 3))) + ->count(fake()->numberBetween(1, 3)) + ) + ->createOne(); + + $anime->unsetRelations()->load([ + Anime::RELATION_ENTRIES => function (HasMany $query) use ($nsfwFilter) { + $query->where(AnimeThemeEntry::ATTRIBUTE_NSFW, $nsfwFilter); + }, + ]); + + $response = get(route('api.anime.show', ['anime' => $anime] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnimeResource($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('entries by spoiler', function () { + $spoilerFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + AnimeThemeEntry::ATTRIBUTE_SPOILER => $spoilerFilter, + ], + IncludeParser::param() => Anime::RELATION_ENTRIES, + ]; + + $anime = Anime::factory() + ->has( + AnimeTheme::factory() + ->has(AnimeThemeEntry::factory()->count(fake()->numberBetween(1, 3))) + ->count(fake()->numberBetween(1, 3)) + ) + ->createOne(); + + $anime->unsetRelations()->load([ + Anime::RELATION_ENTRIES => function (HasMany $query) use ($spoilerFilter) { + $query->where(AnimeThemeEntry::ATTRIBUTE_SPOILER, $spoilerFilter); + }, + ]); + + $response = get(route('api.anime.show', ['anime' => $anime] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnimeResource($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('entries by version', function () { + $versionFilter = fake()->numberBetween(1, 3); + $excludedVersion = $versionFilter + 1; + + $parameters = [ + FilterParser::param() => [ + AnimeThemeEntry::ATTRIBUTE_VERSION => $versionFilter, + ], + IncludeParser::param() => Anime::RELATION_ENTRIES, + ]; + + $anime = Anime::factory() + ->has( + AnimeTheme::factory() + ->count(fake()->numberBetween(1, 3)) + ->has( + AnimeThemeEntry::factory() + ->count(fake()->numberBetween(1, 3)) + ->state(new Sequence( + [AnimeThemeEntry::ATTRIBUTE_VERSION => $versionFilter], + [AnimeThemeEntry::ATTRIBUTE_VERSION => $excludedVersion], + )) + ) + ) + ->createOne(); + + $anime->unsetRelations()->load([ + Anime::RELATION_ENTRIES => function (HasMany $query) use ($versionFilter) { + $query->where(AnimeThemeEntry::ATTRIBUTE_VERSION, $versionFilter); + }, + ]); + + $response = get(route('api.anime.show', ['anime' => $anime] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnimeResource($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('resources by site', function () { + $siteFilter = Arr::random(ResourceSite::cases()); + + $parameters = [ + FilterParser::param() => [ + ExternalResource::ATTRIBUTE_SITE => $siteFilter->localize(), + ], + IncludeParser::param() => Anime::RELATION_RESOURCES, + ]; + + $anime = Anime::factory() + ->has(ExternalResource::factory()->count(fake()->randomDigitNotNull()), Anime::RELATION_RESOURCES) + ->createOne(); + + $anime->unsetRelations()->load([ + Anime::RELATION_RESOURCES => function (BelongsToMany $query) use ($siteFilter) { + $query->where(ExternalResource::ATTRIBUTE_SITE, $siteFilter->value); + }, + ]); + + $response = get(route('api.anime.show', ['anime' => $anime] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnimeResource($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('images by facet', function () { + $facetFilter = Arr::random(ImageFacet::cases()); + + $parameters = [ + FilterParser::param() => [ + Image::ATTRIBUTE_FACET => $facetFilter->localize(), + ], + IncludeParser::param() => Anime::RELATION_IMAGES, + ]; + + $anime = Anime::factory() + ->has(Image::factory()->count(fake()->randomDigitNotNull())) + ->createOne(); + + $anime->unsetRelations()->load([ + Anime::RELATION_IMAGES => function (BelongsToMany $query) use ($facetFilter) { + $query->where(Image::ATTRIBUTE_FACET, $facetFilter->value); + }, + ]); + + $response = get(route('api.anime.show', ['anime' => $anime] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnimeResource($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by lyrics', function () { + $lyricsFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_LYRICS => $lyricsFilter, + ], + IncludeParser::param() => Anime::RELATION_VIDEOS, + ]; + + $anime = Anime::factory()->jsonApiResource()->createOne(); + + $anime->unsetRelations()->load([ + Anime::RELATION_VIDEOS => function (BelongsToMany $query) use ($lyricsFilter) { + $query->where(Video::ATTRIBUTE_LYRICS, $lyricsFilter); + }, + ]); + + $response = get(route('api.anime.show', ['anime' => $anime] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnimeResource($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by nc', function () { + $ncFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_NC => $ncFilter, + ], + IncludeParser::param() => Anime::RELATION_VIDEOS, + ]; + + $anime = Anime::factory()->jsonApiResource()->createOne(); + + $anime->unsetRelations()->load([ + Anime::RELATION_VIDEOS => function (BelongsToMany $query) use ($ncFilter) { + $query->where(Video::ATTRIBUTE_NC, $ncFilter); + }, + ]); + + $response = get(route('api.anime.show', ['anime' => $anime] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnimeResource($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by overlap', function () { + $overlapFilter = Arr::random(VideoOverlap::cases()); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_OVERLAP => $overlapFilter->localize(), + ], + IncludeParser::param() => Anime::RELATION_VIDEOS, + ]; + + $anime = Anime::factory()->jsonApiResource()->createOne(); + + $anime->unsetRelations()->load([ + Anime::RELATION_VIDEOS => function (BelongsToMany $query) use ($overlapFilter) { + $query->where(Video::ATTRIBUTE_OVERLAP, $overlapFilter->value); + }, + ]); + + $response = get(route('api.anime.show', ['anime' => $anime] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnimeResource($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by resolution', function () { + $resolutionFilter = fake()->randomNumber(); + $excludedResolution = $resolutionFilter + 1; + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_RESOLUTION => $resolutionFilter, + ], + IncludeParser::param() => Anime::RELATION_VIDEOS, + ]; + + $anime = Anime::factory() + ->has( + AnimeTheme::factory() + ->count(fake()->numberBetween(1, 3)) + ->has( + AnimeThemeEntry::factory() + ->count(fake()->numberBetween(1, 3)) + ->has( + Video::factory() + ->count(fake()->numberBetween(1, 3)) + ->state(new Sequence( + [Video::ATTRIBUTE_RESOLUTION => $resolutionFilter], + [Video::ATTRIBUTE_RESOLUTION => $excludedResolution], + )) + ) + ) + ) + ->create(); + + $anime->unsetRelations()->load([ + Anime::RELATION_VIDEOS => function (BelongsToMany $query) use ($resolutionFilter) { + $query->where(Video::ATTRIBUTE_RESOLUTION, $resolutionFilter); + }, + ]); + + $response = get(route('api.anime.show', ['anime' => $anime] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnimeResource($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by source', function () { + $sourceFilter = Arr::random(VideoSource::cases()); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_SOURCE => $sourceFilter->localize(), + ], + IncludeParser::param() => Anime::RELATION_VIDEOS, + ]; + + $anime = Anime::factory()->jsonApiResource()->createOne(); + + $anime->unsetRelations()->load([ + Anime::RELATION_VIDEOS => function (BelongsToMany $query) use ($sourceFilter) { + $query->where(Video::ATTRIBUTE_SOURCE, $sourceFilter->value); + }, + ]); + + $response = get(route('api.anime.show', ['anime' => $anime] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnimeResource($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by subbed', function () { + $subbedFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_SUBBED => $subbedFilter, + ], + IncludeParser::param() => Anime::RELATION_VIDEOS, + ]; + + $anime = Anime::factory()->jsonApiResource()->createOne(); + + $anime->unsetRelations()->load([ + Anime::RELATION_VIDEOS => function (BelongsToMany $query) use ($subbedFilter) { + $query->where(Video::ATTRIBUTE_SUBBED, $subbedFilter); + }, + ]); + + $response = get(route('api.anime.show', ['anime' => $anime] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnimeResource($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by uncen', function () { + $uncenFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_UNCEN => $uncenFilter, + ], + IncludeParser::param() => Anime::RELATION_VIDEOS, + ]; + + $anime = Anime::factory()->jsonApiResource()->createOne(); + + $anime->unsetRelations()->load([ + Anime::RELATION_VIDEOS => function (BelongsToMany $query) use ($uncenFilter) { + $query->where(Video::ATTRIBUTE_UNCEN, $uncenFilter); + }, + ]); + + $response = get(route('api.anime.show', ['anime' => $anime] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AnimeResource($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Wiki/Anime/AnimeStoreTest.php b/tests/Feature/Http/Api/Wiki/Anime/AnimeStoreTest.php index 2b6dc65c9..334909774 100644 --- a/tests/Feature/Http/Api/Wiki/Anime/AnimeStoreTest.php +++ b/tests/Feature/Http/Api/Wiki/Anime/AnimeStoreTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Anime; - use App\Enums\Auth\CrudPermission; use App\Enums\Models\Wiki\AnimeMediaFormat; use App\Enums\Models\Wiki\AnimeSeason; @@ -11,78 +9,60 @@ use App\Models\Auth\User; use App\Models\Wiki\Anime; use Illuminate\Support\Arr; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class AnimeStoreTest extends TestCase -{ - /** - * The Anime Store Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $anime = Anime::factory()->makeOne(); +use function Pest\Laravel\post; - $response = $this->post(route('api.anime.store', $anime->toArray())); +test('protected', function () { + $anime = Anime::factory()->makeOne(); - $response->assertUnauthorized(); - } + $response = post(route('api.anime.store', $anime->toArray())); - /** - * The Anime Store Endpoint shall forbid users without the create anime permission. - */ - public function testForbidden(): void - { - $anime = Anime::factory()->makeOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $anime = Anime::factory()->makeOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->post(route('api.anime.store', $anime->toArray())); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.anime.store', $anime->toArray())); - /** - * The Anime Store Endpoint shall require name, season, media_format, slug & year fields. - */ - public function testRequiredFields(): void - { - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Anime::class))->createOne(); + $response->assertForbidden(); +}); - Sanctum::actingAs($user); +test('required fields', function () { + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Anime::class))->createOne(); - $response = $this->post(route('api.anime.store')); + Sanctum::actingAs($user); - $response->assertJsonValidationErrors([ - Anime::ATTRIBUTE_NAME, - Anime::ATTRIBUTE_SEASON, - Anime::ATTRIBUTE_MEDIA_FORMAT, - Anime::ATTRIBUTE_SLUG, - Anime::ATTRIBUTE_YEAR, - ]); - } + $response = post(route('api.anime.store')); - /** - * The Anime Store Endpoint shall create an anime. - */ - public function testCreate(): void - { - $season = Arr::random(AnimeSeason::cases()); - $mediaFormat = Arr::random(AnimeMediaFormat::cases()); + $response->assertJsonValidationErrors([ + Anime::ATTRIBUTE_NAME, + Anime::ATTRIBUTE_SEASON, + Anime::ATTRIBUTE_MEDIA_FORMAT, + Anime::ATTRIBUTE_SLUG, + Anime::ATTRIBUTE_YEAR, + ]); +}); - $parameters = array_merge( - Anime::factory()->raw(), - [Anime::ATTRIBUTE_SEASON => $season->localize(), Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormat->localize()], - ); +test('create', function () { + $season = Arr::random(AnimeSeason::cases()); + $mediaFormat = Arr::random(AnimeMediaFormat::cases()); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Anime::class))->createOne(); + $parameters = array_merge( + Anime::factory()->raw(), + [Anime::ATTRIBUTE_SEASON => $season->localize(), Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormat->localize()], + ); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Anime::class))->createOne(); - $response = $this->post(route('api.anime.store', $parameters)); + Sanctum::actingAs($user); - $response->assertCreated(); - static::assertDatabaseCount(Anime::class, 1); - } -} + $response = post(route('api.anime.store', $parameters)); + + $response->assertCreated(); + $this->assertDatabaseCount(Anime::class, 1); +}); diff --git a/tests/Feature/Http/Api/Wiki/Anime/AnimeUpdateTest.php b/tests/Feature/Http/Api/Wiki/Anime/AnimeUpdateTest.php index b9bc7f41e..76f1ef3b2 100644 --- a/tests/Feature/Http/Api/Wiki/Anime/AnimeUpdateTest.php +++ b/tests/Feature/Http/Api/Wiki/Anime/AnimeUpdateTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Anime; - use App\Enums\Auth\CrudPermission; use App\Enums\Models\Wiki\AnimeMediaFormat; use App\Enums\Models\Wiki\AnimeSeason; @@ -11,99 +9,81 @@ use App\Models\Auth\User; use App\Models\Wiki\Anime; use Illuminate\Support\Arr; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class AnimeUpdateTest extends TestCase -{ - /** - * The Anime Update Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $anime = Anime::factory()->createOne(); +use function Pest\Laravel\put; - $season = Arr::random(AnimeSeason::cases()); - $mediaFormat = Arr::random(AnimeMediaFormat::cases()); +test('protected', function () { + $anime = Anime::factory()->createOne(); - $parameters = array_merge( - Anime::factory()->raw(), - [Anime::ATTRIBUTE_SEASON => $season->localize(), Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormat->localize()], - ); + $season = Arr::random(AnimeSeason::cases()); + $mediaFormat = Arr::random(AnimeMediaFormat::cases()); - $response = $this->put(route('api.anime.update', ['anime' => $anime] + $parameters)); + $parameters = array_merge( + Anime::factory()->raw(), + [Anime::ATTRIBUTE_SEASON => $season->localize(), Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormat->localize()], + ); - $response->assertUnauthorized(); - } + $response = put(route('api.anime.update', ['anime' => $anime] + $parameters)); - /** - * The Anime Update Endpoint shall forbid users without the update anime permission. - */ - public function testForbidden(): void - { - $anime = Anime::factory()->createOne(); + $response->assertUnauthorized(); +}); - $season = Arr::random(AnimeSeason::cases()); - $mediaFormat = Arr::random(AnimeMediaFormat::cases()); +test('forbidden', function () { + $anime = Anime::factory()->createOne(); - $parameters = array_merge( - Anime::factory()->raw(), - [Anime::ATTRIBUTE_SEASON => $season->localize(), Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormat->localize()], - ); + $season = Arr::random(AnimeSeason::cases()); + $mediaFormat = Arr::random(AnimeMediaFormat::cases()); - $user = User::factory()->createOne(); + $parameters = array_merge( + Anime::factory()->raw(), + [Anime::ATTRIBUTE_SEASON => $season->localize(), Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormat->localize()], + ); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->put(route('api.anime.update', ['anime' => $anime] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.anime.update', ['anime' => $anime] + $parameters)); - /** - * The Anime Update Endpoint shall forbid users from updating an anime that is trashed. - */ - public function testTrashed(): void - { - $anime = Anime::factory()->trashed()->createOne(); + $response->assertForbidden(); +}); - $season = Arr::random(AnimeSeason::cases()); - $mediaFormat = Arr::random(AnimeMediaFormat::cases()); +test('trashed', function () { + $anime = Anime::factory()->trashed()->createOne(); - $parameters = array_merge( - Anime::factory()->raw(), - [Anime::ATTRIBUTE_SEASON => $season->localize(), Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormat->localize()], - ); + $season = Arr::random(AnimeSeason::cases()); + $mediaFormat = Arr::random(AnimeMediaFormat::cases()); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Anime::class))->createOne(); + $parameters = array_merge( + Anime::factory()->raw(), + [Anime::ATTRIBUTE_SEASON => $season->localize(), Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormat->localize()], + ); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Anime::class))->createOne(); - $response = $this->put(route('api.anime.update', ['anime' => $anime] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.anime.update', ['anime' => $anime] + $parameters)); - /** - * The Anime Update Endpoint shall update an anime. - */ - public function testUpdate(): void - { - $anime = Anime::factory()->createOne(); + $response->assertForbidden(); +}); - $season = Arr::random(AnimeSeason::cases()); - $mediaFormat = Arr::random(AnimeMediaFormat::cases()); +test('update', function () { + $anime = Anime::factory()->createOne(); - $parameters = array_merge( - Anime::factory()->raw(), - [Anime::ATTRIBUTE_SEASON => $season->localize(), Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormat->localize()], - ); + $season = Arr::random(AnimeSeason::cases()); + $mediaFormat = Arr::random(AnimeMediaFormat::cases()); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Anime::class))->createOne(); + $parameters = array_merge( + Anime::factory()->raw(), + [Anime::ATTRIBUTE_SEASON => $season->localize(), Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormat->localize()], + ); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Anime::class))->createOne(); - $response = $this->put(route('api.anime.update', ['anime' => $anime] + $parameters)); + Sanctum::actingAs($user); - $response->assertOk(); - } -} + $response = put(route('api.anime.update', ['anime' => $anime] + $parameters)); + + $response->assertOk(); +}); diff --git a/tests/Feature/Http/Api/Wiki/Anime/Synonym/SynonymDestroyTest.php b/tests/Feature/Http/Api/Wiki/Anime/Synonym/SynonymDestroyTest.php index 8578581e6..d123b7f1f 100644 --- a/tests/Feature/Http/Api/Wiki/Anime/Synonym/SynonymDestroyTest.php +++ b/tests/Feature/Http/Api/Wiki/Anime/Synonym/SynonymDestroyTest.php @@ -2,78 +2,58 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Anime\Synonym; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Anime; use App\Models\Wiki\Anime\AnimeSynonym; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class SynonymDestroyTest extends TestCase -{ - /** - * The Synonym Destroy Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $synonym = AnimeSynonym::factory()->for(Anime::factory())->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.animesynonym.destroy', ['animesynonym' => $synonym])); +test('protected', function () { + $synonym = AnimeSynonym::factory()->for(Anime::factory())->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.animesynonym.destroy', ['animesynonym' => $synonym])); - /** - * The Synonym Destroy Endpoint shall forbid users without the delete anime synonym permission. - */ - public function testForbidden(): void - { - $synonym = AnimeSynonym::factory()->for(Anime::factory())->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $synonym = AnimeSynonym::factory()->for(Anime::factory())->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.animesynonym.destroy', ['animesynonym' => $synonym])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.animesynonym.destroy', ['animesynonym' => $synonym])); - /** - * The Synonym Destroy Endpoint shall forbid users from updating an anime synonym that is trashed. - */ - public function testTrashed(): void - { - $synonym = AnimeSynonym::factory() - ->trashed() - ->for(Anime::factory()) - ->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(AnimeSynonym::class))->createOne(); +test('trashed', function () { + $synonym = AnimeSynonym::factory() + ->trashed() + ->for(Anime::factory()) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(AnimeSynonym::class))->createOne(); - $response = $this->delete(route('api.animesynonym.destroy', ['animesynonym' => $synonym])); + Sanctum::actingAs($user); - $response->assertNotFound(); - } + $response = delete(route('api.animesynonym.destroy', ['animesynonym' => $synonym])); - /** - * The Synonym Destroy Endpoint shall delete the synonym. - */ - public function testDeleted(): void - { - $synonym = AnimeSynonym::factory()->for(Anime::factory())->createOne(); + $response->assertNotFound(); +}); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(AnimeSynonym::class))->createOne(); +test('deleted', function () { + $synonym = AnimeSynonym::factory()->for(Anime::factory())->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(AnimeSynonym::class))->createOne(); - $response = $this->delete(route('api.animesynonym.destroy', ['animesynonym' => $synonym])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertSoftDeleted($synonym); - } -} + $response = delete(route('api.animesynonym.destroy', ['animesynonym' => $synonym])); + + $response->assertOk(); + $this->assertSoftDeleted($synonym); +}); diff --git a/tests/Feature/Http/Api/Wiki/Anime/Synonym/SynonymForceDeleteTest.php b/tests/Feature/Http/Api/Wiki/Anime/Synonym/SynonymForceDeleteTest.php index 0036c8cdf..8ba37eba2 100644 --- a/tests/Feature/Http/Api/Wiki/Anime/Synonym/SynonymForceDeleteTest.php +++ b/tests/Feature/Http/Api/Wiki/Anime/Synonym/SynonymForceDeleteTest.php @@ -2,59 +2,43 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Anime\Synonym; - use App\Enums\Auth\ExtendedCrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Anime; use App\Models\Wiki\Anime\AnimeSynonym; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class SynonymForceDeleteTest extends TestCase -{ - /** - * The Synonym Force Delete Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $synonym = AnimeSynonym::factory()->for(Anime::factory())->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.animesynonym.forceDelete', ['animesynonym' => $synonym])); +test('protected', function () { + $synonym = AnimeSynonym::factory()->for(Anime::factory())->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.animesynonym.forceDelete', ['animesynonym' => $synonym])); - /** - * The Synonym Force Delete Endpoint shall forbid users without the force delete anime synonym permission. - */ - public function testForbidden(): void - { - $synonym = AnimeSynonym::factory()->for(Anime::factory())->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $synonym = AnimeSynonym::factory()->for(Anime::factory())->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.animesynonym.forceDelete', ['animesynonym' => $synonym])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.animesynonym.forceDelete', ['animesynonym' => $synonym])); - /** - * The Synonym Force Delete Endpoint shall force delete the synonym. - */ - public function testDeleted(): void - { - $synonym = AnimeSynonym::factory()->for(Anime::factory())->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::FORCE_DELETE->format(AnimeSynonym::class))->createOne(); +test('deleted', function () { + $synonym = AnimeSynonym::factory()->for(Anime::factory())->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::FORCE_DELETE->format(AnimeSynonym::class))->createOne(); - $response = $this->delete(route('api.animesynonym.forceDelete', ['animesynonym' => $synonym])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertModelMissing($synonym); - } -} + $response = delete(route('api.animesynonym.forceDelete', ['animesynonym' => $synonym])); + + $response->assertOk(); + $this->assertModelMissing($synonym); +}); diff --git a/tests/Feature/Http/Api/Wiki/Anime/Synonym/SynonymIndexTest.php b/tests/Feature/Http/Api/Wiki/Anime/Synonym/SynonymIndexTest.php index b4ac47f3a..4cf32553e 100644 --- a/tests/Feature/Http/Api/Wiki/Anime/Synonym/SynonymIndexTest.php +++ b/tests/Feature/Http/Api/Wiki/Anime/Synonym/SynonymIndexTest.php @@ -2,9 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Anime\Synonym; - -use App\Concerns\Actions\Http\Api\SortsModels; use App\Constants\ModelConstants; use App\Contracts\Http\Api\Field\SortableField; use App\Enums\Http\Api\Filter\TrashedStatus; @@ -30,565 +27,507 @@ use App\Models\BaseModel; use App\Models\Wiki\Anime; use App\Models\Wiki\Anime\AnimeSynonym; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; -use Tests\TestCase; -class SynonymIndexTest extends TestCase -{ - use SortsModels; - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the Synonym Index Endpoint shall return a collection of Synonym Resources. - */ - public function testDefault(): void - { +uses(App\Concerns\Actions\Http\Api\SortsModels::class); + +uses(Illuminate\Foundation\Testing\WithFaker::class); + +test('default', function () { + AnimeSynonym::factory() + ->for(Anime::factory()) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $synonyms = AnimeSynonym::all(); + + $response = get(route('api.animesynonym.index')); + + $response->assertJson( + json_decode( + json_encode( + new SynonymCollection($synonyms, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('paginated', function () { + AnimeSynonym::factory() + ->for(Anime::factory()) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $response = get(route('api.animesynonym.index')); + + $response->assertJsonStructure([ + SynonymCollection::$wrap, + 'links', + 'meta', + ]); +}); + +test('allowed include paths', function () { + $schema = new SynonymSchema(); + + $allowedIncludes = collect($schema->allowedIncludes()); + + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); + + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; + + AnimeSynonym::factory() + ->for(Anime::factory()) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $synonyms = AnimeSynonym::with($includedPaths->all())->get(); + + $response = get(route('api.animesynonym.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new SynonymCollection($synonyms, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sparse fieldsets', function () { + $schema = new SynonymSchema(); + + $fields = collect($schema->fields()); + + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + SynonymResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + AnimeSynonym::factory() + ->for(Anime::factory()) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $synonyms = AnimeSynonym::all(); + + $response = get(route('api.animesynonym.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new SynonymCollection($synonyms, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sorts', function () { + $schema = new SynonymSchema(); + + /** @var Sort $sort */ + $sort = collect($schema->fields()) + ->filter(fn (Field $field) => $field instanceof SortableField) + ->map(fn (SortableField $field) => $field->getSort()) + ->random(); + + $parameters = [ + SortParser::param() => $sort->format(Arr::random(Direction::cases())), + ]; + + $query = new Query($parameters); + + AnimeSynonym::factory() + ->for(Anime::factory()) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $response = get(route('api.animesynonym.index', $parameters)); + + $synonyms = $this->sort(AnimeSynonym::query(), $query, $schema)->get(); + + $response->assertJson( + json_decode( + json_encode( + new SynonymCollection($synonyms, $query) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('created at filter', function () { + $createdFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($createdFilter, function () { AnimeSynonym::factory() ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) + ->count(fake()->randomDigitNotNull()) ->create(); + }); - $synonyms = AnimeSynonym::all(); - - $response = $this->get(route('api.animesynonym.index')); - - $response->assertJson( - json_decode( - json_encode( - new SynonymCollection($synonyms, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Synonym Index Endpoint shall be paginated. - */ - public function testPaginated(): void - { + Carbon::withTestNow($excludedDate, function () { AnimeSynonym::factory() ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) + ->count(fake()->randomDigitNotNull()) ->create(); + }); - $response = $this->get(route('api.animesynonym.index')); + $synonym = AnimeSynonym::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - $response->assertJsonStructure([ - SynonymCollection::$wrap, - 'links', - 'meta', - ]); - } + $response = get(route('api.animesynonym.index', $parameters)); - /** - * The Synonym Index Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new SynonymSchema(); + $response->assertJson( + json_decode( + json_encode( + new SynonymCollection($synonym, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('updated at filter', function () { + $updatedFilter = fake()->date(); + $excludedDate = fake()->date(); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); - - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + Carbon::withTestNow($updatedFilter, function () { AnimeSynonym::factory() ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) + ->count(fake()->randomDigitNotNull()) ->create(); + }); - $synonyms = AnimeSynonym::with($includedPaths->all())->get(); - - $response = $this->get(route('api.animesynonym.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new SynonymCollection($synonyms, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Synonym Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new SynonymSchema(); - - $fields = collect($schema->fields()); - - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); - - $parameters = [ - FieldParser::param() => [ - SynonymResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; - + Carbon::withTestNow($excludedDate, function () { AnimeSynonym::factory() ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) + ->count(fake()->randomDigitNotNull()) ->create(); + }); - $synonyms = AnimeSynonym::all(); + $synonym = AnimeSynonym::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - $response = $this->get(route('api.animesynonym.index', $parameters)); + $response = get(route('api.animesynonym.index', $parameters)); - $response->assertJson( - json_decode( - json_encode( - new SynonymCollection($synonyms, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response->assertJson( + json_decode( + json_encode( + new SynonymCollection($synonym, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - /** - * The Synonym Index Endpoint shall support sorting resources. - */ - public function testSorts(): void - { - $schema = new SynonymSchema(); +test('without trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITHOUT->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; - /** @var Sort $sort */ - $sort = collect($schema->fields()) - ->filter(fn (Field $field) => $field instanceof SortableField) - ->map(fn (SortableField $field) => $field->getSort()) - ->random(); + AnimeSynonym::factory() + ->for(Anime::factory()) + ->count(fake()->randomDigitNotNull()) + ->create(); - $parameters = [ - SortParser::param() => $sort->format(Arr::random(Direction::cases())), - ]; + AnimeSynonym::factory() + ->trashed() + ->for(Anime::factory()) + ->count(fake()->randomDigitNotNull()) + ->create(); - $query = new Query($parameters); + $synonym = AnimeSynonym::withoutTrashed()->get(); + $response = get(route('api.animesynonym.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new SynonymCollection($synonym, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('with trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + AnimeSynonym::factory() + ->for(Anime::factory()) + ->count(fake()->randomDigitNotNull()) + ->create(); + + AnimeSynonym::factory() + ->trashed() + ->for(Anime::factory()) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $synonym = AnimeSynonym::withTrashed()->get(); + + $response = get(route('api.animesynonym.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new SynonymCollection($synonym, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('only trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::ONLY->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + AnimeSynonym::factory() + ->for(Anime::factory()) + ->count(fake()->randomDigitNotNull()) + ->create(); + + AnimeSynonym::factory() + ->trashed() + ->for(Anime::factory()) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $synonym = AnimeSynonym::onlyTrashed()->get(); + + $response = get(route('api.animesynonym.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new SynonymCollection($synonym, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('deleted at filter', function () { + $deletedFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + ModelConstants::ATTRIBUTE_DELETED_AT => $deletedFilter, + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($deletedFilter, function () { AnimeSynonym::factory() ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) + ->count(fake()->randomDigitNotNull()) ->create(); + }); - $response = $this->get(route('api.animesynonym.index', $parameters)); - - $synonyms = $this->sort(AnimeSynonym::query(), $query, $schema)->get(); - - $response->assertJson( - json_decode( - json_encode( - new SynonymCollection($synonyms, $query) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Synonym Index Endpoint shall support filtering by created_at. - */ - public function testCreatedAtFilter(): void - { - $createdFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($createdFilter, function () { - AnimeSynonym::factory() - ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) - ->create(); - }); - - Carbon::withTestNow($excludedDate, function () { - AnimeSynonym::factory() - ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) - ->create(); - }); - - $synonym = AnimeSynonym::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - - $response = $this->get(route('api.animesynonym.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new SynonymCollection($synonym, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Synonym Index Endpoint shall support filtering by updated_at. - */ - public function testUpdatedAtFilter(): void - { - $updatedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($updatedFilter, function () { - AnimeSynonym::factory() - ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) - ->create(); - }); - - Carbon::withTestNow($excludedDate, function () { - AnimeSynonym::factory() - ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) - ->create(); - }); - - $synonym = AnimeSynonym::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - - $response = $this->get(route('api.animesynonym.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new SynonymCollection($synonym, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Synonym Index Endpoint shall support filtering by trashed. - */ - public function testWithoutTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITHOUT->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - + Carbon::withTestNow($excludedDate, function () { AnimeSynonym::factory() ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) + ->count(fake()->randomDigitNotNull()) ->create(); + }); - AnimeSynonym::factory() - ->trashed() - ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) - ->create(); + $synonym = AnimeSynonym::withTrashed()->where(ModelConstants::ATTRIBUTE_DELETED_AT, $deletedFilter)->get(); - $synonym = AnimeSynonym::withoutTrashed()->get(); + $response = get(route('api.animesynonym.index', $parameters)); - $response = $this->get(route('api.animesynonym.index', $parameters)); + $response->assertJson( + json_decode( + json_encode( + new SynonymCollection($synonym, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $response->assertJson( - json_decode( - json_encode( - new SynonymCollection($synonym, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } +test('anime by media format', function () { + $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); - /** - * The Synonym Index Endpoint shall support filtering by trashed. - */ - public function testWithTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), + ], + IncludeParser::param() => AnimeSynonym::RELATION_ANIME, + ]; - AnimeSynonym::factory() - ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) - ->create(); + AnimeSynonym::factory() + ->for(Anime::factory()) + ->count(fake()->randomDigitNotNull()) + ->create(); - AnimeSynonym::factory() - ->trashed() - ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) - ->create(); + $synonyms = AnimeSynonym::with([ + AnimeSynonym::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { + $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); + }, + ]) + ->get(); - $synonym = AnimeSynonym::withTrashed()->get(); + $response = get(route('api.animesynonym.index', $parameters)); - $response = $this->get(route('api.animesynonym.index', $parameters)); + $response->assertJson( + json_decode( + json_encode( + new SynonymCollection($synonyms, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $response->assertJson( - json_decode( - json_encode( - new SynonymCollection($synonym, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } +test('anime by season', function () { + $seasonFilter = Arr::random(AnimeSeason::cases()); - /** - * The Synonym Index Endpoint shall support filtering by trashed. - */ - public function testOnlyTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::ONLY->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), + ], + IncludeParser::param() => AnimeSynonym::RELATION_ANIME, + ]; - AnimeSynonym::factory() - ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) - ->create(); + AnimeSynonym::factory() + ->for(Anime::factory()) + ->count(fake()->randomDigitNotNull()) + ->create(); - AnimeSynonym::factory() - ->trashed() - ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) - ->create(); + $synonyms = AnimeSynonym::with([ + AnimeSynonym::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { + $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); + }, + ]) + ->get(); - $synonym = AnimeSynonym::onlyTrashed()->get(); + $response = get(route('api.animesynonym.index', $parameters)); - $response = $this->get(route('api.animesynonym.index', $parameters)); + $response->assertJson( + json_decode( + json_encode( + new SynonymCollection($synonyms, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $response->assertJson( - json_decode( - json_encode( - new SynonymCollection($synonym, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } +test('anime by year', function () { + $yearFilter = intval(fake()->year()); + $excludedYear = $yearFilter + 1; - /** - * The Synonym Index Endpoint shall support filtering by deleted_at. - */ - public function testDeletedAtFilter(): void - { - $deletedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_YEAR => $yearFilter, + ], + IncludeParser::param() => AnimeSynonym::RELATION_ANIME, + ]; - $parameters = [ - FilterParser::param() => [ - ModelConstants::ATTRIBUTE_DELETED_AT => $deletedFilter, - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; + AnimeSynonym::factory() + ->for( + Anime::factory() + ->state([ + Anime::ATTRIBUTE_YEAR => fake()->boolean() ? $yearFilter : $excludedYear, + ]) + ) + ->count(fake()->randomDigitNotNull()) + ->create(); - Carbon::withTestNow($deletedFilter, function () { - AnimeSynonym::factory() - ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) - ->create(); - }); + $synonyms = AnimeSynonym::with([ + AnimeSynonym::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { + $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); + }, + ]) + ->get(); - Carbon::withTestNow($excludedDate, function () { - AnimeSynonym::factory() - ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) - ->create(); - }); + $response = get(route('api.animesynonym.index', $parameters)); - $synonym = AnimeSynonym::withTrashed()->where(ModelConstants::ATTRIBUTE_DELETED_AT, $deletedFilter)->get(); - - $response = $this->get(route('api.animesynonym.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new SynonymCollection($synonym, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Synonym Index Endpoint shall support constrained eager loading of anime by media format. - */ - public function testAnimeByMediaFormat(): void - { - $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), - ], - IncludeParser::param() => AnimeSynonym::RELATION_ANIME, - ]; - - AnimeSynonym::factory() - ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $synonyms = AnimeSynonym::with([ - AnimeSynonym::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { - $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.animesynonym.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new SynonymCollection($synonyms, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Synonym Index Endpoint shall support constrained eager loading of anime by season. - */ - public function testAnimeBySeason(): void - { - $seasonFilter = Arr::random(AnimeSeason::cases()); - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), - ], - IncludeParser::param() => AnimeSynonym::RELATION_ANIME, - ]; - - AnimeSynonym::factory() - ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $synonyms = AnimeSynonym::with([ - AnimeSynonym::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { - $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.animesynonym.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new SynonymCollection($synonyms, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Synonym Index Endpoint shall support constrained eager loading of anime by year. - */ - public function testAnimeByYear(): void - { - $yearFilter = intval($this->faker->year()); - $excludedYear = $yearFilter + 1; - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_YEAR => $yearFilter, - ], - IncludeParser::param() => AnimeSynonym::RELATION_ANIME, - ]; - - AnimeSynonym::factory() - ->for( - Anime::factory() - ->state([ - Anime::ATTRIBUTE_YEAR => $this->faker->boolean() ? $yearFilter : $excludedYear, - ]) - ) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $synonyms = AnimeSynonym::with([ - AnimeSynonym::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { - $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); - }, - ]) - ->get(); - - $response = $this->get(route('api.animesynonym.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new SynonymCollection($synonyms, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response->assertJson( + json_decode( + json_encode( + new SynonymCollection($synonyms, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Wiki/Anime/Synonym/SynonymRestoreTest.php b/tests/Feature/Http/Api/Wiki/Anime/Synonym/SynonymRestoreTest.php index 94c28635e..bce3ee349 100644 --- a/tests/Feature/Http/Api/Wiki/Anime/Synonym/SynonymRestoreTest.php +++ b/tests/Feature/Http/Api/Wiki/Anime/Synonym/SynonymRestoreTest.php @@ -2,84 +2,64 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Anime\Synonym; - use App\Enums\Auth\ExtendedCrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Anime; use App\Models\Wiki\Anime\AnimeSynonym; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class SynonymRestoreTest extends TestCase -{ - /** - * The Synonym Restore Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $synonym = AnimeSynonym::factory() - ->trashed() - ->for(Anime::factory()) - ->createOne(); +use function Pest\Laravel\patch; - $response = $this->patch(route('api.animesynonym.restore', ['animesynonym' => $synonym])); +test('protected', function () { + $synonym = AnimeSynonym::factory() + ->trashed() + ->for(Anime::factory()) + ->createOne(); - $response->assertUnauthorized(); - } + $response = patch(route('api.animesynonym.restore', ['animesynonym' => $synonym])); - /** - * The Synonym Restore Endpoint shall forbid users without the restore anime synonym permission. - */ - public function testForbidden(): void - { - $synonym = AnimeSynonym::factory() - ->trashed() - ->for(Anime::factory()) - ->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $synonym = AnimeSynonym::factory() + ->trashed() + ->for(Anime::factory()) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->patch(route('api.animesynonym.restore', ['animesynonym' => $synonym])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = patch(route('api.animesynonym.restore', ['animesynonym' => $synonym])); - /** - * The Synonym Restore Endpoint shall forbid users from restoring an anime synonym that isn't trashed. - */ - public function testTrashed(): void - { - $synonym = AnimeSynonym::factory()->for(Anime::factory())->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(AnimeSynonym::class))->createOne(); +test('trashed', function () { + $synonym = AnimeSynonym::factory()->for(Anime::factory())->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(AnimeSynonym::class))->createOne(); - $response = $this->patch(route('api.animesynonym.restore', ['animesynonym' => $synonym])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = patch(route('api.animesynonym.restore', ['animesynonym' => $synonym])); - /** - * The Synonym Restore Endpoint shall restore the synonym. - */ - public function testRestored(): void - { - $synonym = AnimeSynonym::factory() - ->trashed() - ->for(Anime::factory()) - ->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(AnimeSynonym::class))->createOne(); +test('restored', function () { + $synonym = AnimeSynonym::factory() + ->trashed() + ->for(Anime::factory()) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(AnimeSynonym::class))->createOne(); - $response = $this->patch(route('api.animesynonym.restore', ['animesynonym' => $synonym])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertNotSoftDeleted($synonym); - } -} + $response = patch(route('api.animesynonym.restore', ['animesynonym' => $synonym])); + + $response->assertOk(); + $this->assertNotSoftDeleted($synonym); +}); diff --git a/tests/Feature/Http/Api/Wiki/Anime/Synonym/SynonymShowTest.php b/tests/Feature/Http/Api/Wiki/Anime/Synonym/SynonymShowTest.php index d773f7848..cae7f33c5 100644 --- a/tests/Feature/Http/Api/Wiki/Anime/Synonym/SynonymShowTest.php +++ b/tests/Feature/Http/Api/Wiki/Anime/Synonym/SynonymShowTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Anime\Synonym; - use App\Enums\Models\Wiki\AnimeMediaFormat; use App\Enums\Models\Wiki\AnimeSeason; use App\Http\Api\Field\Field; @@ -17,244 +15,213 @@ use App\Http\Resources\Wiki\Anime\Resource\SynonymResource; use App\Models\Wiki\Anime; use App\Models\Wiki\Anime\AnimeSynonym; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; -use Tests\TestCase; -class SynonymShowTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the Synonym Show Endpoint shall return a Synonym Resource. - */ - public function testDefault(): void - { - $synonym = AnimeSynonym::factory()->for(Anime::factory())->createOne(); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $synonym->unsetRelations(); +test('default', function () { + $synonym = AnimeSynonym::factory()->for(Anime::factory())->createOne(); - $response = $this->get(route('api.animesynonym.show', ['animesynonym' => $synonym])); + $synonym->unsetRelations(); - $response->assertJson( - json_decode( - json_encode( - new SynonymResource($synonym, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.animesynonym.show', ['animesynonym' => $synonym])); - /** - * The Synonym Show Endpoint shall return a Synonym Resource for soft deleted synonyms. - */ - public function testSoftDelete(): void - { - $synonym = AnimeSynonym::factory() - ->trashed() - ->for(Anime::factory()) - ->createOne(); + $response->assertJson( + json_decode( + json_encode( + new SynonymResource($synonym, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $synonym->unsetRelations(); +test('soft delete', function () { + $synonym = AnimeSynonym::factory() + ->trashed() + ->for(Anime::factory()) + ->createOne(); - $response = $this->get(route('api.animesynonym.show', ['animesynonym' => $synonym])); + $synonym->unsetRelations(); - $response->assertJson( - json_decode( - json_encode( - new SynonymResource($synonym, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.animesynonym.show', ['animesynonym' => $synonym])); - /** - * The Synonym Show Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new SynonymSchema(); + $response->assertJson( + json_decode( + json_encode( + new SynonymResource($synonym, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('allowed include paths', function () { + $schema = new SynonymSchema(); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $allowedIncludes = collect($schema->allowedIncludes()); - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - $synonym = AnimeSynonym::factory()->for(Anime::factory())->createOne(); + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; - $response = $this->get(route('api.animesynonym.show', ['animesynonym' => $synonym] + $parameters)); + $synonym = AnimeSynonym::factory()->for(Anime::factory())->createOne(); - $response->assertJson( - json_decode( - json_encode( - new SynonymResource($synonym, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.animesynonym.show', ['animesynonym' => $synonym] + $parameters)); - /** - * The Synonym Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new SynonymSchema(); + $response->assertJson( + json_decode( + json_encode( + new SynonymResource($synonym, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $fields = collect($schema->fields()); +test('sparse fieldsets', function () { + $schema = new SynonymSchema(); - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); + $fields = collect($schema->fields()); - $parameters = [ - FieldParser::param() => [ - SynonymResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); - $synonym = AnimeSynonym::factory()->for(Anime::factory())->createOne(); + $parameters = [ + FieldParser::param() => [ + SynonymResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; - $synonym->unsetRelations(); + $synonym = AnimeSynonym::factory()->for(Anime::factory())->createOne(); - $response = $this->get(route('api.animesynonym.show', ['animesynonym' => $synonym] + $parameters)); + $synonym->unsetRelations(); - $response->assertJson( - json_decode( - json_encode( - new SynonymResource($synonym, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.animesynonym.show', ['animesynonym' => $synonym] + $parameters)); - /** - * The Synonym Show Endpoint shall support constrained eager loading of anime by media format. - */ - public function testAnimeByMediaFormat(): void - { - $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); + $response->assertJson( + json_decode( + json_encode( + new SynonymResource($synonym, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), - ], - IncludeParser::param() => AnimeSynonym::RELATION_ANIME, - ]; +test('anime by media format', function () { + $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); - $synonym = AnimeSynonym::factory()->for(Anime::factory())->createOne(); + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), + ], + IncludeParser::param() => AnimeSynonym::RELATION_ANIME, + ]; - $synonym->unsetRelations()->load([ - AnimeSynonym::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { - $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); - }, - ]); + $synonym = AnimeSynonym::factory()->for(Anime::factory())->createOne(); - $response = $this->get(route('api.animesynonym.show', ['animesynonym' => $synonym] + $parameters)); + $synonym->unsetRelations()->load([ + AnimeSynonym::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { + $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); + }, + ]); - $response->assertJson( - json_decode( - json_encode( - new SynonymResource($synonym, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.animesynonym.show', ['animesynonym' => $synonym] + $parameters)); - /** - * The Synonym Show Endpoint shall support constrained eager loading of anime by season. - */ - public function testAnimeBySeason(): void - { - $seasonFilter = Arr::random(AnimeSeason::cases()); + $response->assertJson( + json_decode( + json_encode( + new SynonymResource($synonym, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), - ], - IncludeParser::param() => AnimeSynonym::RELATION_ANIME, - ]; +test('anime by season', function () { + $seasonFilter = Arr::random(AnimeSeason::cases()); - $synonym = AnimeSynonym::factory()->for(Anime::factory())->createOne(); + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), + ], + IncludeParser::param() => AnimeSynonym::RELATION_ANIME, + ]; - $synonym->unsetRelations()->load([ - AnimeSynonym::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { - $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); - }, - ]); + $synonym = AnimeSynonym::factory()->for(Anime::factory())->createOne(); - $response = $this->get(route('api.animesynonym.show', ['animesynonym' => $synonym] + $parameters)); + $synonym->unsetRelations()->load([ + AnimeSynonym::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { + $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); + }, + ]); - $response->assertJson( - json_decode( - json_encode( - new SynonymResource($synonym, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.animesynonym.show', ['animesynonym' => $synonym] + $parameters)); - /** - * The Synonym Show Endpoint shall support constrained eager loading of anime by year. - */ - public function testAnimeByYear(): void - { - $yearFilter = intval($this->faker->year()); - $excludedYear = $yearFilter + 1; + $response->assertJson( + json_decode( + json_encode( + new SynonymResource($synonym, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_YEAR => $yearFilter, - ], - IncludeParser::param() => AnimeSynonym::RELATION_ANIME, - ]; +test('anime by year', function () { + $yearFilter = intval(fake()->year()); + $excludedYear = $yearFilter + 1; - $synonym = AnimeSynonym::factory() - ->for( - Anime::factory() - ->state([ - Anime::ATTRIBUTE_YEAR => $this->faker->boolean() ? $yearFilter : $excludedYear, - ]) - ) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_YEAR => $yearFilter, + ], + IncludeParser::param() => AnimeSynonym::RELATION_ANIME, + ]; - $synonym->unsetRelations()->load([ - AnimeSynonym::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { - $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); - }, - ]); + $synonym = AnimeSynonym::factory() + ->for( + Anime::factory() + ->state([ + Anime::ATTRIBUTE_YEAR => fake()->boolean() ? $yearFilter : $excludedYear, + ]) + ) + ->createOne(); - $response = $this->get(route('api.animesynonym.show', ['animesynonym' => $synonym] + $parameters)); + $synonym->unsetRelations()->load([ + AnimeSynonym::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { + $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); + }, + ]); - $response->assertJson( - json_decode( - json_encode( - new SynonymResource($synonym, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response = get(route('api.animesynonym.show', ['animesynonym' => $synonym] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new SynonymResource($synonym, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Wiki/Anime/Synonym/SynonymStoreTest.php b/tests/Feature/Http/Api/Wiki/Anime/Synonym/SynonymStoreTest.php index b8d3f3c3d..99cfce2b3 100644 --- a/tests/Feature/Http/Api/Wiki/Anime/Synonym/SynonymStoreTest.php +++ b/tests/Feature/Http/Api/Wiki/Anime/Synonym/SynonymStoreTest.php @@ -2,80 +2,60 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Anime\Synonym; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Anime; use App\Models\Wiki\Anime\AnimeSynonym; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class SynonymStoreTest extends TestCase -{ - /** - * The Synonym Store Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $synonym = AnimeSynonym::factory()->for(Anime::factory())->makeOne(); +use function Pest\Laravel\post; - $response = $this->post(route('api.animesynonym.store', $synonym->toArray())); +test('protected', function () { + $synonym = AnimeSynonym::factory()->for(Anime::factory())->makeOne(); - $response->assertUnauthorized(); - } + $response = post(route('api.animesynonym.store', $synonym->toArray())); - /** - * The Synonym Store Endpoint shall forbid users without the create anime synonym permission. - */ - public function testForbidden(): void - { - $synonym = AnimeSynonym::factory()->for(Anime::factory())->makeOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $synonym = AnimeSynonym::factory()->for(Anime::factory())->makeOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->post(route('api.animesynonym.store', $synonym->toArray())); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.animesynonym.store', $synonym->toArray())); - /** - * The Synonym Store Endpoint shall require the text field. - */ - public function testRequiredFields(): void - { - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(AnimeSynonym::class))->createOne(); + $response->assertForbidden(); +}); - Sanctum::actingAs($user); +test('required fields', function () { + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(AnimeSynonym::class))->createOne(); - $response = $this->post(route('api.animesynonym.store')); + Sanctum::actingAs($user); - $response->assertJsonValidationErrors([ - AnimeSynonym::ATTRIBUTE_TEXT, - ]); - } + $response = post(route('api.animesynonym.store')); - /** - * The Synonym Store Endpoint shall create a synonym. - */ - public function testCreate(): void - { - $anime = Anime::factory()->createOne(); + $response->assertJsonValidationErrors([ + AnimeSynonym::ATTRIBUTE_TEXT, + ]); +}); - $parameters = array_merge( - AnimeSynonym::factory()->raw(), - [AnimeSynonym::ATTRIBUTE_ANIME => $anime->getKey()], - ); +test('create', function () { + $anime = Anime::factory()->createOne(); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(AnimeSynonym::class))->createOne(); + $parameters = array_merge( + AnimeSynonym::factory()->raw(), + [AnimeSynonym::ATTRIBUTE_ANIME => $anime->getKey()], + ); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(AnimeSynonym::class))->createOne(); - $response = $this->post(route('api.animesynonym.store', $parameters)); + Sanctum::actingAs($user); - $response->assertCreated(); - static::assertDatabaseCount(AnimeSynonym::class, 1); - } -} + $response = post(route('api.animesynonym.store', $parameters)); + + $response->assertCreated(); + $this->assertDatabaseCount(AnimeSynonym::class, 1); +}); diff --git a/tests/Feature/Http/Api/Wiki/Anime/Synonym/SynonymUpdateTest.php b/tests/Feature/Http/Api/Wiki/Anime/Synonym/SynonymUpdateTest.php index af3e79103..4c77bec52 100644 --- a/tests/Feature/Http/Api/Wiki/Anime/Synonym/SynonymUpdateTest.php +++ b/tests/Feature/Http/Api/Wiki/Anime/Synonym/SynonymUpdateTest.php @@ -2,85 +2,65 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Anime\Synonym; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Anime; use App\Models\Wiki\Anime\AnimeSynonym; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class SynonymUpdateTest extends TestCase -{ - /** - * The Synonym Update Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $synonym = AnimeSynonym::factory()->for(Anime::factory())->createOne(); +use function Pest\Laravel\put; - $parameters = AnimeSynonym::factory()->raw(); +test('protected', function () { + $synonym = AnimeSynonym::factory()->for(Anime::factory())->createOne(); - $response = $this->put(route('api.animesynonym.update', ['animesynonym' => $synonym] + $parameters)); + $parameters = AnimeSynonym::factory()->raw(); - $response->assertUnauthorized(); - } + $response = put(route('api.animesynonym.update', ['animesynonym' => $synonym] + $parameters)); - /** - * The Synonym Update Endpoint shall forbid users without the update anime synonym permission. - */ - public function testForbidden(): void - { - $synonym = AnimeSynonym::factory()->for(Anime::factory())->createOne(); + $response->assertUnauthorized(); +}); - $parameters = AnimeSynonym::factory()->raw(); +test('forbidden', function () { + $synonym = AnimeSynonym::factory()->for(Anime::factory())->createOne(); - $user = User::factory()->createOne(); + $parameters = AnimeSynonym::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->put(route('api.animesynonym.update', ['animesynonym' => $synonym] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.animesynonym.update', ['animesynonym' => $synonym] + $parameters)); - /** - * The Synonym Update Endpoint shall forbid users from updating an anime synonym that is trashed. - */ - public function testTrashed(): void - { - $synonym = AnimeSynonym::factory() - ->trashed() - ->for(Anime::factory()) - ->createOne(); + $response->assertForbidden(); +}); - $parameters = AnimeSynonym::factory()->raw(); +test('trashed', function () { + $synonym = AnimeSynonym::factory() + ->trashed() + ->for(Anime::factory()) + ->createOne(); - $user = User::factory()->withPermissions(CrudPermission::VIEW->format(AnimeSynonym::class))->createOne(); + $parameters = AnimeSynonym::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::VIEW->format(AnimeSynonym::class))->createOne(); - $response = $this->put(route('api.animesynonym.update', ['animesynonym' => $synonym] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.animesynonym.update', ['animesynonym' => $synonym] + $parameters)); - /** - * The Synonym Update Endpoint shall update a synonym. - */ - public function testUpdate(): void - { - $synonym = AnimeSynonym::factory()->for(Anime::factory())->createOne(); + $response->assertForbidden(); +}); - $parameters = AnimeSynonym::factory()->raw(); +test('update', function () { + $synonym = AnimeSynonym::factory()->for(Anime::factory())->createOne(); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(AnimeSynonym::class))->createOne(); + $parameters = AnimeSynonym::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(AnimeSynonym::class))->createOne(); - $response = $this->put(route('api.animesynonym.update', ['animesynonym' => $synonym] + $parameters)); + Sanctum::actingAs($user); - $response->assertOk(); - } -} + $response = put(route('api.animesynonym.update', ['animesynonym' => $synonym] + $parameters)); + + $response->assertOk(); +}); diff --git a/tests/Feature/Http/Api/Wiki/Anime/Theme/Entry/EntryDestroyTest.php b/tests/Feature/Http/Api/Wiki/Anime/Theme/Entry/EntryDestroyTest.php index a5b165c89..d38e7c606 100644 --- a/tests/Feature/Http/Api/Wiki/Anime/Theme/Entry/EntryDestroyTest.php +++ b/tests/Feature/Http/Api/Wiki/Anime/Theme/Entry/EntryDestroyTest.php @@ -2,85 +2,65 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Anime\Theme\Entry; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Anime; use App\Models\Wiki\Anime\AnimeTheme; use App\Models\Wiki\Anime\Theme\AnimeThemeEntry; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class EntryDestroyTest extends TestCase -{ - /** - * The Entry Destroy Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.animethemeentry.destroy', ['animethemeentry' => $entry])); +test('protected', function () { + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.animethemeentry.destroy', ['animethemeentry' => $entry])); - /** - * The Entry Destroy Endpoint shall forbid users without the delete anime theme entry permission. - */ - public function testForbidden(): void - { - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.animethemeentry.destroy', ['animethemeentry' => $entry])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.animethemeentry.destroy', ['animethemeentry' => $entry])); - /** - * The Entry Destroy Endpoint shall forbid users from updating an anime theme entry that is trashed. - */ - public function testTrashed(): void - { - $entry = AnimeThemeEntry::factory() - ->trashed() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(AnimeThemeEntry::class))->createOne(); +test('trashed', function () { + $entry = AnimeThemeEntry::factory() + ->trashed() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(AnimeThemeEntry::class))->createOne(); - $response = $this->delete(route('api.animethemeentry.destroy', ['animethemeentry' => $entry])); + Sanctum::actingAs($user); - $response->assertNotFound(); - } + $response = delete(route('api.animethemeentry.destroy', ['animethemeentry' => $entry])); - /** - * The Entry Destroy Endpoint shall delete the entry. - */ - public function testDeleted(): void - { - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); + $response->assertNotFound(); +}); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(AnimeThemeEntry::class))->createOne(); +test('deleted', function () { + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(AnimeThemeEntry::class))->createOne(); - $response = $this->delete(route('api.animethemeentry.destroy', ['animethemeentry' => $entry])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertSoftDeleted($entry); - } -} + $response = delete(route('api.animethemeentry.destroy', ['animethemeentry' => $entry])); + + $response->assertOk(); + $this->assertSoftDeleted($entry); +}); diff --git a/tests/Feature/Http/Api/Wiki/Anime/Theme/Entry/EntryForceDeleteTest.php b/tests/Feature/Http/Api/Wiki/Anime/Theme/Entry/EntryForceDeleteTest.php index 88d7cc650..65ebeeade 100644 --- a/tests/Feature/Http/Api/Wiki/Anime/Theme/Entry/EntryForceDeleteTest.php +++ b/tests/Feature/Http/Api/Wiki/Anime/Theme/Entry/EntryForceDeleteTest.php @@ -2,66 +2,50 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Anime\Theme\Entry; - use App\Enums\Auth\ExtendedCrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Anime; use App\Models\Wiki\Anime\AnimeTheme; use App\Models\Wiki\Anime\Theme\AnimeThemeEntry; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class EntryForceDeleteTest extends TestCase -{ - /** - * The Entry Force Delete Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.animethemeentry.forceDelete', ['animethemeentry' => $entry])); +test('protected', function () { + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.animethemeentry.forceDelete', ['animethemeentry' => $entry])); - /** - * The Entry Force Delete Endpoint shall forbid users without the force delete anime theme entry permission. - */ - public function testForbidden(): void - { - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.animethemeentry.forceDelete', ['animethemeentry' => $entry])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.animethemeentry.forceDelete', ['animethemeentry' => $entry])); - /** - * The Entry Force Delete Endpoint shall force delete the entry. - */ - public function testDeleted(): void - { - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::FORCE_DELETE->format(AnimeThemeEntry::class))->createOne(); +test('deleted', function () { + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::FORCE_DELETE->format(AnimeThemeEntry::class))->createOne(); - $response = $this->delete(route('api.animethemeentry.forceDelete', ['animethemeentry' => $entry])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertModelMissing($entry); - } -} + $response = delete(route('api.animethemeentry.forceDelete', ['animethemeentry' => $entry])); + + $response->assertOk(); + $this->assertModelMissing($entry); +}); diff --git a/tests/Feature/Http/Api/Wiki/Anime/Theme/Entry/EntryIndexTest.php b/tests/Feature/Http/Api/Wiki/Anime/Theme/Entry/EntryIndexTest.php index 933131a18..562d2d4b8 100644 --- a/tests/Feature/Http/Api/Wiki/Anime/Theme/Entry/EntryIndexTest.php +++ b/tests/Feature/Http/Api/Wiki/Anime/Theme/Entry/EntryIndexTest.php @@ -2,9 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Anime\Theme\Entry; - -use App\Concerns\Actions\Http\Api\SortsModels; use App\Constants\ModelConstants; use App\Contracts\Http\Api\Field\SortableField; use App\Enums\Http\Api\Filter\TrashedStatus; @@ -34,760 +31,682 @@ use App\Models\Wiki\Anime\Theme\AnimeThemeEntry; use App\Models\Wiki\Video; use Illuminate\Database\Eloquent\Factories\Sequence; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; -use Tests\TestCase; -class EntryIndexTest extends TestCase -{ - use SortsModels; - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the Entry Index Endpoint shall return a collection of Entry Resources. - */ - public function testDefault(): void - { - $entries = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->count($this->faker->randomDigitNotNull()) - ->create(); +uses(App\Concerns\Actions\Http\Api\SortsModels::class); - $response = $this->get(route('api.animethemeentry.index')); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response->assertJson( - json_decode( - json_encode( - new EntryCollection($entries, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } +test('default', function () { + $entries = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->count(fake()->randomDigitNotNull()) + ->create(); - /** - * The Entry Index Endpoint shall be paginated. - */ - public function testPaginated(): void - { + $response = get(route('api.animethemeentry.index')); + + $response->assertJson( + json_decode( + json_encode( + new EntryCollection($entries, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('paginated', function () { + AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $response = get(route('api.animethemeentry.index')); + + $response->assertJsonStructure([ + EntryCollection::$wrap, + 'links', + 'meta', + ]); +}); + +test('allowed include paths', function () { + $schema = new EntrySchema(); + + $allowedIncludes = collect($schema->allowedIncludes()); + + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); + + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; + + AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->count(fake()->randomDigitNotNull()) + ->has(Video::factory()->count(fake()->randomDigitNotNull())) + ->create(); + + $entries = AnimeThemeEntry::with($includedPaths->all())->get(); + + $response = get(route('api.animethemeentry.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new EntryCollection($entries, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sparse fieldsets', function () { + $schema = new EntrySchema(); + + $fields = collect($schema->fields()); + + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + EntryResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + $entries = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $response = get(route('api.animethemeentry.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new EntryCollection($entries, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sorts', function () { + $schema = new EntrySchema(); + + /** @var Sort $sort */ + $sort = collect($schema->fields()) + ->filter(fn (Field $field) => $field instanceof SortableField) + ->map(fn (SortableField $field) => $field->getSort()) + ->random(); + + $parameters = [ + SortParser::param() => $sort->format(Arr::random(Direction::cases())), + ]; + + $query = new Query($parameters); + + AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $response = get(route('api.animethemeentry.index', $parameters)); + + $entries = $this->sort(AnimeThemeEntry::query(), $query, $schema)->get(); + + $response->assertJson( + json_decode( + json_encode( + new EntryCollection($entries, $query) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('created at filter', function () { + $createdFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($createdFilter, function () { AnimeThemeEntry::factory() ->for(AnimeTheme::factory()->for(Anime::factory())) - ->count($this->faker->randomDigitNotNull()) + ->count(fake()->randomDigitNotNull()) ->create(); + }); - $response = $this->get(route('api.animethemeentry.index')); - - $response->assertJsonStructure([ - EntryCollection::$wrap, - 'links', - 'meta', - ]); - } - - /** - * The Entry Index Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new EntrySchema(); - - $allowedIncludes = collect($schema->allowedIncludes()); - - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); - - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; - + Carbon::withTestNow($excludedDate, function () { AnimeThemeEntry::factory() ->for(AnimeTheme::factory()->for(Anime::factory())) - ->count($this->faker->randomDigitNotNull()) - ->has(Video::factory()->count($this->faker->randomDigitNotNull())) + ->count(fake()->randomDigitNotNull()) ->create(); + }); - $entries = AnimeThemeEntry::with($includedPaths->all())->get(); + $entry = AnimeThemeEntry::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - $response = $this->get(route('api.animethemeentry.index', $parameters)); + $response = get(route('api.animethemeentry.index', $parameters)); - $response->assertJson( - json_decode( - json_encode( - new EntryCollection($entries, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response->assertJson( + json_decode( + json_encode( + new EntryCollection($entry, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - /** - * The Entry Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new EntrySchema(); +test('updated at filter', function () { + $updatedFilter = fake()->date(); + $excludedDate = fake()->date(); - $fields = collect($schema->fields()); - - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); - - $parameters = [ - FieldParser::param() => [ - EntryResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; - - $entries = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $response = $this->get(route('api.animethemeentry.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new EntryCollection($entries, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Entry Index Endpoint shall support sorting resources. - */ - public function testSorts(): void - { - $schema = new EntrySchema(); - - /** @var Sort $sort */ - $sort = collect($schema->fields()) - ->filter(fn (Field $field) => $field instanceof SortableField) - ->map(fn (SortableField $field) => $field->getSort()) - ->random(); - - $parameters = [ - SortParser::param() => $sort->format(Arr::random(Direction::cases())), - ]; - - $query = new Query($parameters); + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + Carbon::withTestNow($updatedFilter, function () { AnimeThemeEntry::factory() ->for(AnimeTheme::factory()->for(Anime::factory())) - ->count($this->faker->randomDigitNotNull()) + ->count(fake()->randomDigitNotNull()) ->create(); + }); - $response = $this->get(route('api.animethemeentry.index', $parameters)); - - $entries = $this->sort(AnimeThemeEntry::query(), $query, $schema)->get(); - - $response->assertJson( - json_decode( - json_encode( - new EntryCollection($entries, $query) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Entry Index Endpoint shall support filtering by created_at. - */ - public function testCreatedAtFilter(): void - { - $createdFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($createdFilter, function () { - AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->count($this->faker->randomDigitNotNull()) - ->create(); - }); - - Carbon::withTestNow($excludedDate, function () { - AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->count($this->faker->randomDigitNotNull()) - ->create(); - }); - - $entry = AnimeThemeEntry::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - - $response = $this->get(route('api.animethemeentry.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new EntryCollection($entry, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Entry Index Endpoint shall support filtering by updated_at. - */ - public function testUpdatedAtFilter(): void - { - $updatedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($updatedFilter, function () { - AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->count($this->faker->randomDigitNotNull()) - ->create(); - }); - - Carbon::withTestNow($excludedDate, function () { - AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->count($this->faker->randomDigitNotNull()) - ->create(); - }); - - $entry = AnimeThemeEntry::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - - $response = $this->get(route('api.animethemeentry.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new EntryCollection($entry, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Entry Index Endpoint shall support filtering by trashed. - */ - public function testWithoutTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITHOUT->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - + Carbon::withTestNow($excludedDate, function () { AnimeThemeEntry::factory() ->for(AnimeTheme::factory()->for(Anime::factory())) - ->count($this->faker->randomDigitNotNull()) + ->count(fake()->randomDigitNotNull()) ->create(); + }); + $entry = AnimeThemeEntry::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); + + $response = get(route('api.animethemeentry.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new EntryCollection($entry, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('without trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITHOUT->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + AnimeThemeEntry::factory() + ->trashed() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $entry = AnimeThemeEntry::withoutTrashed()->get(); + + $response = get(route('api.animethemeentry.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new EntryCollection($entry, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('with trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + AnimeThemeEntry::factory() + ->trashed() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $entry = AnimeThemeEntry::withTrashed()->get(); + + $response = get(route('api.animethemeentry.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new EntryCollection($entry, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('only trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::ONLY->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + AnimeThemeEntry::factory() + ->trashed() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $entry = AnimeThemeEntry::onlyTrashed()->get(); + + $response = get(route('api.animethemeentry.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new EntryCollection($entry, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('deleted at filter', function () { + $deletedFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + ModelConstants::ATTRIBUTE_DELETED_AT => $deletedFilter, + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($deletedFilter, function () { AnimeThemeEntry::factory() ->trashed() ->for(AnimeTheme::factory()->for(Anime::factory())) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $entry = AnimeThemeEntry::withoutTrashed()->get(); - - $response = $this->get(route('api.animethemeentry.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new EntryCollection($entry, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Entry Index Endpoint shall support filtering by trashed. - */ - public function testWithTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->count($this->faker->randomDigitNotNull()) + ->count(fake()->randomDigitNotNull()) ->create(); + }); + Carbon::withTestNow($excludedDate, function () { AnimeThemeEntry::factory() ->trashed() ->for(AnimeTheme::factory()->for(Anime::factory())) - ->count($this->faker->randomDigitNotNull()) + ->count(fake()->randomDigitNotNull()) ->create(); + }); - $entry = AnimeThemeEntry::withTrashed()->get(); + $entry = AnimeThemeEntry::withTrashed()->where(ModelConstants::ATTRIBUTE_DELETED_AT, $deletedFilter)->get(); - $response = $this->get(route('api.animethemeentry.index', $parameters)); + $response = get(route('api.animethemeentry.index', $parameters)); - $response->assertJson( - json_decode( - json_encode( - new EntryCollection($entry, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response->assertJson( + json_decode( + json_encode( + new EntryCollection($entry, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - /** - * The Entry Index Endpoint shall support filtering by trashed. - */ - public function testOnlyTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::ONLY->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; +test('entries by nsfw', function () { + $nsfwFilter = fake()->boolean(); - AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->count($this->faker->randomDigitNotNull()) - ->create(); + $parameters = [ + FilterParser::param() => [ + AnimeThemeEntry::ATTRIBUTE_NSFW => $nsfwFilter, + ], + ]; - AnimeThemeEntry::factory() - ->trashed() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->count($this->faker->randomDigitNotNull()) - ->create(); + AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->count(fake()->randomDigitNotNull()) + ->create(); - $entry = AnimeThemeEntry::onlyTrashed()->get(); + $entries = AnimeThemeEntry::query()->where(AnimeThemeEntry::ATTRIBUTE_NSFW, $nsfwFilter)->get(); - $response = $this->get(route('api.animethemeentry.index', $parameters)); + $response = get(route('api.animethemeentry.index', $parameters)); - $response->assertJson( - json_decode( - json_encode( - new EntryCollection($entry, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response->assertJson( + json_decode( + json_encode( + new EntryCollection($entries, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - /** - * The Entry Index Endpoint shall support filtering by deleted_at. - */ - public function testDeletedAtFilter(): void - { - $deletedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); +test('entries by spoiler', function () { + $spoilerFilter = fake()->boolean(); - $parameters = [ - FilterParser::param() => [ - ModelConstants::ATTRIBUTE_DELETED_AT => $deletedFilter, - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; + $parameters = [ + FilterParser::param() => [ + AnimeThemeEntry::ATTRIBUTE_SPOILER => $spoilerFilter, + ], + ]; - Carbon::withTestNow($deletedFilter, function () { - AnimeThemeEntry::factory() - ->trashed() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->count($this->faker->randomDigitNotNull()) - ->create(); - }); + AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->count(fake()->randomDigitNotNull()) + ->create(); - Carbon::withTestNow($excludedDate, function () { - AnimeThemeEntry::factory() - ->trashed() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->count($this->faker->randomDigitNotNull()) - ->create(); - }); + $entries = AnimeThemeEntry::query()->where(AnimeThemeEntry::ATTRIBUTE_SPOILER, $spoilerFilter)->get(); - $entry = AnimeThemeEntry::withTrashed()->where(ModelConstants::ATTRIBUTE_DELETED_AT, $deletedFilter)->get(); + $response = get(route('api.animethemeentry.index', $parameters)); - $response = $this->get(route('api.animethemeentry.index', $parameters)); + $response->assertJson( + json_decode( + json_encode( + new EntryCollection($entries, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $response->assertJson( - json_decode( - json_encode( - new EntryCollection($entry, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } +test('entries by version', function () { + $versionFilter = fake()->randomDigitNotNull(); + $excludedVersion = $versionFilter + 1; - /** - * The Entry Index Endpoint shall support filtering by nsfw. - */ - public function testEntriesByNsfw(): void - { - $nsfwFilter = $this->faker->boolean(); + $parameters = [ + FilterParser::param() => [ + AnimeThemeEntry::ATTRIBUTE_VERSION => $versionFilter, + ], + ]; - $parameters = [ - FilterParser::param() => [ - AnimeThemeEntry::ATTRIBUTE_NSFW => $nsfwFilter, - ], - ]; + AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->count(fake()->randomDigitNotNull()) + ->state(new Sequence( + [AnimeThemeEntry::ATTRIBUTE_VERSION => $versionFilter], + [AnimeThemeEntry::ATTRIBUTE_VERSION => $excludedVersion], + )) + ->create(); - AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->count($this->faker->randomDigitNotNull()) - ->create(); + $entries = AnimeThemeEntry::query()->where(AnimeThemeEntry::ATTRIBUTE_VERSION, $versionFilter)->get(); - $entries = AnimeThemeEntry::query()->where(AnimeThemeEntry::ATTRIBUTE_NSFW, $nsfwFilter)->get(); + $response = get(route('api.animethemeentry.index', $parameters)); - $response = $this->get(route('api.animethemeentry.index', $parameters)); + $response->assertJson( + json_decode( + json_encode( + new EntryCollection($entries, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $response->assertJson( - json_decode( - json_encode( - new EntryCollection($entries, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } +test('anime by media format', function () { + $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); - /** - * The Entry Index Endpoint shall support filtering by spoiler. - */ - public function testEntriesBySpoiler(): void - { - $spoilerFilter = $this->faker->boolean(); + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), + ], + IncludeParser::param() => AnimeThemeEntry::RELATION_ANIME, + ]; - $parameters = [ - FilterParser::param() => [ - AnimeThemeEntry::ATTRIBUTE_SPOILER => $spoilerFilter, - ], - ]; + AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->count(fake()->randomDigitNotNull()) + ->create(); - AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->count($this->faker->randomDigitNotNull()) - ->create(); + $entries = AnimeThemeEntry::with([ + AnimeThemeEntry::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { + $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); + }, + ]) + ->get(); - $entries = AnimeThemeEntry::query()->where(AnimeThemeEntry::ATTRIBUTE_SPOILER, $spoilerFilter)->get(); + $response = get(route('api.animethemeentry.index', $parameters)); - $response = $this->get(route('api.animethemeentry.index', $parameters)); + $response->assertJson( + json_decode( + json_encode( + new EntryCollection($entries, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $response->assertJson( - json_decode( - json_encode( - new EntryCollection($entries, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } +test('anime by season', function () { + $seasonFilter = Arr::random(AnimeSeason::cases()); - /** - * The Entry Index Endpoint shall support filtering by version. - */ - public function testEntriesByVersion(): void - { - $versionFilter = $this->faker->randomDigitNotNull(); - $excludedVersion = $versionFilter + 1; + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), + ], + IncludeParser::param() => AnimeThemeEntry::RELATION_ANIME, + ]; - $parameters = [ - FilterParser::param() => [ - AnimeThemeEntry::ATTRIBUTE_VERSION => $versionFilter, - ], - ]; + AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->count(fake()->randomDigitNotNull()) + ->create(); - AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->count($this->faker->randomDigitNotNull()) - ->state(new Sequence( - [AnimeThemeEntry::ATTRIBUTE_VERSION => $versionFilter], - [AnimeThemeEntry::ATTRIBUTE_VERSION => $excludedVersion], - )) - ->create(); + $entries = AnimeThemeEntry::with([ + AnimeThemeEntry::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { + $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); + }, + ]) + ->get(); - $entries = AnimeThemeEntry::query()->where(AnimeThemeEntry::ATTRIBUTE_VERSION, $versionFilter)->get(); + $response = get(route('api.animethemeentry.index', $parameters)); - $response = $this->get(route('api.animethemeentry.index', $parameters)); + $response->assertJson( + json_decode( + json_encode( + new EntryCollection($entries, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $response->assertJson( - json_decode( - json_encode( - new EntryCollection($entries, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } +test('anime by year', function () { + $yearFilter = intval(fake()->year()); + $excludedYear = $yearFilter + 1; - /** - * The Entry Index Endpoint shall support constrained eager loading of anime by media format. - */ - public function testAnimeByMediaFormat(): void - { - $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_YEAR => $yearFilter, + ], + IncludeParser::param() => AnimeThemeEntry::RELATION_ANIME, + ]; - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), - ], - IncludeParser::param() => AnimeThemeEntry::RELATION_ANIME, - ]; - - AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $entries = AnimeThemeEntry::with([ - AnimeThemeEntry::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { - $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.animethemeentry.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new EntryCollection($entries, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Entry Index Endpoint shall support constrained eager loading of anime by season. - */ - public function testAnimeBySeason(): void - { - $seasonFilter = Arr::random(AnimeSeason::cases()); - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), - ], - IncludeParser::param() => AnimeThemeEntry::RELATION_ANIME, - ]; - - AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $entries = AnimeThemeEntry::with([ - AnimeThemeEntry::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { - $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.animethemeentry.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new EntryCollection($entries, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Entry Index Endpoint shall support constrained eager loading of anime by year. - */ - public function testAnimeByYear(): void - { - $yearFilter = intval($this->faker->year()); - $excludedYear = $yearFilter + 1; - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_YEAR => $yearFilter, - ], - IncludeParser::param() => AnimeThemeEntry::RELATION_ANIME, - ]; - - AnimeThemeEntry::factory() - ->for( - AnimeTheme::factory()->for( - Anime::factory() - ->state([ - Anime::ATTRIBUTE_YEAR => $this->faker->boolean() ? $yearFilter : $excludedYear, - ]) - ) - ) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $entries = AnimeThemeEntry::with([ - AnimeThemeEntry::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { - $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); - }, - ]) - ->get(); - - $response = $this->get(route('api.animethemeentry.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new EntryCollection($entries, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Entry Index Endpoint shall support constrained eager loading of themes by sequence. - */ - public function testThemesBySequence(): void - { - $sequenceFilter = $this->faker->randomDigitNotNull(); - $excludedSequence = $sequenceFilter + 1; - - $parameters = [ - FilterParser::param() => [ - AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter, - ], - IncludeParser::param() => AnimeThemeEntry::RELATION_THEME, - ]; - - AnimeThemeEntry::factory() - ->for( - AnimeTheme::factory() - ->for(Anime::factory()) + AnimeThemeEntry::factory() + ->for( + AnimeTheme::factory()->for( + Anime::factory() ->state([ - AnimeTheme::ATTRIBUTE_SEQUENCE => $this->faker->boolean() ? $sequenceFilter : $excludedSequence, + Anime::ATTRIBUTE_YEAR => fake()->boolean() ? $yearFilter : $excludedYear, ]) ) - ->count($this->faker->randomDigitNotNull()) - ->create(); + ) + ->count(fake()->randomDigitNotNull()) + ->create(); - $entries = AnimeThemeEntry::with([ - AnimeThemeEntry::RELATION_THEME => function (BelongsTo $query) use ($sequenceFilter) { - $query->where(AnimeTheme::ATTRIBUTE_SEQUENCE, $sequenceFilter); - }, - ]) - ->get(); + $entries = AnimeThemeEntry::with([ + AnimeThemeEntry::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { + $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); + }, + ]) + ->get(); - $response = $this->get(route('api.animethemeentry.index', $parameters)); + $response = get(route('api.animethemeentry.index', $parameters)); - $response->assertJson( - json_decode( - json_encode( - new EntryCollection($entries, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response->assertJson( + json_decode( + json_encode( + new EntryCollection($entries, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - /** - * The Entry Index Endpoint shall support constrained eager loading of themes by type. - */ - public function testThemesByType(): void - { - $typeFilter = Arr::random(ThemeType::cases()); +test('themes by sequence', function () { + $sequenceFilter = fake()->randomDigitNotNull(); + $excludedSequence = $sequenceFilter + 1; - $parameters = [ - FilterParser::param() => [ - AnimeTheme::ATTRIBUTE_TYPE => $typeFilter->localize(), - ], - IncludeParser::param() => AnimeThemeEntry::RELATION_THEME, - ]; + $parameters = [ + FilterParser::param() => [ + AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter, + ], + IncludeParser::param() => AnimeThemeEntry::RELATION_THEME, + ]; - AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->count($this->faker->randomDigitNotNull()) - ->create(); + AnimeThemeEntry::factory() + ->for( + AnimeTheme::factory() + ->for(Anime::factory()) + ->state([ + AnimeTheme::ATTRIBUTE_SEQUENCE => fake()->boolean() ? $sequenceFilter : $excludedSequence, + ]) + ) + ->count(fake()->randomDigitNotNull()) + ->create(); - $entries = AnimeThemeEntry::with([ - AnimeThemeEntry::RELATION_THEME => function (BelongsTo $query) use ($typeFilter) { - $query->where(AnimeTheme::ATTRIBUTE_TYPE, $typeFilter->value); - }, - ]) - ->get(); + $entries = AnimeThemeEntry::with([ + AnimeThemeEntry::RELATION_THEME => function (BelongsTo $query) use ($sequenceFilter) { + $query->where(AnimeTheme::ATTRIBUTE_SEQUENCE, $sequenceFilter); + }, + ]) + ->get(); - $response = $this->get(route('api.animethemeentry.index', $parameters)); + $response = get(route('api.animethemeentry.index', $parameters)); - $response->assertJson( - json_decode( - json_encode( - new EntryCollection($entries, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response->assertJson( + json_decode( + json_encode( + new EntryCollection($entries, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('themes by type', function () { + $typeFilter = Arr::random(ThemeType::cases()); + + $parameters = [ + FilterParser::param() => [ + AnimeTheme::ATTRIBUTE_TYPE => $typeFilter->localize(), + ], + IncludeParser::param() => AnimeThemeEntry::RELATION_THEME, + ]; + + AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $entries = AnimeThemeEntry::with([ + AnimeThemeEntry::RELATION_THEME => function (BelongsTo $query) use ($typeFilter) { + $query->where(AnimeTheme::ATTRIBUTE_TYPE, $typeFilter->value); + }, + ]) + ->get(); + + $response = get(route('api.animethemeentry.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new EntryCollection($entries, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Wiki/Anime/Theme/Entry/EntryRestoreTest.php b/tests/Feature/Http/Api/Wiki/Anime/Theme/Entry/EntryRestoreTest.php index 943971c44..600540c2e 100644 --- a/tests/Feature/Http/Api/Wiki/Anime/Theme/Entry/EntryRestoreTest.php +++ b/tests/Feature/Http/Api/Wiki/Anime/Theme/Entry/EntryRestoreTest.php @@ -2,87 +2,67 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Anime\Theme\Entry; - use App\Enums\Auth\ExtendedCrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Anime; use App\Models\Wiki\Anime\AnimeTheme; use App\Models\Wiki\Anime\Theme\AnimeThemeEntry; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class EntryRestoreTest extends TestCase -{ - /** - * The Entry Restore Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $entry = AnimeThemeEntry::factory() - ->trashed() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); +use function Pest\Laravel\patch; - $response = $this->patch(route('api.animethemeentry.restore', ['animethemeentry' => $entry])); +test('protected', function () { + $entry = AnimeThemeEntry::factory() + ->trashed() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - $response->assertUnauthorized(); - } + $response = patch(route('api.animethemeentry.restore', ['animethemeentry' => $entry])); - /** - * The Entry Restore Endpoint shall forbid users without the restore anime theme entry permission. - */ - public function testForbidden(): void - { - $entry = AnimeThemeEntry::factory() - ->trashed() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $entry = AnimeThemeEntry::factory() + ->trashed() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->patch(route('api.animethemeentry.restore', ['animethemeentry' => $entry])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = patch(route('api.animethemeentry.restore', ['animethemeentry' => $entry])); - /** - * The Entry Restore Endpoint shall forbid users from restoring an anime theme entry that isn't trashed. - */ - public function testTrashed(): void - { - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(AnimeThemeEntry::class))->createOne(); +test('trashed', function () { + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(AnimeThemeEntry::class))->createOne(); - $response = $this->patch(route('api.animethemeentry.restore', ['animethemeentry' => $entry])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = patch(route('api.animethemeentry.restore', ['animethemeentry' => $entry])); - /** - * The Entry Restore Endpoint shall restore the entry. - */ - public function testRestored(): void - { - $entry = AnimeThemeEntry::factory() - ->trashed() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(AnimeThemeEntry::class))->createOne(); +test('restored', function () { + $entry = AnimeThemeEntry::factory() + ->trashed() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(AnimeThemeEntry::class))->createOne(); - $response = $this->patch(route('api.animethemeentry.restore', ['animethemeentry' => $entry])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertNotSoftDeleted($entry); - } -} + $response = patch(route('api.animethemeentry.restore', ['animethemeentry' => $entry])); + + $response->assertOk(); + $this->assertNotSoftDeleted($entry); +}); diff --git a/tests/Feature/Http/Api/Wiki/Anime/Theme/Entry/EntryShowTest.php b/tests/Feature/Http/Api/Wiki/Anime/Theme/Entry/EntryShowTest.php index 1f44972bb..a019f6c46 100644 --- a/tests/Feature/Http/Api/Wiki/Anime/Theme/Entry/EntryShowTest.php +++ b/tests/Feature/Http/Api/Wiki/Anime/Theme/Entry/EntryShowTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Anime\Theme\Entry; - use App\Enums\Models\Wiki\AnimeMediaFormat; use App\Enums\Models\Wiki\AnimeSeason; use App\Enums\Models\Wiki\ThemeType; @@ -20,336 +18,297 @@ use App\Models\Wiki\Anime\AnimeTheme; use App\Models\Wiki\Anime\Theme\AnimeThemeEntry; use App\Models\Wiki\Video; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; -use Tests\TestCase; -class EntryShowTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the Entry Show Endpoint shall return an Entry Resource. - */ - public function testDefault(): void - { - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->create(); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response = $this->get(route('api.animethemeentry.show', ['animethemeentry' => $entry])); +test('default', function () { + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->create(); - $response->assertJson( - json_decode( - json_encode( - new EntryResource($entry, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.animethemeentry.show', ['animethemeentry' => $entry])); - /** - * The Entry Show Endpoint shall return an Entry Resource for soft deleted images. - */ - public function testSoftDelete(): void - { - $entry = AnimeThemeEntry::factory() - ->trashed() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); + $response->assertJson( + json_decode( + json_encode( + new EntryResource($entry, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $entry->unsetRelations(); +test('soft delete', function () { + $entry = AnimeThemeEntry::factory() + ->trashed() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - $response = $this->get(route('api.animethemeentry.show', ['animethemeentry' => $entry])); + $entry->unsetRelations(); - $response->assertJson( - json_decode( - json_encode( - new EntryResource($entry, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.animethemeentry.show', ['animethemeentry' => $entry])); - /** - * The Entry Show Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new EntrySchema(); + $response->assertJson( + json_decode( + json_encode( + new EntryResource($entry, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('allowed include paths', function () { + $schema = new EntrySchema(); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $allowedIncludes = collect($schema->allowedIncludes()); - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->has(Video::factory()->count($this->faker->randomDigitNotNull())) - ->createOne(); + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; - $response = $this->get(route('api.animethemeentry.show', ['animethemeentry' => $entry] + $parameters)); + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->has(Video::factory()->count(fake()->randomDigitNotNull())) + ->createOne(); - $response->assertJson( - json_decode( - json_encode( - new EntryResource($entry, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.animethemeentry.show', ['animethemeentry' => $entry] + $parameters)); - /** - * The Entry Show Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new EntrySchema(); + $response->assertJson( + json_decode( + json_encode( + new EntryResource($entry, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $fields = collect($schema->fields()); +test('sparse fieldsets', function () { + $schema = new EntrySchema(); - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); + $fields = collect($schema->fields()); - $parameters = [ - FieldParser::param() => [ - EntryResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->create(); + $parameters = [ + FieldParser::param() => [ + EntryResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; - $response = $this->get(route('api.animethemeentry.show', ['animethemeentry' => $entry] + $parameters)); + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->create(); - $response->assertJson( - json_decode( - json_encode( - new EntryResource($entry, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.animethemeentry.show', ['animethemeentry' => $entry] + $parameters)); - /** - * The Entry Show Endpoint shall support constrained eager loading of anime by media format. - */ - public function testAnimeByMediaFormat(): void - { - $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); + $response->assertJson( + json_decode( + json_encode( + new EntryResource($entry, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), - ], - IncludeParser::param() => AnimeThemeEntry::RELATION_ANIME, - ]; +test('anime by media format', function () { + $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), + ], + IncludeParser::param() => AnimeThemeEntry::RELATION_ANIME, + ]; - $entry->unsetRelations()->load([ - AnimeThemeEntry::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { - $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); - }, - ]); + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - $response = $this->get(route('api.animethemeentry.show', ['animethemeentry' => $entry] + $parameters)); + $entry->unsetRelations()->load([ + AnimeThemeEntry::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { + $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); + }, + ]); - $response->assertJson( - json_decode( - json_encode( - new EntryResource($entry, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.animethemeentry.show', ['animethemeentry' => $entry] + $parameters)); - /** - * The Entry Show Endpoint shall support constrained eager loading of anime by season. - */ - public function testAnimeBySeason(): void - { - $seasonFilter = Arr::random(AnimeSeason::cases()); + $response->assertJson( + json_decode( + json_encode( + new EntryResource($entry, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), - ], - IncludeParser::param() => AnimeThemeEntry::RELATION_ANIME, - ]; +test('anime by season', function () { + $seasonFilter = Arr::random(AnimeSeason::cases()); - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), + ], + IncludeParser::param() => AnimeThemeEntry::RELATION_ANIME, + ]; - $entry->unsetRelations()->load([ - AnimeThemeEntry::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { - $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); - }, - ]); + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - $response = $this->get(route('api.animethemeentry.show', ['animethemeentry' => $entry] + $parameters)); + $entry->unsetRelations()->load([ + AnimeThemeEntry::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { + $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); + }, + ]); - $response->assertJson( - json_decode( - json_encode( - new EntryResource($entry, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.animethemeentry.show', ['animethemeentry' => $entry] + $parameters)); - /** - * The Entry Show Endpoint shall support constrained eager loading of anime by year. - */ - public function testAnimeByYear(): void - { - $yearFilter = intval($this->faker->year()); - $excludedYear = $yearFilter + 1; + $response->assertJson( + json_decode( + json_encode( + new EntryResource($entry, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_YEAR => $yearFilter, - ], - IncludeParser::param() => AnimeThemeEntry::RELATION_ANIME, - ]; +test('anime by year', function () { + $yearFilter = intval(fake()->year()); + $excludedYear = $yearFilter + 1; - $entry = AnimeThemeEntry::factory() - ->for( - AnimeTheme::factory()->for( - Anime::factory() - ->state([ - Anime::ATTRIBUTE_YEAR => $this->faker->boolean() ? $yearFilter : $excludedYear, - ]) - ) - ) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_YEAR => $yearFilter, + ], + IncludeParser::param() => AnimeThemeEntry::RELATION_ANIME, + ]; - $entry->unsetRelations()->load([ - AnimeThemeEntry::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { - $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); - }, - ]); - - $response = $this->get(route('api.animethemeentry.show', ['animethemeentry' => $entry] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new EntryResource($entry, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Entry Show Endpoint shall support constrained eager loading of themes by sequence. - */ - public function testThemesBySequence(): void - { - $sequenceFilter = $this->faker->randomDigitNotNull(); - $excludedSequence = $sequenceFilter + 1; - - $parameters = [ - FilterParser::param() => [ - AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter, - ], - IncludeParser::param() => AnimeThemeEntry::RELATION_THEME, - ]; - - $entry = AnimeThemeEntry::factory() - ->for( - AnimeTheme::factory() - ->for(Anime::factory()) + $entry = AnimeThemeEntry::factory() + ->for( + AnimeTheme::factory()->for( + Anime::factory() ->state([ - AnimeTheme::ATTRIBUTE_SEQUENCE => $this->faker->boolean() ? $sequenceFilter : $excludedSequence, + Anime::ATTRIBUTE_YEAR => fake()->boolean() ? $yearFilter : $excludedYear, ]) ) - ->createOne(); + ) + ->createOne(); - $entry->unsetRelations()->load([ - AnimeThemeEntry::RELATION_THEME => function (BelongsTo $query) use ($sequenceFilter) { - $query->where(AnimeTheme::ATTRIBUTE_SEQUENCE, $sequenceFilter); - }, - ]); + $entry->unsetRelations()->load([ + AnimeThemeEntry::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { + $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); + }, + ]); - $response = $this->get(route('api.animethemeentry.show', ['animethemeentry' => $entry] + $parameters)); + $response = get(route('api.animethemeentry.show', ['animethemeentry' => $entry] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new EntryResource($entry, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response->assertJson( + json_decode( + json_encode( + new EntryResource($entry, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - /** - * The Entry Show Endpoint shall support constrained eager loading of themes by type. - */ - public function testThemesByType(): void - { - $typeFilter = Arr::random(ThemeType::cases()); +test('themes by sequence', function () { + $sequenceFilter = fake()->randomDigitNotNull(); + $excludedSequence = $sequenceFilter + 1; - $parameters = [ - FilterParser::param() => [ - AnimeTheme::ATTRIBUTE_TYPE => $typeFilter->localize(), - ], - IncludeParser::param() => AnimeThemeEntry::RELATION_THEME, - ]; + $parameters = [ + FilterParser::param() => [ + AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter, + ], + IncludeParser::param() => AnimeThemeEntry::RELATION_THEME, + ]; - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); + $entry = AnimeThemeEntry::factory() + ->for( + AnimeTheme::factory() + ->for(Anime::factory()) + ->state([ + AnimeTheme::ATTRIBUTE_SEQUENCE => fake()->boolean() ? $sequenceFilter : $excludedSequence, + ]) + ) + ->createOne(); - $entry->unsetRelations()->load([ - AnimeThemeEntry::RELATION_THEME => function (BelongsTo $query) use ($typeFilter) { - $query->where(AnimeTheme::ATTRIBUTE_TYPE, $typeFilter->value); - }, - ]); + $entry->unsetRelations()->load([ + AnimeThemeEntry::RELATION_THEME => function (BelongsTo $query) use ($sequenceFilter) { + $query->where(AnimeTheme::ATTRIBUTE_SEQUENCE, $sequenceFilter); + }, + ]); - $response = $this->get(route('api.animethemeentry.show', ['animethemeentry' => $entry] + $parameters)); + $response = get(route('api.animethemeentry.show', ['animethemeentry' => $entry] + $parameters)); - $response->assertJson( - json_decode( - json_encode( - new EntryResource($entry, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response->assertJson( + json_decode( + json_encode( + new EntryResource($entry, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('themes by type', function () { + $typeFilter = Arr::random(ThemeType::cases()); + + $parameters = [ + FilterParser::param() => [ + AnimeTheme::ATTRIBUTE_TYPE => $typeFilter->localize(), + ], + IncludeParser::param() => AnimeThemeEntry::RELATION_THEME, + ]; + + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); + + $entry->unsetRelations()->load([ + AnimeThemeEntry::RELATION_THEME => function (BelongsTo $query) use ($typeFilter) { + $query->where(AnimeTheme::ATTRIBUTE_TYPE, $typeFilter->value); + }, + ]); + + $response = get(route('api.animethemeentry.show', ['animethemeentry' => $entry] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new EntryResource($entry, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Wiki/Anime/Theme/Entry/EntryStoreTest.php b/tests/Feature/Http/Api/Wiki/Anime/Theme/Entry/EntryStoreTest.php index c2b205c90..b2f01b1b9 100644 --- a/tests/Feature/Http/Api/Wiki/Anime/Theme/Entry/EntryStoreTest.php +++ b/tests/Feature/Http/Api/Wiki/Anime/Theme/Entry/EntryStoreTest.php @@ -2,85 +2,65 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Anime\Theme\Entry; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Anime; use App\Models\Wiki\Anime\AnimeTheme; use App\Models\Wiki\Anime\Theme\AnimeThemeEntry; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class EntryStoreTest extends TestCase -{ - /** - * The Entry Store Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->makeOne(); +use function Pest\Laravel\post; - $response = $this->post(route('api.animethemeentry.store', $entry->toArray())); +test('protected', function () { + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->makeOne(); - $response->assertUnauthorized(); - } + $response = post(route('api.animethemeentry.store', $entry->toArray())); - /** - * The Entry Store Endpoint shall forbid users without the create anime theme entry permission. - */ - public function testForbidden(): void - { - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->makeOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->makeOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->post(route('api.animethemeentry.store', $entry->toArray())); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.animethemeentry.store', $entry->toArray())); - /** - * The Entry Store Endpoint shall require the theme_id field. - */ - public function testRequiredFields(): void - { - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(AnimeThemeEntry::class))->createOne(); + $response->assertForbidden(); +}); - Sanctum::actingAs($user); +test('required fields', function () { + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(AnimeThemeEntry::class))->createOne(); - $response = $this->post(route('api.animethemeentry.store')); + Sanctum::actingAs($user); - $response->assertJsonValidationErrors([ - AnimeThemeEntry::ATTRIBUTE_THEME, - ]); - } + $response = post(route('api.animethemeentry.store')); - /** - * The Entry Store Endpoint shall create an entry. - */ - public function testCreate(): void - { - $theme = AnimeTheme::factory()->for(Anime::factory())->createOne(); + $response->assertJsonValidationErrors([ + AnimeThemeEntry::ATTRIBUTE_THEME, + ]); +}); - $parameters = array_merge( - AnimeThemeEntry::factory()->raw(), - [AnimeThemeEntry::ATTRIBUTE_THEME => $theme->getKey()], - ); +test('create', function () { + $theme = AnimeTheme::factory()->for(Anime::factory())->createOne(); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(AnimeThemeEntry::class))->createOne(); + $parameters = array_merge( + AnimeThemeEntry::factory()->raw(), + [AnimeThemeEntry::ATTRIBUTE_THEME => $theme->getKey()], + ); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(AnimeThemeEntry::class))->createOne(); - $response = $this->post(route('api.animethemeentry.store', $parameters)); + Sanctum::actingAs($user); - $response->assertCreated(); - static::assertDatabaseCount(AnimeThemeEntry::class, 1); - } -} + $response = post(route('api.animethemeentry.store', $parameters)); + + $response->assertCreated(); + $this->assertDatabaseCount(AnimeThemeEntry::class, 1); +}); diff --git a/tests/Feature/Http/Api/Wiki/Anime/Theme/Entry/EntryUpdateTest.php b/tests/Feature/Http/Api/Wiki/Anime/Theme/Entry/EntryUpdateTest.php index 0520c3b60..bbc17ab41 100644 --- a/tests/Feature/Http/Api/Wiki/Anime/Theme/Entry/EntryUpdateTest.php +++ b/tests/Feature/Http/Api/Wiki/Anime/Theme/Entry/EntryUpdateTest.php @@ -2,92 +2,72 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Anime\Theme\Entry; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Anime; use App\Models\Wiki\Anime\AnimeTheme; use App\Models\Wiki\Anime\Theme\AnimeThemeEntry; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class EntryUpdateTest extends TestCase -{ - /** - * The Entry Update Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); +use function Pest\Laravel\put; - $parameters = AnimeThemeEntry::factory()->raw(); +test('protected', function () { + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - $response = $this->put(route('api.animethemeentry.update', ['animethemeentry' => $entry] + $parameters)); + $parameters = AnimeThemeEntry::factory()->raw(); - $response->assertUnauthorized(); - } + $response = put(route('api.animethemeentry.update', ['animethemeentry' => $entry] + $parameters)); - /** - * The Entry Update Endpoint shall forbid users without the update anime theme entry permission. - */ - public function testForbidden(): void - { - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); + $response->assertUnauthorized(); +}); - $parameters = AnimeThemeEntry::factory()->raw(); +test('forbidden', function () { + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - $user = User::factory()->createOne(); + $parameters = AnimeThemeEntry::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->put(route('api.animethemeentry.update', ['animethemeentry' => $entry] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.animethemeentry.update', ['animethemeentry' => $entry] + $parameters)); - /** - * The Entry Update Endpoint shall forbid users from updating an anime theme entry that is trashed. - */ - public function testTrashed(): void - { - $entry = AnimeThemeEntry::factory() - ->trashed() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); + $response->assertForbidden(); +}); - $parameters = AnimeThemeEntry::factory()->raw(); +test('trashed', function () { + $entry = AnimeThemeEntry::factory() + ->trashed() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(AnimeThemeEntry::class))->createOne(); + $parameters = AnimeThemeEntry::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(AnimeThemeEntry::class))->createOne(); - $response = $this->put(route('api.animethemeentry.update', ['animethemeentry' => $entry] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.animethemeentry.update', ['animethemeentry' => $entry] + $parameters)); - /** - * The Entry Update Endpoint shall update an entry. - */ - public function testUpdate(): void - { - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); + $response->assertForbidden(); +}); - $parameters = AnimeThemeEntry::factory()->raw(); +test('update', function () { + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(AnimeThemeEntry::class))->createOne(); + $parameters = AnimeThemeEntry::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(AnimeThemeEntry::class))->createOne(); - $response = $this->put(route('api.animethemeentry.update', ['animethemeentry' => $entry] + $parameters)); + Sanctum::actingAs($user); - $response->assertOk(); - } -} + $response = put(route('api.animethemeentry.update', ['animethemeentry' => $entry] + $parameters)); + + $response->assertOk(); +}); diff --git a/tests/Feature/Http/Api/Wiki/Anime/Theme/ThemeDestroyTest.php b/tests/Feature/Http/Api/Wiki/Anime/Theme/ThemeDestroyTest.php index 32d2a2dec..f8cb2b46e 100644 --- a/tests/Feature/Http/Api/Wiki/Anime/Theme/ThemeDestroyTest.php +++ b/tests/Feature/Http/Api/Wiki/Anime/Theme/ThemeDestroyTest.php @@ -2,78 +2,58 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Anime\Theme; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Anime; use App\Models\Wiki\Anime\AnimeTheme; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ThemeDestroyTest extends TestCase -{ - /** - * The Theme Destroy Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $theme = AnimeTheme::factory()->for(Anime::factory())->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.animetheme.destroy', ['animetheme' => $theme])); +test('protected', function () { + $theme = AnimeTheme::factory()->for(Anime::factory())->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.animetheme.destroy', ['animetheme' => $theme])); - /** - * The Theme Destroy Endpoint shall forbid users without the delete anime theme permission. - */ - public function testForbidden(): void - { - $theme = AnimeTheme::factory()->for(Anime::factory())->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $theme = AnimeTheme::factory()->for(Anime::factory())->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.animetheme.destroy', ['animetheme' => $theme])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.animetheme.destroy', ['animetheme' => $theme])); - /** - * The Theme Destroy Endpoint shall forbid users from updating an anime theme that is trashed. - */ - public function testTrashed(): void - { - $theme = AnimeTheme::factory() - ->trashed() - ->for(Anime::factory()) - ->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(AnimeTheme::class))->createOne(); +test('trashed', function () { + $theme = AnimeTheme::factory() + ->trashed() + ->for(Anime::factory()) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(AnimeTheme::class))->createOne(); - $response = $this->delete(route('api.animetheme.destroy', ['animetheme' => $theme])); + Sanctum::actingAs($user); - $response->assertNotFound(); - } + $response = delete(route('api.animetheme.destroy', ['animetheme' => $theme])); - /** - * The Theme Destroy Endpoint shall delete the theme. - */ - public function testDeleted(): void - { - $theme = AnimeTheme::factory()->for(Anime::factory())->createOne(); + $response->assertNotFound(); +}); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(AnimeTheme::class))->createOne(); +test('deleted', function () { + $theme = AnimeTheme::factory()->for(Anime::factory())->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(AnimeTheme::class))->createOne(); - $response = $this->delete(route('api.animetheme.destroy', ['animetheme' => $theme])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertSoftDeleted($theme); - } -} + $response = delete(route('api.animetheme.destroy', ['animetheme' => $theme])); + + $response->assertOk(); + $this->assertSoftDeleted($theme); +}); diff --git a/tests/Feature/Http/Api/Wiki/Anime/Theme/ThemeForceDeleteTest.php b/tests/Feature/Http/Api/Wiki/Anime/Theme/ThemeForceDeleteTest.php index 3c0a7ee0d..9a02e2529 100644 --- a/tests/Feature/Http/Api/Wiki/Anime/Theme/ThemeForceDeleteTest.php +++ b/tests/Feature/Http/Api/Wiki/Anime/Theme/ThemeForceDeleteTest.php @@ -2,59 +2,43 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Anime\Theme; - use App\Enums\Auth\ExtendedCrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Anime; use App\Models\Wiki\Anime\AnimeTheme; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ThemeForceDeleteTest extends TestCase -{ - /** - * The Theme Force Delete Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $theme = AnimeTheme::factory()->for(Anime::factory())->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.animetheme.forceDelete', ['animetheme' => $theme])); +test('protected', function () { + $theme = AnimeTheme::factory()->for(Anime::factory())->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.animetheme.forceDelete', ['animetheme' => $theme])); - /** - * The Theme Force Delete Endpoint shall forbid users without the force delete anime theme permission. - */ - public function testForbidden(): void - { - $theme = AnimeTheme::factory()->for(Anime::factory())->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $theme = AnimeTheme::factory()->for(Anime::factory())->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.animetheme.forceDelete', ['animetheme' => $theme])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.animetheme.forceDelete', ['animetheme' => $theme])); - /** - * The Theme Force Delete Endpoint shall force delete the theme. - */ - public function testDeleted(): void - { - $theme = AnimeTheme::factory()->for(Anime::factory())->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::FORCE_DELETE->format(AnimeTheme::class))->createOne(); +test('deleted', function () { + $theme = AnimeTheme::factory()->for(Anime::factory())->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::FORCE_DELETE->format(AnimeTheme::class))->createOne(); - $response = $this->delete(route('api.animetheme.forceDelete', ['animetheme' => $theme])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertModelMissing($theme); - } -} + $response = delete(route('api.animetheme.forceDelete', ['animetheme' => $theme])); + + $response->assertOk(); + $this->assertModelMissing($theme); +}); diff --git a/tests/Feature/Http/Api/Wiki/Anime/Theme/ThemeIndexTest.php b/tests/Feature/Http/Api/Wiki/Anime/Theme/ThemeIndexTest.php index 6580550de..9a7fa03a2 100644 --- a/tests/Feature/Http/Api/Wiki/Anime/Theme/ThemeIndexTest.php +++ b/tests/Feature/Http/Api/Wiki/Anime/Theme/ThemeIndexTest.php @@ -2,9 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Anime\Theme; - -use App\Concerns\Actions\Http\Api\SortsModels; use App\Constants\ModelConstants; use App\Contracts\Http\Api\Field\SortableField; use App\Enums\Http\Api\Filter\TrashedStatus; @@ -42,1144 +39,1034 @@ use Illuminate\Database\Eloquent\Factories\Sequence; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\HasMany; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; -use Tests\TestCase; -class ThemeIndexTest extends TestCase -{ - use SortsModels; - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the Theme Index Endpoint shall return a collection of Theme Resources. - */ - public function testDefault(): void - { +uses(App\Concerns\Actions\Http\Api\SortsModels::class); + +uses(Illuminate\Foundation\Testing\WithFaker::class); + +test('default', function () { + AnimeTheme::factory() + ->for(Anime::factory()) + ->for(Group::factory()) + ->for(Song::factory()) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $themes = AnimeTheme::all(); + + $response = get(route('api.animetheme.index')); + + $response->assertJson( + json_decode( + json_encode( + new ThemeCollection($themes, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('paginated', function () { + AnimeTheme::factory() + ->for(Anime::factory()) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $response = get(route('api.animetheme.index')); + + $response->assertJsonStructure([ + ThemeCollection::$wrap, + 'links', + 'meta', + ]); +}); + +test('allowed include paths', function () { + $schema = new ThemeSchema(); + + $allowedIncludes = collect($schema->allowedIncludes()); + + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); + + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; + + AnimeTheme::factory() + ->for(Anime::factory()) + ->for(Group::factory()) + ->for(Song::factory()) + ->has( + AnimeThemeEntry::factory() + ->count(fake()->randomDigitNotNull()) + ->has(Video::factory()->count(fake()->randomDigitNotNull())) + ) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $themes = AnimeTheme::with($includedPaths->all())->get(); + + $response = get(route('api.animetheme.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ThemeCollection($themes, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sparse fieldsets', function () { + $schema = new ThemeSchema(); + + $fields = collect($schema->fields()); + + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + ThemeResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + AnimeTheme::factory() + ->for(Anime::factory()) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $themes = AnimeTheme::all(); + + $response = get(route('api.animetheme.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ThemeCollection($themes, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sorts', function () { + $schema = new ThemeSchema(); + + /** @var Sort $sort */ + $sort = collect($schema->fields()) + ->filter(fn (Field $field) => $field instanceof SortableField) + ->map(fn (SortableField $field) => $field->getSort()) + ->random(); + + $parameters = [ + SortParser::param() => $sort->format(Arr::random(Direction::cases())), + ]; + + $query = new Query($parameters); + + AnimeTheme::factory() + ->for(Anime::factory()) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $response = get(route('api.animetheme.index', $parameters)); + + $themes = $this->sort(AnimeTheme::query(), $query, $schema)->get(); + + $response->assertJson( + json_decode( + json_encode( + new ThemeCollection($themes, $query) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('created at filter', function () { + $createdFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($createdFilter, function () { AnimeTheme::factory() ->for(Anime::factory()) - ->for(Group::factory()) - ->for(Song::factory()) - ->count($this->faker->randomDigitNotNull()) + ->count(fake()->randomDigitNotNull()) ->create(); + }); - $themes = AnimeTheme::all(); - - $response = $this->get(route('api.animetheme.index')); - - $response->assertJson( - json_decode( - json_encode( - new ThemeCollection($themes, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Theme Index Endpoint shall be paginated. - */ - public function testPaginated(): void - { + Carbon::withTestNow($excludedDate, function () { AnimeTheme::factory() ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) + ->count(fake()->randomDigitNotNull()) ->create(); + }); - $response = $this->get(route('api.animetheme.index')); + $theme = AnimeTheme::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - $response->assertJsonStructure([ - ThemeCollection::$wrap, - 'links', - 'meta', - ]); - } + $response = get(route('api.animetheme.index', $parameters)); - /** - * The Theme Index Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new ThemeSchema(); + $response->assertJson( + json_decode( + json_encode( + new ThemeCollection($theme, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('updated at filter', function () { + $updatedFilter = fake()->date(); + $excludedDate = fake()->date(); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); - - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + Carbon::withTestNow($updatedFilter, function () { AnimeTheme::factory() ->for(Anime::factory()) - ->for(Group::factory()) - ->for(Song::factory()) - ->has( - AnimeThemeEntry::factory() - ->count($this->faker->randomDigitNotNull()) - ->has(Video::factory()->count($this->faker->randomDigitNotNull())) - ) - ->count($this->faker->randomDigitNotNull()) + ->count(fake()->randomDigitNotNull()) ->create(); + }); - $themes = AnimeTheme::with($includedPaths->all())->get(); - - $response = $this->get(route('api.animetheme.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ThemeCollection($themes, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Theme Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new ThemeSchema(); - - $fields = collect($schema->fields()); - - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); - - $parameters = [ - FieldParser::param() => [ - ThemeResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; - + Carbon::withTestNow($excludedDate, function () { AnimeTheme::factory() ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) + ->count(fake()->randomDigitNotNull()) ->create(); + }); - $themes = AnimeTheme::all(); + $theme = AnimeTheme::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - $response = $this->get(route('api.animetheme.index', $parameters)); + $response = get(route('api.animetheme.index', $parameters)); - $response->assertJson( - json_decode( - json_encode( - new ThemeCollection($themes, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response->assertJson( + json_decode( + json_encode( + new ThemeCollection($theme, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - /** - * The Theme Index Endpoint shall support sorting resources. - */ - public function testSorts(): void - { - $schema = new ThemeSchema(); +test('without trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITHOUT->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; - /** @var Sort $sort */ - $sort = collect($schema->fields()) - ->filter(fn (Field $field) => $field instanceof SortableField) - ->map(fn (SortableField $field) => $field->getSort()) - ->random(); + AnimeTheme::factory() + ->for(Anime::factory()) + ->count(fake()->randomDigitNotNull()) + ->create(); - $parameters = [ - SortParser::param() => $sort->format(Arr::random(Direction::cases())), - ]; + AnimeTheme::factory() + ->trashed() + ->for(Anime::factory()) + ->count(fake()->randomDigitNotNull()) + ->create(); - $query = new Query($parameters); + $theme = AnimeTheme::withoutTrashed()->get(); + $response = get(route('api.animetheme.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ThemeCollection($theme, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('with trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + AnimeTheme::factory() + ->for(Anime::factory()) + ->count(fake()->randomDigitNotNull()) + ->create(); + + AnimeTheme::factory() + ->trashed() + ->for(Anime::factory()) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $theme = AnimeTheme::withTrashed()->get(); + + $response = get(route('api.animetheme.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ThemeCollection($theme, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('only trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::ONLY->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + AnimeTheme::factory() + ->for(Anime::factory()) + ->count(fake()->randomDigitNotNull()) + ->create(); + + AnimeTheme::factory() + ->trashed() + ->for(Anime::factory()) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $theme = AnimeTheme::onlyTrashed()->get(); + + $response = get(route('api.animetheme.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ThemeCollection($theme, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('deleted at filter', function () { + $deletedFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + ModelConstants::ATTRIBUTE_DELETED_AT => $deletedFilter, + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($deletedFilter, function () { AnimeTheme::factory() ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) + ->count(fake()->randomDigitNotNull()) ->create(); + }); - $response = $this->get(route('api.animetheme.index', $parameters)); - - $themes = $this->sort(AnimeTheme::query(), $query, $schema)->get(); - - $response->assertJson( - json_decode( - json_encode( - new ThemeCollection($themes, $query) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Theme Index Endpoint shall support filtering by created_at. - */ - public function testCreatedAtFilter(): void - { - $createdFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($createdFilter, function () { - AnimeTheme::factory() - ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) - ->create(); - }); - - Carbon::withTestNow($excludedDate, function () { - AnimeTheme::factory() - ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) - ->create(); - }); - - $theme = AnimeTheme::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - - $response = $this->get(route('api.animetheme.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ThemeCollection($theme, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Theme Index Endpoint shall support filtering by updated_at. - */ - public function testUpdatedAtFilter(): void - { - $updatedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($updatedFilter, function () { - AnimeTheme::factory() - ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) - ->create(); - }); - - Carbon::withTestNow($excludedDate, function () { - AnimeTheme::factory() - ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) - ->create(); - }); - - $theme = AnimeTheme::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - - $response = $this->get(route('api.animetheme.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ThemeCollection($theme, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Theme Index Endpoint shall support filtering by trashed. - */ - public function testWithoutTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITHOUT->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - + Carbon::withTestNow($excludedDate, function () { AnimeTheme::factory() ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) + ->count(fake()->randomDigitNotNull()) ->create(); - - AnimeTheme::factory() - ->trashed() - ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $theme = AnimeTheme::withoutTrashed()->get(); - - $response = $this->get(route('api.animetheme.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ThemeCollection($theme, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Theme Index Endpoint shall support filtering by trashed. - */ - public function testWithTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - AnimeTheme::factory() - ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - AnimeTheme::factory() - ->trashed() - ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $theme = AnimeTheme::withTrashed()->get(); - - $response = $this->get(route('api.animetheme.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ThemeCollection($theme, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Theme Index Endpoint shall support filtering by trashed. - */ - public function testOnlyTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::ONLY->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - AnimeTheme::factory() - ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - AnimeTheme::factory() - ->trashed() - ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $theme = AnimeTheme::onlyTrashed()->get(); - - $response = $this->get(route('api.animetheme.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ThemeCollection($theme, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Theme Index Endpoint shall support filtering by deleted_at. - */ - public function testDeletedAtFilter(): void - { - $deletedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - ModelConstants::ATTRIBUTE_DELETED_AT => $deletedFilter, - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($deletedFilter, function () { - AnimeTheme::factory() - ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) - ->create(); - }); - - Carbon::withTestNow($excludedDate, function () { - AnimeTheme::factory() - ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) - ->create(); - }); - - $theme = AnimeTheme::withTrashed()->where(ModelConstants::ATTRIBUTE_DELETED_AT, $deletedFilter)->get(); - - $response = $this->get(route('api.animetheme.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ThemeCollection($theme, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Theme Index Endpoint shall support filtering by sequence. - */ - public function testSequenceFilter(): void - { - $sequenceFilter = $this->faker->randomDigitNotNull(); - $excludedSequence = $sequenceFilter + 1; - - $parameters = [ - FilterParser::param() => [ - AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter, - ], - ]; - - AnimeTheme::factory() - ->for(Anime::factory()) - ->state(new Sequence( - [AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter], - [AnimeTheme::ATTRIBUTE_SEQUENCE => $excludedSequence], - )) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $themes = AnimeTheme::query()->where(AnimeTheme::ATTRIBUTE_SEQUENCE, $sequenceFilter)->get(); - - $response = $this->get(route('api.animetheme.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ThemeCollection($themes, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Theme Index Endpoint shall support filtering by type. - */ - public function testTypeFilter(): void - { - $typeFilter = Arr::random(ThemeType::cases()); - - $parameters = [ - FilterParser::param() => [ - AnimeTheme::ATTRIBUTE_TYPE => $typeFilter->localize(), - ], - ]; - - AnimeTheme::factory() - ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $themes = AnimeTheme::query()->where(AnimeTheme::ATTRIBUTE_TYPE, $typeFilter->value)->get(); - - $response = $this->get(route('api.animetheme.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ThemeCollection($themes, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Theme Index Endpoint shall support constrained eager loading of anime by media format. - */ - public function testAnimeByMediaFormat(): void - { - $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), - ], - IncludeParser::param() => AnimeTheme::RELATION_ANIME, - ]; - - AnimeTheme::factory() - ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $themes = AnimeTheme::with([ - AnimeTheme::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { - $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.animetheme.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ThemeCollection($themes, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Theme Index Endpoint shall support constrained eager loading of anime by season. - */ - public function testAnimeBySeason(): void - { - $seasonFilter = Arr::random(AnimeSeason::cases()); - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), - ], - IncludeParser::param() => AnimeTheme::RELATION_ANIME, - ]; - - AnimeTheme::factory() - ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $themes = AnimeTheme::with([ - AnimeTheme::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { - $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.animetheme.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ThemeCollection($themes, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Theme Index Endpoint shall support constrained eager loading of anime by year. - */ - public function testAnimeByYear(): void - { - $yearFilter = intval($this->faker->year()); - $excludedYear = $yearFilter + 1; - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_YEAR => $yearFilter, - ], - IncludeParser::param() => AnimeTheme::RELATION_ANIME, - ]; - - AnimeTheme::factory() - ->for( - Anime::factory() - ->state([ - Anime::ATTRIBUTE_YEAR => $this->faker->boolean() ? $yearFilter : $excludedYear, - ]) - ) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $themes = AnimeTheme::with([ - AnimeTheme::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { - $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); - }, - ]) - ->get(); - - $response = $this->get(route('api.animetheme.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ThemeCollection($themes, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Theme Index Endpoint shall support constrained eager loading of images by facet. - */ - public function testImagesByFacet(): void - { - $facetFilter = Arr::random(ImageFacet::cases()); - - $parameters = [ - FilterParser::param() => [ - Image::ATTRIBUTE_FACET => $facetFilter->localize(), - ], - IncludeParser::param() => AnimeTheme::RELATION_IMAGES, - ]; - - AnimeTheme::factory() - ->for( - Anime::factory() - ->has(Image::factory()->count($this->faker->randomDigitNotNull())) - ) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $themes = AnimeTheme::with([ - AnimeTheme::RELATION_IMAGES => function (BelongsToMany $query) use ($facetFilter) { - $query->where(Image::ATTRIBUTE_FACET, $facetFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.animetheme.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ThemeCollection($themes, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Theme Index Endpoint shall support constrained eager loading of entries by nsfw. - */ - public function testEntriesByNsfw(): void - { - $nsfwFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - AnimeThemeEntry::ATTRIBUTE_NSFW => $nsfwFilter, - ], - IncludeParser::param() => AnimeTheme::RELATION_ENTRIES, - ]; - - AnimeTheme::factory() - ->for(Anime::factory()) - ->has(AnimeThemeEntry::factory()->count($this->faker->randomDigitNotNull())) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $themes = AnimeTheme::with([ - AnimeTheme::RELATION_ENTRIES => function (HasMany $query) use ($nsfwFilter) { - $query->where(AnimeThemeEntry::ATTRIBUTE_NSFW, $nsfwFilter); - }, - ]) - ->get(); - - $response = $this->get(route('api.animetheme.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ThemeCollection($themes, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Index Endpoint shall support constrained eager loading of entries by spoiler. - */ - public function testEntriesBySpoiler(): void - { - $spoilerFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - AnimeThemeEntry::ATTRIBUTE_SPOILER => $spoilerFilter, - ], - IncludeParser::param() => AnimeTheme::RELATION_ENTRIES, - ]; - - AnimeTheme::factory() - ->for(Anime::factory()) - ->has(AnimeThemeEntry::factory()->count($this->faker->randomDigitNotNull())) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $themes = AnimeTheme::with([ - AnimeTheme::RELATION_ENTRIES => function (HasMany $query) use ($spoilerFilter) { - $query->where(AnimeThemeEntry::ATTRIBUTE_SPOILER, $spoilerFilter); - }, - ]) - ->get(); - - $response = $this->get(route('api.animetheme.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ThemeCollection($themes, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Index Endpoint shall support constrained eager loading of entries by version. - */ - public function testEntriesByVersion(): void - { - $versionFilter = $this->faker->randomDigitNotNull(); - $excludedVersion = $versionFilter + 1; - - $parameters = [ - FilterParser::param() => [ - AnimeThemeEntry::ATTRIBUTE_VERSION => $versionFilter, - ], - IncludeParser::param() => AnimeTheme::RELATION_ENTRIES, - ]; - - AnimeTheme::factory() - ->for(Anime::factory()) - ->has( - AnimeThemeEntry::factory() - ->count($this->faker->randomDigitNotNull()) - ->state(new Sequence( - [AnimeThemeEntry::ATTRIBUTE_VERSION => $versionFilter], - [AnimeThemeEntry::ATTRIBUTE_VERSION => $excludedVersion], - )) - ) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $themes = AnimeTheme::with([ - AnimeTheme::RELATION_ENTRIES => function (HasMany $query) use ($versionFilter) { - $query->where(AnimeThemeEntry::ATTRIBUTE_VERSION, $versionFilter); - }, - ]) - ->get(); - - $response = $this->get(route('api.animetheme.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ThemeCollection($themes, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Theme Index Endpoint shall support constrained eager loading of videos by lyrics. - */ - public function testVideosByLyrics(): void - { - $lyricsFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_LYRICS => $lyricsFilter, - ], - IncludeParser::param() => AnimeTheme::RELATION_VIDEOS, - ]; - - AnimeTheme::factory() - ->for(Anime::factory()) - ->has( - AnimeThemeEntry::factory() - ->count($this->faker->randomDigitNotNull()) - ->has(Video::factory()->count($this->faker->randomDigitNotNull())) - ) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $themes = AnimeTheme::with([ - AnimeTheme::RELATION_VIDEOS => function (BelongsToMany $query) use ($lyricsFilter) { - $query->where(Video::ATTRIBUTE_LYRICS, $lyricsFilter); - }, - ]) - ->get(); - - $response = $this->get(route('api.animetheme.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ThemeCollection($themes, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Theme Index Endpoint shall support constrained eager loading of videos by nc. - */ - public function testVideosByNc(): void - { - $ncFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_NC => $ncFilter, - ], - IncludeParser::param() => AnimeTheme::RELATION_VIDEOS, - ]; - - AnimeTheme::factory() - ->for(Anime::factory()) - ->has( - AnimeThemeEntry::factory() - ->count($this->faker->randomDigitNotNull()) - ->has(Video::factory()->count($this->faker->randomDigitNotNull())) - ) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $themes = AnimeTheme::with([ - AnimeTheme::RELATION_VIDEOS => function (BelongsToMany $query) use ($ncFilter) { - $query->where(Video::ATTRIBUTE_NC, $ncFilter); - }, - ]) - ->get(); - - $response = $this->get(route('api.animetheme.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ThemeCollection($themes, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Theme Index Endpoint shall support constrained eager loading of videos by overlap. - */ - public function testVideosByOverlap(): void - { - $overlapFilter = Arr::random(VideoOverlap::cases()); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_OVERLAP => $overlapFilter->localize(), - ], - IncludeParser::param() => AnimeTheme::RELATION_VIDEOS, - ]; - - AnimeTheme::factory() - ->for(Anime::factory()) - ->has( - AnimeThemeEntry::factory() - ->count($this->faker->randomDigitNotNull()) - ->has(Video::factory()->count($this->faker->randomDigitNotNull())) - ) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $themes = AnimeTheme::with([ - AnimeTheme::RELATION_VIDEOS => function (BelongsToMany $query) use ($overlapFilter) { - $query->where(Video::ATTRIBUTE_OVERLAP, $overlapFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.animetheme.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ThemeCollection($themes, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Theme Index Endpoint shall support constrained eager loading of videos by resolution. - */ - public function testVideosByResolution(): void - { - $resolutionFilter = $this->faker->randomNumber(); - $excludedResolution = $resolutionFilter + 1; - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_RESOLUTION => $resolutionFilter, - ], - IncludeParser::param() => AnimeTheme::RELATION_VIDEOS, - ]; - - AnimeTheme::factory() - ->for(Anime::factory()) - ->has( - AnimeThemeEntry::factory() - ->count($this->faker->randomDigitNotNull()) - ->has( - Video::factory() - ->count($this->faker->randomDigitNotNull()) - ->state(new Sequence( - [Video::ATTRIBUTE_RESOLUTION => $resolutionFilter], - [Video::ATTRIBUTE_RESOLUTION => $excludedResolution], - )) - ) - ) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $themes = AnimeTheme::with([ - AnimeTheme::RELATION_VIDEOS => function (BelongsToMany $query) use ($resolutionFilter) { - $query->where(Video::ATTRIBUTE_RESOLUTION, $resolutionFilter); - }, - ]) - ->get(); - - $response = $this->get(route('api.animetheme.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ThemeCollection($themes, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Theme Index Endpoint shall support constrained eager loading of videos by source. - */ - public function testVideosBySource(): void - { - $sourceFilter = Arr::random(VideoSource::cases()); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_SOURCE => $sourceFilter->localize(), - ], - IncludeParser::param() => AnimeTheme::RELATION_VIDEOS, - ]; - - AnimeTheme::factory() - ->for(Anime::factory()) - ->has( - AnimeThemeEntry::factory() - ->count($this->faker->randomDigitNotNull()) - ->has(Video::factory()->count($this->faker->randomDigitNotNull())) - ) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $themes = AnimeTheme::with([ - AnimeTheme::RELATION_VIDEOS => function (BelongsToMany $query) use ($sourceFilter) { - $query->where(Video::ATTRIBUTE_SOURCE, $sourceFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.animetheme.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ThemeCollection($themes, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Theme Index Endpoint shall support constrained eager loading of videos by subbed. - */ - public function testVideosBySubbed(): void - { - $subbedFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_SUBBED => $subbedFilter, - ], - IncludeParser::param() => AnimeTheme::RELATION_VIDEOS, - ]; - - AnimeTheme::factory() - ->for(Anime::factory()) - ->has( - AnimeThemeEntry::factory() - ->count($this->faker->randomDigitNotNull()) - ->has(Video::factory()->count($this->faker->randomDigitNotNull())) - ) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $themes = AnimeTheme::with([ - AnimeTheme::RELATION_VIDEOS => function (BelongsToMany $query) use ($subbedFilter) { - $query->where(Video::ATTRIBUTE_SUBBED, $subbedFilter); - }, - ]) - ->get(); - - $response = $this->get(route('api.animetheme.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ThemeCollection($themes, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Theme Index Endpoint shall support constrained eager loading of videos by uncen. - */ - public function testVideosByUncen(): void - { - $uncenFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_UNCEN => $uncenFilter, - ], - IncludeParser::param() => AnimeTheme::RELATION_VIDEOS, - ]; - - AnimeTheme::factory() - ->for(Anime::factory()) - ->has( - AnimeThemeEntry::factory() - ->count($this->faker->randomDigitNotNull()) - ->has(Video::factory()->count($this->faker->randomDigitNotNull())) - ) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $themes = AnimeTheme::with([ - AnimeTheme::RELATION_VIDEOS => function (BelongsToMany $query) use ($uncenFilter) { - $query->where(Video::ATTRIBUTE_UNCEN, $uncenFilter); - }, - ]) - ->get(); - - $response = $this->get(route('api.animetheme.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ThemeCollection($themes, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + }); + + $theme = AnimeTheme::withTrashed()->where(ModelConstants::ATTRIBUTE_DELETED_AT, $deletedFilter)->get(); + + $response = get(route('api.animetheme.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ThemeCollection($theme, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sequence filter', function () { + $sequenceFilter = fake()->randomDigitNotNull(); + $excludedSequence = $sequenceFilter + 1; + + $parameters = [ + FilterParser::param() => [ + AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter, + ], + ]; + + AnimeTheme::factory() + ->for(Anime::factory()) + ->state(new Sequence( + [AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter], + [AnimeTheme::ATTRIBUTE_SEQUENCE => $excludedSequence], + )) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $themes = AnimeTheme::query()->where(AnimeTheme::ATTRIBUTE_SEQUENCE, $sequenceFilter)->get(); + + $response = get(route('api.animetheme.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ThemeCollection($themes, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('type filter', function () { + $typeFilter = Arr::random(ThemeType::cases()); + + $parameters = [ + FilterParser::param() => [ + AnimeTheme::ATTRIBUTE_TYPE => $typeFilter->localize(), + ], + ]; + + AnimeTheme::factory() + ->for(Anime::factory()) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $themes = AnimeTheme::query()->where(AnimeTheme::ATTRIBUTE_TYPE, $typeFilter->value)->get(); + + $response = get(route('api.animetheme.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ThemeCollection($themes, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by media format', function () { + $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), + ], + IncludeParser::param() => AnimeTheme::RELATION_ANIME, + ]; + + AnimeTheme::factory() + ->for(Anime::factory()) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $themes = AnimeTheme::with([ + AnimeTheme::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { + $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); + }, + ]) + ->get(); + + $response = get(route('api.animetheme.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ThemeCollection($themes, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by season', function () { + $seasonFilter = Arr::random(AnimeSeason::cases()); + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), + ], + IncludeParser::param() => AnimeTheme::RELATION_ANIME, + ]; + + AnimeTheme::factory() + ->for(Anime::factory()) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $themes = AnimeTheme::with([ + AnimeTheme::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { + $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); + }, + ]) + ->get(); + + $response = get(route('api.animetheme.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ThemeCollection($themes, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by year', function () { + $yearFilter = intval(fake()->year()); + $excludedYear = $yearFilter + 1; + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_YEAR => $yearFilter, + ], + IncludeParser::param() => AnimeTheme::RELATION_ANIME, + ]; + + AnimeTheme::factory() + ->for( + Anime::factory() + ->state([ + Anime::ATTRIBUTE_YEAR => fake()->boolean() ? $yearFilter : $excludedYear, + ]) + ) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $themes = AnimeTheme::with([ + AnimeTheme::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { + $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); + }, + ]) + ->get(); + + $response = get(route('api.animetheme.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ThemeCollection($themes, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('images by facet', function () { + $facetFilter = Arr::random(ImageFacet::cases()); + + $parameters = [ + FilterParser::param() => [ + Image::ATTRIBUTE_FACET => $facetFilter->localize(), + ], + IncludeParser::param() => AnimeTheme::RELATION_IMAGES, + ]; + + AnimeTheme::factory() + ->for( + Anime::factory() + ->has(Image::factory()->count(fake()->randomDigitNotNull())) + ) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $themes = AnimeTheme::with([ + AnimeTheme::RELATION_IMAGES => function (BelongsToMany $query) use ($facetFilter) { + $query->where(Image::ATTRIBUTE_FACET, $facetFilter->value); + }, + ]) + ->get(); + + $response = get(route('api.animetheme.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ThemeCollection($themes, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('entries by nsfw', function () { + $nsfwFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + AnimeThemeEntry::ATTRIBUTE_NSFW => $nsfwFilter, + ], + IncludeParser::param() => AnimeTheme::RELATION_ENTRIES, + ]; + + AnimeTheme::factory() + ->for(Anime::factory()) + ->has(AnimeThemeEntry::factory()->count(fake()->randomDigitNotNull())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $themes = AnimeTheme::with([ + AnimeTheme::RELATION_ENTRIES => function (HasMany $query) use ($nsfwFilter) { + $query->where(AnimeThemeEntry::ATTRIBUTE_NSFW, $nsfwFilter); + }, + ]) + ->get(); + + $response = get(route('api.animetheme.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ThemeCollection($themes, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('entries by spoiler', function () { + $spoilerFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + AnimeThemeEntry::ATTRIBUTE_SPOILER => $spoilerFilter, + ], + IncludeParser::param() => AnimeTheme::RELATION_ENTRIES, + ]; + + AnimeTheme::factory() + ->for(Anime::factory()) + ->has(AnimeThemeEntry::factory()->count(fake()->randomDigitNotNull())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $themes = AnimeTheme::with([ + AnimeTheme::RELATION_ENTRIES => function (HasMany $query) use ($spoilerFilter) { + $query->where(AnimeThemeEntry::ATTRIBUTE_SPOILER, $spoilerFilter); + }, + ]) + ->get(); + + $response = get(route('api.animetheme.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ThemeCollection($themes, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('entries by version', function () { + $versionFilter = fake()->randomDigitNotNull(); + $excludedVersion = $versionFilter + 1; + + $parameters = [ + FilterParser::param() => [ + AnimeThemeEntry::ATTRIBUTE_VERSION => $versionFilter, + ], + IncludeParser::param() => AnimeTheme::RELATION_ENTRIES, + ]; + + AnimeTheme::factory() + ->for(Anime::factory()) + ->has( + AnimeThemeEntry::factory() + ->count(fake()->randomDigitNotNull()) + ->state(new Sequence( + [AnimeThemeEntry::ATTRIBUTE_VERSION => $versionFilter], + [AnimeThemeEntry::ATTRIBUTE_VERSION => $excludedVersion], + )) + ) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $themes = AnimeTheme::with([ + AnimeTheme::RELATION_ENTRIES => function (HasMany $query) use ($versionFilter) { + $query->where(AnimeThemeEntry::ATTRIBUTE_VERSION, $versionFilter); + }, + ]) + ->get(); + + $response = get(route('api.animetheme.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ThemeCollection($themes, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by lyrics', function () { + $lyricsFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_LYRICS => $lyricsFilter, + ], + IncludeParser::param() => AnimeTheme::RELATION_VIDEOS, + ]; + + AnimeTheme::factory() + ->for(Anime::factory()) + ->has( + AnimeThemeEntry::factory() + ->count(fake()->randomDigitNotNull()) + ->has(Video::factory()->count(fake()->randomDigitNotNull())) + ) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $themes = AnimeTheme::with([ + AnimeTheme::RELATION_VIDEOS => function (BelongsToMany $query) use ($lyricsFilter) { + $query->where(Video::ATTRIBUTE_LYRICS, $lyricsFilter); + }, + ]) + ->get(); + + $response = get(route('api.animetheme.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ThemeCollection($themes, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by nc', function () { + $ncFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_NC => $ncFilter, + ], + IncludeParser::param() => AnimeTheme::RELATION_VIDEOS, + ]; + + AnimeTheme::factory() + ->for(Anime::factory()) + ->has( + AnimeThemeEntry::factory() + ->count(fake()->randomDigitNotNull()) + ->has(Video::factory()->count(fake()->randomDigitNotNull())) + ) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $themes = AnimeTheme::with([ + AnimeTheme::RELATION_VIDEOS => function (BelongsToMany $query) use ($ncFilter) { + $query->where(Video::ATTRIBUTE_NC, $ncFilter); + }, + ]) + ->get(); + + $response = get(route('api.animetheme.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ThemeCollection($themes, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by overlap', function () { + $overlapFilter = Arr::random(VideoOverlap::cases()); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_OVERLAP => $overlapFilter->localize(), + ], + IncludeParser::param() => AnimeTheme::RELATION_VIDEOS, + ]; + + AnimeTheme::factory() + ->for(Anime::factory()) + ->has( + AnimeThemeEntry::factory() + ->count(fake()->randomDigitNotNull()) + ->has(Video::factory()->count(fake()->randomDigitNotNull())) + ) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $themes = AnimeTheme::with([ + AnimeTheme::RELATION_VIDEOS => function (BelongsToMany $query) use ($overlapFilter) { + $query->where(Video::ATTRIBUTE_OVERLAP, $overlapFilter->value); + }, + ]) + ->get(); + + $response = get(route('api.animetheme.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ThemeCollection($themes, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by resolution', function () { + $resolutionFilter = fake()->randomNumber(); + $excludedResolution = $resolutionFilter + 1; + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_RESOLUTION => $resolutionFilter, + ], + IncludeParser::param() => AnimeTheme::RELATION_VIDEOS, + ]; + + AnimeTheme::factory() + ->for(Anime::factory()) + ->has( + AnimeThemeEntry::factory() + ->count(fake()->randomDigitNotNull()) + ->has( + Video::factory() + ->count(fake()->randomDigitNotNull()) + ->state(new Sequence( + [Video::ATTRIBUTE_RESOLUTION => $resolutionFilter], + [Video::ATTRIBUTE_RESOLUTION => $excludedResolution], + )) + ) + ) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $themes = AnimeTheme::with([ + AnimeTheme::RELATION_VIDEOS => function (BelongsToMany $query) use ($resolutionFilter) { + $query->where(Video::ATTRIBUTE_RESOLUTION, $resolutionFilter); + }, + ]) + ->get(); + + $response = get(route('api.animetheme.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ThemeCollection($themes, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by source', function () { + $sourceFilter = Arr::random(VideoSource::cases()); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_SOURCE => $sourceFilter->localize(), + ], + IncludeParser::param() => AnimeTheme::RELATION_VIDEOS, + ]; + + AnimeTheme::factory() + ->for(Anime::factory()) + ->has( + AnimeThemeEntry::factory() + ->count(fake()->randomDigitNotNull()) + ->has(Video::factory()->count(fake()->randomDigitNotNull())) + ) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $themes = AnimeTheme::with([ + AnimeTheme::RELATION_VIDEOS => function (BelongsToMany $query) use ($sourceFilter) { + $query->where(Video::ATTRIBUTE_SOURCE, $sourceFilter->value); + }, + ]) + ->get(); + + $response = get(route('api.animetheme.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ThemeCollection($themes, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by subbed', function () { + $subbedFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_SUBBED => $subbedFilter, + ], + IncludeParser::param() => AnimeTheme::RELATION_VIDEOS, + ]; + + AnimeTheme::factory() + ->for(Anime::factory()) + ->has( + AnimeThemeEntry::factory() + ->count(fake()->randomDigitNotNull()) + ->has(Video::factory()->count(fake()->randomDigitNotNull())) + ) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $themes = AnimeTheme::with([ + AnimeTheme::RELATION_VIDEOS => function (BelongsToMany $query) use ($subbedFilter) { + $query->where(Video::ATTRIBUTE_SUBBED, $subbedFilter); + }, + ]) + ->get(); + + $response = get(route('api.animetheme.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ThemeCollection($themes, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by uncen', function () { + $uncenFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_UNCEN => $uncenFilter, + ], + IncludeParser::param() => AnimeTheme::RELATION_VIDEOS, + ]; + + AnimeTheme::factory() + ->for(Anime::factory()) + ->has( + AnimeThemeEntry::factory() + ->count(fake()->randomDigitNotNull()) + ->has(Video::factory()->count(fake()->randomDigitNotNull())) + ) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $themes = AnimeTheme::with([ + AnimeTheme::RELATION_VIDEOS => function (BelongsToMany $query) use ($uncenFilter) { + $query->where(Video::ATTRIBUTE_UNCEN, $uncenFilter); + }, + ]) + ->get(); + + $response = get(route('api.animetheme.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ThemeCollection($themes, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Wiki/Anime/Theme/ThemeRestoreTest.php b/tests/Feature/Http/Api/Wiki/Anime/Theme/ThemeRestoreTest.php index 60a5a9e41..ffb1651c1 100644 --- a/tests/Feature/Http/Api/Wiki/Anime/Theme/ThemeRestoreTest.php +++ b/tests/Feature/Http/Api/Wiki/Anime/Theme/ThemeRestoreTest.php @@ -2,84 +2,64 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Anime\Theme; - use App\Enums\Auth\ExtendedCrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Anime; use App\Models\Wiki\Anime\AnimeTheme; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ThemeRestoreTest extends TestCase -{ - /** - * The Theme Restore Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $theme = AnimeTheme::factory() - ->trashed() - ->for(Anime::factory()) - ->createOne(); +use function Pest\Laravel\patch; - $response = $this->patch(route('api.animetheme.restore', ['animetheme' => $theme])); +test('protected', function () { + $theme = AnimeTheme::factory() + ->trashed() + ->for(Anime::factory()) + ->createOne(); - $response->assertUnauthorized(); - } + $response = patch(route('api.animetheme.restore', ['animetheme' => $theme])); - /** - * The Theme Restore Endpoint shall forbid users without the restore anime theme permission. - */ - public function testForbidden(): void - { - $theme = AnimeTheme::factory() - ->trashed() - ->for(Anime::factory()) - ->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $theme = AnimeTheme::factory() + ->trashed() + ->for(Anime::factory()) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->patch(route('api.animetheme.restore', ['animetheme' => $theme])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = patch(route('api.animetheme.restore', ['animetheme' => $theme])); - /** - * The Theme Restore Endpoint shall forbid users from restoring an anime theme that isn't trashed. - */ - public function testTrashed(): void - { - $theme = AnimeTheme::factory()->for(Anime::factory())->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(AnimeTheme::class))->createOne(); +test('trashed', function () { + $theme = AnimeTheme::factory()->for(Anime::factory())->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(AnimeTheme::class))->createOne(); - $response = $this->patch(route('api.animetheme.restore', ['animetheme' => $theme])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = patch(route('api.animetheme.restore', ['animetheme' => $theme])); - /** - * The Theme Restore Endpoint shall restore the theme. - */ - public function testRestored(): void - { - $theme = AnimeTheme::factory() - ->trashed() - ->for(Anime::factory()) - ->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(AnimeTheme::class))->createOne(); +test('restored', function () { + $theme = AnimeTheme::factory() + ->trashed() + ->for(Anime::factory()) + ->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(AnimeTheme::class))->createOne(); - $response = $this->patch(route('api.animetheme.restore', ['animetheme' => $theme])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertNotSoftDeleted($theme); - } -} + $response = patch(route('api.animetheme.restore', ['animetheme' => $theme])); + + $response->assertOk(); + $this->assertNotSoftDeleted($theme); +}); diff --git a/tests/Feature/Http/Api/Wiki/Anime/Theme/ThemeShowTest.php b/tests/Feature/Http/Api/Wiki/Anime/Theme/ThemeShowTest.php index 83bf43400..d67b993a2 100644 --- a/tests/Feature/Http/Api/Wiki/Anime/Theme/ThemeShowTest.php +++ b/tests/Feature/Http/Api/Wiki/Anime/Theme/ThemeShowTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Anime\Theme; - use App\Enums\Models\Wiki\AnimeMediaFormat; use App\Enums\Models\Wiki\AnimeSeason; use App\Enums\Models\Wiki\ImageFacet; @@ -27,738 +25,663 @@ use Illuminate\Database\Eloquent\Factories\Sequence; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\HasMany; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; -use Tests\TestCase; - -class ThemeShowTest extends TestCase -{ - use WithFaker; - - /** - * By default, the Theme Show Endpoint shall return a Theme Resource. - */ - public function testDefault(): void - { - $theme = AnimeTheme::factory() - ->for(Anime::factory()) - ->createOne(); - - $theme->unsetRelations(); - - $response = $this->get(route('api.animetheme.show', ['animetheme' => $theme])); - - $response->assertJson( - json_decode( - json_encode( - new ThemeResource($theme, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Theme Show Endpoint shall return a Theme Resource for soft deleted themes. - */ - public function testSoftDelete(): void - { - $theme = AnimeTheme::factory() - ->trashed() - ->for(Anime::factory()) - ->createOne(); - - $theme->unsetRelations(); - - $response = $this->get(route('api.animetheme.show', ['animetheme' => $theme])); - - $response->assertJson( - json_decode( - json_encode( - new ThemeResource($theme, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Theme Show Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new ThemeSchema(); - - $allowedIncludes = collect($schema->allowedIncludes()); - - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); - - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; - - $theme = AnimeTheme::factory() - ->for(Anime::factory()) - ->for(Song::factory()) - ->has( - AnimeThemeEntry::factory() - ->count($this->faker->randomDigitNotNull()) - ->has(Video::factory()->count($this->faker->randomDigitNotNull())) - ) - ->createOne(); - - $theme->unsetRelations()->load($includedPaths->all()); - - $response = $this->get(route('api.animetheme.show', ['animetheme' => $theme] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ThemeResource($theme, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Theme Show Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new ThemeSchema(); - - $fields = collect($schema->fields()); - - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); - - $parameters = [ - FieldParser::param() => [ - ThemeResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; - - $theme = AnimeTheme::factory() - ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) - ->createOne(); - - $theme->unsetRelations(); - - $response = $this->get(route('api.animetheme.show', ['animetheme' => $theme] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ThemeResource($theme, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Theme Show Endpoint shall support constrained eager loading of anime by media format. - */ - public function testAnimeByMediaFormat(): void - { - $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), - ], - IncludeParser::param() => AnimeTheme::RELATION_ANIME, - ]; - - $theme = AnimeTheme::factory() - ->for(Anime::factory()) - ->createOne(); - - $theme->unsetRelations()->load([ - AnimeTheme::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { - $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); - }, - ]); - - $response = $this->get(route('api.animetheme.show', ['animetheme' => $theme] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ThemeResource($theme, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Theme Show Endpoint shall support constrained eager loading of anime by season. - */ - public function testAnimeBySeason(): void - { - $seasonFilter = Arr::random(AnimeSeason::cases()); - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), - ], - IncludeParser::param() => AnimeTheme::RELATION_ANIME, - ]; - - $theme = AnimeTheme::factory() - ->for(Anime::factory()) - ->createOne(); - - $theme->unsetRelations()->load([ - AnimeTheme::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { - $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); - }, - ]); - - $response = $this->get(route('api.animetheme.show', ['animetheme' => $theme] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ThemeResource($theme, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Theme Show Endpoint shall support constrained eager loading of anime by year. - */ - public function testAnimeByYear(): void - { - $yearFilter = intval($this->faker->year()); - $excludedYear = $yearFilter + 1; - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_YEAR => $yearFilter, - ], - IncludeParser::param() => AnimeTheme::RELATION_ANIME, - ]; - - $theme = AnimeTheme::factory() - ->for( - Anime::factory() - ->state([ - Anime::ATTRIBUTE_YEAR => $this->faker->boolean() ? $yearFilter : $excludedYear, - ]) - ) - ->createOne(); - - $theme->unsetRelations()->load([ - AnimeTheme::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { - $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); - }, - ]); - - $response = $this->get(route('api.animetheme.show', ['animetheme' => $theme] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ThemeResource($theme, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Theme Show Endpoint shall support constrained eager loading of images by facet. - */ - public function testImagesByFacet(): void - { - $facetFilter = Arr::random(ImageFacet::cases()); - - $parameters = [ - FilterParser::param() => [ - Image::ATTRIBUTE_FACET => $facetFilter->localize(), - ], - IncludeParser::param() => AnimeTheme::RELATION_IMAGES, - ]; - - $theme = AnimeTheme::factory() - ->for( - Anime::factory() - ->has(Image::factory()->count($this->faker->randomDigitNotNull())) - ) - ->createOne(); - - $theme->unsetRelations()->load([ - AnimeTheme::RELATION_IMAGES => function (BelongsToMany $query) use ($facetFilter) { - $query->where(Image::ATTRIBUTE_FACET, $facetFilter->value); - }, - ]); - - $response = $this->get(route('api.animetheme.show', ['animetheme' => $theme] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ThemeResource($theme, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Theme Show Endpoint shall support constrained eager loading of entries by nsfw. - */ - public function testEntriesByNsfw(): void - { - $nsfwFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - AnimeThemeEntry::ATTRIBUTE_NSFW => $nsfwFilter, - ], - IncludeParser::param() => AnimeTheme::RELATION_ENTRIES, - ]; - - $theme = AnimeTheme::factory() - ->for(Anime::factory()) - ->has(AnimeThemeEntry::factory()->count($this->faker->randomDigitNotNull())) - ->createOne(); - - $theme->unsetRelations()->load([ - AnimeTheme::RELATION_ENTRIES => function (HasMany $query) use ($nsfwFilter) { - $query->where(AnimeThemeEntry::ATTRIBUTE_NSFW, $nsfwFilter); - }, - ]); - - $response = $this->get(route('api.animetheme.show', ['animetheme' => $theme] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ThemeResource($theme, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Index Endpoint shall support constrained eager loading of entries by spoiler. - */ - public function testEntriesBySpoiler(): void - { - $spoilerFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - AnimeThemeEntry::ATTRIBUTE_SPOILER => $spoilerFilter, - ], - IncludeParser::param() => AnimeTheme::RELATION_ENTRIES, - ]; - - $theme = AnimeTheme::factory() - ->for(Anime::factory()) - ->has(AnimeThemeEntry::factory()->count($this->faker->randomDigitNotNull())) - ->createOne(); - - $theme->unsetRelations()->load([ - AnimeTheme::RELATION_ENTRIES => function (HasMany $query) use ($spoilerFilter) { - $query->where(AnimeThemeEntry::ATTRIBUTE_SPOILER, $spoilerFilter); - }, - ]); - - $response = $this->get(route('api.animetheme.show', ['animetheme' => $theme] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ThemeResource($theme, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Anime Index Endpoint shall support constrained eager loading of entries by version. - */ - public function testEntriesByVersion(): void - { - $versionFilter = $this->faker->randomDigitNotNull(); - $excludedVersion = $versionFilter + 1; - - $parameters = [ - FilterParser::param() => [ - AnimeThemeEntry::ATTRIBUTE_VERSION => $versionFilter, - ], - IncludeParser::param() => AnimeTheme::RELATION_ENTRIES, - ]; - - $theme = AnimeTheme::factory() - ->for(Anime::factory()) - ->has( - AnimeThemeEntry::factory() - ->count($this->faker->randomDigitNotNull()) - ->state(new Sequence( - [AnimeThemeEntry::ATTRIBUTE_VERSION => $versionFilter], - [AnimeThemeEntry::ATTRIBUTE_VERSION => $excludedVersion], - )) - ) - ->createOne(); - - $theme->unsetRelations()->load([ - AnimeTheme::RELATION_ENTRIES => function (HasMany $query) use ($versionFilter) { - $query->where(AnimeThemeEntry::ATTRIBUTE_VERSION, $versionFilter); - }, - ]); - - $response = $this->get(route('api.animetheme.show', ['animetheme' => $theme] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ThemeResource($theme, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Theme Show Endpoint shall support constrained eager loading of videos by lyrics. - */ - public function testVideosByLyrics(): void - { - $lyricsFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_LYRICS => $lyricsFilter, - ], - IncludeParser::param() => AnimeTheme::RELATION_VIDEOS, - ]; - - $theme = AnimeTheme::factory() - ->for(Anime::factory()) - ->has( - AnimeThemeEntry::factory() - ->count($this->faker->randomDigitNotNull()) - ->has(Video::factory()->count($this->faker->randomDigitNotNull())) - ) - ->createOne(); - - $theme->unsetRelations()->load([ - AnimeTheme::RELATION_VIDEOS => function (BelongsToMany $query) use ($lyricsFilter) { - $query->where(Video::ATTRIBUTE_LYRICS, $lyricsFilter); - }, - ]); - - $response = $this->get(route('api.animetheme.show', ['animetheme' => $theme] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ThemeResource($theme, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Theme Show Endpoint shall support constrained eager loading of videos by nc. - */ - public function testVideosByNc(): void - { - $ncFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_NC => $ncFilter, - ], - IncludeParser::param() => AnimeTheme::RELATION_VIDEOS, - ]; - - $theme = AnimeTheme::factory() - ->for(Anime::factory()) - ->has( - AnimeThemeEntry::factory() - ->count($this->faker->randomDigitNotNull()) - ->has(Video::factory()->count($this->faker->randomDigitNotNull())) - ) - ->createOne(); - - $theme->unsetRelations()->load([ - AnimeTheme::RELATION_VIDEOS => function (BelongsToMany $query) use ($ncFilter) { - $query->where(Video::ATTRIBUTE_NC, $ncFilter); - }, - ]); - - $response = $this->get(route('api.animetheme.show', ['animetheme' => $theme] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ThemeResource($theme, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Theme Show Endpoint shall support constrained eager loading of videos by overlap. - */ - public function testVideosByOverlap(): void - { - $overlapFilter = Arr::random(VideoOverlap::cases()); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_OVERLAP => $overlapFilter->localize(), - ], - IncludeParser::param() => AnimeTheme::RELATION_VIDEOS, - ]; - - $theme = AnimeTheme::factory() - ->for(Anime::factory()) - ->has( - AnimeThemeEntry::factory() - ->count($this->faker->randomDigitNotNull()) - ->has(Video::factory()->count($this->faker->randomDigitNotNull())) - ) - ->createOne(); - - $theme->unsetRelations()->load([ - AnimeTheme::RELATION_VIDEOS => function (BelongsToMany $query) use ($overlapFilter) { - $query->where(Video::ATTRIBUTE_OVERLAP, $overlapFilter->value); - }, - ]); - - $response = $this->get(route('api.animetheme.show', ['animetheme' => $theme] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ThemeResource($theme, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Theme Show Endpoint shall support constrained eager loading of videos by resolution. - */ - public function testVideosByResolution(): void - { - $resolutionFilter = $this->faker->randomNumber(); - $excludedResolution = $resolutionFilter + 1; - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_RESOLUTION => $resolutionFilter, - ], - IncludeParser::param() => AnimeTheme::RELATION_VIDEOS, - ]; - - $theme = AnimeTheme::factory() - ->for(Anime::factory()) - ->has( - AnimeThemeEntry::factory() - ->count($this->faker->randomDigitNotNull()) - ->has( - Video::factory() - ->count($this->faker->randomDigitNotNull()) - ->state(new Sequence( - [Video::ATTRIBUTE_RESOLUTION => $resolutionFilter], - [Video::ATTRIBUTE_RESOLUTION => $excludedResolution], - )) - ) - ) - ->createOne(); - - $theme->unsetRelations()->load([ - AnimeTheme::RELATION_VIDEOS => function (BelongsToMany $query) use ($resolutionFilter) { - $query->where(Video::ATTRIBUTE_RESOLUTION, $resolutionFilter); - }, - ]); - - $response = $this->get(route('api.animetheme.show', ['animetheme' => $theme] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ThemeResource($theme, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Theme Show Endpoint shall support constrained eager loading of videos by source. - */ - public function testVideosBySource(): void - { - $sourceFilter = Arr::random(VideoSource::cases()); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_SOURCE => $sourceFilter->localize(), - ], - IncludeParser::param() => AnimeTheme::RELATION_VIDEOS, - ]; - - $theme = AnimeTheme::factory() - ->for(Anime::factory()) - ->has( - AnimeThemeEntry::factory() - ->count($this->faker->randomDigitNotNull()) - ->has(Video::factory()->count($this->faker->randomDigitNotNull())) - ) - ->createOne(); - - $theme->unsetRelations()->load([ - AnimeTheme::RELATION_VIDEOS => function (BelongsToMany $query) use ($sourceFilter) { - $query->where(Video::ATTRIBUTE_SOURCE, $sourceFilter->value); - }, - ]); - - $response = $this->get(route('api.animetheme.show', ['animetheme' => $theme] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ThemeResource($theme, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Theme Show Endpoint shall support constrained eager loading of videos by subbed. - */ - public function testVideosBySubbed(): void - { - $subbedFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_SUBBED => $subbedFilter, - ], - IncludeParser::param() => AnimeTheme::RELATION_VIDEOS, - ]; - - $theme = AnimeTheme::factory() - ->for(Anime::factory()) - ->has( - AnimeThemeEntry::factory() - ->count($this->faker->randomDigitNotNull()) - ->has(Video::factory()->count($this->faker->randomDigitNotNull())) - ) - ->createOne(); - - $theme->unsetRelations()->load([ - AnimeTheme::RELATION_VIDEOS => function (BelongsToMany $query) use ($subbedFilter) { - $query->where(Video::ATTRIBUTE_SUBBED, $subbedFilter); - }, - ]); - - $response = $this->get(route('api.animetheme.show', ['animetheme' => $theme] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ThemeResource($theme, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Theme Show Endpoint shall support constrained eager loading of videos by uncen. - */ - public function testVideosByUncen(): void - { - $uncenFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_UNCEN => $uncenFilter, - ], - IncludeParser::param() => AnimeTheme::RELATION_VIDEOS, - ]; - - $theme = AnimeTheme::factory() - ->for(Anime::factory()) - ->has( - AnimeThemeEntry::factory() - ->count($this->faker->randomDigitNotNull()) - ->has(Video::factory()->count($this->faker->randomDigitNotNull())) - ) - ->createOne(); - - $theme->unsetRelations()->load([ - AnimeTheme::RELATION_VIDEOS => function (BelongsToMany $query) use ($uncenFilter) { - $query->where(Video::ATTRIBUTE_UNCEN, $uncenFilter); - }, - ]); - - $response = $this->get(route('api.animetheme.show', ['animetheme' => $theme] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ThemeResource($theme, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + +use function Pest\Laravel\get; + +uses(Illuminate\Foundation\Testing\WithFaker::class); + +test('default', function () { + $theme = AnimeTheme::factory() + ->for(Anime::factory()) + ->createOne(); + + $theme->unsetRelations(); + + $response = get(route('api.animetheme.show', ['animetheme' => $theme])); + + $response->assertJson( + json_decode( + json_encode( + new ThemeResource($theme, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('soft delete', function () { + $theme = AnimeTheme::factory() + ->trashed() + ->for(Anime::factory()) + ->createOne(); + + $theme->unsetRelations(); + + $response = get(route('api.animetheme.show', ['animetheme' => $theme])); + + $response->assertJson( + json_decode( + json_encode( + new ThemeResource($theme, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('allowed include paths', function () { + $schema = new ThemeSchema(); + + $allowedIncludes = collect($schema->allowedIncludes()); + + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); + + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; + + $theme = AnimeTheme::factory() + ->for(Anime::factory()) + ->for(Song::factory()) + ->has( + AnimeThemeEntry::factory() + ->count(fake()->randomDigitNotNull()) + ->has(Video::factory()->count(fake()->randomDigitNotNull())) + ) + ->createOne(); + + $theme->unsetRelations()->load($includedPaths->all()); + + $response = get(route('api.animetheme.show', ['animetheme' => $theme] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ThemeResource($theme, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sparse fieldsets', function () { + $schema = new ThemeSchema(); + + $fields = collect($schema->fields()); + + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + ThemeResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + $theme = AnimeTheme::factory() + ->for(Anime::factory()) + ->count(fake()->randomDigitNotNull()) + ->createOne(); + + $theme->unsetRelations(); + + $response = get(route('api.animetheme.show', ['animetheme' => $theme] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ThemeResource($theme, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by media format', function () { + $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), + ], + IncludeParser::param() => AnimeTheme::RELATION_ANIME, + ]; + + $theme = AnimeTheme::factory() + ->for(Anime::factory()) + ->createOne(); + + $theme->unsetRelations()->load([ + AnimeTheme::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { + $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); + }, + ]); + + $response = get(route('api.animetheme.show', ['animetheme' => $theme] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ThemeResource($theme, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by season', function () { + $seasonFilter = Arr::random(AnimeSeason::cases()); + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), + ], + IncludeParser::param() => AnimeTheme::RELATION_ANIME, + ]; + + $theme = AnimeTheme::factory() + ->for(Anime::factory()) + ->createOne(); + + $theme->unsetRelations()->load([ + AnimeTheme::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { + $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); + }, + ]); + + $response = get(route('api.animetheme.show', ['animetheme' => $theme] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ThemeResource($theme, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by year', function () { + $yearFilter = intval(fake()->year()); + $excludedYear = $yearFilter + 1; + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_YEAR => $yearFilter, + ], + IncludeParser::param() => AnimeTheme::RELATION_ANIME, + ]; + + $theme = AnimeTheme::factory() + ->for( + Anime::factory() + ->state([ + Anime::ATTRIBUTE_YEAR => fake()->boolean() ? $yearFilter : $excludedYear, + ]) + ) + ->createOne(); + + $theme->unsetRelations()->load([ + AnimeTheme::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { + $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); + }, + ]); + + $response = get(route('api.animetheme.show', ['animetheme' => $theme] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ThemeResource($theme, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('images by facet', function () { + $facetFilter = Arr::random(ImageFacet::cases()); + + $parameters = [ + FilterParser::param() => [ + Image::ATTRIBUTE_FACET => $facetFilter->localize(), + ], + IncludeParser::param() => AnimeTheme::RELATION_IMAGES, + ]; + + $theme = AnimeTheme::factory() + ->for( + Anime::factory() + ->has(Image::factory()->count(fake()->randomDigitNotNull())) + ) + ->createOne(); + + $theme->unsetRelations()->load([ + AnimeTheme::RELATION_IMAGES => function (BelongsToMany $query) use ($facetFilter) { + $query->where(Image::ATTRIBUTE_FACET, $facetFilter->value); + }, + ]); + + $response = get(route('api.animetheme.show', ['animetheme' => $theme] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ThemeResource($theme, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('entries by nsfw', function () { + $nsfwFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + AnimeThemeEntry::ATTRIBUTE_NSFW => $nsfwFilter, + ], + IncludeParser::param() => AnimeTheme::RELATION_ENTRIES, + ]; + + $theme = AnimeTheme::factory() + ->for(Anime::factory()) + ->has(AnimeThemeEntry::factory()->count(fake()->randomDigitNotNull())) + ->createOne(); + + $theme->unsetRelations()->load([ + AnimeTheme::RELATION_ENTRIES => function (HasMany $query) use ($nsfwFilter) { + $query->where(AnimeThemeEntry::ATTRIBUTE_NSFW, $nsfwFilter); + }, + ]); + + $response = get(route('api.animetheme.show', ['animetheme' => $theme] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ThemeResource($theme, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('entries by spoiler', function () { + $spoilerFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + AnimeThemeEntry::ATTRIBUTE_SPOILER => $spoilerFilter, + ], + IncludeParser::param() => AnimeTheme::RELATION_ENTRIES, + ]; + + $theme = AnimeTheme::factory() + ->for(Anime::factory()) + ->has(AnimeThemeEntry::factory()->count(fake()->randomDigitNotNull())) + ->createOne(); + + $theme->unsetRelations()->load([ + AnimeTheme::RELATION_ENTRIES => function (HasMany $query) use ($spoilerFilter) { + $query->where(AnimeThemeEntry::ATTRIBUTE_SPOILER, $spoilerFilter); + }, + ]); + + $response = get(route('api.animetheme.show', ['animetheme' => $theme] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ThemeResource($theme, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('entries by version', function () { + $versionFilter = fake()->randomDigitNotNull(); + $excludedVersion = $versionFilter + 1; + + $parameters = [ + FilterParser::param() => [ + AnimeThemeEntry::ATTRIBUTE_VERSION => $versionFilter, + ], + IncludeParser::param() => AnimeTheme::RELATION_ENTRIES, + ]; + + $theme = AnimeTheme::factory() + ->for(Anime::factory()) + ->has( + AnimeThemeEntry::factory() + ->count(fake()->randomDigitNotNull()) + ->state(new Sequence( + [AnimeThemeEntry::ATTRIBUTE_VERSION => $versionFilter], + [AnimeThemeEntry::ATTRIBUTE_VERSION => $excludedVersion], + )) + ) + ->createOne(); + + $theme->unsetRelations()->load([ + AnimeTheme::RELATION_ENTRIES => function (HasMany $query) use ($versionFilter) { + $query->where(AnimeThemeEntry::ATTRIBUTE_VERSION, $versionFilter); + }, + ]); + + $response = get(route('api.animetheme.show', ['animetheme' => $theme] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ThemeResource($theme, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by lyrics', function () { + $lyricsFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_LYRICS => $lyricsFilter, + ], + IncludeParser::param() => AnimeTheme::RELATION_VIDEOS, + ]; + + $theme = AnimeTheme::factory() + ->for(Anime::factory()) + ->has( + AnimeThemeEntry::factory() + ->count(fake()->randomDigitNotNull()) + ->has(Video::factory()->count(fake()->randomDigitNotNull())) + ) + ->createOne(); + + $theme->unsetRelations()->load([ + AnimeTheme::RELATION_VIDEOS => function (BelongsToMany $query) use ($lyricsFilter) { + $query->where(Video::ATTRIBUTE_LYRICS, $lyricsFilter); + }, + ]); + + $response = get(route('api.animetheme.show', ['animetheme' => $theme] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ThemeResource($theme, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by nc', function () { + $ncFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_NC => $ncFilter, + ], + IncludeParser::param() => AnimeTheme::RELATION_VIDEOS, + ]; + + $theme = AnimeTheme::factory() + ->for(Anime::factory()) + ->has( + AnimeThemeEntry::factory() + ->count(fake()->randomDigitNotNull()) + ->has(Video::factory()->count(fake()->randomDigitNotNull())) + ) + ->createOne(); + + $theme->unsetRelations()->load([ + AnimeTheme::RELATION_VIDEOS => function (BelongsToMany $query) use ($ncFilter) { + $query->where(Video::ATTRIBUTE_NC, $ncFilter); + }, + ]); + + $response = get(route('api.animetheme.show', ['animetheme' => $theme] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ThemeResource($theme, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by overlap', function () { + $overlapFilter = Arr::random(VideoOverlap::cases()); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_OVERLAP => $overlapFilter->localize(), + ], + IncludeParser::param() => AnimeTheme::RELATION_VIDEOS, + ]; + + $theme = AnimeTheme::factory() + ->for(Anime::factory()) + ->has( + AnimeThemeEntry::factory() + ->count(fake()->randomDigitNotNull()) + ->has(Video::factory()->count(fake()->randomDigitNotNull())) + ) + ->createOne(); + + $theme->unsetRelations()->load([ + AnimeTheme::RELATION_VIDEOS => function (BelongsToMany $query) use ($overlapFilter) { + $query->where(Video::ATTRIBUTE_OVERLAP, $overlapFilter->value); + }, + ]); + + $response = get(route('api.animetheme.show', ['animetheme' => $theme] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ThemeResource($theme, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by resolution', function () { + $resolutionFilter = fake()->randomNumber(); + $excludedResolution = $resolutionFilter + 1; + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_RESOLUTION => $resolutionFilter, + ], + IncludeParser::param() => AnimeTheme::RELATION_VIDEOS, + ]; + + $theme = AnimeTheme::factory() + ->for(Anime::factory()) + ->has( + AnimeThemeEntry::factory() + ->count(fake()->randomDigitNotNull()) + ->has( + Video::factory() + ->count(fake()->randomDigitNotNull()) + ->state(new Sequence( + [Video::ATTRIBUTE_RESOLUTION => $resolutionFilter], + [Video::ATTRIBUTE_RESOLUTION => $excludedResolution], + )) + ) + ) + ->createOne(); + + $theme->unsetRelations()->load([ + AnimeTheme::RELATION_VIDEOS => function (BelongsToMany $query) use ($resolutionFilter) { + $query->where(Video::ATTRIBUTE_RESOLUTION, $resolutionFilter); + }, + ]); + + $response = get(route('api.animetheme.show', ['animetheme' => $theme] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ThemeResource($theme, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by source', function () { + $sourceFilter = Arr::random(VideoSource::cases()); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_SOURCE => $sourceFilter->localize(), + ], + IncludeParser::param() => AnimeTheme::RELATION_VIDEOS, + ]; + + $theme = AnimeTheme::factory() + ->for(Anime::factory()) + ->has( + AnimeThemeEntry::factory() + ->count(fake()->randomDigitNotNull()) + ->has(Video::factory()->count(fake()->randomDigitNotNull())) + ) + ->createOne(); + + $theme->unsetRelations()->load([ + AnimeTheme::RELATION_VIDEOS => function (BelongsToMany $query) use ($sourceFilter) { + $query->where(Video::ATTRIBUTE_SOURCE, $sourceFilter->value); + }, + ]); + + $response = get(route('api.animetheme.show', ['animetheme' => $theme] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ThemeResource($theme, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by subbed', function () { + $subbedFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_SUBBED => $subbedFilter, + ], + IncludeParser::param() => AnimeTheme::RELATION_VIDEOS, + ]; + + $theme = AnimeTheme::factory() + ->for(Anime::factory()) + ->has( + AnimeThemeEntry::factory() + ->count(fake()->randomDigitNotNull()) + ->has(Video::factory()->count(fake()->randomDigitNotNull())) + ) + ->createOne(); + + $theme->unsetRelations()->load([ + AnimeTheme::RELATION_VIDEOS => function (BelongsToMany $query) use ($subbedFilter) { + $query->where(Video::ATTRIBUTE_SUBBED, $subbedFilter); + }, + ]); + + $response = get(route('api.animetheme.show', ['animetheme' => $theme] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ThemeResource($theme, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by uncen', function () { + $uncenFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_UNCEN => $uncenFilter, + ], + IncludeParser::param() => AnimeTheme::RELATION_VIDEOS, + ]; + + $theme = AnimeTheme::factory() + ->for(Anime::factory()) + ->has( + AnimeThemeEntry::factory() + ->count(fake()->randomDigitNotNull()) + ->has(Video::factory()->count(fake()->randomDigitNotNull())) + ) + ->createOne(); + + $theme->unsetRelations()->load([ + AnimeTheme::RELATION_VIDEOS => function (BelongsToMany $query) use ($uncenFilter) { + $query->where(Video::ATTRIBUTE_UNCEN, $uncenFilter); + }, + ]); + + $response = get(route('api.animetheme.show', ['animetheme' => $theme] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ThemeResource($theme, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Wiki/Anime/Theme/ThemeStoreTest.php b/tests/Feature/Http/Api/Wiki/Anime/Theme/ThemeStoreTest.php index 69ad763ee..6002d776b 100644 --- a/tests/Feature/Http/Api/Wiki/Anime/Theme/ThemeStoreTest.php +++ b/tests/Feature/Http/Api/Wiki/Anime/Theme/ThemeStoreTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Anime\Theme; - use App\Enums\Auth\CrudPermission; use App\Enums\Models\Wiki\ThemeType; use App\Models\Auth\User; @@ -11,78 +9,60 @@ use App\Models\Wiki\Anime; use App\Models\Wiki\Anime\AnimeTheme; use Illuminate\Support\Arr; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ThemeStoreTest extends TestCase -{ - /** - * The Theme Store Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $theme = AnimeTheme::factory()->for(Anime::factory())->makeOne(); +use function Pest\Laravel\post; - $response = $this->post(route('api.animetheme.store', $theme->toArray())); +test('protected', function () { + $theme = AnimeTheme::factory()->for(Anime::factory())->makeOne(); - $response->assertUnauthorized(); - } + $response = post(route('api.animetheme.store', $theme->toArray())); - /** - * The Theme Store Endpoint shall forbid users without the store anime theme permission. - */ - public function testForbidden(): void - { - $theme = AnimeTheme::factory()->for(Anime::factory())->makeOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $theme = AnimeTheme::factory()->for(Anime::factory())->makeOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->post(route('api.animetheme.store', $theme->toArray())); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.animetheme.store', $theme->toArray())); - /** - * The Theme Store Endpoint shall require the anime_id & type field. - */ - public function testRequiredFields(): void - { - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(AnimeTheme::class))->createOne(); + $response->assertForbidden(); +}); - Sanctum::actingAs($user); +test('required fields', function () { + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(AnimeTheme::class))->createOne(); - $response = $this->post(route('api.animetheme.store')); + Sanctum::actingAs($user); - $response->assertJsonValidationErrors([ - AnimeTheme::ATTRIBUTE_ANIME, - AnimeTheme::ATTRIBUTE_SLUG, - AnimeTheme::ATTRIBUTE_TYPE, - ]); - } + $response = post(route('api.animetheme.store')); - /** - * The Theme Store Endpoint shall create a theme. - */ - public function testCreate(): void - { - $anime = Anime::factory()->createOne(); + $response->assertJsonValidationErrors([ + AnimeTheme::ATTRIBUTE_ANIME, + AnimeTheme::ATTRIBUTE_SLUG, + AnimeTheme::ATTRIBUTE_TYPE, + ]); +}); - $type = Arr::random(ThemeType::cases()); +test('create', function () { + $anime = Anime::factory()->createOne(); - $parameters = array_merge( - AnimeTheme::factory()->raw(), - [AnimeTheme::ATTRIBUTE_TYPE => $type->localize()], - [AnimeTheme::ATTRIBUTE_ANIME => $anime->getKey()], - ); + $type = Arr::random(ThemeType::cases()); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(AnimeTheme::class))->createOne(); + $parameters = array_merge( + AnimeTheme::factory()->raw(), + [AnimeTheme::ATTRIBUTE_TYPE => $type->localize()], + [AnimeTheme::ATTRIBUTE_ANIME => $anime->getKey()], + ); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(AnimeTheme::class))->createOne(); - $response = $this->post(route('api.animetheme.store', $parameters)); + Sanctum::actingAs($user); - $response->assertCreated(); - static::assertDatabaseCount(AnimeTheme::class, 1); - } -} + $response = post(route('api.animetheme.store', $parameters)); + + $response->assertCreated(); + $this->assertDatabaseCount(AnimeTheme::class, 1); +}); diff --git a/tests/Feature/Http/Api/Wiki/Anime/Theme/ThemeUpdateTest.php b/tests/Feature/Http/Api/Wiki/Anime/Theme/ThemeUpdateTest.php index 6d762be6f..ae686e16d 100644 --- a/tests/Feature/Http/Api/Wiki/Anime/Theme/ThemeUpdateTest.php +++ b/tests/Feature/Http/Api/Wiki/Anime/Theme/ThemeUpdateTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Anime\Theme; - use App\Enums\Auth\CrudPermission; use App\Enums\Models\Wiki\ThemeType; use App\Models\Auth\User; @@ -11,98 +9,80 @@ use App\Models\Wiki\Anime; use App\Models\Wiki\Anime\AnimeTheme; use Illuminate\Support\Arr; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ThemeUpdateTest extends TestCase -{ - /** - * The Theme Update Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $theme = AnimeTheme::factory()->for(Anime::factory())->createOne(); +use function Pest\Laravel\put; - $type = Arr::random(ThemeType::cases()); +test('protected', function () { + $theme = AnimeTheme::factory()->for(Anime::factory())->createOne(); - $parameters = array_merge( - AnimeTheme::factory()->raw(), - [AnimeTheme::ATTRIBUTE_TYPE => $type->localize()], - ); + $type = Arr::random(ThemeType::cases()); - $response = $this->put(route('api.animetheme.update', ['animetheme' => $theme] + $parameters)); + $parameters = array_merge( + AnimeTheme::factory()->raw(), + [AnimeTheme::ATTRIBUTE_TYPE => $type->localize()], + ); - $response->assertUnauthorized(); - } + $response = put(route('api.animetheme.update', ['animetheme' => $theme] + $parameters)); - /** - * The Theme Update Endpoint shall forbid users without the update anime theme permission. - */ - public function testForbidden(): void - { - $theme = AnimeTheme::factory()->for(Anime::factory())->createOne(); + $response->assertUnauthorized(); +}); - $type = Arr::random(ThemeType::cases()); +test('forbidden', function () { + $theme = AnimeTheme::factory()->for(Anime::factory())->createOne(); - $parameters = array_merge( - AnimeTheme::factory()->raw(), - [AnimeTheme::ATTRIBUTE_TYPE => $type->localize()], - ); + $type = Arr::random(ThemeType::cases()); - $user = User::factory()->createOne(); + $parameters = array_merge( + AnimeTheme::factory()->raw(), + [AnimeTheme::ATTRIBUTE_TYPE => $type->localize()], + ); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->put(route('api.animetheme.update', ['animetheme' => $theme] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.animetheme.update', ['animetheme' => $theme] + $parameters)); - /** - * The Theme Update Endpoint shall forbid users from updating an anime theme that is trashed. - */ - public function testTrashed(): void - { - $theme = AnimeTheme::factory() - ->trashed() - ->for(Anime::factory()) - ->createOne(); + $response->assertForbidden(); +}); - $type = Arr::random(ThemeType::cases()); +test('trashed', function () { + $theme = AnimeTheme::factory() + ->trashed() + ->for(Anime::factory()) + ->createOne(); - $parameters = array_merge( - AnimeTheme::factory()->raw(), - [AnimeTheme::ATTRIBUTE_TYPE => $type->localize()], - ); + $type = Arr::random(ThemeType::cases()); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(AnimeTheme::class))->createOne(); + $parameters = array_merge( + AnimeTheme::factory()->raw(), + [AnimeTheme::ATTRIBUTE_TYPE => $type->localize()], + ); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(AnimeTheme::class))->createOne(); - $response = $this->put(route('api.animetheme.update', ['animetheme' => $theme] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.animetheme.update', ['animetheme' => $theme] + $parameters)); - /** - * The Theme Update Endpoint shall update a theme. - */ - public function testUpdate(): void - { - $theme = AnimeTheme::factory()->for(Anime::factory())->createOne(); + $response->assertForbidden(); +}); - $type = Arr::random(ThemeType::cases()); +test('update', function () { + $theme = AnimeTheme::factory()->for(Anime::factory())->createOne(); - $parameters = array_merge( - AnimeTheme::factory()->raw(), - [AnimeTheme::ATTRIBUTE_TYPE => $type->localize()], - ); + $type = Arr::random(ThemeType::cases()); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(AnimeTheme::class))->createOne(); + $parameters = array_merge( + AnimeTheme::factory()->raw(), + [AnimeTheme::ATTRIBUTE_TYPE => $type->localize()], + ); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(AnimeTheme::class))->createOne(); - $response = $this->put(route('api.animetheme.update', ['animetheme' => $theme] + $parameters)); + Sanctum::actingAs($user); - $response->assertOk(); - } -} + $response = put(route('api.animetheme.update', ['animetheme' => $theme] + $parameters)); + + $response->assertOk(); +}); diff --git a/tests/Feature/Http/Api/Wiki/Anime/YearIndexTest.php b/tests/Feature/Http/Api/Wiki/Anime/YearIndexTest.php index c4b153feb..aef211c89 100644 --- a/tests/Feature/Http/Api/Wiki/Anime/YearIndexTest.php +++ b/tests/Feature/Http/Api/Wiki/Anime/YearIndexTest.php @@ -2,29 +2,20 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Anime; - use App\Models\Wiki\Anime; -use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; -class YearIndexTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * The Year Index Endpoint shall display a list of unique years of anime. - */ - public function testDefault(): void - { - $anime = Anime::factory() - ->count($this->faker->randomDigitNotNull()) - ->create(); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response = $this->get(route('api.animeyear.index')); +test('default', function () { + $anime = Anime::factory() + ->count(fake()->randomDigitNotNull()) + ->create(); - $response->assertJson( - $anime->unique(Anime::ATTRIBUTE_YEAR)->sortBy(Anime::ATTRIBUTE_YEAR)->pluck(Anime::ATTRIBUTE_YEAR)->all(), - ); - } -} + $response = get(route('api.animeyear.index')); + + $response->assertJson( + $anime->unique(Anime::ATTRIBUTE_YEAR)->sortBy(Anime::ATTRIBUTE_YEAR)->pluck(Anime::ATTRIBUTE_YEAR)->all(), + ); +}); diff --git a/tests/Feature/Http/Api/Wiki/Anime/YearShowTest.php b/tests/Feature/Http/Api/Wiki/Anime/YearShowTest.php index 54f84fa02..92e84c7cc 100644 --- a/tests/Feature/Http/Api/Wiki/Anime/YearShowTest.php +++ b/tests/Feature/Http/Api/Wiki/Anime/YearShowTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Anime; - use App\Enums\Models\Wiki\AnimeSeason; use App\Http\Api\Field\Field; use App\Http\Api\Include\AllowedInclude; @@ -14,198 +12,183 @@ use App\Http\Api\Schema\Wiki\AnimeSchema; use App\Http\Resources\Wiki\Collection\AnimeCollection; use App\Http\Resources\Wiki\Resource\AnimeResource; use App\Models\Wiki\Anime; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Str; -use Tests\TestCase; -class YearShowTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the Year Show Endpoint shall return a grouping of Anime Resources of year by season. - */ - public function testDefault(): void - { - $year = intval($this->faker->year()); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $winterAnime = Anime::factory() - ->count($this->faker->numberBetween(1, 3)) - ->create([ - Anime::ATTRIBUTE_YEAR => $year, - Anime::ATTRIBUTE_SEASON => AnimeSeason::WINTER->value, - ]); +test('default', function () { + $year = intval(fake()->year()); - $winterResources = new AnimeCollection($winterAnime->sortBy(Anime::ATTRIBUTE_NAME)->values(), new Query()); - - $springAnime = Anime::factory() - ->count($this->faker->numberBetween(1, 3)) - ->create([ - Anime::ATTRIBUTE_YEAR => $year, - Anime::ATTRIBUTE_SEASON => AnimeSeason::SPRING->value, - ]); - - $springResources = new AnimeCollection($springAnime->sortBy(Anime::ATTRIBUTE_NAME)->values(), new Query()); - - $summerAnime = Anime::factory() - ->count($this->faker->numberBetween(1, 3)) - ->create([ - Anime::ATTRIBUTE_YEAR => $year, - Anime::ATTRIBUTE_SEASON => AnimeSeason::SUMMER->value, - ]); - - $summerResources = new AnimeCollection($summerAnime->sortBy(Anime::ATTRIBUTE_NAME)->values(), new Query()); - - $fallAnime = Anime::factory() - ->count($this->faker->numberBetween(1, 3)) - ->create([ - Anime::ATTRIBUTE_YEAR => $year, - Anime::ATTRIBUTE_SEASON => AnimeSeason::FALL->value, - ]); - - $fallResources = new AnimeCollection($fallAnime->sortBy(Anime::ATTRIBUTE_NAME)->values(), new Query()); - - $response = $this->get(route('api.animeyear.show', [Anime::ATTRIBUTE_YEAR => $year])); - - $response->assertJson([ - Str::lower(AnimeSeason::WINTER->localize()) => json_decode(json_encode($winterResources->response()->getData()->anime), true), - Str::lower(AnimeSeason::SPRING->localize()) => json_decode(json_encode($springResources->response()->getData()->anime), true), - Str::lower(AnimeSeason::SUMMER->localize()) => json_decode(json_encode($summerResources->response()->getData()->anime), true), - Str::lower(AnimeSeason::FALL->localize()) => json_decode(json_encode($fallResources->response()->getData()->anime), true), + $winterAnime = Anime::factory() + ->count(fake()->numberBetween(1, 3)) + ->create([ + Anime::ATTRIBUTE_YEAR => $year, + Anime::ATTRIBUTE_SEASON => AnimeSeason::WINTER->value, ]); - } - /** - * The Year Show Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $year = intval($this->faker->year()); + $winterResources = new AnimeCollection($winterAnime->sortBy(Anime::ATTRIBUTE_NAME)->values(), new Query()); - $schema = new AnimeSchema(); - - $allowedIncludes = collect($schema->allowedIncludes()); - - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); - - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; - - $winterAnime = Anime::factory() - ->count($this->faker->numberBetween(1, 3)) - ->jsonApiResource() - ->create([ - Anime::ATTRIBUTE_YEAR => $year, - Anime::ATTRIBUTE_SEASON => AnimeSeason::WINTER->value, - ]); - - $winterResources = new AnimeCollection($winterAnime->sortBy(Anime::ATTRIBUTE_NAME)->values(), new Query($parameters)); - - $springAnime = Anime::factory() - ->count($this->faker->numberBetween(1, 3)) - ->jsonApiResource() - ->create([ - Anime::ATTRIBUTE_YEAR => $year, - Anime::ATTRIBUTE_SEASON => AnimeSeason::SPRING->value, - ]); - - $springResources = new AnimeCollection($springAnime->sortBy(Anime::ATTRIBUTE_NAME)->values(), new Query($parameters)); - - $summerAnime = Anime::factory() - ->count($this->faker->numberBetween(1, 3)) - ->jsonApiResource() - ->create([ - Anime::ATTRIBUTE_YEAR => $year, - Anime::ATTRIBUTE_SEASON => AnimeSeason::SUMMER->value, - ]); - - $summerResources = new AnimeCollection($summerAnime->sortBy(Anime::ATTRIBUTE_NAME)->values(), new Query($parameters)); - - $fallAnime = Anime::factory() - ->count($this->faker->numberBetween(1, 3)) - ->jsonApiResource() - ->create([ - Anime::ATTRIBUTE_YEAR => $year, - Anime::ATTRIBUTE_SEASON => AnimeSeason::FALL->value, - ]); - - $fallResources = new AnimeCollection($fallAnime->sortBy(Anime::ATTRIBUTE_NAME)->values(), new Query($parameters)); - - $response = $this->get(route('api.animeyear.show', [Anime::ATTRIBUTE_YEAR => $year] + $parameters)); - - $response->assertJson([ - Str::lower(AnimeSeason::WINTER->localize()) => json_decode(json_encode($winterResources->response()->getData()->anime), true), - Str::lower(AnimeSeason::SPRING->localize()) => json_decode(json_encode($springResources->response()->getData()->anime), true), - Str::lower(AnimeSeason::SUMMER->localize()) => json_decode(json_encode($summerResources->response()->getData()->anime), true), - Str::lower(AnimeSeason::FALL->localize()) => json_decode(json_encode($fallResources->response()->getData()->anime), true), + $springAnime = Anime::factory() + ->count(fake()->numberBetween(1, 3)) + ->create([ + Anime::ATTRIBUTE_YEAR => $year, + Anime::ATTRIBUTE_SEASON => AnimeSeason::SPRING->value, ]); - } - /** - * The Year Show Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $year = intval($this->faker->year()); + $springResources = new AnimeCollection($springAnime->sortBy(Anime::ATTRIBUTE_NAME)->values(), new Query()); - $schema = new AnimeSchema(); - - $fields = collect($schema->fields()); - - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); - - $parameters = [ - FieldParser::param() => [ - AnimeResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; - - $winterAnime = Anime::factory() - ->count($this->faker->numberBetween(1, 3)) - ->create([ - Anime::ATTRIBUTE_YEAR => $year, - Anime::ATTRIBUTE_SEASON => AnimeSeason::WINTER->value, - ]); - - $winterResources = new AnimeCollection($winterAnime->sortBy(Anime::ATTRIBUTE_NAME)->values(), new Query($parameters)); - - $springAnime = Anime::factory() - ->count($this->faker->numberBetween(1, 3)) - ->create([ - Anime::ATTRIBUTE_YEAR => $year, - Anime::ATTRIBUTE_SEASON => AnimeSeason::SPRING->value, - ]); - - $springResources = new AnimeCollection($springAnime->sortBy(Anime::ATTRIBUTE_NAME)->values(), new Query($parameters)); - - $summerAnime = Anime::factory() - ->count($this->faker->numberBetween(1, 3)) - ->create([ - Anime::ATTRIBUTE_YEAR => $year, - Anime::ATTRIBUTE_SEASON => AnimeSeason::SUMMER->value, - ]); - - $summerResources = new AnimeCollection($summerAnime->sortBy(Anime::ATTRIBUTE_NAME)->values(), new Query($parameters)); - - $fallAnime = Anime::factory() - ->count($this->faker->numberBetween(1, 3)) - ->create([ - Anime::ATTRIBUTE_YEAR => $year, - Anime::ATTRIBUTE_SEASON => AnimeSeason::FALL->value, - ]); - - $fallResources = new AnimeCollection($fallAnime->sortBy(Anime::ATTRIBUTE_NAME)->values(), new Query($parameters)); - - $response = $this->get(route('api.animeyear.show', [Anime::ATTRIBUTE_YEAR => $year] + $parameters)); - - $response->assertJson([ - Str::lower(AnimeSeason::WINTER->localize()) => json_decode(json_encode($winterResources->response()->getData()->anime), true), - Str::lower(AnimeSeason::SPRING->localize()) => json_decode(json_encode($springResources->response()->getData()->anime), true), - Str::lower(AnimeSeason::SUMMER->localize()) => json_decode(json_encode($summerResources->response()->getData()->anime), true), - Str::lower(AnimeSeason::FALL->localize()) => json_decode(json_encode($fallResources->response()->getData()->anime), true), + $summerAnime = Anime::factory() + ->count(fake()->numberBetween(1, 3)) + ->create([ + Anime::ATTRIBUTE_YEAR => $year, + Anime::ATTRIBUTE_SEASON => AnimeSeason::SUMMER->value, ]); - } -} + + $summerResources = new AnimeCollection($summerAnime->sortBy(Anime::ATTRIBUTE_NAME)->values(), new Query()); + + $fallAnime = Anime::factory() + ->count(fake()->numberBetween(1, 3)) + ->create([ + Anime::ATTRIBUTE_YEAR => $year, + Anime::ATTRIBUTE_SEASON => AnimeSeason::FALL->value, + ]); + + $fallResources = new AnimeCollection($fallAnime->sortBy(Anime::ATTRIBUTE_NAME)->values(), new Query()); + + $response = get(route('api.animeyear.show', [Anime::ATTRIBUTE_YEAR => $year])); + + $response->assertJson([ + Str::lower(AnimeSeason::WINTER->localize()) => json_decode(json_encode($winterResources->response()->getData()->anime), true), + Str::lower(AnimeSeason::SPRING->localize()) => json_decode(json_encode($springResources->response()->getData()->anime), true), + Str::lower(AnimeSeason::SUMMER->localize()) => json_decode(json_encode($summerResources->response()->getData()->anime), true), + Str::lower(AnimeSeason::FALL->localize()) => json_decode(json_encode($fallResources->response()->getData()->anime), true), + ]); +}); + +test('allowed include paths', function () { + $year = intval(fake()->year()); + + $schema = new AnimeSchema(); + + $allowedIncludes = collect($schema->allowedIncludes()); + + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); + + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; + + $winterAnime = Anime::factory() + ->count(fake()->numberBetween(1, 3)) + ->jsonApiResource() + ->create([ + Anime::ATTRIBUTE_YEAR => $year, + Anime::ATTRIBUTE_SEASON => AnimeSeason::WINTER->value, + ]); + + $winterResources = new AnimeCollection($winterAnime->sortBy(Anime::ATTRIBUTE_NAME)->values(), new Query($parameters)); + + $springAnime = Anime::factory() + ->count(fake()->numberBetween(1, 3)) + ->jsonApiResource() + ->create([ + Anime::ATTRIBUTE_YEAR => $year, + Anime::ATTRIBUTE_SEASON => AnimeSeason::SPRING->value, + ]); + + $springResources = new AnimeCollection($springAnime->sortBy(Anime::ATTRIBUTE_NAME)->values(), new Query($parameters)); + + $summerAnime = Anime::factory() + ->count(fake()->numberBetween(1, 3)) + ->jsonApiResource() + ->create([ + Anime::ATTRIBUTE_YEAR => $year, + Anime::ATTRIBUTE_SEASON => AnimeSeason::SUMMER->value, + ]); + + $summerResources = new AnimeCollection($summerAnime->sortBy(Anime::ATTRIBUTE_NAME)->values(), new Query($parameters)); + + $fallAnime = Anime::factory() + ->count(fake()->numberBetween(1, 3)) + ->jsonApiResource() + ->create([ + Anime::ATTRIBUTE_YEAR => $year, + Anime::ATTRIBUTE_SEASON => AnimeSeason::FALL->value, + ]); + + $fallResources = new AnimeCollection($fallAnime->sortBy(Anime::ATTRIBUTE_NAME)->values(), new Query($parameters)); + + $response = get(route('api.animeyear.show', [Anime::ATTRIBUTE_YEAR => $year] + $parameters)); + + $response->assertJson([ + Str::lower(AnimeSeason::WINTER->localize()) => json_decode(json_encode($winterResources->response()->getData()->anime), true), + Str::lower(AnimeSeason::SPRING->localize()) => json_decode(json_encode($springResources->response()->getData()->anime), true), + Str::lower(AnimeSeason::SUMMER->localize()) => json_decode(json_encode($summerResources->response()->getData()->anime), true), + Str::lower(AnimeSeason::FALL->localize()) => json_decode(json_encode($fallResources->response()->getData()->anime), true), + ]); +}); + +test('sparse fieldsets', function () { + $year = intval(fake()->year()); + + $schema = new AnimeSchema(); + + $fields = collect($schema->fields()); + + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + AnimeResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + $winterAnime = Anime::factory() + ->count(fake()->numberBetween(1, 3)) + ->create([ + Anime::ATTRIBUTE_YEAR => $year, + Anime::ATTRIBUTE_SEASON => AnimeSeason::WINTER->value, + ]); + + $winterResources = new AnimeCollection($winterAnime->sortBy(Anime::ATTRIBUTE_NAME)->values(), new Query($parameters)); + + $springAnime = Anime::factory() + ->count(fake()->numberBetween(1, 3)) + ->create([ + Anime::ATTRIBUTE_YEAR => $year, + Anime::ATTRIBUTE_SEASON => AnimeSeason::SPRING->value, + ]); + + $springResources = new AnimeCollection($springAnime->sortBy(Anime::ATTRIBUTE_NAME)->values(), new Query($parameters)); + + $summerAnime = Anime::factory() + ->count(fake()->numberBetween(1, 3)) + ->create([ + Anime::ATTRIBUTE_YEAR => $year, + Anime::ATTRIBUTE_SEASON => AnimeSeason::SUMMER->value, + ]); + + $summerResources = new AnimeCollection($summerAnime->sortBy(Anime::ATTRIBUTE_NAME)->values(), new Query($parameters)); + + $fallAnime = Anime::factory() + ->count(fake()->numberBetween(1, 3)) + ->create([ + Anime::ATTRIBUTE_YEAR => $year, + Anime::ATTRIBUTE_SEASON => AnimeSeason::FALL->value, + ]); + + $fallResources = new AnimeCollection($fallAnime->sortBy(Anime::ATTRIBUTE_NAME)->values(), new Query($parameters)); + + $response = get(route('api.animeyear.show', [Anime::ATTRIBUTE_YEAR => $year] + $parameters)); + + $response->assertJson([ + Str::lower(AnimeSeason::WINTER->localize()) => json_decode(json_encode($winterResources->response()->getData()->anime), true), + Str::lower(AnimeSeason::SPRING->localize()) => json_decode(json_encode($springResources->response()->getData()->anime), true), + Str::lower(AnimeSeason::SUMMER->localize()) => json_decode(json_encode($summerResources->response()->getData()->anime), true), + Str::lower(AnimeSeason::FALL->localize()) => json_decode(json_encode($fallResources->response()->getData()->anime), true), + ]); +}); diff --git a/tests/Feature/Http/Api/Wiki/Artist/ArtistDestroyTest.php b/tests/Feature/Http/Api/Wiki/Artist/ArtistDestroyTest.php index 9fac47f5c..027c23f6f 100644 --- a/tests/Feature/Http/Api/Wiki/Artist/ArtistDestroyTest.php +++ b/tests/Feature/Http/Api/Wiki/Artist/ArtistDestroyTest.php @@ -2,74 +2,54 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Artist; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Artist; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ArtistDestroyTest extends TestCase -{ - /** - * The Artist Destroy Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $artist = Artist::factory()->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.artist.destroy', ['artist' => $artist])); +test('protected', function () { + $artist = Artist::factory()->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.artist.destroy', ['artist' => $artist])); - /** - * The Artist Destroy Endpoint shall forbid users without the delete artist permission. - */ - public function testForbidden(): void - { - $artist = Artist::factory()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $artist = Artist::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.artist.destroy', ['artist' => $artist])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.artist.destroy', ['artist' => $artist])); - /** - * The Artist Destroy Endpoint shall forbid users from updating an artist that is trashed. - */ - public function testTrashed(): void - { - $artist = Artist::factory()->trashed()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Artist::class))->createOne(); +test('trashed', function () { + $artist = Artist::factory()->trashed()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Artist::class))->createOne(); - $response = $this->delete(route('api.artist.destroy', ['artist' => $artist])); + Sanctum::actingAs($user); - $response->assertNotFound(); - } + $response = delete(route('api.artist.destroy', ['artist' => $artist])); - /** - * The Artist Destroy Endpoint shall delete the artist. - */ - public function testDeleted(): void - { - $artist = Artist::factory()->createOne(); + $response->assertNotFound(); +}); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Artist::class))->createOne(); +test('deleted', function () { + $artist = Artist::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Artist::class))->createOne(); - $response = $this->delete(route('api.artist.destroy', ['artist' => $artist])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertSoftDeleted($artist); - } -} + $response = delete(route('api.artist.destroy', ['artist' => $artist])); + + $response->assertOk(); + $this->assertSoftDeleted($artist); +}); diff --git a/tests/Feature/Http/Api/Wiki/Artist/ArtistForceDeleteTest.php b/tests/Feature/Http/Api/Wiki/Artist/ArtistForceDeleteTest.php index bb4d143a2..44110973a 100644 --- a/tests/Feature/Http/Api/Wiki/Artist/ArtistForceDeleteTest.php +++ b/tests/Feature/Http/Api/Wiki/Artist/ArtistForceDeleteTest.php @@ -2,58 +2,42 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Artist; - use App\Enums\Auth\ExtendedCrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Artist; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ArtistForceDeleteTest extends TestCase -{ - /** - * The Artist Force Delete Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $artist = Artist::factory()->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.artist.forceDelete', ['artist' => $artist])); +test('protected', function () { + $artist = Artist::factory()->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.artist.forceDelete', ['artist' => $artist])); - /** - * The Artist Force Delete Endpoint shall forbid users without the force delete artist permission. - */ - public function testForbidden(): void - { - $artist = Artist::factory()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $artist = Artist::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.artist.forceDelete', ['artist' => $artist])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.artist.forceDelete', ['artist' => $artist])); - /** - * The Artist Force Delete Endpoint shall force delete the artist. - */ - public function testDeleted(): void - { - $artist = Artist::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::FORCE_DELETE->format(Artist::class))->createOne(); +test('deleted', function () { + $artist = Artist::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::FORCE_DELETE->format(Artist::class))->createOne(); - $response = $this->delete(route('api.artist.forceDelete', ['artist' => $artist])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertModelMissing($artist); - } -} + $response = delete(route('api.artist.forceDelete', ['artist' => $artist])); + + $response->assertOk(); + $this->assertModelMissing($artist); +}); diff --git a/tests/Feature/Http/Api/Wiki/Artist/ArtistIndexTest.php b/tests/Feature/Http/Api/Wiki/Artist/ArtistIndexTest.php index 1397c082f..b74d1d8ce 100644 --- a/tests/Feature/Http/Api/Wiki/Artist/ArtistIndexTest.php +++ b/tests/Feature/Http/Api/Wiki/Artist/ArtistIndexTest.php @@ -2,9 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Artist; - -use App\Concerns\Actions\Http\Api\SortsModels; use App\Constants\ModelConstants; use App\Contracts\Http\Api\Field\SortableField; use App\Enums\Http\Api\Filter\TrashedStatus; @@ -40,714 +37,640 @@ use Illuminate\Database\Eloquent\Factories\Sequence; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\HasMany; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; -use Tests\TestCase; - -class ArtistIndexTest extends TestCase -{ - use SortsModels; - use WithFaker; - - /** - * By default, the Artist Index Endpoint shall return a collection of Artist Resources. - */ - public function testDefault(): void - { - $artists = Artist::factory()->count($this->faker->randomDigitNotNull())->create(); - - $response = $this->get(route('api.artist.index')); - - $response->assertJson( - json_decode( - json_encode( - new ArtistCollection($artists, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Index Endpoint shall be paginated. - */ - public function testPaginated(): void - { - Artist::factory()->count($this->faker->randomDigitNotNull())->create(); - - $response = $this->get(route('api.artist.index')); - - $response->assertJsonStructure([ - ArtistCollection::$wrap, - 'links', - 'meta', - ]); - } - - /** - * The Artist Index Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new ArtistSchema(); - - $allowedIncludes = collect($schema->allowedIncludes()); - - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); - - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Artist::factory()->jsonApiResource()->create(); - $artists = Artist::with($includedPaths->all())->get(); - - $response = $this->get(route('api.artist.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ArtistCollection($artists, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new ArtistSchema(); - - $fields = collect($schema->fields()); - - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); - - $parameters = [ - FieldParser::param() => [ - ArtistResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; - - $artists = Artist::factory()->count($this->faker->randomDigitNotNull())->create(); - - $response = $this->get(route('api.artist.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ArtistCollection($artists, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Index Endpoint shall support sorting resources. - */ - public function testSorts(): void - { - $schema = new ArtistSchema(); - - /** @var Sort $sort */ - $sort = collect($schema->fields()) - ->filter(fn (Field $field) => $field instanceof SortableField) - ->map(fn (SortableField $field) => $field->getSort()) - ->random(); - - $parameters = [ - SortParser::param() => $sort->format(Arr::random(Direction::cases())), - ]; - - $query = new Query($parameters); - - Artist::factory()->count($this->faker->randomDigitNotNull())->create(); - - $response = $this->get(route('api.artist.index', $parameters)); - - $artists = $this->sort(Artist::query(), $query, $schema)->get(); - - $response->assertJson( - json_decode( - json_encode( - new ArtistCollection($artists, $query) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Index Endpoint shall support filtering by created_at. - */ - public function testCreatedAtFilter(): void - { - $createdFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($createdFilter, function () { - Artist::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - Carbon::withTestNow($excludedDate, function () { - Artist::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - $artist = Artist::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - - $response = $this->get(route('api.artist.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ArtistCollection($artist, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Index Endpoint shall support filtering by updated_at. - */ - public function testUpdatedAtFilter(): void - { - $updatedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($updatedFilter, function () { - Artist::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - Carbon::withTestNow($excludedDate, function () { - Artist::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - $artist = Artist::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - - $response = $this->get(route('api.artist.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ArtistCollection($artist, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Index Endpoint shall support filtering by trashed. - */ - public function testWithoutTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITHOUT->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Artist::factory()->count($this->faker->randomDigitNotNull())->create(); - - Artist::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - - $artist = Artist::withoutTrashed()->get(); - - $response = $this->get(route('api.artist.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ArtistCollection($artist, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Index Endpoint shall support filtering by trashed. - */ - public function testWithTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Artist::factory()->count($this->faker->randomDigitNotNull())->create(); - - Artist::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - - $artist = Artist::withTrashed()->get(); - - $response = $this->get(route('api.artist.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ArtistCollection($artist, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Index Endpoint shall support filtering by trashed. - */ - public function testOnlyTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::ONLY->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Artist::factory()->count($this->faker->randomDigitNotNull())->create(); - - Artist::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - - $artist = Artist::onlyTrashed()->get(); - - $response = $this->get(route('api.artist.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ArtistCollection($artist, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Index Endpoint shall support filtering by deleted_at. - */ - public function testDeletedAtFilter(): void - { - $deletedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - ModelConstants::ATTRIBUTE_DELETED_AT => $deletedFilter, - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($deletedFilter, function () { - Artist::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - }); - - Carbon::withTestNow($excludedDate, function () { - Artist::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - }); - - $artist = Artist::withTrashed()->where(ModelConstants::ATTRIBUTE_DELETED_AT, $deletedFilter)->get(); - - $response = $this->get(route('api.artist.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ArtistCollection($artist, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Index Endpoint shall support constrained eager loading of themes by sequence. - */ - public function testThemesBySequence(): void - { - $sequenceFilter = $this->faker->randomDigitNotNull(); - $excludedSequence = $sequenceFilter + 1; - - $parameters = [ - FilterParser::param() => [ - AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter, - ], - IncludeParser::param() => Artist::RELATION_ANIMETHEMES, - ]; - - Artist::factory() - ->has( - Song::factory() - ->count($this->faker->randomDigitNotNull()) - ->has( - AnimeTheme::factory() - ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) - ->state(new Sequence( - [AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter], - [AnimeTheme::ATTRIBUTE_SEQUENCE => $excludedSequence], - )) - ) - ) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $artists = Artist::with([ - Artist::RELATION_ANIMETHEMES => function (HasMany $query) use ($sequenceFilter) { - $query->where(AnimeTheme::ATTRIBUTE_SEQUENCE, $sequenceFilter); - }, - ]) - ->get(); - - $response = $this->get(route('api.artist.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ArtistCollection($artists, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Index Endpoint shall support constrained eager loading of themes by type. - */ - public function testThemesByType(): void - { - $typeFilter = Arr::random(ThemeType::cases()); - - $parameters = [ - FilterParser::param() => [ - AnimeTheme::ATTRIBUTE_TYPE => $typeFilter->localize(), - ], - IncludeParser::param() => Artist::RELATION_ANIMETHEMES, - ]; - - Artist::factory() - ->has( - Song::factory() - ->count($this->faker->randomDigitNotNull()) - ->has( - AnimeTheme::factory() - ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) - ) - ) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $artists = Artist::with([ - Artist::RELATION_ANIMETHEMES => function (HasMany $query) use ($typeFilter) { - $query->where(AnimeTheme::ATTRIBUTE_TYPE, $typeFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.artist.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ArtistCollection($artists, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Index Endpoint shall support constrained eager loading of anime by media format. - */ - public function testAnimeByMediaFormat(): void - { - $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), - ], - IncludeParser::param() => Artist::RELATION_ANIME, - ]; - - Artist::factory() - ->has( - Song::factory() - ->count($this->faker->randomDigitNotNull()) - ->has( - AnimeTheme::factory() - ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) - ) - ) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $artists = Artist::with([ - Artist::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { - $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.artist.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ArtistCollection($artists, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Index Endpoint shall support constrained eager loading of anime by season. - */ - public function testAnimeBySeason(): void - { - $seasonFilter = Arr::random(AnimeSeason::cases()); - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), - ], - IncludeParser::param() => Artist::RELATION_ANIME, - ]; - - Artist::factory() - ->has( - Song::factory() - ->count($this->faker->randomDigitNotNull()) - ->has( - AnimeTheme::factory() - ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) - ) - ) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $artists = Artist::with([ - Artist::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { - $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.artist.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ArtistCollection($artists, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Index Endpoint shall support constrained eager loading of anime by year. - */ - public function testAnimeByYear(): void - { - $yearFilter = intval($this->faker->year()); - $excludedYear = $yearFilter + 1; - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_YEAR => $yearFilter, - ], - IncludeParser::param() => Artist::RELATION_ANIME, - ]; - - Artist::factory() - ->has( - Song::factory() - ->count($this->faker->randomDigitNotNull()) - ->has( - AnimeTheme::factory() - ->for( - Anime::factory() - ->state([ - Anime::ATTRIBUTE_YEAR => $this->faker->boolean() ? $yearFilter : $excludedYear, - ]) - ) - ->count($this->faker->randomDigitNotNull()) - ) - ) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $artists = Artist::with([ - Artist::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { - $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); - }, - ]) - ->get(); - - $response = $this->get(route('api.artist.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ArtistCollection($artists, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Index Endpoint shall support constrained eager loading of resources by site. - */ - public function testResourcesBySite(): void - { - $siteFilter = Arr::random(ResourceSite::cases()); - - $parameters = [ - FilterParser::param() => [ - ExternalResource::ATTRIBUTE_SITE => $siteFilter->localize(), - ], - IncludeParser::param() => Artist::RELATION_RESOURCES, - ]; - - Artist::factory() - ->has(ExternalResource::factory()->count($this->faker->randomDigitNotNull()), Artist::RELATION_RESOURCES) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $artists = Artist::with([ - Artist::RELATION_RESOURCES => function (BelongsToMany $query) use ($siteFilter) { - $query->where(ExternalResource::ATTRIBUTE_SITE, $siteFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.artist.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ArtistCollection($artists, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Index Endpoint shall support constrained eager loading of images by facet. - */ - public function testImagesByFacet(): void - { - $facetFilter = Arr::random(ImageFacet::cases()); - - $parameters = [ - FilterParser::param() => [ - Image::ATTRIBUTE_FACET => $facetFilter->localize(), - ], - IncludeParser::param() => Artist::RELATION_IMAGES, - ]; - - Artist::factory() - ->has(Image::factory()->count($this->faker->randomDigitNotNull())) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $artists = Artist::with([ - Artist::RELATION_IMAGES => function (BelongsToMany $query) use ($facetFilter) { - $query->where(Image::ATTRIBUTE_FACET, $facetFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.artist.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ArtistCollection($artists, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + +use function Pest\Laravel\get; + +uses(App\Concerns\Actions\Http\Api\SortsModels::class); + +uses(Illuminate\Foundation\Testing\WithFaker::class); + +test('default', function () { + $artists = Artist::factory()->count(fake()->randomDigitNotNull())->create(); + + $response = get(route('api.artist.index')); + + $response->assertJson( + json_decode( + json_encode( + new ArtistCollection($artists, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('paginated', function () { + Artist::factory()->count(fake()->randomDigitNotNull())->create(); + + $response = get(route('api.artist.index')); + + $response->assertJsonStructure([ + ArtistCollection::$wrap, + 'links', + 'meta', + ]); +}); + +test('allowed include paths', function () { + $schema = new ArtistSchema(); + + $allowedIncludes = collect($schema->allowedIncludes()); + + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); + + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Artist::factory()->jsonApiResource()->create(); + $artists = Artist::with($includedPaths->all())->get(); + + $response = get(route('api.artist.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ArtistCollection($artists, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sparse fieldsets', function () { + $schema = new ArtistSchema(); + + $fields = collect($schema->fields()); + + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + ArtistResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + $artists = Artist::factory()->count(fake()->randomDigitNotNull())->create(); + + $response = get(route('api.artist.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ArtistCollection($artists, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sorts', function () { + $schema = new ArtistSchema(); + + /** @var Sort $sort */ + $sort = collect($schema->fields()) + ->filter(fn (Field $field) => $field instanceof SortableField) + ->map(fn (SortableField $field) => $field->getSort()) + ->random(); + + $parameters = [ + SortParser::param() => $sort->format(Arr::random(Direction::cases())), + ]; + + $query = new Query($parameters); + + Artist::factory()->count(fake()->randomDigitNotNull())->create(); + + $response = get(route('api.artist.index', $parameters)); + + $artists = $this->sort(Artist::query(), $query, $schema)->get(); + + $response->assertJson( + json_decode( + json_encode( + new ArtistCollection($artists, $query) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('created at filter', function () { + $createdFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($createdFilter, function () { + Artist::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + Carbon::withTestNow($excludedDate, function () { + Artist::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + $artist = Artist::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); + + $response = get(route('api.artist.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ArtistCollection($artist, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('updated at filter', function () { + $updatedFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($updatedFilter, function () { + Artist::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + Carbon::withTestNow($excludedDate, function () { + Artist::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + $artist = Artist::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); + + $response = get(route('api.artist.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ArtistCollection($artist, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('without trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITHOUT->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Artist::factory()->count(fake()->randomDigitNotNull())->create(); + + Artist::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + + $artist = Artist::withoutTrashed()->get(); + + $response = get(route('api.artist.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ArtistCollection($artist, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('with trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Artist::factory()->count(fake()->randomDigitNotNull())->create(); + + Artist::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + + $artist = Artist::withTrashed()->get(); + + $response = get(route('api.artist.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ArtistCollection($artist, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('only trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::ONLY->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Artist::factory()->count(fake()->randomDigitNotNull())->create(); + + Artist::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + + $artist = Artist::onlyTrashed()->get(); + + $response = get(route('api.artist.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ArtistCollection($artist, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('deleted at filter', function () { + $deletedFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + ModelConstants::ATTRIBUTE_DELETED_AT => $deletedFilter, + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($deletedFilter, function () { + Artist::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + }); + + Carbon::withTestNow($excludedDate, function () { + Artist::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + }); + + $artist = Artist::withTrashed()->where(ModelConstants::ATTRIBUTE_DELETED_AT, $deletedFilter)->get(); + + $response = get(route('api.artist.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ArtistCollection($artist, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('themes by sequence', function () { + $sequenceFilter = fake()->randomDigitNotNull(); + $excludedSequence = $sequenceFilter + 1; + + $parameters = [ + FilterParser::param() => [ + AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter, + ], + IncludeParser::param() => Artist::RELATION_ANIMETHEMES, + ]; + + Artist::factory() + ->has( + Song::factory() + ->count(fake()->randomDigitNotNull()) + ->has( + AnimeTheme::factory() + ->for(Anime::factory()) + ->count(fake()->randomDigitNotNull()) + ->state(new Sequence( + [AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter], + [AnimeTheme::ATTRIBUTE_SEQUENCE => $excludedSequence], + )) + ) + ) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $artists = Artist::with([ + Artist::RELATION_ANIMETHEMES => function (HasMany $query) use ($sequenceFilter) { + $query->where(AnimeTheme::ATTRIBUTE_SEQUENCE, $sequenceFilter); + }, + ]) + ->get(); + + $response = get(route('api.artist.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ArtistCollection($artists, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('themes by type', function () { + $typeFilter = Arr::random(ThemeType::cases()); + + $parameters = [ + FilterParser::param() => [ + AnimeTheme::ATTRIBUTE_TYPE => $typeFilter->localize(), + ], + IncludeParser::param() => Artist::RELATION_ANIMETHEMES, + ]; + + Artist::factory() + ->has( + Song::factory() + ->count(fake()->randomDigitNotNull()) + ->has( + AnimeTheme::factory() + ->for(Anime::factory()) + ->count(fake()->randomDigitNotNull()) + ) + ) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $artists = Artist::with([ + Artist::RELATION_ANIMETHEMES => function (HasMany $query) use ($typeFilter) { + $query->where(AnimeTheme::ATTRIBUTE_TYPE, $typeFilter->value); + }, + ]) + ->get(); + + $response = get(route('api.artist.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ArtistCollection($artists, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by media format', function () { + $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), + ], + IncludeParser::param() => Artist::RELATION_ANIME, + ]; + + Artist::factory() + ->has( + Song::factory() + ->count(fake()->randomDigitNotNull()) + ->has( + AnimeTheme::factory() + ->for(Anime::factory()) + ->count(fake()->randomDigitNotNull()) + ) + ) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $artists = Artist::with([ + Artist::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { + $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); + }, + ]) + ->get(); + + $response = get(route('api.artist.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ArtistCollection($artists, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by season', function () { + $seasonFilter = Arr::random(AnimeSeason::cases()); + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), + ], + IncludeParser::param() => Artist::RELATION_ANIME, + ]; + + Artist::factory() + ->has( + Song::factory() + ->count(fake()->randomDigitNotNull()) + ->has( + AnimeTheme::factory() + ->for(Anime::factory()) + ->count(fake()->randomDigitNotNull()) + ) + ) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $artists = Artist::with([ + Artist::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { + $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); + }, + ]) + ->get(); + + $response = get(route('api.artist.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ArtistCollection($artists, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by year', function () { + $yearFilter = intval(fake()->year()); + $excludedYear = $yearFilter + 1; + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_YEAR => $yearFilter, + ], + IncludeParser::param() => Artist::RELATION_ANIME, + ]; + + Artist::factory() + ->has( + Song::factory() + ->count(fake()->randomDigitNotNull()) + ->has( + AnimeTheme::factory() + ->for( + Anime::factory() + ->state([ + Anime::ATTRIBUTE_YEAR => fake()->boolean() ? $yearFilter : $excludedYear, + ]) + ) + ->count(fake()->randomDigitNotNull()) + ) + ) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $artists = Artist::with([ + Artist::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { + $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); + }, + ]) + ->get(); + + $response = get(route('api.artist.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ArtistCollection($artists, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('resources by site', function () { + $siteFilter = Arr::random(ResourceSite::cases()); + + $parameters = [ + FilterParser::param() => [ + ExternalResource::ATTRIBUTE_SITE => $siteFilter->localize(), + ], + IncludeParser::param() => Artist::RELATION_RESOURCES, + ]; + + Artist::factory() + ->has(ExternalResource::factory()->count(fake()->randomDigitNotNull()), Artist::RELATION_RESOURCES) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $artists = Artist::with([ + Artist::RELATION_RESOURCES => function (BelongsToMany $query) use ($siteFilter) { + $query->where(ExternalResource::ATTRIBUTE_SITE, $siteFilter->value); + }, + ]) + ->get(); + + $response = get(route('api.artist.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ArtistCollection($artists, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('images by facet', function () { + $facetFilter = Arr::random(ImageFacet::cases()); + + $parameters = [ + FilterParser::param() => [ + Image::ATTRIBUTE_FACET => $facetFilter->localize(), + ], + IncludeParser::param() => Artist::RELATION_IMAGES, + ]; + + Artist::factory() + ->has(Image::factory()->count(fake()->randomDigitNotNull())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $artists = Artist::with([ + Artist::RELATION_IMAGES => function (BelongsToMany $query) use ($facetFilter) { + $query->where(Image::ATTRIBUTE_FACET, $facetFilter->value); + }, + ]) + ->get(); + + $response = get(route('api.artist.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ArtistCollection($artists, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Wiki/Artist/ArtistRestoreTest.php b/tests/Feature/Http/Api/Wiki/Artist/ArtistRestoreTest.php index 583686f33..efc465e91 100644 --- a/tests/Feature/Http/Api/Wiki/Artist/ArtistRestoreTest.php +++ b/tests/Feature/Http/Api/Wiki/Artist/ArtistRestoreTest.php @@ -2,74 +2,54 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Artist; - use App\Enums\Auth\ExtendedCrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Artist; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ArtistRestoreTest extends TestCase -{ - /** - * The Artist Restore Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $artist = Artist::factory()->trashed()->createOne(); +use function Pest\Laravel\patch; - $response = $this->patch(route('api.artist.restore', ['artist' => $artist])); +test('protected', function () { + $artist = Artist::factory()->trashed()->createOne(); - $response->assertUnauthorized(); - } + $response = patch(route('api.artist.restore', ['artist' => $artist])); - /** - * The Artist Restore Endpoint shall forbid users without the restore artist permission. - */ - public function testForbidden(): void - { - $artist = Artist::factory()->trashed()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $artist = Artist::factory()->trashed()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->patch(route('api.artist.restore', ['artist' => $artist])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = patch(route('api.artist.restore', ['artist' => $artist])); - /** - * The Artist Restore Endpoint shall forbid users from restoring an artist that isn't trashed. - */ - public function testTrashed(): void - { - $artist = Artist::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(Artist::class))->createOne(); +test('trashed', function () { + $artist = Artist::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(Artist::class))->createOne(); - $response = $this->patch(route('api.artist.restore', ['artist' => $artist])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = patch(route('api.artist.restore', ['artist' => $artist])); - /** - * The Artist Restore Endpoint shall restore the artist. - */ - public function testRestored(): void - { - $artist = Artist::factory()->trashed()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(Artist::class))->createOne(); +test('restored', function () { + $artist = Artist::factory()->trashed()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(Artist::class))->createOne(); - $response = $this->patch(route('api.artist.restore', ['artist' => $artist])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertNotSoftDeleted($artist); - } -} + $response = patch(route('api.artist.restore', ['artist' => $artist])); + + $response->assertOk(); + $this->assertNotSoftDeleted($artist); +}); diff --git a/tests/Feature/Http/Api/Wiki/Artist/ArtistShowTest.php b/tests/Feature/Http/Api/Wiki/Artist/ArtistShowTest.php index 0ef21ca6d..4b83bee69 100644 --- a/tests/Feature/Http/Api/Wiki/Artist/ArtistShowTest.php +++ b/tests/Feature/Http/Api/Wiki/Artist/ArtistShowTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Artist; - use App\Enums\Models\Wiki\AnimeMediaFormat; use App\Enums\Models\Wiki\AnimeSeason; use App\Enums\Models\Wiki\ImageFacet; @@ -27,438 +25,391 @@ use Illuminate\Database\Eloquent\Factories\Sequence; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\HasMany; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; -use Tests\TestCase; - -class ArtistShowTest extends TestCase -{ - use WithFaker; - - /** - * By default, the Artist Show Endpoint shall return an Artist Resource. - */ - public function testDefault(): void - { - $artist = Artist::factory()->create(); - - $response = $this->get(route('api.artist.show', ['artist' => $artist])); - - $response->assertJson( - json_decode( - json_encode( - new ArtistResource($artist, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Show Endpoint shall return an Artist Resource for soft deleted images. - */ - public function testSoftDelete(): void - { - $artist = Artist::factory()->trashed()->createOne(); - - $artist->unsetRelations(); - - $response = $this->get(route('api.artist.show', ['artist' => $artist])); - - $response->assertJson( - json_decode( - json_encode( - new ArtistResource($artist, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Show Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new ArtistSchema(); - - $allowedIncludes = collect($schema->allowedIncludes()); - - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); - - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; - - $artist = Artist::factory()->jsonApiResource()->createOne(); - - $response = $this->get(route('api.artist.show', ['artist' => $artist] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ArtistResource($artist, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Show Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new ArtistSchema(); - - $fields = collect($schema->fields()); - - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); - - $parameters = [ - FieldParser::param() => [ - ArtistResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; - - $artist = Artist::factory()->create(); - - $response = $this->get(route('api.artist.show', ['artist' => $artist] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ArtistResource($artist, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Show Endpoint shall support constrained eager loading of themes by sequence. - */ - public function testThemesBySequence(): void - { - $sequenceFilter = $this->faker->randomDigitNotNull(); - $excludedSequence = $sequenceFilter + 1; - - $parameters = [ - FilterParser::param() => [ - AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter, - ], - IncludeParser::param() => Artist::RELATION_ANIMETHEMES, - ]; - - $artist = Artist::factory() - ->has( - Song::factory() - ->count($this->faker->randomDigitNotNull()) - ->has( - AnimeTheme::factory() - ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) - ->state(new Sequence( - [AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter], - [AnimeTheme::ATTRIBUTE_SEQUENCE => $excludedSequence], - )) - ) - ) - ->createOne(); - - $artist->unsetRelations()->load([ - Artist::RELATION_ANIMETHEMES => function (HasMany $query) use ($sequenceFilter) { - $query->where(AnimeTheme::ATTRIBUTE_SEQUENCE, $sequenceFilter); - }, - ]); - - $response = $this->get(route('api.artist.show', ['artist' => $artist] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ArtistResource($artist, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Show Endpoint shall support constrained eager loading of themes by type. - */ - public function testThemesByType(): void - { - $typeFilter = Arr::random(ThemeType::cases()); - - $parameters = [ - FilterParser::param() => [ - AnimeTheme::ATTRIBUTE_TYPE => $typeFilter->localize(), - ], - IncludeParser::param() => Artist::RELATION_ANIMETHEMES, - ]; - - $artist = Artist::factory() - ->has( - Song::factory() - ->count($this->faker->randomDigitNotNull()) - ->has( - AnimeTheme::factory() - ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) - ) - ) - ->createOne(); - - $artist->unsetRelations()->load([ - Artist::RELATION_ANIMETHEMES => function (HasMany $query) use ($typeFilter) { - $query->where(AnimeTheme::ATTRIBUTE_TYPE, $typeFilter->value); - }, - ]); - - $response = $this->get(route('api.artist.show', ['artist' => $artist] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ArtistResource($artist, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Show Endpoint shall support constrained eager loading of anime by media format. - */ - public function testAnimeByMediaFormat(): void - { - $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), - ], - IncludeParser::param() => Artist::RELATION_ANIME, - ]; - - $artist = Artist::factory() - ->has( - Song::factory() - ->count($this->faker->randomDigitNotNull()) - ->has( - AnimeTheme::factory() - ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) - ) - ) - ->createOne(); - - $artist->unsetRelations()->load([ - Artist::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { - $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); - }, - ]); - - $response = $this->get(route('api.artist.show', ['artist' => $artist] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ArtistResource($artist, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Show Endpoint shall support constrained eager loading of anime by season. - */ - public function testAnimeBySeason(): void - { - $seasonFilter = Arr::random(AnimeSeason::cases()); - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), - ], - IncludeParser::param() => Artist::RELATION_ANIME, - ]; - - $artist = Artist::factory() - ->has( - Song::factory() - ->count($this->faker->randomDigitNotNull()) - ->has( - AnimeTheme::factory() - ->for(Anime::factory()) - ->count($this->faker->randomDigitNotNull()) - ) - ) - ->createOne(); - - $artist->unsetRelations()->load([ - Artist::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { - $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); - }, - ]); - - $response = $this->get(route('api.artist.show', ['artist' => $artist] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ArtistResource($artist, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Show Endpoint shall support constrained eager loading of anime by year. - */ - public function testAnimeByYear(): void - { - $yearFilter = intval($this->faker->year()); - $excludedYear = $yearFilter + 1; - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_YEAR => $yearFilter, - ], - IncludeParser::param() => Artist::RELATION_ANIME, - ]; - - $artist = Artist::factory() - ->has( - Song::factory() - ->count($this->faker->randomDigitNotNull()) - ->has( - AnimeTheme::factory() - ->for( - Anime::factory() - ->state([ - Anime::ATTRIBUTE_YEAR => $this->faker->boolean() ? $yearFilter : $excludedYear, - ]) - ) - ->count($this->faker->randomDigitNotNull()) - ) - ) - ->createOne(); - - $artist->unsetRelations()->load([ - Artist::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { - $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); - }, - ]); - - $response = $this->get(route('api.artist.show', ['artist' => $artist] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ArtistResource($artist, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Show Endpoint shall support constrained eager loading of resources by site. - */ - public function testResourcesBySite(): void - { - $siteFilter = Arr::random(ResourceSite::cases()); - - $parameters = [ - FilterParser::param() => [ - ExternalResource::ATTRIBUTE_SITE => $siteFilter->localize(), - ], - IncludeParser::param() => Artist::RELATION_RESOURCES, - ]; - - $artist = Artist::factory() - ->has(ExternalResource::factory()->count($this->faker->randomDigitNotNull()), Artist::RELATION_RESOURCES) - ->createOne(); - - $artist->unsetRelations()->load([ - Artist::RELATION_RESOURCES => function (BelongsToMany $query) use ($siteFilter) { - $query->where(ExternalResource::ATTRIBUTE_SITE, $siteFilter->value); - }, - ]); - - $response = $this->get(route('api.artist.show', ['artist' => $artist] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ArtistResource($artist, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Artist Show Endpoint shall support constrained eager loading of images by facet. - */ - public function testImagesByFacet(): void - { - $facetFilter = Arr::random(ImageFacet::cases()); - - $parameters = [ - FilterParser::param() => [ - Image::ATTRIBUTE_FACET => $facetFilter->localize(), - ], - IncludeParser::param() => Artist::RELATION_IMAGES, - ]; - - $artist = Artist::factory() - ->has(Image::factory()->count($this->faker->randomDigitNotNull())) - ->createOne(); - - $artist->unsetRelations()->load([ - Artist::RELATION_IMAGES => function (BelongsToMany $query) use ($facetFilter) { - $query->where(Image::ATTRIBUTE_FACET, $facetFilter->value); - }, - ]); - - $response = $this->get(route('api.artist.show', ['artist' => $artist] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ArtistResource($artist, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + +use function Pest\Laravel\get; + +uses(Illuminate\Foundation\Testing\WithFaker::class); + +test('default', function () { + $artist = Artist::factory()->create(); + + $response = get(route('api.artist.show', ['artist' => $artist])); + + $response->assertJson( + json_decode( + json_encode( + new ArtistResource($artist, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('soft delete', function () { + $artist = Artist::factory()->trashed()->createOne(); + + $artist->unsetRelations(); + + $response = get(route('api.artist.show', ['artist' => $artist])); + + $response->assertJson( + json_decode( + json_encode( + new ArtistResource($artist, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('allowed include paths', function () { + $schema = new ArtistSchema(); + + $allowedIncludes = collect($schema->allowedIncludes()); + + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); + + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; + + $artist = Artist::factory()->jsonApiResource()->createOne(); + + $response = get(route('api.artist.show', ['artist' => $artist] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ArtistResource($artist, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sparse fieldsets', function () { + $schema = new ArtistSchema(); + + $fields = collect($schema->fields()); + + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + ArtistResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + $artist = Artist::factory()->create(); + + $response = get(route('api.artist.show', ['artist' => $artist] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ArtistResource($artist, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('themes by sequence', function () { + $sequenceFilter = fake()->randomDigitNotNull(); + $excludedSequence = $sequenceFilter + 1; + + $parameters = [ + FilterParser::param() => [ + AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter, + ], + IncludeParser::param() => Artist::RELATION_ANIMETHEMES, + ]; + + $artist = Artist::factory() + ->has( + Song::factory() + ->count(fake()->randomDigitNotNull()) + ->has( + AnimeTheme::factory() + ->for(Anime::factory()) + ->count(fake()->randomDigitNotNull()) + ->state(new Sequence( + [AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter], + [AnimeTheme::ATTRIBUTE_SEQUENCE => $excludedSequence], + )) + ) + ) + ->createOne(); + + $artist->unsetRelations()->load([ + Artist::RELATION_ANIMETHEMES => function (HasMany $query) use ($sequenceFilter) { + $query->where(AnimeTheme::ATTRIBUTE_SEQUENCE, $sequenceFilter); + }, + ]); + + $response = get(route('api.artist.show', ['artist' => $artist] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ArtistResource($artist, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('themes by type', function () { + $typeFilter = Arr::random(ThemeType::cases()); + + $parameters = [ + FilterParser::param() => [ + AnimeTheme::ATTRIBUTE_TYPE => $typeFilter->localize(), + ], + IncludeParser::param() => Artist::RELATION_ANIMETHEMES, + ]; + + $artist = Artist::factory() + ->has( + Song::factory() + ->count(fake()->randomDigitNotNull()) + ->has( + AnimeTheme::factory() + ->for(Anime::factory()) + ->count(fake()->randomDigitNotNull()) + ) + ) + ->createOne(); + + $artist->unsetRelations()->load([ + Artist::RELATION_ANIMETHEMES => function (HasMany $query) use ($typeFilter) { + $query->where(AnimeTheme::ATTRIBUTE_TYPE, $typeFilter->value); + }, + ]); + + $response = get(route('api.artist.show', ['artist' => $artist] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ArtistResource($artist, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by media format', function () { + $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), + ], + IncludeParser::param() => Artist::RELATION_ANIME, + ]; + + $artist = Artist::factory() + ->has( + Song::factory() + ->count(fake()->randomDigitNotNull()) + ->has( + AnimeTheme::factory() + ->for(Anime::factory()) + ->count(fake()->randomDigitNotNull()) + ) + ) + ->createOne(); + + $artist->unsetRelations()->load([ + Artist::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { + $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); + }, + ]); + + $response = get(route('api.artist.show', ['artist' => $artist] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ArtistResource($artist, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by season', function () { + $seasonFilter = Arr::random(AnimeSeason::cases()); + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), + ], + IncludeParser::param() => Artist::RELATION_ANIME, + ]; + + $artist = Artist::factory() + ->has( + Song::factory() + ->count(fake()->randomDigitNotNull()) + ->has( + AnimeTheme::factory() + ->for(Anime::factory()) + ->count(fake()->randomDigitNotNull()) + ) + ) + ->createOne(); + + $artist->unsetRelations()->load([ + Artist::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { + $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); + }, + ]); + + $response = get(route('api.artist.show', ['artist' => $artist] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ArtistResource($artist, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by year', function () { + $yearFilter = intval(fake()->year()); + $excludedYear = $yearFilter + 1; + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_YEAR => $yearFilter, + ], + IncludeParser::param() => Artist::RELATION_ANIME, + ]; + + $artist = Artist::factory() + ->has( + Song::factory() + ->count(fake()->randomDigitNotNull()) + ->has( + AnimeTheme::factory() + ->for( + Anime::factory() + ->state([ + Anime::ATTRIBUTE_YEAR => fake()->boolean() ? $yearFilter : $excludedYear, + ]) + ) + ->count(fake()->randomDigitNotNull()) + ) + ) + ->createOne(); + + $artist->unsetRelations()->load([ + Artist::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { + $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); + }, + ]); + + $response = get(route('api.artist.show', ['artist' => $artist] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ArtistResource($artist, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('resources by site', function () { + $siteFilter = Arr::random(ResourceSite::cases()); + + $parameters = [ + FilterParser::param() => [ + ExternalResource::ATTRIBUTE_SITE => $siteFilter->localize(), + ], + IncludeParser::param() => Artist::RELATION_RESOURCES, + ]; + + $artist = Artist::factory() + ->has(ExternalResource::factory()->count(fake()->randomDigitNotNull()), Artist::RELATION_RESOURCES) + ->createOne(); + + $artist->unsetRelations()->load([ + Artist::RELATION_RESOURCES => function (BelongsToMany $query) use ($siteFilter) { + $query->where(ExternalResource::ATTRIBUTE_SITE, $siteFilter->value); + }, + ]); + + $response = get(route('api.artist.show', ['artist' => $artist] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ArtistResource($artist, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('images by facet', function () { + $facetFilter = Arr::random(ImageFacet::cases()); + + $parameters = [ + FilterParser::param() => [ + Image::ATTRIBUTE_FACET => $facetFilter->localize(), + ], + IncludeParser::param() => Artist::RELATION_IMAGES, + ]; + + $artist = Artist::factory() + ->has(Image::factory()->count(fake()->randomDigitNotNull())) + ->createOne(); + + $artist->unsetRelations()->load([ + Artist::RELATION_IMAGES => function (BelongsToMany $query) use ($facetFilter) { + $query->where(Image::ATTRIBUTE_FACET, $facetFilter->value); + }, + ]); + + $response = get(route('api.artist.show', ['artist' => $artist] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ArtistResource($artist, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Wiki/Artist/ArtistStoreTest.php b/tests/Feature/Http/Api/Wiki/Artist/ArtistStoreTest.php index a9fb6ba7b..bb9944105 100644 --- a/tests/Feature/Http/Api/Wiki/Artist/ArtistStoreTest.php +++ b/tests/Feature/Http/Api/Wiki/Artist/ArtistStoreTest.php @@ -2,75 +2,55 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Artist; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Artist; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ArtistStoreTest extends TestCase -{ - /** - * The Artist Store Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $artist = Artist::factory()->makeOne(); +use function Pest\Laravel\post; - $response = $this->post(route('api.artist.store', $artist->toArray())); +test('protected', function () { + $artist = Artist::factory()->makeOne(); - $response->assertUnauthorized(); - } + $response = post(route('api.artist.store', $artist->toArray())); - /** - * The Artist Store Endpoint shall forbid users without the create artist permission. - */ - public function testForbidden(): void - { - $artist = Artist::factory()->makeOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $artist = Artist::factory()->makeOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->post(route('api.artist.store', $artist->toArray())); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.artist.store', $artist->toArray())); - /** - * The Artist Store Endpoint shall require name & slug fields. - */ - public function testRequiredFields(): void - { - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Artist::class))->createOne(); + $response->assertForbidden(); +}); - Sanctum::actingAs($user); +test('required fields', function () { + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Artist::class))->createOne(); - $response = $this->post(route('api.artist.store')); + Sanctum::actingAs($user); - $response->assertJsonValidationErrors([ - Artist::ATTRIBUTE_NAME, - Artist::ATTRIBUTE_SLUG, - ]); - } + $response = post(route('api.artist.store')); - /** - * The Artist Store Endpoint shall create an artist. - */ - public function testCreate(): void - { - $parameters = Artist::factory()->raw(); + $response->assertJsonValidationErrors([ + Artist::ATTRIBUTE_NAME, + Artist::ATTRIBUTE_SLUG, + ]); +}); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Artist::class))->createOne(); +test('create', function () { + $parameters = Artist::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Artist::class))->createOne(); - $response = $this->post(route('api.artist.store', $parameters)); + Sanctum::actingAs($user); - $response->assertCreated(); - static::assertDatabaseCount(Artist::class, 1); - } -} + $response = post(route('api.artist.store', $parameters)); + + $response->assertCreated(); + $this->assertDatabaseCount(Artist::class, 1); +}); diff --git a/tests/Feature/Http/Api/Wiki/Artist/ArtistUpdateTest.php b/tests/Feature/Http/Api/Wiki/Artist/ArtistUpdateTest.php index 687c59c7e..f26a30f75 100644 --- a/tests/Feature/Http/Api/Wiki/Artist/ArtistUpdateTest.php +++ b/tests/Feature/Http/Api/Wiki/Artist/ArtistUpdateTest.php @@ -2,81 +2,61 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Artist; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Artist; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ArtistUpdateTest extends TestCase -{ - /** - * The Artist Update Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $artist = Artist::factory()->createOne(); +use function Pest\Laravel\put; - $parameters = Artist::factory()->raw(); +test('protected', function () { + $artist = Artist::factory()->createOne(); - $response = $this->put(route('api.artist.update', ['artist' => $artist] + $parameters)); + $parameters = Artist::factory()->raw(); - $response->assertUnauthorized(); - } + $response = put(route('api.artist.update', ['artist' => $artist] + $parameters)); - /** - * The Artist Update Endpoint shall forbid users without the update artist permission. - */ - public function testForbidden(): void - { - $artist = Artist::factory()->createOne(); + $response->assertUnauthorized(); +}); - $parameters = Artist::factory()->raw(); +test('forbidden', function () { + $artist = Artist::factory()->createOne(); - $user = User::factory()->createOne(); + $parameters = Artist::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->put(route('api.artist.update', ['artist' => $artist] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.artist.update', ['artist' => $artist] + $parameters)); - /** - * The Artist Update Endpoint shall forbid users from updating an artist that is trashed. - */ - public function testTrashed(): void - { - $artist = Artist::factory()->trashed()->createOne(); + $response->assertForbidden(); +}); - $parameters = Artist::factory()->raw(); +test('trashed', function () { + $artist = Artist::factory()->trashed()->createOne(); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Artist::class))->createOne(); + $parameters = Artist::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Artist::class))->createOne(); - $response = $this->put(route('api.artist.update', ['artist' => $artist] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.artist.update', ['artist' => $artist] + $parameters)); - /** - * The Artist Update Endpoint shall update an artist. - */ - public function testUpdate(): void - { - $artist = Artist::factory()->createOne(); + $response->assertForbidden(); +}); - $parameters = Artist::factory()->raw(); +test('update', function () { + $artist = Artist::factory()->createOne(); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Artist::class))->createOne(); + $parameters = Artist::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Artist::class))->createOne(); - $response = $this->put(route('api.artist.update', ['artist' => $artist] + $parameters)); + Sanctum::actingAs($user); - $response->assertOk(); - } -} + $response = put(route('api.artist.update', ['artist' => $artist] + $parameters)); + + $response->assertOk(); +}); diff --git a/tests/Feature/Http/Api/Wiki/Audio/AudioDestroyTest.php b/tests/Feature/Http/Api/Wiki/Audio/AudioDestroyTest.php index 82febb59c..25bc27170 100644 --- a/tests/Feature/Http/Api/Wiki/Audio/AudioDestroyTest.php +++ b/tests/Feature/Http/Api/Wiki/Audio/AudioDestroyTest.php @@ -2,74 +2,54 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Audio; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Audio; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class AudioDestroyTest extends TestCase -{ - /** - * The Audio Destroy Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $audio = Audio::factory()->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.audio.destroy', ['audio' => $audio])); +test('protected', function () { + $audio = Audio::factory()->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.audio.destroy', ['audio' => $audio])); - /** - * The Audio Destroy Endpoint shall forbid users without the delete audio permission. - */ - public function testForbidden(): void - { - $audio = Audio::factory()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $audio = Audio::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.audio.destroy', ['audio' => $audio])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.audio.destroy', ['audio' => $audio])); - /** - * The Audio Destroy Endpoint shall forbid users from updating an audio that is trashed. - */ - public function testTrashed(): void - { - $audio = Audio::factory()->trashed()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Audio::class))->createOne(); +test('trashed', function () { + $audio = Audio::factory()->trashed()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Audio::class))->createOne(); - $response = $this->delete(route('api.audio.destroy', ['audio' => $audio])); + Sanctum::actingAs($user); - $response->assertNotFound(); - } + $response = delete(route('api.audio.destroy', ['audio' => $audio])); - /** - * The Audio Destroy Endpoint shall delete the audio. - */ - public function testDeleted(): void - { - $audio = Audio::factory()->createOne(); + $response->assertNotFound(); +}); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Audio::class))->createOne(); +test('deleted', function () { + $audio = Audio::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Audio::class))->createOne(); - $response = $this->delete(route('api.audio.destroy', ['audio' => $audio])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertSoftDeleted($audio); - } -} + $response = delete(route('api.audio.destroy', ['audio' => $audio])); + + $response->assertOk(); + $this->assertSoftDeleted($audio); +}); diff --git a/tests/Feature/Http/Api/Wiki/Audio/AudioForceDeleteTest.php b/tests/Feature/Http/Api/Wiki/Audio/AudioForceDeleteTest.php index 603a71d47..3323c834a 100644 --- a/tests/Feature/Http/Api/Wiki/Audio/AudioForceDeleteTest.php +++ b/tests/Feature/Http/Api/Wiki/Audio/AudioForceDeleteTest.php @@ -2,58 +2,42 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Audio; - use App\Enums\Auth\ExtendedCrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Audio; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class AudioForceDeleteTest extends TestCase -{ - /** - * The Audio Force Delete Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $audio = Audio::factory()->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.audio.forceDelete', ['audio' => $audio])); +test('protected', function () { + $audio = Audio::factory()->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.audio.forceDelete', ['audio' => $audio])); - /** - * The Audio Force Delete Endpoint shall forbid users without the force delete audio permission. - */ - public function testForbidden(): void - { - $audio = Audio::factory()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $audio = Audio::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.audio.forceDelete', ['audio' => $audio])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.audio.forceDelete', ['audio' => $audio])); - /** - * The Audio Force Delete Endpoint shall force delete the audio. - */ - public function testDeleted(): void - { - $audio = Audio::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::FORCE_DELETE->format(Audio::class))->createOne(); +test('deleted', function () { + $audio = Audio::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::FORCE_DELETE->format(Audio::class))->createOne(); - $response = $this->delete(route('api.audio.forceDelete', ['audio' => $audio])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertModelMissing($audio); - } -} + $response = delete(route('api.audio.forceDelete', ['audio' => $audio])); + + $response->assertOk(); + $this->assertModelMissing($audio); +}); diff --git a/tests/Feature/Http/Api/Wiki/Audio/AudioIndexTest.php b/tests/Feature/Http/Api/Wiki/Audio/AudioIndexTest.php index e36f5861c..b0a46ab55 100644 --- a/tests/Feature/Http/Api/Wiki/Audio/AudioIndexTest.php +++ b/tests/Feature/Http/Api/Wiki/Audio/AudioIndexTest.php @@ -2,9 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Audio; - -use App\Concerns\Actions\Http\Api\SortsModels; use App\Constants\ModelConstants; use App\Contracts\Http\Api\Field\SortableField; use App\Enums\Http\Api\Filter\TrashedStatus; @@ -27,392 +24,346 @@ use App\Http\Resources\Wiki\Resource\AudioResource; use App\Models\BaseModel; use App\Models\Wiki\Audio; use App\Models\Wiki\Video; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; -use Tests\TestCase; - -class AudioIndexTest extends TestCase -{ - use SortsModels; - use WithFaker; - - /** - * By default, the Audio Index Endpoint shall return a collection of Audio Resources. - */ - public function testDefault(): void - { - $audios = Audio::factory() - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $response = $this->get(route('api.audio.index')); - - $response->assertJson( - json_decode( - json_encode( - new AudioCollection($audios, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Audio Index Endpoint shall be paginated. - */ - public function testPaginated(): void - { - Audio::factory() - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $response = $this->get(route('api.audio.index')); - - $response->assertJsonStructure([ - AudioCollection::$wrap, - 'links', - 'meta', - ]); - } - - /** - * The Audio Index Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new AudioSchema(); - - $allowedIncludes = collect($schema->allowedIncludes()); - - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); - - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; - - Audio::factory() - ->count($this->faker->randomDigitNotNull()) - ->has(Video::factory()->count($this->faker->randomDigitNotNull())) - ->create(); - - $audios = Audio::with($includedPaths->all())->get(); - - $response = $this->get(route('api.audio.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AudioCollection($audios, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Audio Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new AudioSchema(); - - $fields = collect($schema->fields()); - - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); - - $parameters = [ - FieldParser::param() => [ - AudioResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; - - $audios = Audio::factory() - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $response = $this->get(route('api.audio.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AudioCollection($audios, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Synonym Index Endpoint shall support sorting resources. - */ - public function testSorts(): void - { - $schema = new AudioSchema(); - - /** @var Sort $sort */ - $sort = collect($schema->fields()) - ->filter(fn (Field $field) => $field instanceof SortableField) - ->map(fn (SortableField $field) => $field->getSort()) - ->random(); - - $parameters = [ - SortParser::param() => $sort->format(Arr::random(Direction::cases())), - ]; - - $query = new Query($parameters); - - Audio::factory() - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $response = $this->get(route('api.audio.index', $parameters)); - - $audios = $this->sort(Audio::query(), $query, $schema)->get(); - - $response->assertJson( - json_decode( - json_encode( - new AudioCollection($audios, $query) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Audio Index Endpoint shall support filtering by created_at. - */ - public function testCreatedAtFilter(): void - { - $createdFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($createdFilter, function () { - Audio::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - Carbon::withTestNow($excludedDate, function () { - Audio::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - $audio = Audio::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - - $response = $this->get(route('api.audio.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AudioCollection($audio, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Audio Index Endpoint shall support filtering by updated_at. - */ - public function testUpdatedAtFilter(): void - { - $updatedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($updatedFilter, function () { - Audio::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - Carbon::withTestNow($excludedDate, function () { - Audio::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - $audio = Audio::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - - $response = $this->get(route('api.audio.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AudioCollection($audio, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Audio Index Endpoint shall support filtering by trashed. - */ - public function testWithoutTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITHOUT->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Audio::factory()->count($this->faker->randomDigitNotNull())->create(); - - Audio::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - - $audio = Audio::withoutTrashed()->get(); - - $response = $this->get(route('api.audio.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AudioCollection($audio, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Audio Index Endpoint shall support filtering by trashed. - */ - public function testWithTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Audio::factory()->count($this->faker->randomDigitNotNull())->create(); - - Audio::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - - $audio = Audio::withTrashed()->get(); - - $response = $this->get(route('api.audio.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AudioCollection($audio, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Audio Index Endpoint shall support filtering by trashed. - */ - public function testOnlyTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::ONLY->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Audio::factory()->count($this->faker->randomDigitNotNull())->create(); - - Audio::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - - $audio = Audio::onlyTrashed()->get(); - - $response = $this->get(route('api.audio.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AudioCollection($audio, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Audio Index Endpoint shall support filtering by deleted_at. - */ - public function testDeletedAtFilter(): void - { - $deletedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - ModelConstants::ATTRIBUTE_DELETED_AT => $deletedFilter, - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($deletedFilter, function () { - Audio::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - }); - - Carbon::withTestNow($excludedDate, function () { - Audio::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - }); - - $audio = Audio::withTrashed()->where(ModelConstants::ATTRIBUTE_DELETED_AT, $deletedFilter)->get(); - - $response = $this->get(route('api.audio.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new AudioCollection($audio, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + +use function Pest\Laravel\get; + +uses(App\Concerns\Actions\Http\Api\SortsModels::class); + +uses(Illuminate\Foundation\Testing\WithFaker::class); + +test('default', function () { + $audios = Audio::factory() + ->count(fake()->randomDigitNotNull()) + ->create(); + + $response = get(route('api.audio.index')); + + $response->assertJson( + json_decode( + json_encode( + new AudioCollection($audios, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('paginated', function () { + Audio::factory() + ->count(fake()->randomDigitNotNull()) + ->create(); + + $response = get(route('api.audio.index')); + + $response->assertJsonStructure([ + AudioCollection::$wrap, + 'links', + 'meta', + ]); +}); + +test('allowed include paths', function () { + $schema = new AudioSchema(); + + $allowedIncludes = collect($schema->allowedIncludes()); + + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); + + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; + + Audio::factory() + ->count(fake()->randomDigitNotNull()) + ->has(Video::factory()->count(fake()->randomDigitNotNull())) + ->create(); + + $audios = Audio::with($includedPaths->all())->get(); + + $response = get(route('api.audio.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AudioCollection($audios, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sparse fieldsets', function () { + $schema = new AudioSchema(); + + $fields = collect($schema->fields()); + + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + AudioResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + $audios = Audio::factory() + ->count(fake()->randomDigitNotNull()) + ->create(); + + $response = get(route('api.audio.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AudioCollection($audios, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sorts', function () { + $schema = new AudioSchema(); + + /** @var Sort $sort */ + $sort = collect($schema->fields()) + ->filter(fn (Field $field) => $field instanceof SortableField) + ->map(fn (SortableField $field) => $field->getSort()) + ->random(); + + $parameters = [ + SortParser::param() => $sort->format(Arr::random(Direction::cases())), + ]; + + $query = new Query($parameters); + + Audio::factory() + ->count(fake()->randomDigitNotNull()) + ->create(); + + $response = get(route('api.audio.index', $parameters)); + + $audios = $this->sort(Audio::query(), $query, $schema)->get(); + + $response->assertJson( + json_decode( + json_encode( + new AudioCollection($audios, $query) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('created at filter', function () { + $createdFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($createdFilter, function () { + Audio::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + Carbon::withTestNow($excludedDate, function () { + Audio::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + $audio = Audio::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); + + $response = get(route('api.audio.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AudioCollection($audio, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('updated at filter', function () { + $updatedFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($updatedFilter, function () { + Audio::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + Carbon::withTestNow($excludedDate, function () { + Audio::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + $audio = Audio::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); + + $response = get(route('api.audio.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AudioCollection($audio, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('without trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITHOUT->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Audio::factory()->count(fake()->randomDigitNotNull())->create(); + + Audio::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + + $audio = Audio::withoutTrashed()->get(); + + $response = get(route('api.audio.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AudioCollection($audio, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('with trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Audio::factory()->count(fake()->randomDigitNotNull())->create(); + + Audio::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + + $audio = Audio::withTrashed()->get(); + + $response = get(route('api.audio.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AudioCollection($audio, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('only trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::ONLY->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Audio::factory()->count(fake()->randomDigitNotNull())->create(); + + Audio::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + + $audio = Audio::onlyTrashed()->get(); + + $response = get(route('api.audio.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AudioCollection($audio, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('deleted at filter', function () { + $deletedFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + ModelConstants::ATTRIBUTE_DELETED_AT => $deletedFilter, + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($deletedFilter, function () { + Audio::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + }); + + Carbon::withTestNow($excludedDate, function () { + Audio::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + }); + + $audio = Audio::withTrashed()->where(ModelConstants::ATTRIBUTE_DELETED_AT, $deletedFilter)->get(); + + $response = get(route('api.audio.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AudioCollection($audio, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Wiki/Audio/AudioRestoreTest.php b/tests/Feature/Http/Api/Wiki/Audio/AudioRestoreTest.php index 06df82240..11ff9b43d 100644 --- a/tests/Feature/Http/Api/Wiki/Audio/AudioRestoreTest.php +++ b/tests/Feature/Http/Api/Wiki/Audio/AudioRestoreTest.php @@ -2,74 +2,54 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Audio; - use App\Enums\Auth\ExtendedCrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Audio; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class AudioRestoreTest extends TestCase -{ - /** - * The Audio Restore Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $audio = Audio::factory()->trashed()->createOne(); +use function Pest\Laravel\patch; - $response = $this->patch(route('api.audio.restore', ['audio' => $audio])); +test('protected', function () { + $audio = Audio::factory()->trashed()->createOne(); - $response->assertUnauthorized(); - } + $response = patch(route('api.audio.restore', ['audio' => $audio])); - /** - * The Audio Restore Endpoint shall forbid users without the restore audio permission. - */ - public function testForbidden(): void - { - $audio = Audio::factory()->trashed()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $audio = Audio::factory()->trashed()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->patch(route('api.audio.restore', ['audio' => $audio])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = patch(route('api.audio.restore', ['audio' => $audio])); - /** - * The Audio Restore Endpoint shall forbid users from restoring an audio that isn't trashed. - */ - public function testTrashed(): void - { - $audio = Audio::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(Audio::class))->createOne(); +test('trashed', function () { + $audio = Audio::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(Audio::class))->createOne(); - $response = $this->patch(route('api.audio.restore', ['audio' => $audio])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = patch(route('api.audio.restore', ['audio' => $audio])); - /** - * The Audio Restore Endpoint shall restore the audio. - */ - public function testRestored(): void - { - $audio = Audio::factory()->trashed()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(Audio::class))->createOne(); +test('restored', function () { + $audio = Audio::factory()->trashed()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(Audio::class))->createOne(); - $response = $this->patch(route('api.audio.restore', ['audio' => $audio])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertNotSoftDeleted($audio); - } -} + $response = patch(route('api.audio.restore', ['audio' => $audio])); + + $response->assertOk(); + $this->assertNotSoftDeleted($audio); +}); diff --git a/tests/Feature/Http/Api/Wiki/Audio/AudioShowTest.php b/tests/Feature/Http/Api/Wiki/Audio/AudioShowTest.php index c4ea87269..f1b0d1c0e 100644 --- a/tests/Feature/Http/Api/Wiki/Audio/AudioShowTest.php +++ b/tests/Feature/Http/Api/Wiki/Audio/AudioShowTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Audio; - use App\Http\Api\Field\Field; use App\Http\Api\Include\AllowedInclude; use App\Http\Api\Parser\FieldParser; @@ -13,120 +11,101 @@ use App\Http\Api\Schema\Wiki\AudioSchema; use App\Http\Resources\Wiki\Resource\AudioResource; use App\Models\Wiki\Audio; use App\Models\Wiki\Video; -use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; -class AudioShowTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the Audio Show Endpoint shall return an Audio Resource. - */ - public function testDefault(): void - { - $audio = Audio::factory()->create(); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response = $this->get(route('api.audio.show', ['audio' => $audio])); +test('default', function () { + $audio = Audio::factory()->create(); - $response->assertJson( - json_decode( - json_encode( - new AudioResource($audio, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.audio.show', ['audio' => $audio])); - /** - * The Audio Show Endpoint shall return an Audio Resource for soft deleted audios. - */ - public function testSoftDelete(): void - { - $audio = Audio::factory()->trashed()->createOne(); + $response->assertJson( + json_decode( + json_encode( + new AudioResource($audio, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $response = $this->get(route('api.audio.show', ['audio' => $audio])); +test('soft delete', function () { + $audio = Audio::factory()->trashed()->createOne(); - $response->assertJson( - json_decode( - json_encode( - new AudioResource($audio, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.audio.show', ['audio' => $audio])); - /** - * The Audio Show Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new AudioSchema(); + $response->assertJson( + json_decode( + json_encode( + new AudioResource($audio, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('allowed include paths', function () { + $schema = new AudioSchema(); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $allowedIncludes = collect($schema->allowedIncludes()); - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - $audio = Audio::factory() - ->has(Video::factory()->count($this->faker->randomDigitNotNull())) - ->create(); + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; - $response = $this->get(route('api.audio.show', ['audio' => $audio] + $parameters)); + $audio = Audio::factory() + ->has(Video::factory()->count(fake()->randomDigitNotNull())) + ->create(); - $response->assertJson( - json_decode( - json_encode( - new AudioResource($audio, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.audio.show', ['audio' => $audio] + $parameters)); - /** - * The Audio Show Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new AudioSchema(); + $response->assertJson( + json_decode( + json_encode( + new AudioResource($audio, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $fields = collect($schema->fields()); +test('sparse fieldsets', function () { + $schema = new AudioSchema(); - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); + $fields = collect($schema->fields()); - $parameters = [ - FieldParser::param() => [ - AudioResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); - $audio = Audio::factory()->create(); + $parameters = [ + FieldParser::param() => [ + AudioResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; - $response = $this->get(route('api.audio.show', ['audio' => $audio] + $parameters)); + $audio = Audio::factory()->create(); - $response->assertJson( - json_decode( - json_encode( - new AudioResource($audio, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response = get(route('api.audio.show', ['audio' => $audio] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new AudioResource($audio, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Wiki/Audio/AudioStoreTest.php b/tests/Feature/Http/Api/Wiki/Audio/AudioStoreTest.php index 99c5eaf35..11e0e1c2d 100644 --- a/tests/Feature/Http/Api/Wiki/Audio/AudioStoreTest.php +++ b/tests/Feature/Http/Api/Wiki/Audio/AudioStoreTest.php @@ -2,78 +2,58 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Audio; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Audio; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class AudioStoreTest extends TestCase -{ - /** - * The Audio Store Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $audio = Audio::factory()->makeOne(); +use function Pest\Laravel\post; - $response = $this->post(route('api.audio.store', $audio->toArray())); +test('protected', function () { + $audio = Audio::factory()->makeOne(); - $response->assertUnauthorized(); - } + $response = post(route('api.audio.store', $audio->toArray())); - /** - * The Audio Store Endpoint shall forbid users without the create audio permission. - */ - public function testForbidden(): void - { - $audio = Audio::factory()->makeOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $audio = Audio::factory()->makeOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->post(route('api.audio.store', $audio->toArray())); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.audio.store', $audio->toArray())); - /** - * The Audio Store Endpoint shall require basename, filename, mimetype, path & size fields. - */ - public function testRequiredFields(): void - { - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Audio::class))->createOne(); + $response->assertForbidden(); +}); - Sanctum::actingAs($user); +test('required fields', function () { + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Audio::class))->createOne(); - $response = $this->post(route('api.audio.store')); + Sanctum::actingAs($user); - $response->assertJsonValidationErrors([ - Audio::ATTRIBUTE_BASENAME, - Audio::ATTRIBUTE_FILENAME, - Audio::ATTRIBUTE_MIMETYPE, - Audio::ATTRIBUTE_PATH, - Audio::ATTRIBUTE_SIZE, - ]); - } + $response = post(route('api.audio.store')); - /** - * The Audio Store Endpoint shall create an audio. - */ - public function testCreate(): void - { - $parameters = Audio::factory()->raw(); + $response->assertJsonValidationErrors([ + Audio::ATTRIBUTE_BASENAME, + Audio::ATTRIBUTE_FILENAME, + Audio::ATTRIBUTE_MIMETYPE, + Audio::ATTRIBUTE_PATH, + Audio::ATTRIBUTE_SIZE, + ]); +}); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Audio::class))->createOne(); +test('create', function () { + $parameters = Audio::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Audio::class))->createOne(); - $response = $this->post(route('api.audio.store', $parameters)); + Sanctum::actingAs($user); - $response->assertCreated(); - static::assertDatabaseCount(Audio::class, 1); - } -} + $response = post(route('api.audio.store', $parameters)); + + $response->assertCreated(); + $this->assertDatabaseCount(Audio::class, 1); +}); diff --git a/tests/Feature/Http/Api/Wiki/Audio/AudioUpdateTest.php b/tests/Feature/Http/Api/Wiki/Audio/AudioUpdateTest.php index c759ff2ca..5374e68d7 100644 --- a/tests/Feature/Http/Api/Wiki/Audio/AudioUpdateTest.php +++ b/tests/Feature/Http/Api/Wiki/Audio/AudioUpdateTest.php @@ -2,81 +2,61 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Audio; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Audio; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class AudioUpdateTest extends TestCase -{ - /** - * The Audio Update Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $audio = Audio::factory()->createOne(); +use function Pest\Laravel\put; - $parameters = Audio::factory()->raw(); +test('protected', function () { + $audio = Audio::factory()->createOne(); - $response = $this->put(route('api.audio.update', ['audio' => $audio] + $parameters)); + $parameters = Audio::factory()->raw(); - $response->assertUnauthorized(); - } + $response = put(route('api.audio.update', ['audio' => $audio] + $parameters)); - /** - * The Audio Update Endpoint shall forbid users without the update audio permission. - */ - public function testForbidden(): void - { - $audio = Audio::factory()->createOne(); + $response->assertUnauthorized(); +}); - $parameters = Audio::factory()->raw(); +test('forbidden', function () { + $audio = Audio::factory()->createOne(); - $user = User::factory()->createOne(); + $parameters = Audio::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->put(route('api.audio.update', ['audio' => $audio] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.audio.update', ['audio' => $audio] + $parameters)); - /** - * The Audio Update Endpoint shall forbid users from updating an audio that is trashed. - */ - public function testTrashed(): void - { - $audio = Audio::factory()->trashed()->createOne(); + $response->assertForbidden(); +}); - $parameters = Audio::factory()->raw(); +test('trashed', function () { + $audio = Audio::factory()->trashed()->createOne(); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Audio::class))->createOne(); + $parameters = Audio::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Audio::class))->createOne(); - $response = $this->put(route('api.audio.update', ['audio' => $audio] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.audio.update', ['audio' => $audio] + $parameters)); - /** - * The Audio Update Endpoint shall update an audio. - */ - public function testUpdate(): void - { - $audio = Audio::factory()->createOne(); + $response->assertForbidden(); +}); - $parameters = Audio::factory()->raw(); +test('update', function () { + $audio = Audio::factory()->createOne(); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Audio::class))->createOne(); + $parameters = Audio::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Audio::class))->createOne(); - $response = $this->put(route('api.audio.update', ['audio' => $audio] + $parameters)); + Sanctum::actingAs($user); - $response->assertOk(); - } -} + $response = put(route('api.audio.update', ['audio' => $audio] + $parameters)); + + $response->assertOk(); +}); diff --git a/tests/Feature/Http/Api/Wiki/ExternalResource/ExternalResourceDestroyTest.php b/tests/Feature/Http/Api/Wiki/ExternalResource/ExternalResourceDestroyTest.php index 5b7ff513a..0c375cdb2 100644 --- a/tests/Feature/Http/Api/Wiki/ExternalResource/ExternalResourceDestroyTest.php +++ b/tests/Feature/Http/Api/Wiki/ExternalResource/ExternalResourceDestroyTest.php @@ -2,74 +2,54 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\ExternalResource; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\ExternalResource; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ExternalResourceDestroyTest extends TestCase -{ - /** - * The External Resource Destroy Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $resource = ExternalResource::factory()->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.resource.destroy', ['resource' => $resource])); +test('protected', function () { + $resource = ExternalResource::factory()->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.resource.destroy', ['resource' => $resource])); - /** - * The External Resource Destroy Endpoint shall forbid users without the delete external resource permission. - */ - public function testForbidden(): void - { - $resource = ExternalResource::factory()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $resource = ExternalResource::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.resource.destroy', ['resource' => $resource])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.resource.destroy', ['resource' => $resource])); - /** - * The External Resource Destroy Endpoint shall forbid users from updating a resource that is trashed. - */ - public function testTrashed(): void - { - $resource = ExternalResource::factory()->trashed()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(ExternalResource::class))->createOne(); +test('trashed', function () { + $resource = ExternalResource::factory()->trashed()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(ExternalResource::class))->createOne(); - $response = $this->delete(route('api.resource.destroy', ['resource' => $resource])); + Sanctum::actingAs($user); - $response->assertNotFound(); - } + $response = delete(route('api.resource.destroy', ['resource' => $resource])); - /** - * The External Resource Destroy Endpoint shall delete the resource. - */ - public function testDeleted(): void - { - $resource = ExternalResource::factory()->createOne(); + $response->assertNotFound(); +}); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(ExternalResource::class))->createOne(); +test('deleted', function () { + $resource = ExternalResource::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(ExternalResource::class))->createOne(); - $response = $this->delete(route('api.resource.destroy', ['resource' => $resource])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertSoftDeleted($resource); - } -} + $response = delete(route('api.resource.destroy', ['resource' => $resource])); + + $response->assertOk(); + $this->assertSoftDeleted($resource); +}); diff --git a/tests/Feature/Http/Api/Wiki/ExternalResource/ExternalResourceForceDeleteTest.php b/tests/Feature/Http/Api/Wiki/ExternalResource/ExternalResourceForceDeleteTest.php index 50244a0fb..908df77a3 100644 --- a/tests/Feature/Http/Api/Wiki/ExternalResource/ExternalResourceForceDeleteTest.php +++ b/tests/Feature/Http/Api/Wiki/ExternalResource/ExternalResourceForceDeleteTest.php @@ -2,58 +2,42 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\ExternalResource; - use App\Enums\Auth\ExtendedCrudPermission; use App\Models\Auth\User; use App\Models\Wiki\ExternalResource; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ExternalResourceForceDeleteTest extends TestCase -{ - /** - * The External Resource Force Delete Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $resource = ExternalResource::factory()->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.resource.forceDelete', ['resource' => $resource])); +test('protected', function () { + $resource = ExternalResource::factory()->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.resource.forceDelete', ['resource' => $resource])); - /** - * The External Resource Force Delete Endpoint shall forbid users without the force delete external resource permission. - */ - public function testForbidden(): void - { - $resource = ExternalResource::factory()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $resource = ExternalResource::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.resource.forceDelete', ['resource' => $resource])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.resource.forceDelete', ['resource' => $resource])); - /** - * The External Resource Force Delete Endpoint shall force delete the resource. - */ - public function testDeleted(): void - { - $resource = ExternalResource::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::FORCE_DELETE->format(ExternalResource::class))->createOne(); +test('deleted', function () { + $resource = ExternalResource::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::FORCE_DELETE->format(ExternalResource::class))->createOne(); - $response = $this->delete(route('api.resource.forceDelete', ['resource' => $resource])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertModelMissing($resource); - } -} + $response = delete(route('api.resource.forceDelete', ['resource' => $resource])); + + $response->assertOk(); + $this->assertModelMissing($resource); +}); diff --git a/tests/Feature/Http/Api/Wiki/ExternalResource/ExternalResourceIndexTest.php b/tests/Feature/Http/Api/Wiki/ExternalResource/ExternalResourceIndexTest.php index 4b5826c84..3dc2bc6a8 100644 --- a/tests/Feature/Http/Api/Wiki/ExternalResource/ExternalResourceIndexTest.php +++ b/tests/Feature/Http/Api/Wiki/ExternalResource/ExternalResourceIndexTest.php @@ -2,9 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\ExternalResource; - -use App\Concerns\Actions\Http\Api\SortsModels; use App\Constants\ModelConstants; use App\Contracts\Http\Api\Field\SortableField; use App\Enums\Http\Api\Filter\TrashedStatus; @@ -32,549 +29,487 @@ use App\Models\Wiki\Anime; use App\Models\Wiki\Artist; use App\Models\Wiki\ExternalResource; use Illuminate\Database\Eloquent\Relations\BelongsToMany; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; -use Tests\TestCase; - -class ExternalResourceIndexTest extends TestCase -{ - use SortsModels; - use WithFaker; - - /** - * By default, the Resource Index Endpoint shall return a collection of ExternalResource Resources. - */ - public function testDefault(): void - { - $resources = ExternalResource::factory() - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $response = $this->get(route('api.resource.index')); - - $response->assertJson( - json_decode( - json_encode( - new ExternalResourceCollection($resources, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Resource Index Endpoint shall be paginated. - */ - public function testPaginated(): void - { - ExternalResource::factory()->count($this->faker->randomDigitNotNull())->create(); - - $response = $this->get(route('api.resource.index')); - - $response->assertJsonStructure([ - ExternalResourceCollection::$wrap, - 'links', - 'meta', - ]); - } - - /** - * The Resource Index Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new ExternalResourceSchema(); - - $allowedIncludes = collect($schema->allowedIncludes()); - - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); - - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; - - ExternalResource::factory() - ->has(Anime::factory()->count($this->faker->randomDigitNotNull())) - ->has(Artist::factory()->count($this->faker->randomDigitNotNull())) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $resources = ExternalResource::with($includedPaths->all())->get(); - - $response = $this->get(route('api.resource.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ExternalResourceCollection($resources, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Resource Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new ExternalResourceSchema(); - - $fields = collect($schema->fields()); - - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); - - $parameters = [ - FieldParser::param() => [ - ExternalResourceResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; - - $resources = ExternalResource::factory() - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $response = $this->get(route('api.resource.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ExternalResourceCollection($resources, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Resource Index Endpoint shall support sorting resources. - */ - public function testSorts(): void - { - $schema = new ExternalResourceSchema(); - - /** @var Sort $sort */ - $sort = collect($schema->fields()) - ->filter(fn (Field $field) => $field instanceof SortableField) - ->map(fn (SortableField $field) => $field->getSort()) - ->random(); - - $parameters = [ - SortParser::param() => $sort->format(Arr::random(Direction::cases())), - ]; - - $query = new Query($parameters); - - ExternalResource::factory()->count($this->faker->randomDigitNotNull())->create(); - - $response = $this->get(route('api.resource.index', $parameters)); - - $resources = $this->sort(ExternalResource::query(), $query, $schema)->get(); - - $response->assertJson( - json_decode( - json_encode( - new ExternalResourceCollection($resources, $query) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Resource Index Endpoint shall support filtering by created_at. - */ - public function testCreatedAtFilter(): void - { - $createdFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($createdFilter, function () { - ExternalResource::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - Carbon::withTestNow($excludedDate, function () { - ExternalResource::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - $resource = ExternalResource::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - - $response = $this->get(route('api.resource.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ExternalResourceCollection($resource, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Resource Index Endpoint shall support filtering by updated_at. - */ - public function testUpdatedAtFilter(): void - { - $updatedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($updatedFilter, function () { - ExternalResource::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - Carbon::withTestNow($excludedDate, function () { - ExternalResource::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - $resource = ExternalResource::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - - $response = $this->get(route('api.resource.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ExternalResourceCollection($resource, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Resource Index Endpoint shall support filtering by trashed. - */ - public function testWithoutTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITHOUT->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - ExternalResource::factory()->count($this->faker->randomDigitNotNull())->create(); - - ExternalResource::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - - $resource = ExternalResource::withoutTrashed()->get(); - - $response = $this->get(route('api.resource.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ExternalResourceCollection($resource, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Resource Index Endpoint shall support filtering by trashed. - */ - public function testWithTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - ExternalResource::factory()->count($this->faker->randomDigitNotNull())->create(); - - ExternalResource::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - - $resource = ExternalResource::withTrashed()->get(); - - $response = $this->get(route('api.resource.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ExternalResourceCollection($resource, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Resource Index Endpoint shall support filtering by trashed. - */ - public function testOnlyTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::ONLY->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - ExternalResource::factory()->count($this->faker->randomDigitNotNull())->create(); - - ExternalResource::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - - $resource = ExternalResource::onlyTrashed()->get(); - - $response = $this->get(route('api.resource.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ExternalResourceCollection($resource, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Resource Index Endpoint shall support filtering by deleted_at. - */ - public function testDeletedAtFilter(): void - { - $deletedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - ModelConstants::ATTRIBUTE_DELETED_AT => $deletedFilter, - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($deletedFilter, function () { - ExternalResource::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - }); - - Carbon::withTestNow($excludedDate, function () { - ExternalResource::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - }); - - $resource = ExternalResource::withTrashed()->where(ModelConstants::ATTRIBUTE_DELETED_AT, $deletedFilter)->get(); - - $response = $this->get(route('api.resource.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ExternalResourceCollection($resource, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Resource Index Endpoint shall support filtering by site. - */ - public function testSiteFilter(): void - { - $siteFilter = Arr::random(ResourceSite::cases()); - - $parameters = [ - FilterParser::param() => [ - ExternalResource::ATTRIBUTE_SITE => $siteFilter->localize(), - ], - ]; - - ExternalResource::factory() - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $resources = ExternalResource::query()->where(ExternalResource::ATTRIBUTE_SITE, $siteFilter->value)->get(); - - $response = $this->get(route('api.resource.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ExternalResourceCollection($resources, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Resource Index Endpoint shall support constrained eager loading of anime by media format. - */ - public function testAnimeByMediaFormat(): void - { - $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), - ], - IncludeParser::param() => ExternalResource::RELATION_ANIME, - ]; - - ExternalResource::factory() - ->has(Anime::factory()->count($this->faker->randomDigitNotNull())) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $resources = ExternalResource::with([ - ExternalResource::RELATION_ANIME => function (BelongsToMany $query) use ($mediaFormatFilter) { - $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.resource.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ExternalResourceCollection($resources, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Resource Index Endpoint shall support constrained eager loading of anime by season. - */ - public function testAnimeBySeason(): void - { - $seasonFilter = Arr::random(AnimeSeason::cases()); - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), - ], - IncludeParser::param() => ExternalResource::RELATION_ANIME, - ]; - - ExternalResource::factory() - ->has(Anime::factory()->count($this->faker->randomDigitNotNull())) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $resources = ExternalResource::with([ - ExternalResource::RELATION_ANIME => function (BelongsToMany $query) use ($seasonFilter) { - $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.resource.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ExternalResourceCollection($resources, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Resource Index Endpoint shall support constrained eager loading of anime by year. - */ - public function testAnimeByYear(): void - { - $yearFilter = intval($this->faker->year()); - $excludedYear = $yearFilter + 1; - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_YEAR => $yearFilter, - ], - IncludeParser::param() => ExternalResource::RELATION_ANIME, - ]; - - ExternalResource::factory() - ->has( - Anime::factory() - ->count($this->faker->randomDigitNotNull()) - ->state([ - Anime::ATTRIBUTE_YEAR => $this->faker->boolean() ? $yearFilter : $excludedYear, - ]) - ) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $resources = ExternalResource::with([ - ExternalResource::RELATION_ANIME => function (BelongsToMany $query) use ($yearFilter) { - $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); - }, - ]) - ->get(); - - $response = $this->get(route('api.resource.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ExternalResourceCollection($resources, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + +use function Pest\Laravel\get; + +uses(App\Concerns\Actions\Http\Api\SortsModels::class); + +uses(Illuminate\Foundation\Testing\WithFaker::class); + +test('default', function () { + $resources = ExternalResource::factory() + ->count(fake()->randomDigitNotNull()) + ->create(); + + $response = get(route('api.resource.index')); + + $response->assertJson( + json_decode( + json_encode( + new ExternalResourceCollection($resources, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('paginated', function () { + ExternalResource::factory()->count(fake()->randomDigitNotNull())->create(); + + $response = get(route('api.resource.index')); + + $response->assertJsonStructure([ + ExternalResourceCollection::$wrap, + 'links', + 'meta', + ]); +}); + +test('allowed include paths', function () { + $schema = new ExternalResourceSchema(); + + $allowedIncludes = collect($schema->allowedIncludes()); + + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); + + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; + + ExternalResource::factory() + ->has(Anime::factory()->count(fake()->randomDigitNotNull())) + ->has(Artist::factory()->count(fake()->randomDigitNotNull())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $resources = ExternalResource::with($includedPaths->all())->get(); + + $response = get(route('api.resource.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ExternalResourceCollection($resources, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sparse fieldsets', function () { + $schema = new ExternalResourceSchema(); + + $fields = collect($schema->fields()); + + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + ExternalResourceResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + $resources = ExternalResource::factory() + ->count(fake()->randomDigitNotNull()) + ->create(); + + $response = get(route('api.resource.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ExternalResourceCollection($resources, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sorts', function () { + $schema = new ExternalResourceSchema(); + + /** @var Sort $sort */ + $sort = collect($schema->fields()) + ->filter(fn (Field $field) => $field instanceof SortableField) + ->map(fn (SortableField $field) => $field->getSort()) + ->random(); + + $parameters = [ + SortParser::param() => $sort->format(Arr::random(Direction::cases())), + ]; + + $query = new Query($parameters); + + ExternalResource::factory()->count(fake()->randomDigitNotNull())->create(); + + $response = get(route('api.resource.index', $parameters)); + + $resources = $this->sort(ExternalResource::query(), $query, $schema)->get(); + + $response->assertJson( + json_decode( + json_encode( + new ExternalResourceCollection($resources, $query) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('created at filter', function () { + $createdFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($createdFilter, function () { + ExternalResource::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + Carbon::withTestNow($excludedDate, function () { + ExternalResource::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + $resource = ExternalResource::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); + + $response = get(route('api.resource.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ExternalResourceCollection($resource, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('updated at filter', function () { + $updatedFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($updatedFilter, function () { + ExternalResource::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + Carbon::withTestNow($excludedDate, function () { + ExternalResource::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + $resource = ExternalResource::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); + + $response = get(route('api.resource.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ExternalResourceCollection($resource, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('without trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITHOUT->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + ExternalResource::factory()->count(fake()->randomDigitNotNull())->create(); + + ExternalResource::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + + $resource = ExternalResource::withoutTrashed()->get(); + + $response = get(route('api.resource.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ExternalResourceCollection($resource, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('with trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + ExternalResource::factory()->count(fake()->randomDigitNotNull())->create(); + + ExternalResource::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + + $resource = ExternalResource::withTrashed()->get(); + + $response = get(route('api.resource.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ExternalResourceCollection($resource, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('only trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::ONLY->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + ExternalResource::factory()->count(fake()->randomDigitNotNull())->create(); + + ExternalResource::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + + $resource = ExternalResource::onlyTrashed()->get(); + + $response = get(route('api.resource.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ExternalResourceCollection($resource, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('deleted at filter', function () { + $deletedFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + ModelConstants::ATTRIBUTE_DELETED_AT => $deletedFilter, + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($deletedFilter, function () { + ExternalResource::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + }); + + Carbon::withTestNow($excludedDate, function () { + ExternalResource::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + }); + + $resource = ExternalResource::withTrashed()->where(ModelConstants::ATTRIBUTE_DELETED_AT, $deletedFilter)->get(); + + $response = get(route('api.resource.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ExternalResourceCollection($resource, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('site filter', function () { + $siteFilter = Arr::random(ResourceSite::cases()); + + $parameters = [ + FilterParser::param() => [ + ExternalResource::ATTRIBUTE_SITE => $siteFilter->localize(), + ], + ]; + + ExternalResource::factory() + ->count(fake()->randomDigitNotNull()) + ->create(); + + $resources = ExternalResource::query()->where(ExternalResource::ATTRIBUTE_SITE, $siteFilter->value)->get(); + + $response = get(route('api.resource.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ExternalResourceCollection($resources, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by media format', function () { + $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), + ], + IncludeParser::param() => ExternalResource::RELATION_ANIME, + ]; + + ExternalResource::factory() + ->has(Anime::factory()->count(fake()->randomDigitNotNull())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $resources = ExternalResource::with([ + ExternalResource::RELATION_ANIME => function (BelongsToMany $query) use ($mediaFormatFilter) { + $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); + }, + ]) + ->get(); + + $response = get(route('api.resource.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ExternalResourceCollection($resources, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by season', function () { + $seasonFilter = Arr::random(AnimeSeason::cases()); + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), + ], + IncludeParser::param() => ExternalResource::RELATION_ANIME, + ]; + + ExternalResource::factory() + ->has(Anime::factory()->count(fake()->randomDigitNotNull())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $resources = ExternalResource::with([ + ExternalResource::RELATION_ANIME => function (BelongsToMany $query) use ($seasonFilter) { + $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); + }, + ]) + ->get(); + + $response = get(route('api.resource.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ExternalResourceCollection($resources, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by year', function () { + $yearFilter = intval(fake()->year()); + $excludedYear = $yearFilter + 1; + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_YEAR => $yearFilter, + ], + IncludeParser::param() => ExternalResource::RELATION_ANIME, + ]; + + ExternalResource::factory() + ->has( + Anime::factory() + ->count(fake()->randomDigitNotNull()) + ->state([ + Anime::ATTRIBUTE_YEAR => fake()->boolean() ? $yearFilter : $excludedYear, + ]) + ) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $resources = ExternalResource::with([ + ExternalResource::RELATION_ANIME => function (BelongsToMany $query) use ($yearFilter) { + $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); + }, + ]) + ->get(); + + $response = get(route('api.resource.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ExternalResourceCollection($resources, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Wiki/ExternalResource/ExternalResourceRestoreTest.php b/tests/Feature/Http/Api/Wiki/ExternalResource/ExternalResourceRestoreTest.php index 8e6f4cb6b..d45c2baf6 100644 --- a/tests/Feature/Http/Api/Wiki/ExternalResource/ExternalResourceRestoreTest.php +++ b/tests/Feature/Http/Api/Wiki/ExternalResource/ExternalResourceRestoreTest.php @@ -2,74 +2,54 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\ExternalResource; - use App\Enums\Auth\ExtendedCrudPermission; use App\Models\Auth\User; use App\Models\Wiki\ExternalResource; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ExternalResourceRestoreTest extends TestCase -{ - /** - * The External Resource Restore Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $resource = ExternalResource::factory()->trashed()->createOne(); +use function Pest\Laravel\patch; - $response = $this->patch(route('api.resource.restore', ['resource' => $resource])); +test('protected', function () { + $resource = ExternalResource::factory()->trashed()->createOne(); - $response->assertUnauthorized(); - } + $response = patch(route('api.resource.restore', ['resource' => $resource])); - /** - * The External Resource Restore Endpoint shall forbid users without the restore external resource permission. - */ - public function testForbidden(): void - { - $resource = ExternalResource::factory()->trashed()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $resource = ExternalResource::factory()->trashed()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->patch(route('api.resource.restore', ['resource' => $resource])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = patch(route('api.resource.restore', ['resource' => $resource])); - /** - * The External Resource Restore Endpoint shall forbid users from restoring a resource that isn't trashed. - */ - public function testTrashed(): void - { - $resource = ExternalResource::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(ExternalResource::class))->createOne(); +test('trashed', function () { + $resource = ExternalResource::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(ExternalResource::class))->createOne(); - $response = $this->patch(route('api.resource.restore', ['resource' => $resource])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = patch(route('api.resource.restore', ['resource' => $resource])); - /** - * The External Resource Restore Endpoint shall restore the resource. - */ - public function testRestored(): void - { - $resource = ExternalResource::factory()->trashed()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(ExternalResource::class))->createOne(); +test('restored', function () { + $resource = ExternalResource::factory()->trashed()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(ExternalResource::class))->createOne(); - $response = $this->patch(route('api.resource.restore', ['resource' => $resource])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertNotSoftDeleted($resource); - } -} + $response = patch(route('api.resource.restore', ['resource' => $resource])); + + $response->assertOk(); + $this->assertNotSoftDeleted($resource); +}); diff --git a/tests/Feature/Http/Api/Wiki/ExternalResource/ExternalResourceShowTest.php b/tests/Feature/Http/Api/Wiki/ExternalResource/ExternalResourceShowTest.php index 3e33b398f..227dd7729 100644 --- a/tests/Feature/Http/Api/Wiki/ExternalResource/ExternalResourceShowTest.php +++ b/tests/Feature/Http/Api/Wiki/ExternalResource/ExternalResourceShowTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\ExternalResource; - use App\Enums\Models\Wiki\AnimeMediaFormat; use App\Enums\Models\Wiki\AnimeSeason; use App\Http\Api\Field\Field; @@ -18,245 +16,214 @@ use App\Models\Wiki\Anime; use App\Models\Wiki\Artist; use App\Models\Wiki\ExternalResource; use Illuminate\Database\Eloquent\Relations\BelongsToMany; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; -use Tests\TestCase; -class ExternalResourceShowTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the Resource Show Endpoint shall return an ExternalResource Resource. - */ - public function testDefault(): void - { - $resource = ExternalResource::factory()->create(); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response = $this->get(route('api.resource.show', ['resource' => $resource])); +test('default', function () { + $resource = ExternalResource::factory()->create(); - $response->assertJson( - json_decode( - json_encode( - new ExternalResourceResource($resource, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.resource.show', ['resource' => $resource])); - /** - * The Resource Show Endpoint shall return an External Resource for soft deleted images. - */ - public function testSoftDelete(): void - { - $resource = ExternalResource::factory()->trashed()->createOne(); + $response->assertJson( + json_decode( + json_encode( + new ExternalResourceResource($resource, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $resource->unsetRelations(); +test('soft delete', function () { + $resource = ExternalResource::factory()->trashed()->createOne(); - $response = $this->get(route('api.resource.show', ['resource' => $resource])); + $resource->unsetRelations(); - $response->assertJson( - json_decode( - json_encode( - new ExternalResourceResource($resource, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.resource.show', ['resource' => $resource])); - /** - * The Resource Show Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new ExternalResourceSchema(); + $response->assertJson( + json_decode( + json_encode( + new ExternalResourceResource($resource, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('allowed include paths', function () { + $schema = new ExternalResourceSchema(); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $allowedIncludes = collect($schema->allowedIncludes()); - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - $resource = ExternalResource::factory() - ->has(Anime::factory()->count($this->faker->randomDigitNotNull())) - ->has(Artist::factory()->count($this->faker->randomDigitNotNull())) - ->createOne(); + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; - $response = $this->get(route('api.resource.show', ['resource' => $resource] + $parameters)); + $resource = ExternalResource::factory() + ->has(Anime::factory()->count(fake()->randomDigitNotNull())) + ->has(Artist::factory()->count(fake()->randomDigitNotNull())) + ->createOne(); - $response->assertJson( - json_decode( - json_encode( - new ExternalResourceResource($resource, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.resource.show', ['resource' => $resource] + $parameters)); - /** - * The Resource Show Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new ExternalResourceSchema(); + $response->assertJson( + json_decode( + json_encode( + new ExternalResourceResource($resource, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $fields = collect($schema->fields()); +test('sparse fieldsets', function () { + $schema = new ExternalResourceSchema(); - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); + $fields = collect($schema->fields()); - $parameters = [ - FieldParser::param() => [ - ExternalResourceResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); - $resource = ExternalResource::factory()->create(); + $parameters = [ + FieldParser::param() => [ + ExternalResourceResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; - $response = $this->get(route('api.resource.show', ['resource' => $resource] + $parameters)); + $resource = ExternalResource::factory()->create(); - $response->assertJson( - json_decode( - json_encode( - new ExternalResourceResource($resource, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.resource.show', ['resource' => $resource] + $parameters)); - /** - * The Resource Show Endpoint shall support constrained eager loading of anime by media format. - */ - public function testAnimeByMediaFormat(): void - { - $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); + $response->assertJson( + json_decode( + json_encode( + new ExternalResourceResource($resource, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), - ], - IncludeParser::param() => ExternalResource::RELATION_ANIME, - ]; +test('anime by media format', function () { + $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); - $resource = ExternalResource::factory() - ->has(Anime::factory()->count($this->faker->randomDigitNotNull())) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), + ], + IncludeParser::param() => ExternalResource::RELATION_ANIME, + ]; - $resource->unsetRelations()->load([ - ExternalResource::RELATION_ANIME => function (BelongsToMany $query) use ($mediaFormatFilter) { - $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); - }, - ]); + $resource = ExternalResource::factory() + ->has(Anime::factory()->count(fake()->randomDigitNotNull())) + ->createOne(); - $response = $this->get(route('api.resource.show', ['resource' => $resource] + $parameters)); + $resource->unsetRelations()->load([ + ExternalResource::RELATION_ANIME => function (BelongsToMany $query) use ($mediaFormatFilter) { + $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); + }, + ]); - $response->assertJson( - json_decode( - json_encode( - new ExternalResourceResource($resource, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.resource.show', ['resource' => $resource] + $parameters)); - /** - * The Resource Show Endpoint shall support constrained eager loading of anime by season. - */ - public function testAnimeBySeason(): void - { - $seasonFilter = Arr::random(AnimeSeason::cases()); + $response->assertJson( + json_decode( + json_encode( + new ExternalResourceResource($resource, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), - ], - IncludeParser::param() => ExternalResource::RELATION_ANIME, - ]; +test('anime by season', function () { + $seasonFilter = Arr::random(AnimeSeason::cases()); - $resource = ExternalResource::factory() - ->has(Anime::factory()->count($this->faker->randomDigitNotNull())) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), + ], + IncludeParser::param() => ExternalResource::RELATION_ANIME, + ]; - $resource->unsetRelations()->load([ - ExternalResource::RELATION_ANIME => function (BelongsToMany $query) use ($seasonFilter) { - $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); - }, - ]); + $resource = ExternalResource::factory() + ->has(Anime::factory()->count(fake()->randomDigitNotNull())) + ->createOne(); - $response = $this->get(route('api.resource.show', ['resource' => $resource] + $parameters)); + $resource->unsetRelations()->load([ + ExternalResource::RELATION_ANIME => function (BelongsToMany $query) use ($seasonFilter) { + $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); + }, + ]); - $response->assertJson( - json_decode( - json_encode( - new ExternalResourceResource($resource, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.resource.show', ['resource' => $resource] + $parameters)); - /** - * The Resource Show Endpoint shall support constrained eager loading of anime by year. - */ - public function testAnimeByYear(): void - { - $yearFilter = intval($this->faker->year()); - $excludedYear = $yearFilter + 1; + $response->assertJson( + json_decode( + json_encode( + new ExternalResourceResource($resource, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_YEAR => $yearFilter, - ], - IncludeParser::param() => ExternalResource::RELATION_ANIME, - ]; +test('anime by year', function () { + $yearFilter = intval(fake()->year()); + $excludedYear = $yearFilter + 1; - $resource = ExternalResource::factory() - ->has( - Anime::factory() - ->count($this->faker->randomDigitNotNull()) - ->state([ - Anime::ATTRIBUTE_YEAR => $this->faker->boolean() ? $yearFilter : $excludedYear, - ]) - ) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_YEAR => $yearFilter, + ], + IncludeParser::param() => ExternalResource::RELATION_ANIME, + ]; - $resource->unsetRelations()->load([ - ExternalResource::RELATION_ANIME => function (BelongsToMany $query) use ($yearFilter) { - $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); - }, - ]); + $resource = ExternalResource::factory() + ->has( + Anime::factory() + ->count(fake()->randomDigitNotNull()) + ->state([ + Anime::ATTRIBUTE_YEAR => fake()->boolean() ? $yearFilter : $excludedYear, + ]) + ) + ->createOne(); - $response = $this->get(route('api.resource.show', ['resource' => $resource] + $parameters)); + $resource->unsetRelations()->load([ + ExternalResource::RELATION_ANIME => function (BelongsToMany $query) use ($yearFilter) { + $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); + }, + ]); - $response->assertJson( - json_decode( - json_encode( - new ExternalResourceResource($resource, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response = get(route('api.resource.show', ['resource' => $resource] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ExternalResourceResource($resource, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Wiki/ExternalResource/ExternalResourceStoreTest.php b/tests/Feature/Http/Api/Wiki/ExternalResource/ExternalResourceStoreTest.php index d72b7fa63..68947e008 100644 --- a/tests/Feature/Http/Api/Wiki/ExternalResource/ExternalResourceStoreTest.php +++ b/tests/Feature/Http/Api/Wiki/ExternalResource/ExternalResourceStoreTest.php @@ -2,79 +2,59 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\ExternalResource; - use App\Enums\Auth\CrudPermission; use App\Enums\Models\Wiki\ResourceSite; use App\Models\Auth\User; use App\Models\Wiki\ExternalResource; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ExternalResourceStoreTest extends TestCase -{ - /** - * The External Resource Store Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $resource = ExternalResource::factory()->makeOne(); +use function Pest\Laravel\post; - $response = $this->post(route('api.resource.store', $resource->toArray())); +test('protected', function () { + $resource = ExternalResource::factory()->makeOne(); - $response->assertUnauthorized(); - } + $response = post(route('api.resource.store', $resource->toArray())); - /** - * The External Resource Store Endpoint shall forbid users without the create external resource permission. - */ - public function testForbidden(): void - { - $resource = ExternalResource::factory()->makeOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $resource = ExternalResource::factory()->makeOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->post(route('api.resource.store', $resource->toArray())); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.resource.store', $resource->toArray())); - /** - * The External Resource Store Endpoint shall require link & site fields. - */ - public function testRequiredFields(): void - { - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(ExternalResource::class))->createOne(); + $response->assertForbidden(); +}); - Sanctum::actingAs($user); +test('required fields', function () { + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(ExternalResource::class))->createOne(); - $response = $this->post(route('api.resource.store')); + Sanctum::actingAs($user); - $response->assertJsonValidationErrors([ - ExternalResource::ATTRIBUTE_LINK, - ExternalResource::ATTRIBUTE_SITE, - ]); - } + $response = post(route('api.resource.store')); - /** - * The External Resource Store Endpoint shall create an resource. - */ - public function testCreate(): void - { - $parameters = array_merge( - ExternalResource::factory()->raw(), - [ExternalResource::ATTRIBUTE_SITE => ResourceSite::OFFICIAL_SITE->localize()], - ); + $response->assertJsonValidationErrors([ + ExternalResource::ATTRIBUTE_LINK, + ExternalResource::ATTRIBUTE_SITE, + ]); +}); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(ExternalResource::class))->createOne(); +test('create', function () { + $parameters = array_merge( + ExternalResource::factory()->raw(), + [ExternalResource::ATTRIBUTE_SITE => ResourceSite::OFFICIAL_SITE->localize()], + ); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(ExternalResource::class))->createOne(); - $response = $this->post(route('api.resource.store', $parameters)); + Sanctum::actingAs($user); - $response->assertCreated(); - static::assertDatabaseCount(ExternalResource::class, 1); - } -} + $response = post(route('api.resource.store', $parameters)); + + $response->assertCreated(); + $this->assertDatabaseCount(ExternalResource::class, 1); +}); diff --git a/tests/Feature/Http/Api/Wiki/ExternalResource/ExternalResourceUpdateTest.php b/tests/Feature/Http/Api/Wiki/ExternalResource/ExternalResourceUpdateTest.php index a4347848d..dea7b3a5a 100644 --- a/tests/Feature/Http/Api/Wiki/ExternalResource/ExternalResourceUpdateTest.php +++ b/tests/Feature/Http/Api/Wiki/ExternalResource/ExternalResourceUpdateTest.php @@ -2,100 +2,80 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\ExternalResource; - use App\Enums\Auth\CrudPermission; use App\Enums\Models\Wiki\ResourceSite; use App\Models\Auth\User; use App\Models\Wiki\ExternalResource; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ExternalResourceUpdateTest extends TestCase -{ - /** - * The External Resource Update Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $resource = ExternalResource::factory()->createOne(); +use function Pest\Laravel\put; - $parameters = array_merge( - ExternalResource::factory()->raw(), - [ExternalResource::ATTRIBUTE_SITE => ResourceSite::OFFICIAL_SITE->localize()] - ); +test('protected', function () { + $resource = ExternalResource::factory()->createOne(); - $response = $this->put(route('api.resource.update', ['resource' => $resource] + $parameters)); + $parameters = array_merge( + ExternalResource::factory()->raw(), + [ExternalResource::ATTRIBUTE_SITE => ResourceSite::OFFICIAL_SITE->localize()] + ); - $response->assertUnauthorized(); - } + $response = put(route('api.resource.update', ['resource' => $resource] + $parameters)); - /** - * The External Resource Update Endpoint shall forbid users without the update external resource permission. - */ - public function testForbidden(): void - { - $resource = ExternalResource::factory()->createOne(); + $response->assertUnauthorized(); +}); - $parameters = array_merge( - ExternalResource::factory()->raw(), - [ExternalResource::ATTRIBUTE_SITE => ResourceSite::OFFICIAL_SITE->localize()] - ); +test('forbidden', function () { + $resource = ExternalResource::factory()->createOne(); - $user = User::factory()->createOne(); + $parameters = array_merge( + ExternalResource::factory()->raw(), + [ExternalResource::ATTRIBUTE_SITE => ResourceSite::OFFICIAL_SITE->localize()] + ); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->put(route('api.resource.update', ['resource' => $resource] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.resource.update', ['resource' => $resource] + $parameters)); - /** - * The External Resource Update Endpoint shall forbid users from updating a resource that is trashed. - */ - public function testTrashed(): void - { - $resource = ExternalResource::factory() - ->trashed() - ->createOne([ - ExternalResource::ATTRIBUTE_SITE => ResourceSite::OFFICIAL_SITE, - ]); + $response->assertForbidden(); +}); - $parameters = array_merge( - ExternalResource::factory()->raw(), - [ExternalResource::ATTRIBUTE_SITE => ResourceSite::OFFICIAL_SITE->localize()] - ); - - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(ExternalResource::class))->createOne(); - - Sanctum::actingAs($user); - - $response = $this->put(route('api.resource.update', ['resource' => $resource] + $parameters)); - - $response->assertForbidden(); - } - - /** - * The External Resource Update Endpoint shall update a resource. - */ - public function testUpdate(): void - { - $resource = ExternalResource::factory()->createOne([ +test('trashed', function () { + $resource = ExternalResource::factory() + ->trashed() + ->createOne([ ExternalResource::ATTRIBUTE_SITE => ResourceSite::OFFICIAL_SITE, ]); - $parameters = array_merge( - ExternalResource::factory()->raw(), - [ExternalResource::ATTRIBUTE_SITE => ResourceSite::OFFICIAL_SITE->localize()] - ); + $parameters = array_merge( + ExternalResource::factory()->raw(), + [ExternalResource::ATTRIBUTE_SITE => ResourceSite::OFFICIAL_SITE->localize()] + ); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(ExternalResource::class))->createOne(); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(ExternalResource::class))->createOne(); - Sanctum::actingAs($user); + Sanctum::actingAs($user); - $response = $this->put(route('api.resource.update', ['resource' => $resource] + $parameters)); + $response = put(route('api.resource.update', ['resource' => $resource] + $parameters)); - $response->assertOk(); - } -} + $response->assertForbidden(); +}); + +test('update', function () { + $resource = ExternalResource::factory()->createOne([ + ExternalResource::ATTRIBUTE_SITE => ResourceSite::OFFICIAL_SITE, + ]); + + $parameters = array_merge( + ExternalResource::factory()->raw(), + [ExternalResource::ATTRIBUTE_SITE => ResourceSite::OFFICIAL_SITE->localize()] + ); + + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(ExternalResource::class))->createOne(); + + Sanctum::actingAs($user); + + $response = put(route('api.resource.update', ['resource' => $resource] + $parameters)); + + $response->assertOk(); +}); diff --git a/tests/Feature/Http/Api/Wiki/Group/GroupDestroyTest.php b/tests/Feature/Http/Api/Wiki/Group/GroupDestroyTest.php index decc14d44..7d51c1d5e 100644 --- a/tests/Feature/Http/Api/Wiki/Group/GroupDestroyTest.php +++ b/tests/Feature/Http/Api/Wiki/Group/GroupDestroyTest.php @@ -2,74 +2,54 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Group; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Group; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class GroupDestroyTest extends TestCase -{ - /** - * The Group Destroy Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $group = Group::factory()->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.group.destroy', ['group' => $group])); +test('protected', function () { + $group = Group::factory()->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.group.destroy', ['group' => $group])); - /** - * The Group Destroy Endpoint shall forbid users without the delete group permission. - */ - public function testForbidden(): void - { - $group = Group::factory()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $group = Group::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.group.destroy', ['group' => $group])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.group.destroy', ['group' => $group])); - /** - * The Group Destroy Endpoint shall forbid users from updating a group that is trashed. - */ - public function testTrashed(): void - { - $group = Group::factory()->trashed()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Group::class))->createOne(); +test('trashed', function () { + $group = Group::factory()->trashed()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Group::class))->createOne(); - $response = $this->delete(route('api.group.destroy', ['group' => $group])); + Sanctum::actingAs($user); - $response->assertNotFound(); - } + $response = delete(route('api.group.destroy', ['group' => $group])); - /** - * The Group Destroy Endpoint shall delete the group. - */ - public function testDeleted(): void - { - $group = Group::factory()->createOne(); + $response->assertNotFound(); +}); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Group::class))->createOne(); +test('deleted', function () { + $group = Group::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Group::class))->createOne(); - $response = $this->delete(route('api.group.destroy', ['group' => $group])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertSoftDeleted($group); - } -} + $response = delete(route('api.group.destroy', ['group' => $group])); + + $response->assertOk(); + $this->assertSoftDeleted($group); +}); diff --git a/tests/Feature/Http/Api/Wiki/Group/GroupForceDeleteTest.php b/tests/Feature/Http/Api/Wiki/Group/GroupForceDeleteTest.php index 0c25c0956..c4e5785aa 100644 --- a/tests/Feature/Http/Api/Wiki/Group/GroupForceDeleteTest.php +++ b/tests/Feature/Http/Api/Wiki/Group/GroupForceDeleteTest.php @@ -2,58 +2,42 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Group; - use App\Enums\Auth\ExtendedCrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Group; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class GroupForceDeleteTest extends TestCase -{ - /** - * The Group Force Delete Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $group = Group::factory()->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.group.forceDelete', ['group' => $group])); +test('protected', function () { + $group = Group::factory()->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.group.forceDelete', ['group' => $group])); - /** - * The Group Force Delete Endpoint shall forbid users without the force delete group permission. - */ - public function testForbidden(): void - { - $group = Group::factory()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $group = Group::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.group.forceDelete', ['group' => $group])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.group.forceDelete', ['group' => $group])); - /** - * The Group Force Delete Endpoint shall force delete the group. - */ - public function testDeleted(): void - { - $group = Group::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::FORCE_DELETE->format(Group::class))->createOne(); +test('deleted', function () { + $group = Group::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::FORCE_DELETE->format(Group::class))->createOne(); - $response = $this->delete(route('api.group.forceDelete', ['group' => $group])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertModelMissing($group); - } -} + $response = delete(route('api.group.forceDelete', ['group' => $group])); + + $response->assertOk(); + $this->assertModelMissing($group); +}); diff --git a/tests/Feature/Http/Api/Wiki/Group/GroupIndexTest.php b/tests/Feature/Http/Api/Wiki/Group/GroupIndexTest.php index d921a7296..21498d0e1 100644 --- a/tests/Feature/Http/Api/Wiki/Group/GroupIndexTest.php +++ b/tests/Feature/Http/Api/Wiki/Group/GroupIndexTest.php @@ -2,9 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Group; - -use App\Concerns\Actions\Http\Api\SortsModels; use App\Constants\ModelConstants; use App\Contracts\Http\Api\Field\SortableField; use App\Enums\Http\Api\Filter\TrashedStatus; @@ -34,603 +31,537 @@ use App\Models\Wiki\Group; use Illuminate\Database\Eloquent\Factories\Sequence; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; -use Tests\TestCase; - -class GroupIndexTest extends TestCase -{ - use SortsModels; - use WithFaker; - - /** - * By default, the Group Index Endpoint shall return a collection of Group Resources. - */ - public function testDefault(): void - { - $groups = Group::factory()->count($this->faker->randomDigitNotNull())->create(); - - $response = $this->get(route('api.group.index')); - - $response->assertJson( - json_decode( - json_encode( - new GroupCollection($groups, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Group Index Endpoint shall be paginated. - */ - public function testPaginated(): void - { - Group::factory()->count($this->faker->randomDigitNotNull())->create(); - - $response = $this->get(route('api.group.index')); - - $response->assertJsonStructure([ - GroupCollection::$wrap, - 'links', - 'meta', - ]); - } - - /** - * The Series Index Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new GroupSchema(); - - $allowedIncludes = collect($schema->allowedIncludes()); - - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); - - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; - - Group::factory() - ->has(AnimeTheme::factory()->count($this->faker->randomDigitNotNull())->for(Anime::factory())) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $groups = Group::with($includedPaths->all())->get(); - - $response = $this->get(route('api.group.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new GroupCollection($groups, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Group Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new GroupSchema(); - - $fields = collect($schema->fields()); - - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); - - $parameters = [ - FieldParser::param() => [ - GroupResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; - - $groups = Group::factory()->count($this->faker->randomDigitNotNull())->create(); - - $response = $this->get(route('api.group.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new GroupCollection($groups, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Group Index Endpoint shall support sorting resources. - */ - public function testSorts(): void - { - $schema = new GroupSchema(); - - /** @var Sort $sort */ - $sort = collect($schema->fields()) - ->filter(fn (Field $field) => $field instanceof SortableField) - ->map(fn (SortableField $field) => $field->getSort()) - ->random(); - - $parameters = [ - SortParser::param() => $sort->format(Arr::random(Direction::cases())), - ]; - - $query = new Query($parameters); - - Group::factory()->count($this->faker->randomDigitNotNull())->create(); - - $response = $this->get(route('api.group.index', $parameters)); - - $groups = $this->sort(Group::query(), $query, $schema)->get(); - - $response->assertJson( - json_decode( - json_encode( - new GroupCollection($groups, $query) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Group Index Endpoint shall support filtering by created_at. - */ - public function testCreatedAtFilter(): void - { - $createdFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($createdFilter, function () { - Group::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - Carbon::withTestNow($excludedDate, function () { - Group::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - $group = Group::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - - $response = $this->get(route('api.group.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new GroupCollection($group, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Group Index Endpoint shall support filtering by updated_at. - */ - public function testUpdatedAtFilter(): void - { - $updatedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($updatedFilter, function () { - Group::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - Carbon::withTestNow($excludedDate, function () { - Group::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - $group = Group::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - - $response = $this->get(route('api.group.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new GroupCollection($group, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Group Index Endpoint shall support filtering by trashed. - */ - public function testWithoutTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITHOUT->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Group::factory()->count($this->faker->randomDigitNotNull())->create(); - - Group::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - - $group = Group::withoutTrashed()->get(); - - $response = $this->get(route('api.group.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new GroupCollection($group, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Group Index Endpoint shall support filtering by trashed. - */ - public function testWithTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Group::factory()->count($this->faker->randomDigitNotNull())->create(); - - Group::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - - $group = Group::withTrashed()->get(); - - $response = $this->get(route('api.group.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new GroupCollection($group, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Group Index Endpoint shall support filtering by trashed. - */ - public function testOnlyTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::ONLY->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Group::factory()->count($this->faker->randomDigitNotNull())->create(); - - Group::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - - $group = Group::onlyTrashed()->get(); - - $response = $this->get(route('api.group.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new GroupCollection($group, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Group Index Endpoint shall support filtering by deleted_at. - */ - public function testDeletedAtFilter(): void - { - $deletedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - ModelConstants::ATTRIBUTE_DELETED_AT => $deletedFilter, - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($deletedFilter, function () { - Group::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - }); - - Carbon::withTestNow($excludedDate, function () { - Group::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - }); - - $groups = Group::withTrashed()->where(ModelConstants::ATTRIBUTE_DELETED_AT, $deletedFilter)->get(); - - $response = $this->get(route('api.group.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new GroupCollection($groups, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Group Index Endpoint shall support constrained eager loading of themes by sequence. - */ - public function testThemesBySequence(): void - { - $sequenceFilter = $this->faker->randomDigitNotNull(); - $excludedSequence = $sequenceFilter + 1; - - $parameters = [ - FilterParser::param() => [ - AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter, - ], - IncludeParser::param() => Group::RELATION_THEMES, - ]; - - Group::factory() - ->has( - AnimeTheme::factory() - ->count($this->faker->randomDigitNotNull()) - ->for(Anime::factory()) - ->state(new Sequence( - [AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter], - [AnimeTheme::ATTRIBUTE_SEQUENCE => $excludedSequence], - )) - ) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $groups = Group::with([ - Group::RELATION_THEMES => function (HasMany $query) use ($sequenceFilter) { - $query->where(AnimeTheme::ATTRIBUTE_SEQUENCE, $sequenceFilter); - }, - ]) - ->get(); - - $response = $this->get(route('api.group.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new GroupCollection($groups, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Group Index Endpoint shall support constrained eager loading of themes by type. - */ - public function testThemesByType(): void - { - $typeFilter = Arr::random(ThemeType::cases()); - - $parameters = [ - FilterParser::param() => [ - AnimeTheme::ATTRIBUTE_TYPE => $typeFilter->localize(), - ], - IncludeParser::param() => Group::RELATION_THEMES, - ]; - - Group::factory() - ->has(AnimeTheme::factory()->count($this->faker->randomDigitNotNull())->for(Anime::factory())) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $groups = Group::with([ - Group::RELATION_THEMES => function (HasMany $query) use ($typeFilter) { - $query->where(AnimeTheme::ATTRIBUTE_TYPE, $typeFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.group.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new GroupCollection($groups, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Group Index Endpoint shall support constrained eager loading of anime by media format. - */ - public function testAnimeByMediaFormat(): void - { - $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), - ], - IncludeParser::param() => Group::RELATION_ANIME, - ]; - - Group::factory() - ->has(AnimeTheme::factory()->count($this->faker->randomDigitNotNull())->for(Anime::factory())) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $groups = Group::with([ - Group::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { - $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.group.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new GroupCollection($groups, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Group Index Endpoint shall support constrained eager loading of anime by season. - */ - public function testAnimeBySeason(): void - { - $seasonFilter = Arr::random(AnimeSeason::cases()); - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), - ], - IncludeParser::param() => Group::RELATION_ANIME, - ]; - - Group::factory() - ->has(AnimeTheme::factory()->count($this->faker->randomDigitNotNull())->for(Anime::factory())) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $groups = Group::with([ - Group::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { - $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.group.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new GroupCollection($groups, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Group Index Endpoint shall support constrained eager loading of anime by year. - */ - public function testAnimeByYear(): void - { - $yearFilter = intval($this->faker->year()); - $excludedYear = $yearFilter + 1; - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_YEAR => $yearFilter, - ], - IncludeParser::param() => Group::RELATION_ANIME, - ]; - - Group::factory() - ->has( - AnimeTheme::factory() - ->count($this->faker->randomDigitNotNull()) - ->for( - Anime::factory() - ->state([ - Anime::ATTRIBUTE_YEAR => $this->faker->boolean() ? $yearFilter : $excludedYear, - ]) - ) - ) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $groups = Group::with([ - Group::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { - $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); - }, - ]) - ->get(); - - $response = $this->get(route('api.group.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new GroupCollection($groups, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + +use function Pest\Laravel\get; + +uses(App\Concerns\Actions\Http\Api\SortsModels::class); + +uses(Illuminate\Foundation\Testing\WithFaker::class); + +test('default', function () { + $groups = Group::factory()->count(fake()->randomDigitNotNull())->create(); + + $response = get(route('api.group.index')); + + $response->assertJson( + json_decode( + json_encode( + new GroupCollection($groups, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('paginated', function () { + Group::factory()->count(fake()->randomDigitNotNull())->create(); + + $response = get(route('api.group.index')); + + $response->assertJsonStructure([ + GroupCollection::$wrap, + 'links', + 'meta', + ]); +}); + +test('allowed include paths', function () { + $schema = new GroupSchema(); + + $allowedIncludes = collect($schema->allowedIncludes()); + + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); + + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; + + Group::factory() + ->has(AnimeTheme::factory()->count(fake()->randomDigitNotNull())->for(Anime::factory())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $groups = Group::with($includedPaths->all())->get(); + + $response = get(route('api.group.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new GroupCollection($groups, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sparse fieldsets', function () { + $schema = new GroupSchema(); + + $fields = collect($schema->fields()); + + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + GroupResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + $groups = Group::factory()->count(fake()->randomDigitNotNull())->create(); + + $response = get(route('api.group.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new GroupCollection($groups, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sorts', function () { + $schema = new GroupSchema(); + + /** @var Sort $sort */ + $sort = collect($schema->fields()) + ->filter(fn (Field $field) => $field instanceof SortableField) + ->map(fn (SortableField $field) => $field->getSort()) + ->random(); + + $parameters = [ + SortParser::param() => $sort->format(Arr::random(Direction::cases())), + ]; + + $query = new Query($parameters); + + Group::factory()->count(fake()->randomDigitNotNull())->create(); + + $response = get(route('api.group.index', $parameters)); + + $groups = $this->sort(Group::query(), $query, $schema)->get(); + + $response->assertJson( + json_decode( + json_encode( + new GroupCollection($groups, $query) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('created at filter', function () { + $createdFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($createdFilter, function () { + Group::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + Carbon::withTestNow($excludedDate, function () { + Group::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + $group = Group::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); + + $response = get(route('api.group.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new GroupCollection($group, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('updated at filter', function () { + $updatedFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($updatedFilter, function () { + Group::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + Carbon::withTestNow($excludedDate, function () { + Group::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + $group = Group::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); + + $response = get(route('api.group.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new GroupCollection($group, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('without trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITHOUT->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Group::factory()->count(fake()->randomDigitNotNull())->create(); + + Group::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + + $group = Group::withoutTrashed()->get(); + + $response = get(route('api.group.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new GroupCollection($group, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('with trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Group::factory()->count(fake()->randomDigitNotNull())->create(); + + Group::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + + $group = Group::withTrashed()->get(); + + $response = get(route('api.group.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new GroupCollection($group, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('only trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::ONLY->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Group::factory()->count(fake()->randomDigitNotNull())->create(); + + Group::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + + $group = Group::onlyTrashed()->get(); + + $response = get(route('api.group.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new GroupCollection($group, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('deleted at filter', function () { + $deletedFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + ModelConstants::ATTRIBUTE_DELETED_AT => $deletedFilter, + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($deletedFilter, function () { + Group::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + }); + + Carbon::withTestNow($excludedDate, function () { + Group::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + }); + + $groups = Group::withTrashed()->where(ModelConstants::ATTRIBUTE_DELETED_AT, $deletedFilter)->get(); + + $response = get(route('api.group.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new GroupCollection($groups, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('themes by sequence', function () { + $sequenceFilter = fake()->randomDigitNotNull(); + $excludedSequence = $sequenceFilter + 1; + + $parameters = [ + FilterParser::param() => [ + AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter, + ], + IncludeParser::param() => Group::RELATION_THEMES, + ]; + + Group::factory() + ->has( + AnimeTheme::factory() + ->count(fake()->randomDigitNotNull()) + ->for(Anime::factory()) + ->state(new Sequence( + [AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter], + [AnimeTheme::ATTRIBUTE_SEQUENCE => $excludedSequence], + )) + ) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $groups = Group::with([ + Group::RELATION_THEMES => function (HasMany $query) use ($sequenceFilter) { + $query->where(AnimeTheme::ATTRIBUTE_SEQUENCE, $sequenceFilter); + }, + ]) + ->get(); + + $response = get(route('api.group.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new GroupCollection($groups, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('themes by type', function () { + $typeFilter = Arr::random(ThemeType::cases()); + + $parameters = [ + FilterParser::param() => [ + AnimeTheme::ATTRIBUTE_TYPE => $typeFilter->localize(), + ], + IncludeParser::param() => Group::RELATION_THEMES, + ]; + + Group::factory() + ->has(AnimeTheme::factory()->count(fake()->randomDigitNotNull())->for(Anime::factory())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $groups = Group::with([ + Group::RELATION_THEMES => function (HasMany $query) use ($typeFilter) { + $query->where(AnimeTheme::ATTRIBUTE_TYPE, $typeFilter->value); + }, + ]) + ->get(); + + $response = get(route('api.group.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new GroupCollection($groups, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by media format', function () { + $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), + ], + IncludeParser::param() => Group::RELATION_ANIME, + ]; + + Group::factory() + ->has(AnimeTheme::factory()->count(fake()->randomDigitNotNull())->for(Anime::factory())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $groups = Group::with([ + Group::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { + $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); + }, + ]) + ->get(); + + $response = get(route('api.group.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new GroupCollection($groups, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by season', function () { + $seasonFilter = Arr::random(AnimeSeason::cases()); + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), + ], + IncludeParser::param() => Group::RELATION_ANIME, + ]; + + Group::factory() + ->has(AnimeTheme::factory()->count(fake()->randomDigitNotNull())->for(Anime::factory())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $groups = Group::with([ + Group::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { + $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); + }, + ]) + ->get(); + + $response = get(route('api.group.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new GroupCollection($groups, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by year', function () { + $yearFilter = intval(fake()->year()); + $excludedYear = $yearFilter + 1; + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_YEAR => $yearFilter, + ], + IncludeParser::param() => Group::RELATION_ANIME, + ]; + + Group::factory() + ->has( + AnimeTheme::factory() + ->count(fake()->randomDigitNotNull()) + ->for( + Anime::factory() + ->state([ + Anime::ATTRIBUTE_YEAR => fake()->boolean() ? $yearFilter : $excludedYear, + ]) + ) + ) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $groups = Group::with([ + Group::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { + $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); + }, + ]) + ->get(); + + $response = get(route('api.group.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new GroupCollection($groups, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Wiki/Group/GroupRestoreTest.php b/tests/Feature/Http/Api/Wiki/Group/GroupRestoreTest.php index 5e86a10b5..ce18ae646 100644 --- a/tests/Feature/Http/Api/Wiki/Group/GroupRestoreTest.php +++ b/tests/Feature/Http/Api/Wiki/Group/GroupRestoreTest.php @@ -2,74 +2,54 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Group; - use App\Enums\Auth\ExtendedCrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Group; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class GroupRestoreTest extends TestCase -{ - /** - * The Group Restore Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $group = Group::factory()->trashed()->createOne(); +use function Pest\Laravel\patch; - $response = $this->patch(route('api.group.restore', ['group' => $group])); +test('protected', function () { + $group = Group::factory()->trashed()->createOne(); - $response->assertUnauthorized(); - } + $response = patch(route('api.group.restore', ['group' => $group])); - /** - * The Group Restore Endpoint shall forbid users without the restore group permission. - */ - public function testForbidden(): void - { - $group = Group::factory()->trashed()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $group = Group::factory()->trashed()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->patch(route('api.group.restore', ['group' => $group])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = patch(route('api.group.restore', ['group' => $group])); - /** - * The Group Restore Endpoint shall forbid users from restoring a group that isn't trashed. - */ - public function testTrashed(): void - { - $group = Group::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(Group::class))->createOne(); +test('trashed', function () { + $group = Group::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(Group::class))->createOne(); - $response = $this->patch(route('api.group.restore', ['group' => $group])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = patch(route('api.group.restore', ['group' => $group])); - /** - * The Group Restore Endpoint shall restore the group. - */ - public function testRestored(): void - { - $group = Group::factory()->trashed()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(Group::class))->createOne(); +test('restored', function () { + $group = Group::factory()->trashed()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(Group::class))->createOne(); - $response = $this->patch(route('api.group.restore', ['group' => $group])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertNotSoftDeleted($group); - } -} + $response = patch(route('api.group.restore', ['group' => $group])); + + $response->assertOk(); + $this->assertNotSoftDeleted($group); +}); diff --git a/tests/Feature/Http/Api/Wiki/Group/GroupShowTest.php b/tests/Feature/Http/Api/Wiki/Group/GroupShowTest.php index 8ee751046..6345e366a 100644 --- a/tests/Feature/Http/Api/Wiki/Group/GroupShowTest.php +++ b/tests/Feature/Http/Api/Wiki/Group/GroupShowTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Group; - use App\Enums\Models\Wiki\AnimeMediaFormat; use App\Enums\Models\Wiki\AnimeSeason; use App\Enums\Models\Wiki\ThemeType; @@ -21,332 +19,293 @@ use App\Models\Wiki\Group; use Illuminate\Database\Eloquent\Factories\Sequence; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; -use Tests\TestCase; -class GroupShowTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the Group Show Endpoint shall return a Group Resource. - */ - public function testDefault(): void - { - $group = Group::factory()->create(); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response = $this->get(route('api.group.show', ['group' => $group])); +test('default', function () { + $group = Group::factory()->create(); - $response->assertJson( - json_decode( - json_encode( - new GroupResource($group, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.group.show', ['group' => $group])); - /** - * The Group Show Endpoint shall return a Group Resource for soft deleted groups. - */ - public function testSoftDelete(): void - { - $group = Group::factory()->trashed()->createOne(); + $response->assertJson( + json_decode( + json_encode( + new GroupResource($group, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $group->unsetRelations(); +test('soft delete', function () { + $group = Group::factory()->trashed()->createOne(); - $response = $this->get(route('api.group.show', ['group' => $group])); + $group->unsetRelations(); - $response->assertJson( - json_decode( - json_encode( - new GroupResource($group, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.group.show', ['group' => $group])); - /** - * The Group Show Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new GroupSchema(); + $response->assertJson( + json_decode( + json_encode( + new GroupResource($group, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('allowed include paths', function () { + $schema = new GroupSchema(); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $allowedIncludes = collect($schema->allowedIncludes()); - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - $group = Group::factory() - ->has(AnimeTheme::factory()->count($this->faker->randomDigitNotNull())->for(Anime::factory())) - ->createOne(); + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; - $response = $this->get(route('api.group.show', ['group' => $group] + $parameters)); + $group = Group::factory() + ->has(AnimeTheme::factory()->count(fake()->randomDigitNotNull())->for(Anime::factory())) + ->createOne(); - $response->assertJson( - json_decode( - json_encode( - new GroupResource($group, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.group.show', ['group' => $group] + $parameters)); - /** - * The Group Show Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new GroupSchema(); + $response->assertJson( + json_decode( + json_encode( + new GroupResource($group, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $fields = collect($schema->fields()); +test('sparse fieldsets', function () { + $schema = new GroupSchema(); - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); + $fields = collect($schema->fields()); - $parameters = [ - FieldParser::param() => [ - GroupResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); - $group = Group::factory()->create(); + $parameters = [ + FieldParser::param() => [ + GroupResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; - $response = $this->get(route('api.group.show', ['group' => $group] + $parameters)); + $group = Group::factory()->create(); - $response->assertJson( - json_decode( - json_encode( - new GroupResource($group, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.group.show', ['group' => $group] + $parameters)); - /** - * The Group Show Endpoint shall support constrained eager loading of themes by sequence. - */ - public function testThemesBySequence(): void - { - $sequenceFilter = $this->faker->randomDigitNotNull(); - $excludedSequence = $sequenceFilter + 1; + $response->assertJson( + json_decode( + json_encode( + new GroupResource($group, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter, - ], - IncludeParser::param() => Group::RELATION_THEMES, - ]; +test('themes by sequence', function () { + $sequenceFilter = fake()->randomDigitNotNull(); + $excludedSequence = $sequenceFilter + 1; - $group = Group::factory() - ->has( - AnimeTheme::factory() - ->count($this->faker->randomDigitNotNull()) - ->for(Anime::factory()) - ->state(new Sequence( - [AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter], - [AnimeTheme::ATTRIBUTE_SEQUENCE => $excludedSequence], - )) - ) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter, + ], + IncludeParser::param() => Group::RELATION_THEMES, + ]; - $group->unsetRelations()->load([ - Group::RELATION_THEMES => function (HasMany $query) use ($sequenceFilter) { - $query->where(AnimeTheme::ATTRIBUTE_SEQUENCE, $sequenceFilter); - }, - ]); + $group = Group::factory() + ->has( + AnimeTheme::factory() + ->count(fake()->randomDigitNotNull()) + ->for(Anime::factory()) + ->state(new Sequence( + [AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter], + [AnimeTheme::ATTRIBUTE_SEQUENCE => $excludedSequence], + )) + ) + ->createOne(); - $response = $this->get(route('api.group.show', ['group' => $group] + $parameters)); + $group->unsetRelations()->load([ + Group::RELATION_THEMES => function (HasMany $query) use ($sequenceFilter) { + $query->where(AnimeTheme::ATTRIBUTE_SEQUENCE, $sequenceFilter); + }, + ]); - $response->assertJson( - json_decode( - json_encode( - new GroupResource($group, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.group.show', ['group' => $group] + $parameters)); - /** - * The Group Show Endpoint shall support constrained eager loading of themes by type. - */ - public function testThemesByType(): void - { - $typeFilter = Arr::random(ThemeType::cases()); + $response->assertJson( + json_decode( + json_encode( + new GroupResource($group, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - AnimeTheme::ATTRIBUTE_TYPE => $typeFilter->localize(), - ], - IncludeParser::param() => Group::RELATION_THEMES, - ]; +test('themes by type', function () { + $typeFilter = Arr::random(ThemeType::cases()); - $group = Group::factory() - ->has(AnimeTheme::factory()->count($this->faker->randomDigitNotNull())->for(Anime::factory())) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + AnimeTheme::ATTRIBUTE_TYPE => $typeFilter->localize(), + ], + IncludeParser::param() => Group::RELATION_THEMES, + ]; - $group->unsetRelations()->load([ - Group::RELATION_THEMES => function (HasMany $query) use ($typeFilter) { - $query->where(AnimeTheme::ATTRIBUTE_TYPE, $typeFilter->value); - }, - ]); + $group = Group::factory() + ->has(AnimeTheme::factory()->count(fake()->randomDigitNotNull())->for(Anime::factory())) + ->createOne(); - $response = $this->get(route('api.group.show', ['group' => $group] + $parameters)); + $group->unsetRelations()->load([ + Group::RELATION_THEMES => function (HasMany $query) use ($typeFilter) { + $query->where(AnimeTheme::ATTRIBUTE_TYPE, $typeFilter->value); + }, + ]); - $response->assertJson( - json_decode( - json_encode( - new GroupResource($group, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.group.show', ['group' => $group] + $parameters)); - /** - * The Group Show Endpoint shall support constrained eager loading of anime by media format. - */ - public function testAnimeByMediaFormat(): void - { - $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); + $response->assertJson( + json_decode( + json_encode( + new GroupResource($group, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), - ], - IncludeParser::param() => Group::RELATION_ANIME, - ]; +test('anime by media format', function () { + $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); - $group = Group::factory() - ->has(AnimeTheme::factory()->count($this->faker->randomDigitNotNull())->for(Anime::factory())) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), + ], + IncludeParser::param() => Group::RELATION_ANIME, + ]; - $group->unsetRelations()->load([ - Group::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { - $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); - }, - ]); + $group = Group::factory() + ->has(AnimeTheme::factory()->count(fake()->randomDigitNotNull())->for(Anime::factory())) + ->createOne(); - $response = $this->get(route('api.group.show', ['group' => $group] + $parameters)); + $group->unsetRelations()->load([ + Group::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { + $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); + }, + ]); - $response->assertJson( - json_decode( - json_encode( - new GroupResource($group, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.group.show', ['group' => $group] + $parameters)); - /** - * The Group Show Endpoint shall support constrained eager loading of anime by season. - */ - public function testAnimeBySeason(): void - { - $seasonFilter = Arr::random(AnimeSeason::cases()); + $response->assertJson( + json_decode( + json_encode( + new GroupResource($group, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), - ], - IncludeParser::param() => Group::RELATION_ANIME, - ]; +test('anime by season', function () { + $seasonFilter = Arr::random(AnimeSeason::cases()); - $group = Group::factory() - ->has(AnimeTheme::factory()->count($this->faker->randomDigitNotNull())->for(Anime::factory())) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), + ], + IncludeParser::param() => Group::RELATION_ANIME, + ]; - $group->unsetRelations()->load([ - Group::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { - $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); - }, - ]); + $group = Group::factory() + ->has(AnimeTheme::factory()->count(fake()->randomDigitNotNull())->for(Anime::factory())) + ->createOne(); - $response = $this->get(route('api.group.show', ['group' => $group] + $parameters)); + $group->unsetRelations()->load([ + Group::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { + $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); + }, + ]); - $response->assertJson( - json_decode( - json_encode( - new GroupResource($group, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.group.show', ['group' => $group] + $parameters)); - /** - * The Group Show Endpoint shall support constrained eager loading of anime by year. - */ - public function testAnimeByYear(): void - { - $yearFilter = intval($this->faker->year()); - $excludedYear = $yearFilter + 1; + $response->assertJson( + json_decode( + json_encode( + new GroupResource($group, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_YEAR => $yearFilter, - ], - IncludeParser::param() => Group::RELATION_ANIME, - ]; +test('anime by year', function () { + $yearFilter = intval(fake()->year()); + $excludedYear = $yearFilter + 1; - $group = Group::factory() - ->has( - AnimeTheme::factory() - ->count($this->faker->randomDigitNotNull()) - ->for( - Anime::factory() - ->state([ - Anime::ATTRIBUTE_YEAR => $this->faker->boolean() ? $yearFilter : $excludedYear, - ]) - ) - ) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_YEAR => $yearFilter, + ], + IncludeParser::param() => Group::RELATION_ANIME, + ]; - $group->unsetRelations()->load([ - Group::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { - $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); - }, - ]); + $group = Group::factory() + ->has( + AnimeTheme::factory() + ->count(fake()->randomDigitNotNull()) + ->for( + Anime::factory() + ->state([ + Anime::ATTRIBUTE_YEAR => fake()->boolean() ? $yearFilter : $excludedYear, + ]) + ) + ) + ->createOne(); - $response = $this->get(route('api.group.show', ['group' => $group] + $parameters)); + $group->unsetRelations()->load([ + Group::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { + $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); + }, + ]); - $response->assertJson( - json_decode( - json_encode( - new GroupResource($group, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response = get(route('api.group.show', ['group' => $group] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new GroupResource($group, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Wiki/Group/GroupStoreTest.php b/tests/Feature/Http/Api/Wiki/Group/GroupStoreTest.php index 72c6cad3c..e6944ac6d 100644 --- a/tests/Feature/Http/Api/Wiki/Group/GroupStoreTest.php +++ b/tests/Feature/Http/Api/Wiki/Group/GroupStoreTest.php @@ -2,58 +2,42 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Group; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Group; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class GroupStoreTest extends TestCase -{ - /** - * The Group Store Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $group = Group::factory()->makeOne(); +use function Pest\Laravel\post; - $response = $this->post(route('api.group.store', $group->toArray())); +test('protected', function () { + $group = Group::factory()->makeOne(); - $response->assertUnauthorized(); - } + $response = post(route('api.group.store', $group->toArray())); - /** - * The Group Store Endpoint shall forbid users without the create group permission. - */ - public function testForbidden(): void - { - $group = Group::factory()->makeOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $group = Group::factory()->makeOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->post(route('api.group.store', $group->toArray())); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.group.store', $group->toArray())); - /** - * The Group Store Endpoint shall create a group. - */ - public function testCreate(): void - { - $parameters = Group::factory()->raw(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Group::class))->createOne(); +test('create', function () { + $parameters = Group::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Group::class))->createOne(); - $response = $this->post(route('api.group.store', $parameters)); + Sanctum::actingAs($user); - $response->assertCreated(); - static::assertDatabaseCount(Group::class, 1); - } -} + $response = post(route('api.group.store', $parameters)); + + $response->assertCreated(); + $this->assertDatabaseCount(Group::class, 1); +}); diff --git a/tests/Feature/Http/Api/Wiki/Group/GroupUpdateTest.php b/tests/Feature/Http/Api/Wiki/Group/GroupUpdateTest.php index 1130b8647..8eb24bbb2 100644 --- a/tests/Feature/Http/Api/Wiki/Group/GroupUpdateTest.php +++ b/tests/Feature/Http/Api/Wiki/Group/GroupUpdateTest.php @@ -2,81 +2,61 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Group; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Group; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class GroupUpdateTest extends TestCase -{ - /** - * The Group Update Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $group = Group::factory()->createOne(); +use function Pest\Laravel\put; - $parameters = Group::factory()->raw(); +test('protected', function () { + $group = Group::factory()->createOne(); - $response = $this->put(route('api.group.update', ['group' => $group] + $parameters)); + $parameters = Group::factory()->raw(); - $response->assertUnauthorized(); - } + $response = put(route('api.group.update', ['group' => $group] + $parameters)); - /** - * The Group Store Endpoint shall forbid users without the create group permission. - */ - public function testForbidden(): void - { - $group = Group::factory()->createOne(); + $response->assertUnauthorized(); +}); - $parameters = Group::factory()->raw(); +test('forbidden', function () { + $group = Group::factory()->createOne(); - $user = User::factory()->createOne(); + $parameters = Group::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->put(route('api.group.update', ['group' => $group] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.group.update', ['group' => $group] + $parameters)); - /** - * The Group Update Endpoint shall forbid users from updating a group that is trashed. - */ - public function testTrashed(): void - { - $group = Group::factory()->trashed()->createOne(); + $response->assertForbidden(); +}); - $parameters = Group::factory()->raw(); +test('trashed', function () { + $group = Group::factory()->trashed()->createOne(); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Group::class))->createOne(); + $parameters = Group::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Group::class))->createOne(); - $response = $this->put(route('api.group.update', ['group' => $group] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.group.update', ['group' => $group] + $parameters)); - /** - * The Group Update Endpoint shall update a group. - */ - public function testUpdate(): void - { - $group = Group::factory()->createOne(); + $response->assertForbidden(); +}); - $parameters = Group::factory()->raw(); +test('update', function () { + $group = Group::factory()->createOne(); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Group::class))->createOne(); + $parameters = Group::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Group::class))->createOne(); - $response = $this->put(route('api.group.update', ['group' => $group] + $parameters)); + Sanctum::actingAs($user); - $response->assertOk(); - } -} + $response = put(route('api.group.update', ['group' => $group] + $parameters)); + + $response->assertOk(); +}); diff --git a/tests/Feature/Http/Api/Wiki/Image/ImageDestroyTest.php b/tests/Feature/Http/Api/Wiki/Image/ImageDestroyTest.php index 22370c371..1d341cecc 100644 --- a/tests/Feature/Http/Api/Wiki/Image/ImageDestroyTest.php +++ b/tests/Feature/Http/Api/Wiki/Image/ImageDestroyTest.php @@ -2,74 +2,54 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Image; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Image; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ImageDestroyTest extends TestCase -{ - /** - * The Image Destroy Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $image = Image::factory()->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.image.destroy', ['image' => $image])); +test('protected', function () { + $image = Image::factory()->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.image.destroy', ['image' => $image])); - /** - * The Image Destroy Endpoint shall forbid users without the delete image permission. - */ - public function testForbidden(): void - { - $image = Image::factory()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $image = Image::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.image.destroy', ['image' => $image])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.image.destroy', ['image' => $image])); - /** - * The Image Destroy Endpoint shall forbid users from deleting an image that is trashed. - */ - public function testTrashed(): void - { - $image = Image::factory()->trashed()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Image::class))->createOne(); +test('trashed', function () { + $image = Image::factory()->trashed()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Image::class))->createOne(); - $response = $this->delete(route('api.image.destroy', ['image' => $image])); + Sanctum::actingAs($user); - $response->assertNotFound(); - } + $response = delete(route('api.image.destroy', ['image' => $image])); - /** - * The Image Destroy Endpoint shall delete the image. - */ - public function testDeleted(): void - { - $image = Image::factory()->createOne(); + $response->assertNotFound(); +}); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Image::class))->createOne(); +test('deleted', function () { + $image = Image::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Image::class))->createOne(); - $response = $this->delete(route('api.image.destroy', ['image' => $image])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertSoftDeleted($image); - } -} + $response = delete(route('api.image.destroy', ['image' => $image])); + + $response->assertOk(); + $this->assertSoftDeleted($image); +}); diff --git a/tests/Feature/Http/Api/Wiki/Image/ImageForceDeleteTest.php b/tests/Feature/Http/Api/Wiki/Image/ImageForceDeleteTest.php index 10c954b66..528698e07 100644 --- a/tests/Feature/Http/Api/Wiki/Image/ImageForceDeleteTest.php +++ b/tests/Feature/Http/Api/Wiki/Image/ImageForceDeleteTest.php @@ -2,57 +2,41 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Image; - use App\Enums\Auth\ExtendedCrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Image; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ImageForceDeleteTest extends TestCase -{ - /** - * The Image Force Delete Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $image = Image::factory()->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.image.forceDelete', ['image' => $image])); +test('protected', function () { + $image = Image::factory()->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.image.forceDelete', ['image' => $image])); - /** - * The Image Force Delete Endpoint shall forbid users without the force delete image permission. - */ - public function testForbidden(): void - { - $image = Image::factory()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $image = Image::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.image.forceDelete', ['image' => $image])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.image.forceDelete', ['image' => $image])); - /** - * The Image Force Delete Endpoint shall force delete the image. - */ - public function testDeleted(): void - { - $image = Image::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::FORCE_DELETE->format(Image::class))->createOne(); +test('deleted', function () { + $image = Image::factory()->createOne(); - Sanctum::actingAs($user); - $response = $this->delete(route('api.image.forceDelete', ['image' => $image])); + $user = User::factory()->withPermissions(ExtendedCrudPermission::FORCE_DELETE->format(Image::class))->createOne(); - $response->assertOk(); - static::assertModelMissing($image); - } -} + Sanctum::actingAs($user); + $response = delete(route('api.image.forceDelete', ['image' => $image])); + + $response->assertOk(); + $this->assertModelMissing($image); +}); diff --git a/tests/Feature/Http/Api/Wiki/Image/ImageIndexTest.php b/tests/Feature/Http/Api/Wiki/Image/ImageIndexTest.php index 445ba215a..d0e21d950 100644 --- a/tests/Feature/Http/Api/Wiki/Image/ImageIndexTest.php +++ b/tests/Feature/Http/Api/Wiki/Image/ImageIndexTest.php @@ -2,9 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Image; - -use App\Concerns\Actions\Http\Api\SortsModels; use App\Constants\ModelConstants; use App\Contracts\Http\Api\Field\SortableField; use App\Enums\Http\Api\Filter\TrashedStatus; @@ -32,549 +29,487 @@ use App\Models\Wiki\Anime; use App\Models\Wiki\Artist; use App\Models\Wiki\Image; use Illuminate\Database\Eloquent\Relations\BelongsToMany; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; -use Tests\TestCase; - -class ImageIndexTest extends TestCase -{ - use SortsModels; - use WithFaker; - - /** - * By default, the Image Index Endpoint shall return a collection of Image Resources. - */ - public function testDefault(): void - { - $images = Image::factory() - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $response = $this->get(route('api.image.index')); - - $response->assertJson( - json_decode( - json_encode( - new ImageCollection($images, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Image Index Endpoint shall be paginated. - */ - public function testPaginated(): void - { - Image::factory()->count($this->faker->randomDigitNotNull())->create(); - - $response = $this->get(route('api.image.index')); - - $response->assertJsonStructure([ - ImageCollection::$wrap, - 'links', - 'meta', - ]); - } - - /** - * The Image Index Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new ImageSchema(); - - $allowedIncludes = collect($schema->allowedIncludes()); - - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); - - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; - - Image::factory() - ->has(Anime::factory()->count($this->faker->randomDigitNotNull())) - ->has(Artist::factory()->count($this->faker->randomDigitNotNull())) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $images = Image::with($includedPaths->all())->get(); - - $response = $this->get(route('api.image.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ImageCollection($images, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Image Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new ImageSchema(); - - $fields = collect($schema->fields()); - - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); - - $parameters = [ - FieldParser::param() => [ - ImageResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; - - $images = Image::factory() - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $response = $this->get(route('api.image.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ImageCollection($images, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Image Index Endpoint shall support sorting resources. - */ - public function testSorts(): void - { - $schema = new ImageSchema(); - - /** @var Sort $sort */ - $sort = collect($schema->fields()) - ->filter(fn (Field $field) => $field instanceof SortableField) - ->map(fn (SortableField $field) => $field->getSort()) - ->random(); - - $parameters = [ - SortParser::param() => $sort->format(Arr::random(Direction::cases())), - ]; - - $query = new Query($parameters); - - Image::factory()->count($this->faker->randomDigitNotNull())->create(); - - $response = $this->get(route('api.image.index', $parameters)); - - $images = $this->sort(Image::query(), $query, $schema)->get(); - - $response->assertJson( - json_decode( - json_encode( - new ImageCollection($images, $query) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Image Index Endpoint shall support filtering by created_at. - */ - public function testCreatedAtFilter(): void - { - $createdFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($createdFilter, function () { - Image::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - Carbon::withTestNow($excludedDate, function () { - Image::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - $image = Image::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - - $response = $this->get(route('api.image.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ImageCollection($image, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Image Index Endpoint shall support filtering by updated_at. - */ - public function testUpdatedAtFilter(): void - { - $updatedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($updatedFilter, function () { - Image::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - Carbon::withTestNow($excludedDate, function () { - Image::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - $image = Image::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - - $response = $this->get(route('api.image.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ImageCollection($image, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Image Index Endpoint shall support filtering by trashed. - */ - public function testWithoutTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITHOUT->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Image::factory()->count($this->faker->randomDigitNotNull())->create(); - - Image::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - - $image = Image::withoutTrashed()->get(); - - $response = $this->get(route('api.image.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ImageCollection($image, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Image Index Endpoint shall support filtering by trashed. - */ - public function testWithTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Image::factory()->count($this->faker->randomDigitNotNull())->create(); - - Image::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - - $image = Image::withTrashed()->get(); - - $response = $this->get(route('api.image.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ImageCollection($image, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Image Index Endpoint shall support filtering by trashed. - */ - public function testOnlyTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::ONLY->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Image::factory()->count($this->faker->randomDigitNotNull())->create(); - - Image::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - - $image = Image::onlyTrashed()->get(); - - $response = $this->get(route('api.image.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ImageCollection($image, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Image Index Endpoint shall support filtering by deleted_at. - */ - public function testDeletedAtFilter(): void - { - $deletedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - ModelConstants::ATTRIBUTE_DELETED_AT => $deletedFilter, - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($deletedFilter, function () { - Image::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - }); - - Carbon::withTestNow($excludedDate, function () { - Image::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - }); - - $image = Image::withTrashed()->where(ModelConstants::ATTRIBUTE_DELETED_AT, $deletedFilter)->get(); - - $response = $this->get(route('api.image.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ImageCollection($image, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Image Index Endpoint shall support filtering by facet. - */ - public function testFacetFilter(): void - { - $facetFilter = Arr::random(ImageFacet::cases()); - - $parameters = [ - FilterParser::param() => [ - Image::ATTRIBUTE_FACET => $facetFilter->localize(), - ], - ]; - - Image::factory() - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $images = Image::query()->where(Image::ATTRIBUTE_FACET, $facetFilter->value)->get(); - - $response = $this->get(route('api.image.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ImageCollection($images, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Image Index Endpoint shall support constrained eager loading of anime by media format. - */ - public function testAnimeByMediaFormat(): void - { - $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), - ], - IncludeParser::param() => Image::RELATION_ANIME, - ]; - - Image::factory() - ->has(Anime::factory()->count($this->faker->randomDigitNotNull())) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $images = Image::with([ - Image::RELATION_ANIME => function (BelongsToMany $query) use ($mediaFormatFilter) { - $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.image.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ImageCollection($images, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Image Index Endpoint shall support constrained eager loading of anime by season. - */ - public function testAnimeBySeason(): void - { - $seasonFilter = Arr::random(AnimeSeason::cases()); - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), - ], - IncludeParser::param() => Image::RELATION_ANIME, - ]; - - Image::factory() - ->has(Anime::factory()->count($this->faker->randomDigitNotNull())) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $images = Image::with([ - Image::RELATION_ANIME => function (BelongsToMany $query) use ($seasonFilter) { - $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.image.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ImageCollection($images, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Image Index Endpoint shall support constrained eager loading of anime by year. - */ - public function testAnimeByYear(): void - { - $yearFilter = intval($this->faker->year()); - $excludedYear = $yearFilter + 1; - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_YEAR => $yearFilter, - ], - IncludeParser::param() => Image::RELATION_ANIME, - ]; - - Image::factory() - ->has( - Anime::factory() - ->count($this->faker->randomDigitNotNull()) - ->state([ - Anime::ATTRIBUTE_YEAR => $this->faker->boolean() ? $yearFilter : $excludedYear, - ]) - ) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $images = Image::with([ - Image::RELATION_ANIME => function (BelongsToMany $query) use ($yearFilter) { - $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); - }, - ]) - ->get(); - - $response = $this->get(route('api.image.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ImageCollection($images, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + +use function Pest\Laravel\get; + +uses(App\Concerns\Actions\Http\Api\SortsModels::class); + +uses(Illuminate\Foundation\Testing\WithFaker::class); + +test('default', function () { + $images = Image::factory() + ->count(fake()->randomDigitNotNull()) + ->create(); + + $response = get(route('api.image.index')); + + $response->assertJson( + json_decode( + json_encode( + new ImageCollection($images, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('paginated', function () { + Image::factory()->count(fake()->randomDigitNotNull())->create(); + + $response = get(route('api.image.index')); + + $response->assertJsonStructure([ + ImageCollection::$wrap, + 'links', + 'meta', + ]); +}); + +test('allowed include paths', function () { + $schema = new ImageSchema(); + + $allowedIncludes = collect($schema->allowedIncludes()); + + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); + + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; + + Image::factory() + ->has(Anime::factory()->count(fake()->randomDigitNotNull())) + ->has(Artist::factory()->count(fake()->randomDigitNotNull())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $images = Image::with($includedPaths->all())->get(); + + $response = get(route('api.image.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ImageCollection($images, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sparse fieldsets', function () { + $schema = new ImageSchema(); + + $fields = collect($schema->fields()); + + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + ImageResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + $images = Image::factory() + ->count(fake()->randomDigitNotNull()) + ->create(); + + $response = get(route('api.image.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ImageCollection($images, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sorts', function () { + $schema = new ImageSchema(); + + /** @var Sort $sort */ + $sort = collect($schema->fields()) + ->filter(fn (Field $field) => $field instanceof SortableField) + ->map(fn (SortableField $field) => $field->getSort()) + ->random(); + + $parameters = [ + SortParser::param() => $sort->format(Arr::random(Direction::cases())), + ]; + + $query = new Query($parameters); + + Image::factory()->count(fake()->randomDigitNotNull())->create(); + + $response = get(route('api.image.index', $parameters)); + + $images = $this->sort(Image::query(), $query, $schema)->get(); + + $response->assertJson( + json_decode( + json_encode( + new ImageCollection($images, $query) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('created at filter', function () { + $createdFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($createdFilter, function () { + Image::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + Carbon::withTestNow($excludedDate, function () { + Image::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + $image = Image::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); + + $response = get(route('api.image.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ImageCollection($image, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('updated at filter', function () { + $updatedFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($updatedFilter, function () { + Image::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + Carbon::withTestNow($excludedDate, function () { + Image::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + $image = Image::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); + + $response = get(route('api.image.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ImageCollection($image, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('without trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITHOUT->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Image::factory()->count(fake()->randomDigitNotNull())->create(); + + Image::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + + $image = Image::withoutTrashed()->get(); + + $response = get(route('api.image.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ImageCollection($image, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('with trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Image::factory()->count(fake()->randomDigitNotNull())->create(); + + Image::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + + $image = Image::withTrashed()->get(); + + $response = get(route('api.image.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ImageCollection($image, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('only trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::ONLY->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Image::factory()->count(fake()->randomDigitNotNull())->create(); + + Image::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + + $image = Image::onlyTrashed()->get(); + + $response = get(route('api.image.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ImageCollection($image, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('deleted at filter', function () { + $deletedFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + ModelConstants::ATTRIBUTE_DELETED_AT => $deletedFilter, + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($deletedFilter, function () { + Image::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + }); + + Carbon::withTestNow($excludedDate, function () { + Image::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + }); + + $image = Image::withTrashed()->where(ModelConstants::ATTRIBUTE_DELETED_AT, $deletedFilter)->get(); + + $response = get(route('api.image.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ImageCollection($image, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('facet filter', function () { + $facetFilter = Arr::random(ImageFacet::cases()); + + $parameters = [ + FilterParser::param() => [ + Image::ATTRIBUTE_FACET => $facetFilter->localize(), + ], + ]; + + Image::factory() + ->count(fake()->randomDigitNotNull()) + ->create(); + + $images = Image::query()->where(Image::ATTRIBUTE_FACET, $facetFilter->value)->get(); + + $response = get(route('api.image.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ImageCollection($images, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by media format', function () { + $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), + ], + IncludeParser::param() => Image::RELATION_ANIME, + ]; + + Image::factory() + ->has(Anime::factory()->count(fake()->randomDigitNotNull())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $images = Image::with([ + Image::RELATION_ANIME => function (BelongsToMany $query) use ($mediaFormatFilter) { + $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); + }, + ]) + ->get(); + + $response = get(route('api.image.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ImageCollection($images, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by season', function () { + $seasonFilter = Arr::random(AnimeSeason::cases()); + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), + ], + IncludeParser::param() => Image::RELATION_ANIME, + ]; + + Image::factory() + ->has(Anime::factory()->count(fake()->randomDigitNotNull())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $images = Image::with([ + Image::RELATION_ANIME => function (BelongsToMany $query) use ($seasonFilter) { + $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); + }, + ]) + ->get(); + + $response = get(route('api.image.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ImageCollection($images, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by year', function () { + $yearFilter = intval(fake()->year()); + $excludedYear = $yearFilter + 1; + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_YEAR => $yearFilter, + ], + IncludeParser::param() => Image::RELATION_ANIME, + ]; + + Image::factory() + ->has( + Anime::factory() + ->count(fake()->randomDigitNotNull()) + ->state([ + Anime::ATTRIBUTE_YEAR => fake()->boolean() ? $yearFilter : $excludedYear, + ]) + ) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $images = Image::with([ + Image::RELATION_ANIME => function (BelongsToMany $query) use ($yearFilter) { + $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); + }, + ]) + ->get(); + + $response = get(route('api.image.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ImageCollection($images, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Wiki/Image/ImageRestoreTest.php b/tests/Feature/Http/Api/Wiki/Image/ImageRestoreTest.php index 220c4958c..f2984de2e 100644 --- a/tests/Feature/Http/Api/Wiki/Image/ImageRestoreTest.php +++ b/tests/Feature/Http/Api/Wiki/Image/ImageRestoreTest.php @@ -2,74 +2,54 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Image; - use App\Enums\Auth\ExtendedCrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Image; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ImageRestoreTest extends TestCase -{ - /** - * The Image Restore Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $image = Image::factory()->trashed()->createOne(); +use function Pest\Laravel\patch; - $response = $this->patch(route('api.image.restore', ['image' => $image])); +test('protected', function () { + $image = Image::factory()->trashed()->createOne(); - $response->assertUnauthorized(); - } + $response = patch(route('api.image.restore', ['image' => $image])); - /** - * The Image Restore Endpoint shall forbid users without the restore image permission. - */ - public function testForbidden(): void - { - $image = Image::factory()->trashed()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $image = Image::factory()->trashed()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->patch(route('api.image.restore', ['image' => $image])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = patch(route('api.image.restore', ['image' => $image])); - /** - * The Image Restore Endpoint shall forbid users from restoring an image that isn't trashed. - */ - public function testTrashed(): void - { - $image = Image::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(Image::class))->createOne(); +test('trashed', function () { + $image = Image::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(Image::class))->createOne(); - $response = $this->patch(route('api.image.restore', ['image' => $image])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = patch(route('api.image.restore', ['image' => $image])); - /** - * The Image Restore Endpoint shall restore the image. - */ - public function testRestored(): void - { - $image = Image::factory()->trashed()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(Image::class))->createOne(); +test('restored', function () { + $image = Image::factory()->trashed()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(Image::class))->createOne(); - $response = $this->patch(route('api.image.restore', ['image' => $image])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertNotSoftDeleted($image); - } -} + $response = patch(route('api.image.restore', ['image' => $image])); + + $response->assertOk(); + $this->assertNotSoftDeleted($image); +}); diff --git a/tests/Feature/Http/Api/Wiki/Image/ImageShowTest.php b/tests/Feature/Http/Api/Wiki/Image/ImageShowTest.php index 0b45d49fe..be8deab80 100644 --- a/tests/Feature/Http/Api/Wiki/Image/ImageShowTest.php +++ b/tests/Feature/Http/Api/Wiki/Image/ImageShowTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Image; - use App\Enums\Models\Wiki\AnimeMediaFormat; use App\Enums\Models\Wiki\AnimeSeason; use App\Http\Api\Field\Field; @@ -18,245 +16,214 @@ use App\Models\Wiki\Anime; use App\Models\Wiki\Artist; use App\Models\Wiki\Image; use Illuminate\Database\Eloquent\Relations\BelongsToMany; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; -use Tests\TestCase; -class ImageShowTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the Image Show Endpoint shall return an Image Resource. - */ - public function testDefault(): void - { - $image = Image::factory()->create(); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response = $this->get(route('api.image.show', ['image' => $image])); +test('default', function () { + $image = Image::factory()->create(); - $response->assertJson( - json_decode( - json_encode( - new ImageResource($image, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.image.show', ['image' => $image])); - /** - * The Image Show Endpoint shall return an Image Resource for soft deleted images. - */ - public function testSoftDelete(): void - { - $image = Image::factory()->trashed()->createOne(); + $response->assertJson( + json_decode( + json_encode( + new ImageResource($image, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $image->unsetRelations(); +test('soft delete', function () { + $image = Image::factory()->trashed()->createOne(); - $response = $this->get(route('api.image.show', ['image' => $image])); + $image->unsetRelations(); - $response->assertJson( - json_decode( - json_encode( - new ImageResource($image, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.image.show', ['image' => $image])); - /** - * The Image Show Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new ImageSchema(); + $response->assertJson( + json_decode( + json_encode( + new ImageResource($image, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('allowed include paths', function () { + $schema = new ImageSchema(); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $allowedIncludes = collect($schema->allowedIncludes()); - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - $image = Image::factory() - ->has(Anime::factory()->count($this->faker->randomDigitNotNull())) - ->has(Artist::factory()->count($this->faker->randomDigitNotNull())) - ->createOne(); + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; - $response = $this->get(route('api.image.show', ['image' => $image] + $parameters)); + $image = Image::factory() + ->has(Anime::factory()->count(fake()->randomDigitNotNull())) + ->has(Artist::factory()->count(fake()->randomDigitNotNull())) + ->createOne(); - $response->assertJson( - json_decode( - json_encode( - new ImageResource($image, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.image.show', ['image' => $image] + $parameters)); - /** - * The Image Show Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new ImageSchema(); + $response->assertJson( + json_decode( + json_encode( + new ImageResource($image, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $fields = collect($schema->fields()); +test('sparse fieldsets', function () { + $schema = new ImageSchema(); - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); + $fields = collect($schema->fields()); - $parameters = [ - FieldParser::param() => [ - ImageResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); - $image = Image::factory()->create(); + $parameters = [ + FieldParser::param() => [ + ImageResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; - $response = $this->get(route('api.image.show', ['image' => $image] + $parameters)); + $image = Image::factory()->create(); - $response->assertJson( - json_decode( - json_encode( - new ImageResource($image, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.image.show', ['image' => $image] + $parameters)); - /** - * The Image Show Endpoint shall support constrained eager loading of anime by media format. - */ - public function testAnimeByMediaFormat(): void - { - $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); + $response->assertJson( + json_decode( + json_encode( + new ImageResource($image, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), - ], - IncludeParser::param() => Image::RELATION_ANIME, - ]; +test('anime by media format', function () { + $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); - $image = Image::factory() - ->has(Anime::factory()->count($this->faker->randomDigitNotNull())) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), + ], + IncludeParser::param() => Image::RELATION_ANIME, + ]; - $image->unsetRelations()->load([ - Image::RELATION_ANIME => function (BelongsToMany $query) use ($mediaFormatFilter) { - $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); - }, - ]); + $image = Image::factory() + ->has(Anime::factory()->count(fake()->randomDigitNotNull())) + ->createOne(); - $response = $this->get(route('api.image.show', ['image' => $image] + $parameters)); + $image->unsetRelations()->load([ + Image::RELATION_ANIME => function (BelongsToMany $query) use ($mediaFormatFilter) { + $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); + }, + ]); - $response->assertJson( - json_decode( - json_encode( - new ImageResource($image, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.image.show', ['image' => $image] + $parameters)); - /** - * The Image Show Endpoint shall support constrained eager loading of anime by season. - */ - public function testAnimeBySeason(): void - { - $seasonFilter = Arr::random(AnimeSeason::cases()); + $response->assertJson( + json_decode( + json_encode( + new ImageResource($image, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), - ], - IncludeParser::param() => Image::RELATION_ANIME, - ]; +test('anime by season', function () { + $seasonFilter = Arr::random(AnimeSeason::cases()); - $image = Image::factory() - ->has(Anime::factory()->count($this->faker->randomDigitNotNull())) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), + ], + IncludeParser::param() => Image::RELATION_ANIME, + ]; - $image->unsetRelations()->load([ - Image::RELATION_ANIME => function (BelongsToMany $query) use ($seasonFilter) { - $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); - }, - ]); + $image = Image::factory() + ->has(Anime::factory()->count(fake()->randomDigitNotNull())) + ->createOne(); - $response = $this->get(route('api.image.show', ['image' => $image] + $parameters)); + $image->unsetRelations()->load([ + Image::RELATION_ANIME => function (BelongsToMany $query) use ($seasonFilter) { + $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); + }, + ]); - $response->assertJson( - json_decode( - json_encode( - new ImageResource($image, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.image.show', ['image' => $image] + $parameters)); - /** - * The Image Show Endpoint shall support constrained eager loading of anime by year. - */ - public function testAnimeByYear(): void - { - $yearFilter = intval($this->faker->year()); - $excludedYear = $yearFilter + 1; + $response->assertJson( + json_decode( + json_encode( + new ImageResource($image, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_YEAR => $yearFilter, - ], - IncludeParser::param() => Image::RELATION_ANIME, - ]; +test('anime by year', function () { + $yearFilter = intval(fake()->year()); + $excludedYear = $yearFilter + 1; - $image = Image::factory() - ->has( - Anime::factory() - ->count($this->faker->randomDigitNotNull()) - ->state([ - Anime::ATTRIBUTE_YEAR => $this->faker->boolean() ? $yearFilter : $excludedYear, - ]) - ) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_YEAR => $yearFilter, + ], + IncludeParser::param() => Image::RELATION_ANIME, + ]; - $image->unsetRelations()->load([ - Image::RELATION_ANIME => function (BelongsToMany $query) use ($yearFilter) { - $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); - }, - ]); + $image = Image::factory() + ->has( + Anime::factory() + ->count(fake()->randomDigitNotNull()) + ->state([ + Anime::ATTRIBUTE_YEAR => fake()->boolean() ? $yearFilter : $excludedYear, + ]) + ) + ->createOne(); - $response = $this->get(route('api.image.show', ['image' => $image] + $parameters)); + $image->unsetRelations()->load([ + Image::RELATION_ANIME => function (BelongsToMany $query) use ($yearFilter) { + $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); + }, + ]); - $response->assertJson( - json_decode( - json_encode( - new ImageResource($image, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response = get(route('api.image.show', ['image' => $image] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ImageResource($image, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Wiki/Image/ImageStoreTest.php b/tests/Feature/Http/Api/Wiki/Image/ImageStoreTest.php index 129c75319..90e71f74a 100644 --- a/tests/Feature/Http/Api/Wiki/Image/ImageStoreTest.php +++ b/tests/Feature/Http/Api/Wiki/Image/ImageStoreTest.php @@ -2,90 +2,69 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Image; - use App\Enums\Auth\CrudPermission; use App\Enums\Models\Wiki\ImageFacet; use App\Http\Api\Field\Wiki\Image\ImageFileField; use App\Models\Auth\User; use App\Models\Wiki\Image; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Http\UploadedFile; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Storage; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ImageStoreTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\post; - /** - * The Image Store Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $image = Image::factory()->makeOne(); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response = $this->post(route('api.image.store', $image->toArray())); +test('protected', function () { + $image = Image::factory()->makeOne(); - $response->assertUnauthorized(); - } + $response = post(route('api.image.store', $image->toArray())); - /** - * The Image Store Endpoint shall forbid users without the create image permission. - */ - public function testForbidden(): void - { - $image = Image::factory()->makeOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $image = Image::factory()->makeOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->post(route('api.image.store', $image->toArray())); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.image.store', $image->toArray())); - /** - * The Image Store Endpoint shall require the file field. - */ - public function testRequiredFields(): void - { - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Image::class))->createOne(); + $response->assertForbidden(); +}); - Sanctum::actingAs($user); +test('required fields', function () { + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Image::class))->createOne(); - $response = $this->post(route('api.image.store')); + Sanctum::actingAs($user); - $response->assertJsonValidationErrors([ - ImageFileField::ATTRIBUTE_FILE, - ]); - } + $response = post(route('api.image.store')); - /** - * The Image Store Endpoint shall create an image. - */ - public function testCreate(): void - { - $fs = Storage::fake(Config::get('image.disk')); + $response->assertJsonValidationErrors([ + ImageFileField::ATTRIBUTE_FILE, + ]); +}); - $facet = Arr::random(ImageFacet::cases()); +test('create', function () { + $fs = Storage::fake(Config::get('image.disk')); - $parameters = [Image::ATTRIBUTE_FACET => $facet->localize()]; + $facet = Arr::random(ImageFacet::cases()); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Image::class))->createOne(); + $parameters = [Image::ATTRIBUTE_FACET => $facet->localize()]; - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Image::class))->createOne(); - $response = $this->post(route('api.image.store', $parameters), [ - ImageFileField::ATTRIBUTE_FILE => UploadedFile::fake()->image($this->faker->word().'.jpg'), - ]); + Sanctum::actingAs($user); - $response->assertCreated(); - static::assertCount(1, $fs->allFiles()); - static::assertDatabaseCount(Image::class, 1); - } -} + $response = post(route('api.image.store', $parameters), [ + ImageFileField::ATTRIBUTE_FILE => UploadedFile::fake()->image(fake()->word().'.jpg'), + ]); + + $response->assertCreated(); + $this->assertCount(1, $fs->allFiles()); + $this->assertDatabaseCount(Image::class, 1); +}); diff --git a/tests/Feature/Http/Api/Wiki/Image/ImageUpdateTest.php b/tests/Feature/Http/Api/Wiki/Image/ImageUpdateTest.php index ab9949975..907eac367 100644 --- a/tests/Feature/Http/Api/Wiki/Image/ImageUpdateTest.php +++ b/tests/Feature/Http/Api/Wiki/Image/ImageUpdateTest.php @@ -2,103 +2,83 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Image; - use App\Enums\Auth\CrudPermission; use App\Enums\Models\Wiki\ImageFacet; use App\Models\Auth\User; use App\Models\Wiki\Image; use Illuminate\Support\Arr; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ImageUpdateTest extends TestCase -{ - /** - * The Image Update Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $image = Image::factory()->createOne(); +use function Pest\Laravel\put; - $facet = Arr::random(ImageFacet::cases()); +test('protected', function () { + $image = Image::factory()->createOne(); - $parameters = array_merge( - Image::factory()->raw(), - [Image::ATTRIBUTE_FACET => $facet->localize()], - ); + $facet = Arr::random(ImageFacet::cases()); - $response = $this->put(route('api.image.update', ['image' => $image] + $parameters)); + $parameters = array_merge( + Image::factory()->raw(), + [Image::ATTRIBUTE_FACET => $facet->localize()], + ); - $response->assertUnauthorized(); - } + $response = put(route('api.image.update', ['image' => $image] + $parameters)); - /** - * The Image Update Endpoint shall forbid users without the update image permission. - */ - public function testForbidden(): void - { - $image = Image::factory()->createOne(); + $response->assertUnauthorized(); +}); - $facet = Arr::random(ImageFacet::cases()); +test('forbidden', function () { + $image = Image::factory()->createOne(); - $parameters = array_merge( - Image::factory()->raw(), - [Image::ATTRIBUTE_FACET => $facet->localize()], - ); + $facet = Arr::random(ImageFacet::cases()); - $user = User::factory()->createOne(); + $parameters = array_merge( + Image::factory()->raw(), + [Image::ATTRIBUTE_FACET => $facet->localize()], + ); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->put(route('api.image.update', ['image' => $image] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.image.update', ['image' => $image] + $parameters)); - /** - * The Image Update Endpoint shall forbid users from updating an image that is trashed. - */ - public function testTrashed(): void - { - $image = Image::factory()->trashed()->createOne(); + $response->assertForbidden(); +}); - $facet = Arr::random(ImageFacet::cases()); +test('trashed', function () { + $image = Image::factory()->trashed()->createOne(); - $parameters = array_merge( - Image::factory()->raw(), - [Image::ATTRIBUTE_FACET => $facet->localize()], - ); + $facet = Arr::random(ImageFacet::cases()); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Image::class))->createOne(); + $parameters = array_merge( + Image::factory()->raw(), + [Image::ATTRIBUTE_FACET => $facet->localize()], + ); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Image::class))->createOne(); - $response = $this->put(route('api.image.update', ['image' => $image] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.image.update', ['image' => $image] + $parameters)); - /** - * The Image Update Endpoint shall update an image. - */ - public function testUpdate(): void - { - $image = Image::factory()->createOne(); + $response->assertForbidden(); +}); - $facet = Arr::random(ImageFacet::cases()); +test('update', function () { + $image = Image::factory()->createOne(); - $parameters = array_merge( - Image::factory()->raw(), - [Image::ATTRIBUTE_FACET => $facet->localize()], - ); + $facet = Arr::random(ImageFacet::cases()); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Image::class))->createOne(); + $parameters = array_merge( + Image::factory()->raw(), + [Image::ATTRIBUTE_FACET => $facet->localize()], + ); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Image::class))->createOne(); - $response = $this->put(route('api.image.update', ['image' => $image] + $parameters)); + Sanctum::actingAs($user); - $response->assertOk(); - } -} + $response = put(route('api.image.update', ['image' => $image] + $parameters)); + + $response->assertOk(); +}); diff --git a/tests/Feature/Http/Api/Wiki/Series/SeriesDestroyTest.php b/tests/Feature/Http/Api/Wiki/Series/SeriesDestroyTest.php index 52db967e4..d8c244074 100644 --- a/tests/Feature/Http/Api/Wiki/Series/SeriesDestroyTest.php +++ b/tests/Feature/Http/Api/Wiki/Series/SeriesDestroyTest.php @@ -2,74 +2,54 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Series; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Series; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class SeriesDestroyTest extends TestCase -{ - /** - * The Series Destroy Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $series = Series::factory()->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.series.destroy', ['series' => $series])); +test('protected', function () { + $series = Series::factory()->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.series.destroy', ['series' => $series])); - /** - * The Series Destroy Endpoint shall forbid users without the delete series permission. - */ - public function testForbidden(): void - { - $series = Series::factory()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $series = Series::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.series.destroy', ['series' => $series])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.series.destroy', ['series' => $series])); - /** - * The Series Destroy Endpoint shall forbid users from updating a series that is trashed. - */ - public function testTrashed(): void - { - $series = Series::factory()->trashed()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Series::class))->createOne(); +test('trashed', function () { + $series = Series::factory()->trashed()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Series::class))->createOne(); - $response = $this->delete(route('api.series.destroy', ['series' => $series])); + Sanctum::actingAs($user); - $response->assertNotFound(); - } + $response = delete(route('api.series.destroy', ['series' => $series])); - /** - * The Series Destroy Endpoint shall delete the series. - */ - public function testDeleted(): void - { - $series = Series::factory()->createOne(); + $response->assertNotFound(); +}); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Series::class))->createOne(); +test('deleted', function () { + $series = Series::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Series::class))->createOne(); - $response = $this->delete(route('api.series.destroy', ['series' => $series])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertSoftDeleted($series); - } -} + $response = delete(route('api.series.destroy', ['series' => $series])); + + $response->assertOk(); + $this->assertSoftDeleted($series); +}); diff --git a/tests/Feature/Http/Api/Wiki/Series/SeriesForceDeleteTest.php b/tests/Feature/Http/Api/Wiki/Series/SeriesForceDeleteTest.php index 1000bc1cb..bb3818019 100644 --- a/tests/Feature/Http/Api/Wiki/Series/SeriesForceDeleteTest.php +++ b/tests/Feature/Http/Api/Wiki/Series/SeriesForceDeleteTest.php @@ -2,58 +2,42 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Series; - use App\Enums\Auth\ExtendedCrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Series; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class SeriesForceDeleteTest extends TestCase -{ - /** - * The Series Force Delete Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $series = Series::factory()->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.series.forceDelete', ['series' => $series])); +test('protected', function () { + $series = Series::factory()->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.series.forceDelete', ['series' => $series])); - /** - * The Series Force Delete Endpoint shall forbid users without the force delete series permission. - */ - public function testForbidden(): void - { - $series = Series::factory()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $series = Series::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.series.forceDelete', ['series' => $series])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.series.forceDelete', ['series' => $series])); - /** - * The Series Force Delete Endpoint shall force delete the series. - */ - public function testDeleted(): void - { - $series = Series::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::FORCE_DELETE->format(Series::class))->createOne(); +test('deleted', function () { + $series = Series::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::FORCE_DELETE->format(Series::class))->createOne(); - $response = $this->delete(route('api.series.forceDelete', ['series' => $series])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertModelMissing($series); - } -} + $response = delete(route('api.series.forceDelete', ['series' => $series])); + + $response->assertOk(); + $this->assertModelMissing($series); +}); diff --git a/tests/Feature/Http/Api/Wiki/Series/SeriesIndexTest.php b/tests/Feature/Http/Api/Wiki/Series/SeriesIndexTest.php index 800ba2ba1..5f4a237be 100644 --- a/tests/Feature/Http/Api/Wiki/Series/SeriesIndexTest.php +++ b/tests/Feature/Http/Api/Wiki/Series/SeriesIndexTest.php @@ -2,9 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Series; - -use App\Concerns\Actions\Http\Api\SortsModels; use App\Constants\ModelConstants; use App\Contracts\Http\Api\Field\SortableField; use App\Enums\Http\Api\Filter\TrashedStatus; @@ -31,512 +28,454 @@ use App\Models\Wiki\Anime; use App\Models\Wiki\Series; use Illuminate\Database\Eloquent\Factories\Sequence; use Illuminate\Database\Eloquent\Relations\BelongsToMany; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; -use Tests\TestCase; - -class SeriesIndexTest extends TestCase -{ - use SortsModels; - use WithFaker; - - /** - * By default, the Series Index Endpoint shall return a collection of Series Resources. - */ - public function testDefault(): void - { - $series = Series::factory()->count($this->faker->randomDigitNotNull())->create(); - - $response = $this->get(route('api.series.index')); - - $response->assertJson( - json_decode( - json_encode( - new SeriesCollection($series, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Series Index Endpoint shall be paginated. - */ - public function testPaginated(): void - { - Series::factory()->count($this->faker->randomDigitNotNull())->create(); - - $response = $this->get(route('api.series.index')); - - $response->assertJsonStructure([ - SeriesCollection::$wrap, - 'links', - 'meta', - ]); - } - - /** - * The Series Index Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new SeriesSchema(); - - $allowedIncludes = collect($schema->allowedIncludes()); - - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); - - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; - - Series::factory() - ->has(Anime::factory()->count($this->faker->randomDigitNotNull())) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $series = Series::with($includedPaths->all())->get(); - - $response = $this->get(route('api.series.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new SeriesCollection($series, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Series Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new SeriesSchema(); - - $fields = collect($schema->fields()); - - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); - - $parameters = [ - FieldParser::param() => [ - SeriesResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; - - $series = Series::factory()->count($this->faker->randomDigitNotNull())->create(); - - $response = $this->get(route('api.series.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new SeriesCollection($series, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Series Index Endpoint shall support sorting resources. - */ - public function testSorts(): void - { - $schema = new SeriesSchema(); - - /** @var Sort $sort */ - $sort = collect($schema->fields()) - ->filter(fn (Field $field) => $field instanceof SortableField) - ->map(fn (SortableField $field) => $field->getSort()) - ->random(); - - $parameters = [ - SortParser::param() => $sort->format(Arr::random(Direction::cases())), - ]; - - $query = new Query($parameters); - - Series::factory()->count($this->faker->randomDigitNotNull())->create(); - - $response = $this->get(route('api.series.index', $parameters)); - - $series = $this->sort(Series::query(), $query, $schema)->get(); - - $response->assertJson( - json_decode( - json_encode( - new SeriesCollection($series, $query) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Series Index Endpoint shall support filtering by created_at. - */ - public function testCreatedAtFilter(): void - { - $createdFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($createdFilter, function () { - Series::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - Carbon::withTestNow($excludedDate, function () { - Series::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - $series = Series::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - - $response = $this->get(route('api.series.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new SeriesCollection($series, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Series Index Endpoint shall support filtering by updated_at. - */ - public function testUpdatedAtFilter(): void - { - $updatedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($updatedFilter, function () { - Series::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - Carbon::withTestNow($excludedDate, function () { - Series::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - $series = Series::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - - $response = $this->get(route('api.series.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new SeriesCollection($series, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Series Index Endpoint shall support filtering by trashed. - */ - public function testWithoutTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITHOUT->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Series::factory()->count($this->faker->randomDigitNotNull())->create(); - - Series::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - - $series = Series::withoutTrashed()->get(); - - $response = $this->get(route('api.series.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new SeriesCollection($series, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Series Index Endpoint shall support filtering by trashed. - */ - public function testWithTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Series::factory()->count($this->faker->randomDigitNotNull())->create(); - - Series::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - - $series = Series::withTrashed()->get(); - - $response = $this->get(route('api.series.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new SeriesCollection($series, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Series Index Endpoint shall support filtering by trashed. - */ - public function testOnlyTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::ONLY->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Series::factory()->count($this->faker->randomDigitNotNull())->create(); - - Series::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - - $series = Series::onlyTrashed()->get(); - - $response = $this->get(route('api.series.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new SeriesCollection($series, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Series Index Endpoint shall support filtering by deleted_at. - */ - public function testDeletedAtFilter(): void - { - $deletedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - ModelConstants::ATTRIBUTE_DELETED_AT => $deletedFilter, - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($deletedFilter, function () { - Series::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - }); - - Carbon::withTestNow($excludedDate, function () { - Series::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - }); - - $series = Series::withTrashed()->where(ModelConstants::ATTRIBUTE_DELETED_AT, $deletedFilter)->get(); - - $response = $this->get(route('api.series.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new SeriesCollection($series, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Series Index Endpoint shall support constrained eager loading of anime by media format. - */ - public function testAnimeByMediaFormat(): void - { - $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), - ], - IncludeParser::param() => Series::RELATION_ANIME, - ]; - - Series::factory() - ->has(Anime::factory()->count($this->faker->randomDigitNotNull())) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $series = Series::with([ - Series::RELATION_ANIME => function (BelongsToMany $query) use ($mediaFormatFilter) { - $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.series.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new SeriesCollection($series, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Series Index Endpoint shall support constrained eager loading of anime by season. - */ - public function testAnimeBySeason(): void - { - $seasonFilter = Arr::random(AnimeSeason::cases()); - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), - ], - IncludeParser::param() => Series::RELATION_ANIME, - ]; - - Series::factory() - ->has(Anime::factory()->count($this->faker->randomDigitNotNull())) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $series = Series::with([ - Series::RELATION_ANIME => function (BelongsToMany $query) use ($seasonFilter) { - $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.series.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new SeriesCollection($series, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Series Index Endpoint shall support constrained eager loading of anime by year. - */ - public function testAnimeByYear(): void - { - $yearFilter = $this->faker->numberBetween(2000, 2002); - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_YEAR => $yearFilter, - ], - IncludeParser::param() => Series::RELATION_ANIME, - ]; - - Series::factory() - ->has( - Anime::factory() - ->count($this->faker->randomDigitNotNull()) - ->state(new Sequence( - [Anime::ATTRIBUTE_YEAR => 2000], - [Anime::ATTRIBUTE_YEAR => 2001], - [Anime::ATTRIBUTE_YEAR => 2002], - )) - ) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $series = Series::with([ - Series::RELATION_ANIME => function (BelongsToMany $query) use ($yearFilter) { - $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); - }, - ]) - ->get(); - - $response = $this->get(route('api.series.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new SeriesCollection($series, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + +use function Pest\Laravel\get; + +uses(App\Concerns\Actions\Http\Api\SortsModels::class); + +uses(Illuminate\Foundation\Testing\WithFaker::class); + +test('default', function () { + $series = Series::factory()->count(fake()->randomDigitNotNull())->create(); + + $response = get(route('api.series.index')); + + $response->assertJson( + json_decode( + json_encode( + new SeriesCollection($series, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('paginated', function () { + Series::factory()->count(fake()->randomDigitNotNull())->create(); + + $response = get(route('api.series.index')); + + $response->assertJsonStructure([ + SeriesCollection::$wrap, + 'links', + 'meta', + ]); +}); + +test('allowed include paths', function () { + $schema = new SeriesSchema(); + + $allowedIncludes = collect($schema->allowedIncludes()); + + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); + + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; + + Series::factory() + ->has(Anime::factory()->count(fake()->randomDigitNotNull())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $series = Series::with($includedPaths->all())->get(); + + $response = get(route('api.series.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new SeriesCollection($series, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sparse fieldsets', function () { + $schema = new SeriesSchema(); + + $fields = collect($schema->fields()); + + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + SeriesResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + $series = Series::factory()->count(fake()->randomDigitNotNull())->create(); + + $response = get(route('api.series.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new SeriesCollection($series, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sorts', function () { + $schema = new SeriesSchema(); + + /** @var Sort $sort */ + $sort = collect($schema->fields()) + ->filter(fn (Field $field) => $field instanceof SortableField) + ->map(fn (SortableField $field) => $field->getSort()) + ->random(); + + $parameters = [ + SortParser::param() => $sort->format(Arr::random(Direction::cases())), + ]; + + $query = new Query($parameters); + + Series::factory()->count(fake()->randomDigitNotNull())->create(); + + $response = get(route('api.series.index', $parameters)); + + $series = $this->sort(Series::query(), $query, $schema)->get(); + + $response->assertJson( + json_decode( + json_encode( + new SeriesCollection($series, $query) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('created at filter', function () { + $createdFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($createdFilter, function () { + Series::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + Carbon::withTestNow($excludedDate, function () { + Series::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + $series = Series::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); + + $response = get(route('api.series.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new SeriesCollection($series, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('updated at filter', function () { + $updatedFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($updatedFilter, function () { + Series::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + Carbon::withTestNow($excludedDate, function () { + Series::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + $series = Series::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); + + $response = get(route('api.series.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new SeriesCollection($series, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('without trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITHOUT->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Series::factory()->count(fake()->randomDigitNotNull())->create(); + + Series::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + + $series = Series::withoutTrashed()->get(); + + $response = get(route('api.series.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new SeriesCollection($series, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('with trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Series::factory()->count(fake()->randomDigitNotNull())->create(); + + Series::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + + $series = Series::withTrashed()->get(); + + $response = get(route('api.series.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new SeriesCollection($series, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('only trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::ONLY->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Series::factory()->count(fake()->randomDigitNotNull())->create(); + + Series::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + + $series = Series::onlyTrashed()->get(); + + $response = get(route('api.series.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new SeriesCollection($series, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('deleted at filter', function () { + $deletedFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + ModelConstants::ATTRIBUTE_DELETED_AT => $deletedFilter, + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($deletedFilter, function () { + Series::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + }); + + Carbon::withTestNow($excludedDate, function () { + Series::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + }); + + $series = Series::withTrashed()->where(ModelConstants::ATTRIBUTE_DELETED_AT, $deletedFilter)->get(); + + $response = get(route('api.series.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new SeriesCollection($series, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by media format', function () { + $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), + ], + IncludeParser::param() => Series::RELATION_ANIME, + ]; + + Series::factory() + ->has(Anime::factory()->count(fake()->randomDigitNotNull())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $series = Series::with([ + Series::RELATION_ANIME => function (BelongsToMany $query) use ($mediaFormatFilter) { + $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); + }, + ]) + ->get(); + + $response = get(route('api.series.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new SeriesCollection($series, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by season', function () { + $seasonFilter = Arr::random(AnimeSeason::cases()); + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), + ], + IncludeParser::param() => Series::RELATION_ANIME, + ]; + + Series::factory() + ->has(Anime::factory()->count(fake()->randomDigitNotNull())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $series = Series::with([ + Series::RELATION_ANIME => function (BelongsToMany $query) use ($seasonFilter) { + $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); + }, + ]) + ->get(); + + $response = get(route('api.series.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new SeriesCollection($series, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by year', function () { + $yearFilter = fake()->numberBetween(2000, 2002); + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_YEAR => $yearFilter, + ], + IncludeParser::param() => Series::RELATION_ANIME, + ]; + + Series::factory() + ->has( + Anime::factory() + ->count(fake()->randomDigitNotNull()) + ->state(new Sequence( + [Anime::ATTRIBUTE_YEAR => 2000], + [Anime::ATTRIBUTE_YEAR => 2001], + [Anime::ATTRIBUTE_YEAR => 2002], + )) + ) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $series = Series::with([ + Series::RELATION_ANIME => function (BelongsToMany $query) use ($yearFilter) { + $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); + }, + ]) + ->get(); + + $response = get(route('api.series.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new SeriesCollection($series, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Wiki/Series/SeriesRestoreTest.php b/tests/Feature/Http/Api/Wiki/Series/SeriesRestoreTest.php index 48e5fca1d..8cd930a35 100644 --- a/tests/Feature/Http/Api/Wiki/Series/SeriesRestoreTest.php +++ b/tests/Feature/Http/Api/Wiki/Series/SeriesRestoreTest.php @@ -2,74 +2,54 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Series; - use App\Enums\Auth\ExtendedCrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Series; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class SeriesRestoreTest extends TestCase -{ - /** - * The Series Restore Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $series = Series::factory()->trashed()->createOne(); +use function Pest\Laravel\patch; - $response = $this->patch(route('api.series.restore', ['series' => $series])); +test('protected', function () { + $series = Series::factory()->trashed()->createOne(); - $response->assertUnauthorized(); - } + $response = patch(route('api.series.restore', ['series' => $series])); - /** - * The Series Restore Endpoint shall forbid users without the restore series permission. - */ - public function testForbidden(): void - { - $series = Series::factory()->trashed()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $series = Series::factory()->trashed()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->patch(route('api.series.restore', ['series' => $series])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = patch(route('api.series.restore', ['series' => $series])); - /** - * The Series Restore Endpoint shall forbid users from restoring a series that isn't trashed. - */ - public function testTrashed(): void - { - $series = Series::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(Series::class))->createOne(); +test('trashed', function () { + $series = Series::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(Series::class))->createOne(); - $response = $this->patch(route('api.series.restore', ['series' => $series])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = patch(route('api.series.restore', ['series' => $series])); - /** - * The Series Restore Endpoint shall restore the series. - */ - public function testRestored(): void - { - $series = Series::factory()->trashed()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(Series::class))->createOne(); +test('restored', function () { + $series = Series::factory()->trashed()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(Series::class))->createOne(); - $response = $this->patch(route('api.series.restore', ['series' => $series])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertNotSoftDeleted($series); - } -} + $response = patch(route('api.series.restore', ['series' => $series])); + + $response->assertOk(); + $this->assertNotSoftDeleted($series); +}); diff --git a/tests/Feature/Http/Api/Wiki/Series/SeriesShowTest.php b/tests/Feature/Http/Api/Wiki/Series/SeriesShowTest.php index 6561aafa6..74a24e6ee 100644 --- a/tests/Feature/Http/Api/Wiki/Series/SeriesShowTest.php +++ b/tests/Feature/Http/Api/Wiki/Series/SeriesShowTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Series; - use App\Enums\Models\Wiki\AnimeMediaFormat; use App\Enums\Models\Wiki\AnimeSeason; use App\Http\Api\Field\Field; @@ -18,245 +16,214 @@ use App\Models\Wiki\Anime; use App\Models\Wiki\Series; use Illuminate\Database\Eloquent\Factories\Sequence; use Illuminate\Database\Eloquent\Relations\BelongsToMany; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; -use Tests\TestCase; -class SeriesShowTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the Series Show Endpoint shall return a Series Resource. - */ - public function testDefault(): void - { - $series = Series::factory()->create(); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response = $this->get(route('api.series.show', ['series' => $series])); +test('default', function () { + $series = Series::factory()->create(); - $response->assertJson( - json_decode( - json_encode( - new SeriesResource($series, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.series.show', ['series' => $series])); - /** - * The Series Show Endpoint shall return a Series Resource for soft deleted series. - */ - public function testSoftDelete(): void - { - $series = Series::factory()->trashed()->createOne(); + $response->assertJson( + json_decode( + json_encode( + new SeriesResource($series, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $series->unsetRelations(); +test('soft delete', function () { + $series = Series::factory()->trashed()->createOne(); - $response = $this->get(route('api.series.show', ['series' => $series])); + $series->unsetRelations(); - $response->assertJson( - json_decode( - json_encode( - new SeriesResource($series, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.series.show', ['series' => $series])); - /** - * The Series Show Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new SeriesSchema(); + $response->assertJson( + json_decode( + json_encode( + new SeriesResource($series, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('allowed include paths', function () { + $schema = new SeriesSchema(); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $allowedIncludes = collect($schema->allowedIncludes()); - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - $series = Series::factory() - ->has(Anime::factory()->count($this->faker->randomDigitNotNull())) - ->createOne(); + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; - $response = $this->get(route('api.series.show', ['series' => $series] + $parameters)); + $series = Series::factory() + ->has(Anime::factory()->count(fake()->randomDigitNotNull())) + ->createOne(); - $response->assertJson( - json_decode( - json_encode( - new SeriesResource($series, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.series.show', ['series' => $series] + $parameters)); - /** - * The Series Show Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new SeriesSchema(); + $response->assertJson( + json_decode( + json_encode( + new SeriesResource($series, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $fields = collect($schema->fields()); +test('sparse fieldsets', function () { + $schema = new SeriesSchema(); - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); + $fields = collect($schema->fields()); - $parameters = [ - FieldParser::param() => [ - SeriesResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); - $series = Series::factory()->create(); + $parameters = [ + FieldParser::param() => [ + SeriesResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; - $response = $this->get(route('api.series.show', ['series' => $series] + $parameters)); + $series = Series::factory()->create(); - $response->assertJson( - json_decode( - json_encode( - new SeriesResource($series, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.series.show', ['series' => $series] + $parameters)); - /** - * The Series Show Endpoint shall support constrained eager loading of anime by media format. - */ - public function testAnimeByMediaFormat(): void - { - $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); + $response->assertJson( + json_decode( + json_encode( + new SeriesResource($series, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), - ], - IncludeParser::param() => Series::RELATION_ANIME, - ]; +test('anime by media format', function () { + $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); - $series = Series::factory() - ->has(Anime::factory()->count($this->faker->randomDigitNotNull())) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), + ], + IncludeParser::param() => Series::RELATION_ANIME, + ]; - $series->unsetRelations()->load([ - Series::RELATION_ANIME => function (BelongsToMany $query) use ($mediaFormatFilter) { - $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); - }, - ]); + $series = Series::factory() + ->has(Anime::factory()->count(fake()->randomDigitNotNull())) + ->createOne(); - $response = $this->get(route('api.series.show', ['series' => $series] + $parameters)); + $series->unsetRelations()->load([ + Series::RELATION_ANIME => function (BelongsToMany $query) use ($mediaFormatFilter) { + $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); + }, + ]); - $response->assertJson( - json_decode( - json_encode( - new SeriesResource($series, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.series.show', ['series' => $series] + $parameters)); - /** - * The Series Show Endpoint shall support constrained eager loading of anime by season. - */ - public function testAnimeBySeason(): void - { - $seasonFilter = Arr::random(AnimeSeason::cases()); + $response->assertJson( + json_decode( + json_encode( + new SeriesResource($series, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), - ], - IncludeParser::param() => Series::RELATION_ANIME, - ]; +test('anime by season', function () { + $seasonFilter = Arr::random(AnimeSeason::cases()); - $series = Series::factory() - ->has(Anime::factory()->count($this->faker->randomDigitNotNull())) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), + ], + IncludeParser::param() => Series::RELATION_ANIME, + ]; - $series->unsetRelations()->load([ - Series::RELATION_ANIME => function (BelongsToMany $query) use ($seasonFilter) { - $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); - }, - ]); + $series = Series::factory() + ->has(Anime::factory()->count(fake()->randomDigitNotNull())) + ->createOne(); - $response = $this->get(route('api.series.show', ['series' => $series] + $parameters)); + $series->unsetRelations()->load([ + Series::RELATION_ANIME => function (BelongsToMany $query) use ($seasonFilter) { + $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); + }, + ]); - $response->assertJson( - json_decode( - json_encode( - new SeriesResource($series, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.series.show', ['series' => $series] + $parameters)); - /** - * The Series Index Endpoint shall support constrained eager loading of anime by year. - */ - public function testAnimeByYear(): void - { - $yearFilter = $this->faker->numberBetween(2000, 2002); + $response->assertJson( + json_decode( + json_encode( + new SeriesResource($series, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_YEAR => $yearFilter, - ], - IncludeParser::param() => Series::RELATION_ANIME, - ]; +test('anime by year', function () { + $yearFilter = fake()->numberBetween(2000, 2002); - $series = Series::factory() - ->has( - Anime::factory() - ->count($this->faker->randomDigitNotNull()) - ->state(new Sequence( - [Anime::ATTRIBUTE_YEAR => 2000], - [Anime::ATTRIBUTE_YEAR => 2001], - [Anime::ATTRIBUTE_YEAR => 2002], - )) - ) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_YEAR => $yearFilter, + ], + IncludeParser::param() => Series::RELATION_ANIME, + ]; - $series->unsetRelations()->load([ - Series::RELATION_ANIME => function (BelongsToMany $query) use ($yearFilter) { - $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); - }, - ]); + $series = Series::factory() + ->has( + Anime::factory() + ->count(fake()->randomDigitNotNull()) + ->state(new Sequence( + [Anime::ATTRIBUTE_YEAR => 2000], + [Anime::ATTRIBUTE_YEAR => 2001], + [Anime::ATTRIBUTE_YEAR => 2002], + )) + ) + ->createOne(); - $response = $this->get(route('api.series.show', ['series' => $series] + $parameters)); + $series->unsetRelations()->load([ + Series::RELATION_ANIME => function (BelongsToMany $query) use ($yearFilter) { + $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); + }, + ]); - $response->assertJson( - json_decode( - json_encode( - new SeriesResource($series, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response = get(route('api.series.show', ['series' => $series] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new SeriesResource($series, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Wiki/Series/SeriesStoreTest.php b/tests/Feature/Http/Api/Wiki/Series/SeriesStoreTest.php index 5d8397259..7ce1c097a 100644 --- a/tests/Feature/Http/Api/Wiki/Series/SeriesStoreTest.php +++ b/tests/Feature/Http/Api/Wiki/Series/SeriesStoreTest.php @@ -2,75 +2,55 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Series; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Series; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class SeriesStoreTest extends TestCase -{ - /** - * The Series Store Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $series = Series::factory()->makeOne(); +use function Pest\Laravel\post; - $response = $this->post(route('api.series.store', $series->toArray())); +test('protected', function () { + $series = Series::factory()->makeOne(); - $response->assertUnauthorized(); - } + $response = post(route('api.series.store', $series->toArray())); - /** - * The Series Store Endpoint shall forbid users without the create series permission. - */ - public function testForbidden(): void - { - $series = Series::factory()->makeOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $series = Series::factory()->makeOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->post(route('api.series.store', $series->toArray())); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.series.store', $series->toArray())); - /** - * The Series Store Endpoint shall require name & slug fields. - */ - public function testRequiredFields(): void - { - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Series::class))->createOne(); + $response->assertForbidden(); +}); - Sanctum::actingAs($user); +test('required fields', function () { + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Series::class))->createOne(); - $response = $this->post(route('api.series.store')); + Sanctum::actingAs($user); - $response->assertJsonValidationErrors([ - Series::ATTRIBUTE_NAME, - Series::ATTRIBUTE_SLUG, - ]); - } + $response = post(route('api.series.store')); - /** - * The Series Store Endpoint shall create a series. - */ - public function testCreate(): void - { - $parameters = Series::factory()->raw(); + $response->assertJsonValidationErrors([ + Series::ATTRIBUTE_NAME, + Series::ATTRIBUTE_SLUG, + ]); +}); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Series::class))->createOne(); +test('create', function () { + $parameters = Series::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Series::class))->createOne(); - $response = $this->post(route('api.series.store', $parameters)); + Sanctum::actingAs($user); - $response->assertCreated(); - static::assertDatabaseCount(Series::class, 1); - } -} + $response = post(route('api.series.store', $parameters)); + + $response->assertCreated(); + $this->assertDatabaseCount(Series::class, 1); +}); diff --git a/tests/Feature/Http/Api/Wiki/Series/SeriesUpdateTest.php b/tests/Feature/Http/Api/Wiki/Series/SeriesUpdateTest.php index 5c4438246..aaed3124e 100644 --- a/tests/Feature/Http/Api/Wiki/Series/SeriesUpdateTest.php +++ b/tests/Feature/Http/Api/Wiki/Series/SeriesUpdateTest.php @@ -2,81 +2,61 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Series; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Series; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class SeriesUpdateTest extends TestCase -{ - /** - * The Series Update Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $series = Series::factory()->createOne(); +use function Pest\Laravel\put; - $parameters = Series::factory()->raw(); +test('protected', function () { + $series = Series::factory()->createOne(); - $response = $this->put(route('api.series.update', ['series' => $series] + $parameters)); + $parameters = Series::factory()->raw(); - $response->assertUnauthorized(); - } + $response = put(route('api.series.update', ['series' => $series] + $parameters)); - /** - * The Series Update Endpoint shall forbid users without the update series permission. - */ - public function testForbidden(): void - { - $series = Series::factory()->createOne(); + $response->assertUnauthorized(); +}); - $parameters = Series::factory()->raw(); +test('forbidden', function () { + $series = Series::factory()->createOne(); - $user = User::factory()->createOne(); + $parameters = Series::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->put(route('api.series.update', ['series' => $series] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.series.update', ['series' => $series] + $parameters)); - /** - * The Series Update Endpoint shall forbid users from updating a series that is trashed. - */ - public function testTrashed(): void - { - $series = Series::factory()->trashed()->createOne(); + $response->assertForbidden(); +}); - $parameters = Series::factory()->raw(); +test('trashed', function () { + $series = Series::factory()->trashed()->createOne(); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Series::class))->createOne(); + $parameters = Series::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Series::class))->createOne(); - $response = $this->put(route('api.series.update', ['series' => $series] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.series.update', ['series' => $series] + $parameters)); - /** - * The Series Update Endpoint shall update a series. - */ - public function testUpdate(): void - { - $series = Series::factory()->createOne(); + $response->assertForbidden(); +}); - $parameters = Series::factory()->raw(); +test('update', function () { + $series = Series::factory()->createOne(); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Series::class))->createOne(); + $parameters = Series::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Series::class))->createOne(); - $response = $this->put(route('api.series.update', ['series' => $series] + $parameters)); + Sanctum::actingAs($user); - $response->assertOk(); - } -} + $response = put(route('api.series.update', ['series' => $series] + $parameters)); + + $response->assertOk(); +}); diff --git a/tests/Feature/Http/Api/Wiki/Song/SongDestroyTest.php b/tests/Feature/Http/Api/Wiki/Song/SongDestroyTest.php index 5bb543ab2..a3f46a18f 100644 --- a/tests/Feature/Http/Api/Wiki/Song/SongDestroyTest.php +++ b/tests/Feature/Http/Api/Wiki/Song/SongDestroyTest.php @@ -2,74 +2,54 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Song; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Song; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class SongDestroyTest extends TestCase -{ - /** - * The Song Destroy Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $song = Song::factory()->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.song.destroy', ['song' => $song])); +test('protected', function () { + $song = Song::factory()->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.song.destroy', ['song' => $song])); - /** - * The Song Destroy Endpoint shall forbid users without the delete song permission. - */ - public function testForbidden(): void - { - $song = Song::factory()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $song = Song::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.song.destroy', ['song' => $song])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.song.destroy', ['song' => $song])); - /** - * The Song Destroy Endpoint shall forbid users from updating a song that is trashed. - */ - public function testTrashed(): void - { - $song = Song::factory()->trashed()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Song::class))->createOne(); +test('trashed', function () { + $song = Song::factory()->trashed()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Song::class))->createOne(); - $response = $this->delete(route('api.song.destroy', ['song' => $song])); + Sanctum::actingAs($user); - $response->assertNotFound(); - } + $response = delete(route('api.song.destroy', ['song' => $song])); - /** - * The Song Destroy Endpoint shall delete the song. - */ - public function testDeleted(): void - { - $song = Song::factory()->createOne(); + $response->assertNotFound(); +}); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Song::class))->createOne(); +test('deleted', function () { + $song = Song::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Song::class))->createOne(); - $response = $this->delete(route('api.song.destroy', ['song' => $song])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertSoftDeleted($song); - } -} + $response = delete(route('api.song.destroy', ['song' => $song])); + + $response->assertOk(); + $this->assertSoftDeleted($song); +}); diff --git a/tests/Feature/Http/Api/Wiki/Song/SongForceDeleteTest.php b/tests/Feature/Http/Api/Wiki/Song/SongForceDeleteTest.php index eaf3220b2..1bf2de236 100644 --- a/tests/Feature/Http/Api/Wiki/Song/SongForceDeleteTest.php +++ b/tests/Feature/Http/Api/Wiki/Song/SongForceDeleteTest.php @@ -2,58 +2,42 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Song; - use App\Enums\Auth\ExtendedCrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Song; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class SongForceDeleteTest extends TestCase -{ - /** - * The Song Force Delete Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $song = Song::factory()->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.song.forceDelete', ['song' => $song])); +test('protected', function () { + $song = Song::factory()->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.song.forceDelete', ['song' => $song])); - /** - * The Song Force Delete Endpoint shall forbid users without the force delete song permission. - */ - public function testForbidden(): void - { - $song = Song::factory()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $song = Song::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.song.forceDelete', ['song' => $song])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.song.forceDelete', ['song' => $song])); - /** - * The Song Force Delete Endpoint shall force delete the song. - */ - public function testDeleted(): void - { - $song = Song::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::FORCE_DELETE->format(Song::class))->createOne(); +test('deleted', function () { + $song = Song::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::FORCE_DELETE->format(Song::class))->createOne(); - $response = $this->delete(route('api.song.forceDelete', ['song' => $song])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertModelMissing($song); - } -} + $response = delete(route('api.song.forceDelete', ['song' => $song])); + + $response->assertOk(); + $this->assertModelMissing($song); +}); diff --git a/tests/Feature/Http/Api/Wiki/Song/SongIndexTest.php b/tests/Feature/Http/Api/Wiki/Song/SongIndexTest.php index 467a8f7f2..012ca5eb7 100644 --- a/tests/Feature/Http/Api/Wiki/Song/SongIndexTest.php +++ b/tests/Feature/Http/Api/Wiki/Song/SongIndexTest.php @@ -2,9 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Song; - -use App\Concerns\Actions\Http\Api\SortsModels; use App\Constants\ModelConstants; use App\Contracts\Http\Api\Field\SortableField; use App\Enums\Http\Api\Filter\TrashedStatus; @@ -35,604 +32,538 @@ use App\Models\Wiki\Song; use Illuminate\Database\Eloquent\Factories\Sequence; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; -use Tests\TestCase; - -class SongIndexTest extends TestCase -{ - use SortsModels; - use WithFaker; - - /** - * By default, the Song Index Endpoint shall return a collection of Song Resources. - */ - public function testDefault(): void - { - $songs = Song::factory()->count($this->faker->randomDigitNotNull())->create(); - - $response = $this->get(route('api.song.index')); - - $response->assertJson( - json_decode( - json_encode( - new SongCollection($songs, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Song Index Endpoint shall be paginated. - */ - public function testPaginated(): void - { - Song::factory()->count($this->faker->randomDigitNotNull())->create(); - - $response = $this->get(route('api.song.index')); - - $response->assertJsonStructure([ - SongCollection::$wrap, - 'links', - 'meta', - ]); - } - - /** - * The Series Index Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new SongSchema(); - - $allowedIncludes = collect($schema->allowedIncludes()); - - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); - - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; - - Song::factory() - ->has(AnimeTheme::factory()->count($this->faker->randomDigitNotNull())->for(Anime::factory())) - ->has(Artist::factory()->count($this->faker->randomDigitNotNull())) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $songs = Song::with($includedPaths->all())->get(); - - $response = $this->get(route('api.song.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new SongCollection($songs, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Song Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new SongSchema(); - - $fields = collect($schema->fields()); - - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); - - $parameters = [ - FieldParser::param() => [ - SongResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; - - $songs = Song::factory()->count($this->faker->randomDigitNotNull())->create(); - - $response = $this->get(route('api.song.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new SongCollection($songs, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Song Index Endpoint shall support sorting resources. - */ - public function testSorts(): void - { - $schema = new SongSchema(); - - /** @var Sort $sort */ - $sort = collect($schema->fields()) - ->filter(fn (Field $field) => $field instanceof SortableField) - ->map(fn (SortableField $field) => $field->getSort()) - ->random(); - - $parameters = [ - SortParser::param() => $sort->format(Arr::random(Direction::cases())), - ]; - - $query = new Query($parameters); - - Song::factory()->count($this->faker->randomDigitNotNull())->create(); - - $response = $this->get(route('api.song.index', $parameters)); - - $songs = $this->sort(Song::query(), $query, $schema)->get(); - - $response->assertJson( - json_decode( - json_encode( - new SongCollection($songs, $query) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Song Index Endpoint shall support filtering by created_at. - */ - public function testCreatedAtFilter(): void - { - $createdFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($createdFilter, function () { - Song::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - Carbon::withTestNow($excludedDate, function () { - Song::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - $song = Song::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - - $response = $this->get(route('api.song.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new SongCollection($song, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Song Index Endpoint shall support filtering by updated_at. - */ - public function testUpdatedAtFilter(): void - { - $updatedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($updatedFilter, function () { - Song::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - Carbon::withTestNow($excludedDate, function () { - Song::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - $song = Song::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - - $response = $this->get(route('api.song.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new SongCollection($song, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Song Index Endpoint shall support filtering by trashed. - */ - public function testWithoutTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITHOUT->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Song::factory()->count($this->faker->randomDigitNotNull())->create(); - - Song::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - - $song = Song::withoutTrashed()->get(); - - $response = $this->get(route('api.song.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new SongCollection($song, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Song Index Endpoint shall support filtering by trashed. - */ - public function testWithTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Song::factory()->count($this->faker->randomDigitNotNull())->create(); - - Song::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - - $song = Song::withTrashed()->get(); - - $response = $this->get(route('api.song.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new SongCollection($song, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Song Index Endpoint shall support filtering by trashed. - */ - public function testOnlyTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::ONLY->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Song::factory()->count($this->faker->randomDigitNotNull())->create(); - - Song::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - - $song = Song::onlyTrashed()->get(); - - $response = $this->get(route('api.song.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new SongCollection($song, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Song Index Endpoint shall support filtering by deleted_at. - */ - public function testDeletedAtFilter(): void - { - $deletedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - ModelConstants::ATTRIBUTE_DELETED_AT => $deletedFilter, - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($deletedFilter, function () { - Song::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - }); - - Carbon::withTestNow($excludedDate, function () { - Song::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - }); - - $songs = Song::withTrashed()->where(ModelConstants::ATTRIBUTE_DELETED_AT, $deletedFilter)->get(); - - $response = $this->get(route('api.song.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new SongCollection($songs, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Song Index Endpoint shall support constrained eager loading of themes by sequence. - */ - public function testThemesBySequence(): void - { - $sequenceFilter = $this->faker->randomDigitNotNull(); - $excludedSequence = $sequenceFilter + 1; - - $parameters = [ - FilterParser::param() => [ - AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter, - ], - IncludeParser::param() => Song::RELATION_ANIMETHEMES, - ]; - - Song::factory() - ->has( - AnimeTheme::factory() - ->count($this->faker->randomDigitNotNull()) - ->for(Anime::factory()) - ->state(new Sequence( - [AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter], - [AnimeTheme::ATTRIBUTE_SEQUENCE => $excludedSequence], - )) - ) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $songs = Song::with([ - Song::RELATION_ANIMETHEMES => function (HasMany $query) use ($sequenceFilter) { - $query->where(AnimeTheme::ATTRIBUTE_SEQUENCE, $sequenceFilter); - }, - ]) - ->get(); - - $response = $this->get(route('api.song.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new SongCollection($songs, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Song Index Endpoint shall support constrained eager loading of themes by type. - */ - public function testThemesByType(): void - { - $typeFilter = Arr::random(ThemeType::cases()); - - $parameters = [ - FilterParser::param() => [ - AnimeTheme::ATTRIBUTE_TYPE => $typeFilter->localize(), - ], - IncludeParser::param() => Song::RELATION_ANIMETHEMES, - ]; - - Song::factory() - ->has(AnimeTheme::factory()->count($this->faker->randomDigitNotNull())->for(Anime::factory())) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $songs = Song::with([ - Song::RELATION_ANIMETHEMES => function (HasMany $query) use ($typeFilter) { - $query->where(AnimeTheme::ATTRIBUTE_TYPE, $typeFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.song.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new SongCollection($songs, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Song Index Endpoint shall support constrained eager loading of anime by media format. - */ - public function testAnimeByMediaFormat(): void - { - $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), - ], - IncludeParser::param() => Song::RELATION_ANIME, - ]; - - Song::factory() - ->has(AnimeTheme::factory()->count($this->faker->randomDigitNotNull())->for(Anime::factory())) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $songs = Song::with([ - Song::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { - $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.song.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new SongCollection($songs, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Song Index Endpoint shall support constrained eager loading of anime by season. - */ - public function testAnimeBySeason(): void - { - $seasonFilter = Arr::random(AnimeSeason::cases()); - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), - ], - IncludeParser::param() => Song::RELATION_ANIME, - ]; - - Song::factory() - ->has(AnimeTheme::factory()->count($this->faker->randomDigitNotNull())->for(Anime::factory())) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $songs = Song::with([ - Song::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { - $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.song.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new SongCollection($songs, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Song Index Endpoint shall support constrained eager loading of anime by year. - */ - public function testAnimeByYear(): void - { - $yearFilter = intval($this->faker->year()); - $excludedYear = $yearFilter + 1; - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_YEAR => $yearFilter, - ], - IncludeParser::param() => Song::RELATION_ANIME, - ]; - - Song::factory() - ->has( - AnimeTheme::factory() - ->count($this->faker->randomDigitNotNull()) - ->for( - Anime::factory() - ->state([ - Anime::ATTRIBUTE_YEAR => $this->faker->boolean() ? $yearFilter : $excludedYear, - ]) - ) - ) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $songs = Song::with([ - Song::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { - $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); - }, - ]) - ->get(); - - $response = $this->get(route('api.song.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new SongCollection($songs, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + +use function Pest\Laravel\get; + +uses(App\Concerns\Actions\Http\Api\SortsModels::class); + +uses(Illuminate\Foundation\Testing\WithFaker::class); + +test('default', function () { + $songs = Song::factory()->count(fake()->randomDigitNotNull())->create(); + + $response = get(route('api.song.index')); + + $response->assertJson( + json_decode( + json_encode( + new SongCollection($songs, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('paginated', function () { + Song::factory()->count(fake()->randomDigitNotNull())->create(); + + $response = get(route('api.song.index')); + + $response->assertJsonStructure([ + SongCollection::$wrap, + 'links', + 'meta', + ]); +}); + +test('allowed include paths', function () { + $schema = new SongSchema(); + + $allowedIncludes = collect($schema->allowedIncludes()); + + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); + + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; + + Song::factory() + ->has(AnimeTheme::factory()->count(fake()->randomDigitNotNull())->for(Anime::factory())) + ->has(Artist::factory()->count(fake()->randomDigitNotNull())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $songs = Song::with($includedPaths->all())->get(); + + $response = get(route('api.song.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new SongCollection($songs, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sparse fieldsets', function () { + $schema = new SongSchema(); + + $fields = collect($schema->fields()); + + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + SongResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + $songs = Song::factory()->count(fake()->randomDigitNotNull())->create(); + + $response = get(route('api.song.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new SongCollection($songs, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sorts', function () { + $schema = new SongSchema(); + + /** @var Sort $sort */ + $sort = collect($schema->fields()) + ->filter(fn (Field $field) => $field instanceof SortableField) + ->map(fn (SortableField $field) => $field->getSort()) + ->random(); + + $parameters = [ + SortParser::param() => $sort->format(Arr::random(Direction::cases())), + ]; + + $query = new Query($parameters); + + Song::factory()->count(fake()->randomDigitNotNull())->create(); + + $response = get(route('api.song.index', $parameters)); + + $songs = $this->sort(Song::query(), $query, $schema)->get(); + + $response->assertJson( + json_decode( + json_encode( + new SongCollection($songs, $query) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('created at filter', function () { + $createdFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($createdFilter, function () { + Song::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + Carbon::withTestNow($excludedDate, function () { + Song::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + $song = Song::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); + + $response = get(route('api.song.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new SongCollection($song, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('updated at filter', function () { + $updatedFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($updatedFilter, function () { + Song::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + Carbon::withTestNow($excludedDate, function () { + Song::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + $song = Song::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); + + $response = get(route('api.song.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new SongCollection($song, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('without trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITHOUT->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Song::factory()->count(fake()->randomDigitNotNull())->create(); + + Song::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + + $song = Song::withoutTrashed()->get(); + + $response = get(route('api.song.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new SongCollection($song, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('with trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Song::factory()->count(fake()->randomDigitNotNull())->create(); + + Song::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + + $song = Song::withTrashed()->get(); + + $response = get(route('api.song.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new SongCollection($song, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('only trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::ONLY->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Song::factory()->count(fake()->randomDigitNotNull())->create(); + + Song::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + + $song = Song::onlyTrashed()->get(); + + $response = get(route('api.song.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new SongCollection($song, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('deleted at filter', function () { + $deletedFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + ModelConstants::ATTRIBUTE_DELETED_AT => $deletedFilter, + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($deletedFilter, function () { + Song::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + }); + + Carbon::withTestNow($excludedDate, function () { + Song::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + }); + + $songs = Song::withTrashed()->where(ModelConstants::ATTRIBUTE_DELETED_AT, $deletedFilter)->get(); + + $response = get(route('api.song.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new SongCollection($songs, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('themes by sequence', function () { + $sequenceFilter = fake()->randomDigitNotNull(); + $excludedSequence = $sequenceFilter + 1; + + $parameters = [ + FilterParser::param() => [ + AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter, + ], + IncludeParser::param() => Song::RELATION_ANIMETHEMES, + ]; + + Song::factory() + ->has( + AnimeTheme::factory() + ->count(fake()->randomDigitNotNull()) + ->for(Anime::factory()) + ->state(new Sequence( + [AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter], + [AnimeTheme::ATTRIBUTE_SEQUENCE => $excludedSequence], + )) + ) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $songs = Song::with([ + Song::RELATION_ANIMETHEMES => function (HasMany $query) use ($sequenceFilter) { + $query->where(AnimeTheme::ATTRIBUTE_SEQUENCE, $sequenceFilter); + }, + ]) + ->get(); + + $response = get(route('api.song.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new SongCollection($songs, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('themes by type', function () { + $typeFilter = Arr::random(ThemeType::cases()); + + $parameters = [ + FilterParser::param() => [ + AnimeTheme::ATTRIBUTE_TYPE => $typeFilter->localize(), + ], + IncludeParser::param() => Song::RELATION_ANIMETHEMES, + ]; + + Song::factory() + ->has(AnimeTheme::factory()->count(fake()->randomDigitNotNull())->for(Anime::factory())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $songs = Song::with([ + Song::RELATION_ANIMETHEMES => function (HasMany $query) use ($typeFilter) { + $query->where(AnimeTheme::ATTRIBUTE_TYPE, $typeFilter->value); + }, + ]) + ->get(); + + $response = get(route('api.song.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new SongCollection($songs, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by media format', function () { + $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), + ], + IncludeParser::param() => Song::RELATION_ANIME, + ]; + + Song::factory() + ->has(AnimeTheme::factory()->count(fake()->randomDigitNotNull())->for(Anime::factory())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $songs = Song::with([ + Song::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { + $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); + }, + ]) + ->get(); + + $response = get(route('api.song.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new SongCollection($songs, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by season', function () { + $seasonFilter = Arr::random(AnimeSeason::cases()); + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), + ], + IncludeParser::param() => Song::RELATION_ANIME, + ]; + + Song::factory() + ->has(AnimeTheme::factory()->count(fake()->randomDigitNotNull())->for(Anime::factory())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $songs = Song::with([ + Song::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { + $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); + }, + ]) + ->get(); + + $response = get(route('api.song.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new SongCollection($songs, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by year', function () { + $yearFilter = intval(fake()->year()); + $excludedYear = $yearFilter + 1; + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_YEAR => $yearFilter, + ], + IncludeParser::param() => Song::RELATION_ANIME, + ]; + + Song::factory() + ->has( + AnimeTheme::factory() + ->count(fake()->randomDigitNotNull()) + ->for( + Anime::factory() + ->state([ + Anime::ATTRIBUTE_YEAR => fake()->boolean() ? $yearFilter : $excludedYear, + ]) + ) + ) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $songs = Song::with([ + Song::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { + $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); + }, + ]) + ->get(); + + $response = get(route('api.song.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new SongCollection($songs, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Wiki/Song/SongRestoreTest.php b/tests/Feature/Http/Api/Wiki/Song/SongRestoreTest.php index 08278bad0..f3da92d56 100644 --- a/tests/Feature/Http/Api/Wiki/Song/SongRestoreTest.php +++ b/tests/Feature/Http/Api/Wiki/Song/SongRestoreTest.php @@ -2,74 +2,54 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Song; - use App\Enums\Auth\ExtendedCrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Song; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class SongRestoreTest extends TestCase -{ - /** - * The Song Restore Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $song = Song::factory()->trashed()->createOne(); +use function Pest\Laravel\patch; - $response = $this->patch(route('api.song.restore', ['song' => $song])); +test('protected', function () { + $song = Song::factory()->trashed()->createOne(); - $response->assertUnauthorized(); - } + $response = patch(route('api.song.restore', ['song' => $song])); - /** - * The Song Restore Endpoint shall forbid users without the restore song permission. - */ - public function testForbidden(): void - { - $song = Song::factory()->trashed()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $song = Song::factory()->trashed()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->patch(route('api.song.restore', ['song' => $song])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = patch(route('api.song.restore', ['song' => $song])); - /** - * The Song Restore Endpoint shall forbid users from restoring a song that isn't trashed. - */ - public function testTrashed(): void - { - $song = Song::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(Song::class))->createOne(); +test('trashed', function () { + $song = Song::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(Song::class))->createOne(); - $response = $this->patch(route('api.song.restore', ['song' => $song])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = patch(route('api.song.restore', ['song' => $song])); - /** - * The Song Restore Endpoint shall restore the song. - */ - public function testRestored(): void - { - $song = Song::factory()->trashed()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(Song::class))->createOne(); +test('restored', function () { + $song = Song::factory()->trashed()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(Song::class))->createOne(); - $response = $this->patch(route('api.song.restore', ['song' => $song])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertNotSoftDeleted($song); - } -} + $response = patch(route('api.song.restore', ['song' => $song])); + + $response->assertOk(); + $this->assertNotSoftDeleted($song); +}); diff --git a/tests/Feature/Http/Api/Wiki/Song/SongShowTest.php b/tests/Feature/Http/Api/Wiki/Song/SongShowTest.php index 5a9d112b1..0c5fbbe21 100644 --- a/tests/Feature/Http/Api/Wiki/Song/SongShowTest.php +++ b/tests/Feature/Http/Api/Wiki/Song/SongShowTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Song; - use App\Enums\Models\Wiki\AnimeMediaFormat; use App\Enums\Models\Wiki\AnimeSeason; use App\Enums\Models\Wiki\ThemeType; @@ -22,333 +20,294 @@ use App\Models\Wiki\Song; use Illuminate\Database\Eloquent\Factories\Sequence; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; -use Tests\TestCase; -class SongShowTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the Song Show Endpoint shall return a Song Resource. - */ - public function testDefault(): void - { - $song = Song::factory()->create(); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response = $this->get(route('api.song.show', ['song' => $song])); +test('default', function () { + $song = Song::factory()->create(); - $response->assertJson( - json_decode( - json_encode( - new SongResource($song, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.song.show', ['song' => $song])); - /** - * The Song Show Endpoint shall return a Song Resource for soft deleted songs. - */ - public function testSoftDelete(): void - { - $song = Song::factory()->trashed()->createOne(); + $response->assertJson( + json_decode( + json_encode( + new SongResource($song, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $song->unsetRelations(); +test('soft delete', function () { + $song = Song::factory()->trashed()->createOne(); - $response = $this->get(route('api.song.show', ['song' => $song])); + $song->unsetRelations(); - $response->assertJson( - json_decode( - json_encode( - new SongResource($song, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.song.show', ['song' => $song])); - /** - * The Song Show Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new SongSchema(); + $response->assertJson( + json_decode( + json_encode( + new SongResource($song, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('allowed include paths', function () { + $schema = new SongSchema(); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $allowedIncludes = collect($schema->allowedIncludes()); - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - $song = Song::factory() - ->has(AnimeTheme::factory()->count($this->faker->randomDigitNotNull())->for(Anime::factory())) - ->has(Artist::factory()->count($this->faker->randomDigitNotNull())) - ->createOne(); + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; - $response = $this->get(route('api.song.show', ['song' => $song] + $parameters)); + $song = Song::factory() + ->has(AnimeTheme::factory()->count(fake()->randomDigitNotNull())->for(Anime::factory())) + ->has(Artist::factory()->count(fake()->randomDigitNotNull())) + ->createOne(); - $response->assertJson( - json_decode( - json_encode( - new SongResource($song, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.song.show', ['song' => $song] + $parameters)); - /** - * The Song Show Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new SongSchema(); + $response->assertJson( + json_decode( + json_encode( + new SongResource($song, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $fields = collect($schema->fields()); +test('sparse fieldsets', function () { + $schema = new SongSchema(); - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); + $fields = collect($schema->fields()); - $parameters = [ - FieldParser::param() => [ - SongResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); - $song = Song::factory()->create(); + $parameters = [ + FieldParser::param() => [ + SongResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; - $response = $this->get(route('api.song.show', ['song' => $song] + $parameters)); + $song = Song::factory()->create(); - $response->assertJson( - json_decode( - json_encode( - new SongResource($song, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.song.show', ['song' => $song] + $parameters)); - /** - * The Song Show Endpoint shall support constrained eager loading of themes by sequence. - */ - public function testThemesBySequence(): void - { - $sequenceFilter = $this->faker->randomDigitNotNull(); - $excludedSequence = $sequenceFilter + 1; + $response->assertJson( + json_decode( + json_encode( + new SongResource($song, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter, - ], - IncludeParser::param() => Song::RELATION_ANIMETHEMES, - ]; +test('themes by sequence', function () { + $sequenceFilter = fake()->randomDigitNotNull(); + $excludedSequence = $sequenceFilter + 1; - $song = Song::factory() - ->has( - AnimeTheme::factory() - ->count($this->faker->randomDigitNotNull()) - ->for(Anime::factory()) - ->state(new Sequence( - [AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter], - [AnimeTheme::ATTRIBUTE_SEQUENCE => $excludedSequence], - )) - ) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter, + ], + IncludeParser::param() => Song::RELATION_ANIMETHEMES, + ]; - $song->unsetRelations()->load([ - Song::RELATION_ANIMETHEMES => function (HasMany $query) use ($sequenceFilter) { - $query->where(AnimeTheme::ATTRIBUTE_SEQUENCE, $sequenceFilter); - }, - ]); + $song = Song::factory() + ->has( + AnimeTheme::factory() + ->count(fake()->randomDigitNotNull()) + ->for(Anime::factory()) + ->state(new Sequence( + [AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter], + [AnimeTheme::ATTRIBUTE_SEQUENCE => $excludedSequence], + )) + ) + ->createOne(); - $response = $this->get(route('api.song.show', ['song' => $song] + $parameters)); + $song->unsetRelations()->load([ + Song::RELATION_ANIMETHEMES => function (HasMany $query) use ($sequenceFilter) { + $query->where(AnimeTheme::ATTRIBUTE_SEQUENCE, $sequenceFilter); + }, + ]); - $response->assertJson( - json_decode( - json_encode( - new SongResource($song, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.song.show', ['song' => $song] + $parameters)); - /** - * The Song Show Endpoint shall support constrained eager loading of themes by type. - */ - public function testThemesByType(): void - { - $typeFilter = Arr::random(ThemeType::cases()); + $response->assertJson( + json_decode( + json_encode( + new SongResource($song, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - AnimeTheme::ATTRIBUTE_TYPE => $typeFilter->localize(), - ], - IncludeParser::param() => Song::RELATION_ANIMETHEMES, - ]; +test('themes by type', function () { + $typeFilter = Arr::random(ThemeType::cases()); - $song = Song::factory() - ->has(AnimeTheme::factory()->count($this->faker->randomDigitNotNull())->for(Anime::factory())) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + AnimeTheme::ATTRIBUTE_TYPE => $typeFilter->localize(), + ], + IncludeParser::param() => Song::RELATION_ANIMETHEMES, + ]; - $song->unsetRelations()->load([ - Song::RELATION_ANIMETHEMES => function (HasMany $query) use ($typeFilter) { - $query->where(AnimeTheme::ATTRIBUTE_TYPE, $typeFilter->value); - }, - ]); + $song = Song::factory() + ->has(AnimeTheme::factory()->count(fake()->randomDigitNotNull())->for(Anime::factory())) + ->createOne(); - $response = $this->get(route('api.song.show', ['song' => $song] + $parameters)); + $song->unsetRelations()->load([ + Song::RELATION_ANIMETHEMES => function (HasMany $query) use ($typeFilter) { + $query->where(AnimeTheme::ATTRIBUTE_TYPE, $typeFilter->value); + }, + ]); - $response->assertJson( - json_decode( - json_encode( - new SongResource($song, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.song.show', ['song' => $song] + $parameters)); - /** - * The Song Show Endpoint shall support constrained eager loading of anime by media format. - */ - public function testAnimeByMediaFormat(): void - { - $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); + $response->assertJson( + json_decode( + json_encode( + new SongResource($song, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), - ], - IncludeParser::param() => Song::RELATION_ANIME, - ]; +test('anime by media format', function () { + $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); - $song = Song::factory() - ->has(AnimeTheme::factory()->count($this->faker->randomDigitNotNull())->for(Anime::factory())) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), + ], + IncludeParser::param() => Song::RELATION_ANIME, + ]; - $song->unsetRelations()->load([ - Song::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { - $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); - }, - ]); + $song = Song::factory() + ->has(AnimeTheme::factory()->count(fake()->randomDigitNotNull())->for(Anime::factory())) + ->createOne(); - $response = $this->get(route('api.song.show', ['song' => $song] + $parameters)); + $song->unsetRelations()->load([ + Song::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { + $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); + }, + ]); - $response->assertJson( - json_decode( - json_encode( - new SongResource($song, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.song.show', ['song' => $song] + $parameters)); - /** - * The Song Show Endpoint shall support constrained eager loading of anime by season. - */ - public function testAnimeBySeason(): void - { - $seasonFilter = Arr::random(AnimeSeason::cases()); + $response->assertJson( + json_decode( + json_encode( + new SongResource($song, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), - ], - IncludeParser::param() => Song::RELATION_ANIME, - ]; +test('anime by season', function () { + $seasonFilter = Arr::random(AnimeSeason::cases()); - $song = Song::factory() - ->has(AnimeTheme::factory()->count($this->faker->randomDigitNotNull())->for(Anime::factory())) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), + ], + IncludeParser::param() => Song::RELATION_ANIME, + ]; - $song->unsetRelations()->load([ - Song::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { - $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); - }, - ]); + $song = Song::factory() + ->has(AnimeTheme::factory()->count(fake()->randomDigitNotNull())->for(Anime::factory())) + ->createOne(); - $response = $this->get(route('api.song.show', ['song' => $song] + $parameters)); + $song->unsetRelations()->load([ + Song::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { + $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); + }, + ]); - $response->assertJson( - json_decode( - json_encode( - new SongResource($song, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.song.show', ['song' => $song] + $parameters)); - /** - * The Song Show Endpoint shall support constrained eager loading of anime by year. - */ - public function testAnimeByYear(): void - { - $yearFilter = intval($this->faker->year()); - $excludedYear = $yearFilter + 1; + $response->assertJson( + json_decode( + json_encode( + new SongResource($song, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_YEAR => $yearFilter, - ], - IncludeParser::param() => Song::RELATION_ANIME, - ]; +test('anime by year', function () { + $yearFilter = intval(fake()->year()); + $excludedYear = $yearFilter + 1; - $song = Song::factory() - ->has( - AnimeTheme::factory() - ->count($this->faker->randomDigitNotNull()) - ->for( - Anime::factory() - ->state([ - Anime::ATTRIBUTE_YEAR => $this->faker->boolean() ? $yearFilter : $excludedYear, - ]) - ) - ) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_YEAR => $yearFilter, + ], + IncludeParser::param() => Song::RELATION_ANIME, + ]; - $song->unsetRelations()->load([ - Song::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { - $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); - }, - ]); + $song = Song::factory() + ->has( + AnimeTheme::factory() + ->count(fake()->randomDigitNotNull()) + ->for( + Anime::factory() + ->state([ + Anime::ATTRIBUTE_YEAR => fake()->boolean() ? $yearFilter : $excludedYear, + ]) + ) + ) + ->createOne(); - $response = $this->get(route('api.song.show', ['song' => $song] + $parameters)); + $song->unsetRelations()->load([ + Song::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { + $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); + }, + ]); - $response->assertJson( - json_decode( - json_encode( - new SongResource($song, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response = get(route('api.song.show', ['song' => $song] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new SongResource($song, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Wiki/Song/SongStoreTest.php b/tests/Feature/Http/Api/Wiki/Song/SongStoreTest.php index 6691039b3..12a16275c 100644 --- a/tests/Feature/Http/Api/Wiki/Song/SongStoreTest.php +++ b/tests/Feature/Http/Api/Wiki/Song/SongStoreTest.php @@ -2,58 +2,42 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Song; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Song; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class SongStoreTest extends TestCase -{ - /** - * The Song Store Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $song = Song::factory()->makeOne(); +use function Pest\Laravel\post; - $response = $this->post(route('api.song.store', $song->toArray())); +test('protected', function () { + $song = Song::factory()->makeOne(); - $response->assertUnauthorized(); - } + $response = post(route('api.song.store', $song->toArray())); - /** - * The Song Store Endpoint shall forbid users without the create song permission. - */ - public function testForbidden(): void - { - $song = Song::factory()->makeOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $song = Song::factory()->makeOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->post(route('api.song.store', $song->toArray())); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.song.store', $song->toArray())); - /** - * The Song Store Endpoint shall create a song. - */ - public function testCreate(): void - { - $parameters = Song::factory()->raw(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Song::class))->createOne(); +test('create', function () { + $parameters = Song::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Song::class))->createOne(); - $response = $this->post(route('api.song.store', $parameters)); + Sanctum::actingAs($user); - $response->assertCreated(); - static::assertDatabaseCount(Song::class, 1); - } -} + $response = post(route('api.song.store', $parameters)); + + $response->assertCreated(); + $this->assertDatabaseCount(Song::class, 1); +}); diff --git a/tests/Feature/Http/Api/Wiki/Song/SongUpdateTest.php b/tests/Feature/Http/Api/Wiki/Song/SongUpdateTest.php index 399ca5462..06b231e2d 100644 --- a/tests/Feature/Http/Api/Wiki/Song/SongUpdateTest.php +++ b/tests/Feature/Http/Api/Wiki/Song/SongUpdateTest.php @@ -2,81 +2,61 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Song; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Song; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class SongUpdateTest extends TestCase -{ - /** - * The Song Update Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $song = Song::factory()->createOne(); +use function Pest\Laravel\put; - $parameters = Song::factory()->raw(); +test('protected', function () { + $song = Song::factory()->createOne(); - $response = $this->put(route('api.song.update', ['song' => $song] + $parameters)); + $parameters = Song::factory()->raw(); - $response->assertUnauthorized(); - } + $response = put(route('api.song.update', ['song' => $song] + $parameters)); - /** - * The Song Store Endpoint shall forbid users without the create song permission. - */ - public function testForbidden(): void - { - $song = Song::factory()->createOne(); + $response->assertUnauthorized(); +}); - $parameters = Song::factory()->raw(); +test('forbidden', function () { + $song = Song::factory()->createOne(); - $user = User::factory()->createOne(); + $parameters = Song::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->put(route('api.song.update', ['song' => $song] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.song.update', ['song' => $song] + $parameters)); - /** - * The Song Update Endpoint shall forbid users from updating a song that is trashed. - */ - public function testTrashed(): void - { - $song = Song::factory()->trashed()->createOne(); + $response->assertForbidden(); +}); - $parameters = Song::factory()->raw(); +test('trashed', function () { + $song = Song::factory()->trashed()->createOne(); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Song::class))->createOne(); + $parameters = Song::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Song::class))->createOne(); - $response = $this->put(route('api.song.update', ['song' => $song] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.song.update', ['song' => $song] + $parameters)); - /** - * The Song Update Endpoint shall update a song. - */ - public function testUpdate(): void - { - $song = Song::factory()->createOne(); + $response->assertForbidden(); +}); - $parameters = Song::factory()->raw(); +test('update', function () { + $song = Song::factory()->createOne(); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Song::class))->createOne(); + $parameters = Song::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Song::class))->createOne(); - $response = $this->put(route('api.song.update', ['song' => $song] + $parameters)); + Sanctum::actingAs($user); - $response->assertOk(); - } -} + $response = put(route('api.song.update', ['song' => $song] + $parameters)); + + $response->assertOk(); +}); diff --git a/tests/Feature/Http/Api/Wiki/Studio/StudioDestroyTest.php b/tests/Feature/Http/Api/Wiki/Studio/StudioDestroyTest.php index c2802a630..ee9a6719e 100644 --- a/tests/Feature/Http/Api/Wiki/Studio/StudioDestroyTest.php +++ b/tests/Feature/Http/Api/Wiki/Studio/StudioDestroyTest.php @@ -2,74 +2,54 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Studio; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Studio; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class StudioDestroyTest extends TestCase -{ - /** - * The Studio Destroy Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $studio = Studio::factory()->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.studio.destroy', ['studio' => $studio])); +test('protected', function () { + $studio = Studio::factory()->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.studio.destroy', ['studio' => $studio])); - /** - * The Studio Destroy Endpoint shall forbid users without the delete studio permission. - */ - public function testForbidden(): void - { - $studio = Studio::factory()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $studio = Studio::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.studio.destroy', ['studio' => $studio])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.studio.destroy', ['studio' => $studio])); - /** - * The Studio Destroy Endpoint shall forbid users from updating a studio that is trashed. - */ - public function testTrashed(): void - { - $studio = Studio::factory()->trashed()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Studio::class))->createOne(); +test('trashed', function () { + $studio = Studio::factory()->trashed()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Studio::class))->createOne(); - $response = $this->delete(route('api.studio.destroy', ['studio' => $studio])); + Sanctum::actingAs($user); - $response->assertNotFound(); - } + $response = delete(route('api.studio.destroy', ['studio' => $studio])); - /** - * The Studio Destroy Endpoint shall delete the studio. - */ - public function testDeleted(): void - { - $studio = Studio::factory()->createOne(); + $response->assertNotFound(); +}); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Studio::class))->createOne(); +test('deleted', function () { + $studio = Studio::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Studio::class))->createOne(); - $response = $this->delete(route('api.studio.destroy', ['studio' => $studio])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertSoftDeleted($studio); - } -} + $response = delete(route('api.studio.destroy', ['studio' => $studio])); + + $response->assertOk(); + $this->assertSoftDeleted($studio); +}); diff --git a/tests/Feature/Http/Api/Wiki/Studio/StudioForceDeleteTest.php b/tests/Feature/Http/Api/Wiki/Studio/StudioForceDeleteTest.php index 77a2eb922..19671c92a 100644 --- a/tests/Feature/Http/Api/Wiki/Studio/StudioForceDeleteTest.php +++ b/tests/Feature/Http/Api/Wiki/Studio/StudioForceDeleteTest.php @@ -2,58 +2,42 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Studio; - use App\Enums\Auth\ExtendedCrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Studio; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class StudioForceDeleteTest extends TestCase -{ - /** - * The Studio Force Delete Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $studio = Studio::factory()->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.studio.forceDelete', ['studio' => $studio])); +test('protected', function () { + $studio = Studio::factory()->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.studio.forceDelete', ['studio' => $studio])); - /** - * The Studio Force Delete Endpoint shall forbid users without the force delete studio permission. - */ - public function testForbidden(): void - { - $studio = Studio::factory()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $studio = Studio::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.studio.forceDelete', ['studio' => $studio])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.studio.forceDelete', ['studio' => $studio])); - /** - * The Studio Force Delete Endpoint shall force delete the studio. - */ - public function testDeleted(): void - { - $studio = Studio::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::FORCE_DELETE->format(Studio::class))->createOne(); +test('deleted', function () { + $studio = Studio::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::FORCE_DELETE->format(Studio::class))->createOne(); - $response = $this->delete(route('api.studio.forceDelete', ['studio' => $studio])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertModelMissing($studio); - } -} + $response = delete(route('api.studio.forceDelete', ['studio' => $studio])); + + $response->assertOk(); + $this->assertModelMissing($studio); +}); diff --git a/tests/Feature/Http/Api/Wiki/Studio/StudioIndexTest.php b/tests/Feature/Http/Api/Wiki/Studio/StudioIndexTest.php index 2e73301ee..f895a2c70 100644 --- a/tests/Feature/Http/Api/Wiki/Studio/StudioIndexTest.php +++ b/tests/Feature/Http/Api/Wiki/Studio/StudioIndexTest.php @@ -2,9 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Studio; - -use App\Concerns\Actions\Http\Api\SortsModels; use App\Constants\ModelConstants; use App\Contracts\Http\Api\Field\SortableField; use App\Enums\Http\Api\Filter\TrashedStatus; @@ -35,592 +32,526 @@ use App\Models\Wiki\Image; use App\Models\Wiki\Studio; use Illuminate\Database\Eloquent\Factories\Sequence; use Illuminate\Database\Eloquent\Relations\BelongsToMany; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; -use Tests\TestCase; - -class StudioIndexTest extends TestCase -{ - use SortsModels; - use WithFaker; - - /** - * By default, the Studio Index Endpoint shall return a collection of Studio Resources. - */ - public function testDefault(): void - { - $studio = Studio::factory()->count($this->faker->randomDigitNotNull())->create(); - - $response = $this->get(route('api.studio.index')); - - $response->assertJson( - json_decode( - json_encode( - new StudioCollection($studio, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Studio Index Endpoint shall be paginated. - */ - public function testPaginated(): void - { - Studio::factory()->count($this->faker->randomDigitNotNull())->create(); - - $response = $this->get(route('api.studio.index')); - - $response->assertJsonStructure([ - StudioCollection::$wrap, - 'links', - 'meta', - ]); - } - - /** - * The Studio Index Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new StudioSchema(); - - $allowedIncludes = collect($schema->allowedIncludes()); - - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); - - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; - - Studio::factory() - ->has(Anime::factory()->count($this->faker->randomDigitNotNull())) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $studio = Studio::with($includedPaths->all())->get(); - - $response = $this->get(route('api.studio.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new StudioCollection($studio, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Studio Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new StudioSchema(); - - $fields = collect($schema->fields()); - - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); - - $parameters = [ - FieldParser::param() => [ - StudioResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; - - $studio = Studio::factory()->count($this->faker->randomDigitNotNull())->create(); - - $response = $this->get(route('api.studio.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new StudioCollection($studio, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Studio Index Endpoint shall support sorting resources. - */ - public function testSorts(): void - { - $schema = new StudioSchema(); - - /** @var Sort $sort */ - $sort = collect($schema->fields()) - ->filter(fn (Field $field) => $field instanceof SortableField) - ->map(fn (SortableField $field) => $field->getSort()) - ->random(); - - $parameters = [ - SortParser::param() => $sort->format(Arr::random(Direction::cases())), - ]; - - $query = new Query($parameters); - - Studio::factory()->count($this->faker->randomDigitNotNull())->create(); - - $response = $this->get(route('api.studio.index', $parameters)); - - $studios = $this->sort(Studio::query(), $query, $schema)->get(); - - $response->assertJson( - json_decode( - json_encode( - new StudioCollection($studios, $query) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Studio Index Endpoint shall support filtering by created_at. - */ - public function testCreatedAtFilter(): void - { - $createdFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($createdFilter, function () { - Studio::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - Carbon::withTestNow($excludedDate, function () { - Studio::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - $studio = Studio::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - - $response = $this->get(route('api.studio.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new StudioCollection($studio, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Studio Index Endpoint shall support filtering by updated_at. - */ - public function testUpdatedAtFilter(): void - { - $updatedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($updatedFilter, function () { - Studio::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - Carbon::withTestNow($excludedDate, function () { - Studio::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - $studio = Studio::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - - $response = $this->get(route('api.studio.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new StudioCollection($studio, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Studio Index Endpoint shall support filtering by trashed. - */ - public function testWithoutTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITHOUT->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Studio::factory()->count($this->faker->randomDigitNotNull())->create(); - - Studio::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - - $studio = Studio::withoutTrashed()->get(); - - $response = $this->get(route('api.studio.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new StudioCollection($studio, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Studio Index Endpoint shall support filtering by trashed. - */ - public function testWithTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Studio::factory()->count($this->faker->randomDigitNotNull())->create(); - - Studio::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - - $studio = Studio::withTrashed()->get(); - - $response = $this->get(route('api.studio.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new StudioCollection($studio, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Studio Index Endpoint shall support filtering by trashed. - */ - public function testOnlyTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::ONLY->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Studio::factory()->count($this->faker->randomDigitNotNull())->create(); - - Studio::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - - $studio = Studio::onlyTrashed()->get(); - - $response = $this->get(route('api.studio.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new StudioCollection($studio, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Studio Index Endpoint shall support filtering by deleted_at. - */ - public function testDeletedAtFilter(): void - { - $deletedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - ModelConstants::ATTRIBUTE_DELETED_AT => $deletedFilter, - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($deletedFilter, function () { - Studio::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - }); - - Carbon::withTestNow($excludedDate, function () { - Studio::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - }); - - $studio = Studio::withTrashed()->where(ModelConstants::ATTRIBUTE_DELETED_AT, $deletedFilter)->get(); - - $response = $this->get(route('api.studio.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new StudioCollection($studio, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Studio Index Endpoint shall support constrained eager loading of anime by media format. - */ - public function testAnimeByMediaFormat(): void - { - $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), - ], - IncludeParser::param() => Studio::RELATION_ANIME, - ]; - - Studio::factory() - ->has(Anime::factory()->count($this->faker->randomDigitNotNull())) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $studio = Studio::with([ - Studio::RELATION_ANIME => function (BelongsToMany $query) use ($mediaFormatFilter) { - $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.studio.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new StudioCollection($studio, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Studio Index Endpoint shall support constrained eager loading of anime by season. - */ - public function testAnimeBySeason(): void - { - $seasonFilter = Arr::random(AnimeSeason::cases()); - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), - ], - IncludeParser::param() => Studio::RELATION_ANIME, - ]; - - Studio::factory() - ->has(Anime::factory()->count($this->faker->randomDigitNotNull())) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $studio = Studio::with([ - Studio::RELATION_ANIME => function (BelongsToMany $query) use ($seasonFilter) { - $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.studio.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new StudioCollection($studio, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Studio Index Endpoint shall support constrained eager loading of anime by year. - */ - public function testAnimeByYear(): void - { - $yearFilter = $this->faker->numberBetween(2000, 2002); - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_YEAR => $yearFilter, - ], - IncludeParser::param() => Studio::RELATION_ANIME, - ]; - - Studio::factory() - ->has( - Anime::factory() - ->count($this->faker->randomDigitNotNull()) - ->state(new Sequence( - [Anime::ATTRIBUTE_YEAR => 2000], - [Anime::ATTRIBUTE_YEAR => 2001], - [Anime::ATTRIBUTE_YEAR => 2002], - )) - ) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $studio = Studio::with([ - Studio::RELATION_ANIME => function (BelongsToMany $query) use ($yearFilter) { - $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); - }, - ]) - ->get(); - - $response = $this->get(route('api.studio.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new StudioCollection($studio, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Studio Index Endpoint shall support constrained eager loading of resources by site. - */ - public function testResourcesBySite(): void - { - $siteFilter = Arr::random(ResourceSite::cases()); - - $parameters = [ - FilterParser::param() => [ - ExternalResource::ATTRIBUTE_SITE => $siteFilter->localize(), - ], - IncludeParser::param() => Studio::RELATION_RESOURCES, - ]; - - Studio::factory() - ->has(ExternalResource::factory()->count($this->faker->randomDigitNotNull()), Studio::RELATION_RESOURCES) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $studios = Studio::with([ - Studio::RELATION_RESOURCES => function (BelongsToMany $query) use ($siteFilter) { - $query->where(ExternalResource::ATTRIBUTE_SITE, $siteFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.studio.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new StudioCollection($studios, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Studio Index Endpoint shall support constrained eager loading of images by facet. - */ - public function testImagesByFacet(): void - { - $facetFilter = Arr::random(ImageFacet::cases()); - - $parameters = [ - FilterParser::param() => [ - Image::ATTRIBUTE_FACET => $facetFilter->localize(), - ], - IncludeParser::param() => Studio::RELATION_IMAGES, - ]; - - Studio::factory() - ->has(Image::factory()->count($this->faker->randomDigitNotNull())) - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $anime = Studio::with([ - Studio::RELATION_IMAGES => function (BelongsToMany $query) use ($facetFilter) { - $query->where(Image::ATTRIBUTE_FACET, $facetFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.studio.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new StudioCollection($anime, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + +use function Pest\Laravel\get; + +uses(App\Concerns\Actions\Http\Api\SortsModels::class); + +uses(Illuminate\Foundation\Testing\WithFaker::class); + +test('default', function () { + $studio = Studio::factory()->count(fake()->randomDigitNotNull())->create(); + + $response = get(route('api.studio.index')); + + $response->assertJson( + json_decode( + json_encode( + new StudioCollection($studio, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('paginated', function () { + Studio::factory()->count(fake()->randomDigitNotNull())->create(); + + $response = get(route('api.studio.index')); + + $response->assertJsonStructure([ + StudioCollection::$wrap, + 'links', + 'meta', + ]); +}); + +test('allowed include paths', function () { + $schema = new StudioSchema(); + + $allowedIncludes = collect($schema->allowedIncludes()); + + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); + + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; + + Studio::factory() + ->has(Anime::factory()->count(fake()->randomDigitNotNull())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $studio = Studio::with($includedPaths->all())->get(); + + $response = get(route('api.studio.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new StudioCollection($studio, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sparse fieldsets', function () { + $schema = new StudioSchema(); + + $fields = collect($schema->fields()); + + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + StudioResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + $studio = Studio::factory()->count(fake()->randomDigitNotNull())->create(); + + $response = get(route('api.studio.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new StudioCollection($studio, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sorts', function () { + $schema = new StudioSchema(); + + /** @var Sort $sort */ + $sort = collect($schema->fields()) + ->filter(fn (Field $field) => $field instanceof SortableField) + ->map(fn (SortableField $field) => $field->getSort()) + ->random(); + + $parameters = [ + SortParser::param() => $sort->format(Arr::random(Direction::cases())), + ]; + + $query = new Query($parameters); + + Studio::factory()->count(fake()->randomDigitNotNull())->create(); + + $response = get(route('api.studio.index', $parameters)); + + $studios = $this->sort(Studio::query(), $query, $schema)->get(); + + $response->assertJson( + json_decode( + json_encode( + new StudioCollection($studios, $query) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('created at filter', function () { + $createdFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($createdFilter, function () { + Studio::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + Carbon::withTestNow($excludedDate, function () { + Studio::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + $studio = Studio::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); + + $response = get(route('api.studio.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new StudioCollection($studio, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('updated at filter', function () { + $updatedFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($updatedFilter, function () { + Studio::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + Carbon::withTestNow($excludedDate, function () { + Studio::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + $studio = Studio::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); + + $response = get(route('api.studio.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new StudioCollection($studio, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('without trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITHOUT->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Studio::factory()->count(fake()->randomDigitNotNull())->create(); + + Studio::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + + $studio = Studio::withoutTrashed()->get(); + + $response = get(route('api.studio.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new StudioCollection($studio, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('with trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Studio::factory()->count(fake()->randomDigitNotNull())->create(); + + Studio::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + + $studio = Studio::withTrashed()->get(); + + $response = get(route('api.studio.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new StudioCollection($studio, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('only trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::ONLY->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Studio::factory()->count(fake()->randomDigitNotNull())->create(); + + Studio::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + + $studio = Studio::onlyTrashed()->get(); + + $response = get(route('api.studio.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new StudioCollection($studio, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('deleted at filter', function () { + $deletedFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + ModelConstants::ATTRIBUTE_DELETED_AT => $deletedFilter, + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($deletedFilter, function () { + Studio::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + }); + + Carbon::withTestNow($excludedDate, function () { + Studio::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + }); + + $studio = Studio::withTrashed()->where(ModelConstants::ATTRIBUTE_DELETED_AT, $deletedFilter)->get(); + + $response = get(route('api.studio.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new StudioCollection($studio, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by media format', function () { + $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), + ], + IncludeParser::param() => Studio::RELATION_ANIME, + ]; + + Studio::factory() + ->has(Anime::factory()->count(fake()->randomDigitNotNull())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $studio = Studio::with([ + Studio::RELATION_ANIME => function (BelongsToMany $query) use ($mediaFormatFilter) { + $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); + }, + ]) + ->get(); + + $response = get(route('api.studio.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new StudioCollection($studio, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by season', function () { + $seasonFilter = Arr::random(AnimeSeason::cases()); + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), + ], + IncludeParser::param() => Studio::RELATION_ANIME, + ]; + + Studio::factory() + ->has(Anime::factory()->count(fake()->randomDigitNotNull())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $studio = Studio::with([ + Studio::RELATION_ANIME => function (BelongsToMany $query) use ($seasonFilter) { + $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); + }, + ]) + ->get(); + + $response = get(route('api.studio.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new StudioCollection($studio, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by year', function () { + $yearFilter = fake()->numberBetween(2000, 2002); + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_YEAR => $yearFilter, + ], + IncludeParser::param() => Studio::RELATION_ANIME, + ]; + + Studio::factory() + ->has( + Anime::factory() + ->count(fake()->randomDigitNotNull()) + ->state(new Sequence( + [Anime::ATTRIBUTE_YEAR => 2000], + [Anime::ATTRIBUTE_YEAR => 2001], + [Anime::ATTRIBUTE_YEAR => 2002], + )) + ) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $studio = Studio::with([ + Studio::RELATION_ANIME => function (BelongsToMany $query) use ($yearFilter) { + $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); + }, + ]) + ->get(); + + $response = get(route('api.studio.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new StudioCollection($studio, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('resources by site', function () { + $siteFilter = Arr::random(ResourceSite::cases()); + + $parameters = [ + FilterParser::param() => [ + ExternalResource::ATTRIBUTE_SITE => $siteFilter->localize(), + ], + IncludeParser::param() => Studio::RELATION_RESOURCES, + ]; + + Studio::factory() + ->has(ExternalResource::factory()->count(fake()->randomDigitNotNull()), Studio::RELATION_RESOURCES) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $studios = Studio::with([ + Studio::RELATION_RESOURCES => function (BelongsToMany $query) use ($siteFilter) { + $query->where(ExternalResource::ATTRIBUTE_SITE, $siteFilter->value); + }, + ]) + ->get(); + + $response = get(route('api.studio.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new StudioCollection($studios, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('images by facet', function () { + $facetFilter = Arr::random(ImageFacet::cases()); + + $parameters = [ + FilterParser::param() => [ + Image::ATTRIBUTE_FACET => $facetFilter->localize(), + ], + IncludeParser::param() => Studio::RELATION_IMAGES, + ]; + + Studio::factory() + ->has(Image::factory()->count(fake()->randomDigitNotNull())) + ->count(fake()->randomDigitNotNull()) + ->create(); + + $anime = Studio::with([ + Studio::RELATION_IMAGES => function (BelongsToMany $query) use ($facetFilter) { + $query->where(Image::ATTRIBUTE_FACET, $facetFilter->value); + }, + ]) + ->get(); + + $response = get(route('api.studio.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new StudioCollection($anime, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Wiki/Studio/StudioRestoreTest.php b/tests/Feature/Http/Api/Wiki/Studio/StudioRestoreTest.php index 8ded75c1c..04843b935 100644 --- a/tests/Feature/Http/Api/Wiki/Studio/StudioRestoreTest.php +++ b/tests/Feature/Http/Api/Wiki/Studio/StudioRestoreTest.php @@ -2,74 +2,54 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Studio; - use App\Enums\Auth\ExtendedCrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Studio; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class StudioRestoreTest extends TestCase -{ - /** - * The Studio Restore Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $studio = Studio::factory()->trashed()->createOne(); +use function Pest\Laravel\patch; - $response = $this->patch(route('api.studio.restore', ['studio' => $studio])); +test('protected', function () { + $studio = Studio::factory()->trashed()->createOne(); - $response->assertUnauthorized(); - } + $response = patch(route('api.studio.restore', ['studio' => $studio])); - /** - * The Studio Restore Endpoint shall forbid users without the restore studio permission. - */ - public function testForbidden(): void - { - $studio = Studio::factory()->trashed()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $studio = Studio::factory()->trashed()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->patch(route('api.studio.restore', ['studio' => $studio])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = patch(route('api.studio.restore', ['studio' => $studio])); - /** - * The Studio Restore Endpoint shall forbid users from restoring a studio that isn't trashed. - */ - public function testTrashed(): void - { - $studio = Studio::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(Studio::class))->createOne(); +test('trashed', function () { + $studio = Studio::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(Studio::class))->createOne(); - $response = $this->patch(route('api.studio.restore', ['studio' => $studio])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = patch(route('api.studio.restore', ['studio' => $studio])); - /** - * The Studio Restore Endpoint shall restore the studio. - */ - public function testRestored(): void - { - $studio = Studio::factory()->trashed()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(Studio::class))->createOne(); +test('restored', function () { + $studio = Studio::factory()->trashed()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(Studio::class))->createOne(); - $response = $this->patch(route('api.studio.restore', ['studio' => $studio])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertNotSoftDeleted($studio); - } -} + $response = patch(route('api.studio.restore', ['studio' => $studio])); + + $response->assertOk(); + $this->assertNotSoftDeleted($studio); +}); diff --git a/tests/Feature/Http/Api/Wiki/Studio/StudioShowTest.php b/tests/Feature/Http/Api/Wiki/Studio/StudioShowTest.php index 812b50380..dd14d65fe 100644 --- a/tests/Feature/Http/Api/Wiki/Studio/StudioShowTest.php +++ b/tests/Feature/Http/Api/Wiki/Studio/StudioShowTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Studio; - use App\Enums\Models\Wiki\AnimeMediaFormat; use App\Enums\Models\Wiki\AnimeSeason; use App\Enums\Models\Wiki\ImageFacet; @@ -22,321 +20,282 @@ use App\Models\Wiki\Image; use App\Models\Wiki\Studio; use Illuminate\Database\Eloquent\Factories\Sequence; use Illuminate\Database\Eloquent\Relations\BelongsToMany; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; -use Tests\TestCase; -class StudioShowTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the Studio Show Endpoint shall return a Studio Resource. - */ - public function testDefault(): void - { - $studio = Studio::factory()->create(); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response = $this->get(route('api.studio.show', ['studio' => $studio])); +test('default', function () { + $studio = Studio::factory()->create(); - $response->assertJson( - json_decode( - json_encode( - new StudioResource($studio, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.studio.show', ['studio' => $studio])); - /** - * The Studio Show Endpoint shall return a Studio Resource for soft deleted studios. - */ - public function testSoftDelete(): void - { - $studio = Studio::factory()->trashed()->createOne(); + $response->assertJson( + json_decode( + json_encode( + new StudioResource($studio, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $studio->unsetRelations(); +test('soft delete', function () { + $studio = Studio::factory()->trashed()->createOne(); - $response = $this->get(route('api.studio.show', ['studio' => $studio])); + $studio->unsetRelations(); - $response->assertJson( - json_decode( - json_encode( - new StudioResource($studio, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.studio.show', ['studio' => $studio])); - /** - * The Studio Show Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new StudioSchema(); + $response->assertJson( + json_decode( + json_encode( + new StudioResource($studio, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('allowed include paths', function () { + $schema = new StudioSchema(); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $allowedIncludes = collect($schema->allowedIncludes()); - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - $studio = Studio::factory() - ->has(Anime::factory()->count($this->faker->randomDigitNotNull())) - ->createOne(); + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; - $response = $this->get(route('api.studio.show', ['studio' => $studio] + $parameters)); + $studio = Studio::factory() + ->has(Anime::factory()->count(fake()->randomDigitNotNull())) + ->createOne(); - $response->assertJson( - json_decode( - json_encode( - new StudioResource($studio, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.studio.show', ['studio' => $studio] + $parameters)); - /** - * The Studio Show Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new StudioSchema(); + $response->assertJson( + json_decode( + json_encode( + new StudioResource($studio, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $fields = collect($schema->fields()); +test('sparse fieldsets', function () { + $schema = new StudioSchema(); - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); + $fields = collect($schema->fields()); - $parameters = [ - FieldParser::param() => [ - StudioResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); - $studio = Studio::factory()->create(); + $parameters = [ + FieldParser::param() => [ + StudioResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; - $response = $this->get(route('api.studio.show', ['studio' => $studio] + $parameters)); + $studio = Studio::factory()->create(); - $response->assertJson( - json_decode( - json_encode( - new StudioResource($studio, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.studio.show', ['studio' => $studio] + $parameters)); - /** - * The Studio Show Endpoint shall support constrained eager loading of anime by media format. - */ - public function testAnimeByMediaFormat(): void - { - $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); + $response->assertJson( + json_decode( + json_encode( + new StudioResource($studio, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), - ], - IncludeParser::param() => Studio::RELATION_ANIME, - ]; +test('anime by media format', function () { + $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); - $studio = Studio::factory() - ->has(Anime::factory()->count($this->faker->randomDigitNotNull())) - ->create(); + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), + ], + IncludeParser::param() => Studio::RELATION_ANIME, + ]; - $studio->unsetRelations()->load([ - Studio::RELATION_ANIME => function (BelongsToMany $query) use ($mediaFormatFilter) { - $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); - }, - ]); + $studio = Studio::factory() + ->has(Anime::factory()->count(fake()->randomDigitNotNull())) + ->create(); - $response = $this->get(route('api.studio.show', ['studio' => $studio] + $parameters)); + $studio->unsetRelations()->load([ + Studio::RELATION_ANIME => function (BelongsToMany $query) use ($mediaFormatFilter) { + $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); + }, + ]); - $response->assertJson( - json_decode( - json_encode( - new StudioResource($studio, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.studio.show', ['studio' => $studio] + $parameters)); - /** - * The Studio Show Endpoint shall support constrained eager loading of anime by season. - */ - public function testAnimeBySeason(): void - { - $seasonFilter = Arr::random(AnimeSeason::cases()); + $response->assertJson( + json_decode( + json_encode( + new StudioResource($studio, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), - ], - IncludeParser::param() => Studio::RELATION_ANIME, - ]; +test('anime by season', function () { + $seasonFilter = Arr::random(AnimeSeason::cases()); - $studio = Studio::factory() - ->has(Anime::factory()->count($this->faker->randomDigitNotNull())) - ->create(); + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), + ], + IncludeParser::param() => Studio::RELATION_ANIME, + ]; - $studio->unsetRelations()->load([ - Studio::RELATION_ANIME => function (BelongsToMany $query) use ($seasonFilter) { - $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); - }, - ]); + $studio = Studio::factory() + ->has(Anime::factory()->count(fake()->randomDigitNotNull())) + ->create(); - $response = $this->get(route('api.studio.show', ['studio' => $studio] + $parameters)); + $studio->unsetRelations()->load([ + Studio::RELATION_ANIME => function (BelongsToMany $query) use ($seasonFilter) { + $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); + }, + ]); - $response->assertJson( - json_decode( - json_encode( - new StudioResource($studio, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.studio.show', ['studio' => $studio] + $parameters)); - /** - * The Studio Index Endpoint shall support constrained eager loading of anime by year. - */ - public function testAnimeByYear(): void - { - $yearFilter = $this->faker->numberBetween(2000, 2002); + $response->assertJson( + json_decode( + json_encode( + new StudioResource($studio, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_YEAR => $yearFilter, - ], - IncludeParser::param() => Studio::RELATION_ANIME, - ]; +test('anime by year', function () { + $yearFilter = fake()->numberBetween(2000, 2002); - $studio = Studio::factory() - ->has( - Anime::factory() - ->count($this->faker->randomDigitNotNull()) - ->state(new Sequence( - [Anime::ATTRIBUTE_YEAR => 2000], - [Anime::ATTRIBUTE_YEAR => 2001], - [Anime::ATTRIBUTE_YEAR => 2002], - )) - ) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_YEAR => $yearFilter, + ], + IncludeParser::param() => Studio::RELATION_ANIME, + ]; - $studio->unsetRelations()->load([ - Studio::RELATION_ANIME => function (BelongsToMany $query) use ($yearFilter) { - $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); - }, - ]); + $studio = Studio::factory() + ->has( + Anime::factory() + ->count(fake()->randomDigitNotNull()) + ->state(new Sequence( + [Anime::ATTRIBUTE_YEAR => 2000], + [Anime::ATTRIBUTE_YEAR => 2001], + [Anime::ATTRIBUTE_YEAR => 2002], + )) + ) + ->createOne(); - $response = $this->get(route('api.studio.show', ['studio' => $studio] + $parameters)); + $studio->unsetRelations()->load([ + Studio::RELATION_ANIME => function (BelongsToMany $query) use ($yearFilter) { + $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); + }, + ]); - $response->assertJson( - json_decode( - json_encode( - new StudioResource($studio, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.studio.show', ['studio' => $studio] + $parameters)); - /** - * The Studio Show Endpoint shall support constrained eager loading of resources by site. - */ - public function testResourcesBySite(): void - { - $siteFilter = Arr::random(ResourceSite::cases()); + $response->assertJson( + json_decode( + json_encode( + new StudioResource($studio, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - ExternalResource::ATTRIBUTE_SITE => $siteFilter->localize(), - ], - IncludeParser::param() => Studio::RELATION_RESOURCES, - ]; +test('resources by site', function () { + $siteFilter = Arr::random(ResourceSite::cases()); - $studio = Studio::factory() - ->has(ExternalResource::factory()->count($this->faker->randomDigitNotNull()), Studio::RELATION_RESOURCES) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + ExternalResource::ATTRIBUTE_SITE => $siteFilter->localize(), + ], + IncludeParser::param() => Studio::RELATION_RESOURCES, + ]; - $studio->unsetRelations()->load([ - Studio::RELATION_RESOURCES => function (BelongsToMany $query) use ($siteFilter) { - $query->where(ExternalResource::ATTRIBUTE_SITE, $siteFilter->value); - }, - ]); + $studio = Studio::factory() + ->has(ExternalResource::factory()->count(fake()->randomDigitNotNull()), Studio::RELATION_RESOURCES) + ->createOne(); - $response = $this->get(route('api.studio.show', ['studio' => $studio] + $parameters)); + $studio->unsetRelations()->load([ + Studio::RELATION_RESOURCES => function (BelongsToMany $query) use ($siteFilter) { + $query->where(ExternalResource::ATTRIBUTE_SITE, $siteFilter->value); + }, + ]); - $response->assertJson( - json_decode( - json_encode( - new StudioResource($studio, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.studio.show', ['studio' => $studio] + $parameters)); - /** - * The Studio Show Endpoint shall support constrained eager loading of images by facet. - */ - public function testImagesByFacet(): void - { - $facetFilter = Arr::random(ImageFacet::cases()); + $response->assertJson( + json_decode( + json_encode( + new StudioResource($studio, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Image::ATTRIBUTE_FACET => $facetFilter->localize(), - ], - IncludeParser::param() => Studio::RELATION_IMAGES, - ]; +test('images by facet', function () { + $facetFilter = Arr::random(ImageFacet::cases()); - $studio = Studio::factory() - ->has(Image::factory()->count($this->faker->randomDigitNotNull())) - ->createOne(); + $parameters = [ + FilterParser::param() => [ + Image::ATTRIBUTE_FACET => $facetFilter->localize(), + ], + IncludeParser::param() => Studio::RELATION_IMAGES, + ]; - $studio->unsetRelations()->load([ - Studio::RELATION_IMAGES => function (BelongsToMany $query) use ($facetFilter) { - $query->where(Image::ATTRIBUTE_FACET, $facetFilter->value); - }, - ]); + $studio = Studio::factory() + ->has(Image::factory()->count(fake()->randomDigitNotNull())) + ->createOne(); - $response = $this->get(route('api.studio.show', ['studio' => $studio] + $parameters)); + $studio->unsetRelations()->load([ + Studio::RELATION_IMAGES => function (BelongsToMany $query) use ($facetFilter) { + $query->where(Image::ATTRIBUTE_FACET, $facetFilter->value); + }, + ]); - $response->assertJson( - json_decode( - json_encode( - new StudioResource($studio, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response = get(route('api.studio.show', ['studio' => $studio] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new StudioResource($studio, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Wiki/Studio/StudioStoreTest.php b/tests/Feature/Http/Api/Wiki/Studio/StudioStoreTest.php index e1a2017e7..2225631af 100644 --- a/tests/Feature/Http/Api/Wiki/Studio/StudioStoreTest.php +++ b/tests/Feature/Http/Api/Wiki/Studio/StudioStoreTest.php @@ -2,75 +2,55 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Studio; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Studio; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class StudioStoreTest extends TestCase -{ - /** - * The Studio Store Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $studio = Studio::factory()->makeOne(); +use function Pest\Laravel\post; - $response = $this->post(route('api.studio.store', $studio->toArray())); +test('protected', function () { + $studio = Studio::factory()->makeOne(); - $response->assertUnauthorized(); - } + $response = post(route('api.studio.store', $studio->toArray())); - /** - * The Studio Store Endpoint shall forbid users without the create studio permission. - */ - public function testForbidden(): void - { - $studio = Studio::factory()->makeOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $studio = Studio::factory()->makeOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->post(route('api.studio.store', $studio->toArray())); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.studio.store', $studio->toArray())); - /** - * The Studio Store Endpoint shall require name & slug fields. - */ - public function testRequiredFields(): void - { - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Studio::class))->createOne(); + $response->assertForbidden(); +}); - Sanctum::actingAs($user); +test('required fields', function () { + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Studio::class))->createOne(); - $response = $this->post(route('api.studio.store')); + Sanctum::actingAs($user); - $response->assertJsonValidationErrors([ - Studio::ATTRIBUTE_NAME, - Studio::ATTRIBUTE_SLUG, - ]); - } + $response = post(route('api.studio.store')); - /** - * The Studio Store Endpoint shall create a studio. - */ - public function testCreate(): void - { - $parameters = Studio::factory()->raw(); + $response->assertJsonValidationErrors([ + Studio::ATTRIBUTE_NAME, + Studio::ATTRIBUTE_SLUG, + ]); +}); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Studio::class))->createOne(); +test('create', function () { + $parameters = Studio::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Studio::class))->createOne(); - $response = $this->post(route('api.studio.store', $parameters)); + Sanctum::actingAs($user); - $response->assertCreated(); - static::assertDatabaseCount(Studio::class, 1); - } -} + $response = post(route('api.studio.store', $parameters)); + + $response->assertCreated(); + $this->assertDatabaseCount(Studio::class, 1); +}); diff --git a/tests/Feature/Http/Api/Wiki/Studio/StudioUpdateTest.php b/tests/Feature/Http/Api/Wiki/Studio/StudioUpdateTest.php index 5988ade13..c7edcb8a5 100644 --- a/tests/Feature/Http/Api/Wiki/Studio/StudioUpdateTest.php +++ b/tests/Feature/Http/Api/Wiki/Studio/StudioUpdateTest.php @@ -2,81 +2,61 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Studio; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Studio; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class StudioUpdateTest extends TestCase -{ - /** - * The Studio Update Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $studio = Studio::factory()->createOne(); +use function Pest\Laravel\put; - $parameters = Studio::factory()->raw(); +test('protected', function () { + $studio = Studio::factory()->createOne(); - $response = $this->put(route('api.studio.update', ['studio' => $studio] + $parameters)); + $parameters = Studio::factory()->raw(); - $response->assertUnauthorized(); - } + $response = put(route('api.studio.update', ['studio' => $studio] + $parameters)); - /** - * The Studio Update Endpoint shall forbid users without the update studio permission. - */ - public function testForbidden(): void - { - $studio = Studio::factory()->createOne(); + $response->assertUnauthorized(); +}); - $parameters = Studio::factory()->raw(); +test('forbidden', function () { + $studio = Studio::factory()->createOne(); - $user = User::factory()->createOne(); + $parameters = Studio::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->put(route('api.studio.update', ['studio' => $studio] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.studio.update', ['studio' => $studio] + $parameters)); - /** - * The Studio Update Endpoint shall forbid users from updating a studio that is trashed. - */ - public function testTrashed(): void - { - $studio = Studio::factory()->trashed()->createOne(); + $response->assertForbidden(); +}); - $parameters = Studio::factory()->raw(); +test('trashed', function () { + $studio = Studio::factory()->trashed()->createOne(); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Studio::class))->createOne(); + $parameters = Studio::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Studio::class))->createOne(); - $response = $this->put(route('api.studio.update', ['studio' => $studio] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.studio.update', ['studio' => $studio] + $parameters)); - /** - * The Studio Update Endpoint shall update a studio. - */ - public function testUpdate(): void - { - $studio = Studio::factory()->createOne(); + $response->assertForbidden(); +}); - $parameters = Studio::factory()->raw(); +test('update', function () { + $studio = Studio::factory()->createOne(); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Studio::class))->createOne(); + $parameters = Studio::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Studio::class))->createOne(); - $response = $this->put(route('api.studio.update', ['studio' => $studio] + $parameters)); + Sanctum::actingAs($user); - $response->assertOk(); - } -} + $response = put(route('api.studio.update', ['studio' => $studio] + $parameters)); + + $response->assertOk(); +}); diff --git a/tests/Feature/Http/Api/Wiki/Video/Script/ScriptDestroyTest.php b/tests/Feature/Http/Api/Wiki/Video/Script/ScriptDestroyTest.php index a014ff6e1..f6c0d9c23 100644 --- a/tests/Feature/Http/Api/Wiki/Video/Script/ScriptDestroyTest.php +++ b/tests/Feature/Http/Api/Wiki/Video/Script/ScriptDestroyTest.php @@ -2,74 +2,54 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Video\Script; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Video\VideoScript; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ScriptDestroyTest extends TestCase -{ - /** - * The Script Destroy Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $script = VideoScript::factory()->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.videoscript.destroy', ['videoscript' => $script])); +test('protected', function () { + $script = VideoScript::factory()->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.videoscript.destroy', ['videoscript' => $script])); - /** - * The Script Destroy Endpoint shall forbid users without the delete video script permission. - */ - public function testForbidden(): void - { - $script = VideoScript::factory()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $script = VideoScript::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.videoscript.destroy', ['videoscript' => $script])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.videoscript.destroy', ['videoscript' => $script])); - /** - * The Script Destroy Endpoint shall forbid users from updating a script that is trashed. - */ - public function testTrashed(): void - { - $script = VideoScript::factory()->trashed()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(VideoScript::class))->createOne(); +test('trashed', function () { + $script = VideoScript::factory()->trashed()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(VideoScript::class))->createOne(); - $response = $this->delete(route('api.videoscript.destroy', ['videoscript' => $script])); + Sanctum::actingAs($user); - $response->assertNotFound(); - } + $response = delete(route('api.videoscript.destroy', ['videoscript' => $script])); - /** - * The Script Destroy Endpoint shall delete the script. - */ - public function testDeleted(): void - { - $script = VideoScript::factory()->createOne(); + $response->assertNotFound(); +}); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(VideoScript::class))->createOne(); +test('deleted', function () { + $script = VideoScript::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(VideoScript::class))->createOne(); - $response = $this->delete(route('api.videoscript.destroy', ['videoscript' => $script])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertSoftDeleted($script); - } -} + $response = delete(route('api.videoscript.destroy', ['videoscript' => $script])); + + $response->assertOk(); + $this->assertSoftDeleted($script); +}); diff --git a/tests/Feature/Http/Api/Wiki/Video/Script/ScriptForceDeleteTest.php b/tests/Feature/Http/Api/Wiki/Video/Script/ScriptForceDeleteTest.php index 752813b50..ca6e59d2c 100644 --- a/tests/Feature/Http/Api/Wiki/Video/Script/ScriptForceDeleteTest.php +++ b/tests/Feature/Http/Api/Wiki/Video/Script/ScriptForceDeleteTest.php @@ -2,58 +2,42 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Video\Script; - use App\Enums\Auth\ExtendedCrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Video\VideoScript; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ScriptForceDeleteTest extends TestCase -{ - /** - * The Script Force Delete Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $script = VideoScript::factory()->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.videoscript.forceDelete', ['videoscript' => $script])); +test('protected', function () { + $script = VideoScript::factory()->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.videoscript.forceDelete', ['videoscript' => $script])); - /** - * The Script Force Delete Endpoint shall forbid users without the force delete video script permission. - */ - public function testForbidden(): void - { - $script = VideoScript::factory()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $script = VideoScript::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.videoscript.forceDelete', ['videoscript' => $script])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.videoscript.forceDelete', ['videoscript' => $script])); - /** - * The Script Force Delete Endpoint shall force delete the script. - */ - public function testDeleted(): void - { - $script = VideoScript::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::FORCE_DELETE->format(VideoScript::class))->createOne(); +test('deleted', function () { + $script = VideoScript::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::FORCE_DELETE->format(VideoScript::class))->createOne(); - $response = $this->delete(route('api.videoscript.forceDelete', ['videoscript' => $script])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertModelMissing($script); - } -} + $response = delete(route('api.videoscript.forceDelete', ['videoscript' => $script])); + + $response->assertOk(); + $this->assertModelMissing($script); +}); diff --git a/tests/Feature/Http/Api/Wiki/Video/Script/ScriptIndexTest.php b/tests/Feature/Http/Api/Wiki/Video/Script/ScriptIndexTest.php index d42a04f77..a63c35378 100644 --- a/tests/Feature/Http/Api/Wiki/Video/Script/ScriptIndexTest.php +++ b/tests/Feature/Http/Api/Wiki/Video/Script/ScriptIndexTest.php @@ -2,9 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Video\Script; - -use App\Concerns\Actions\Http\Api\SortsModels; use App\Constants\ModelConstants; use App\Contracts\Http\Api\Field\SortableField; use App\Enums\Http\Api\Filter\TrashedStatus; @@ -31,676 +28,602 @@ use App\Models\Wiki\Video; use App\Models\Wiki\Video\VideoScript; use Carbon\Carbon; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; -use Tests\TestCase; - -class ScriptIndexTest extends TestCase -{ - use SortsModels; - use WithFaker; - - /** - * By default, the Script Index Endpoint shall return a collection of Script Resources. - */ - public function testDefault(): void - { - $scripts = VideoScript::factory() - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $response = $this->get(route('api.videoscript.index')); - - $response->assertJson( - json_decode( - json_encode( - new ScriptCollection($scripts, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Script Index Endpoint shall be paginated. - */ - public function testPaginated(): void - { - VideoScript::factory() - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $response = $this->get(route('api.videoscript.index')); - - $response->assertJsonStructure([ - ScriptCollection::$wrap, - 'links', - 'meta', - ]); - } - - /** - * The Script Index Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new ScriptSchema(); - - $allowedIncludes = collect($schema->allowedIncludes()); - - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); - - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; - - VideoScript::factory() - ->count($this->faker->randomDigitNotNull()) - ->for(Video::factory()) - ->create(); - - $scripts = VideoScript::with($includedPaths->all())->get(); - - $response = $this->get(route('api.videoscript.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ScriptCollection($scripts, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Script Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new ScriptSchema(); - - $fields = collect($schema->fields()); - - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); - - $parameters = [ - FieldParser::param() => [ - ScriptResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; - - $scripts = VideoScript::factory() - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $response = $this->get(route('api.videoscript.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ScriptCollection($scripts, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Synonym Index Endpoint shall support sorting resources. - */ - public function testSorts(): void - { - $schema = new ScriptSchema(); - - /** @var Sort $sort */ - $sort = collect($schema->fields()) - ->filter(fn (Field $field) => $field instanceof SortableField) - ->map(fn (SortableField $field) => $field->getSort()) - ->random(); - - $parameters = [ - SortParser::param() => $sort->format(Arr::random(Direction::cases())), - ]; - - $query = new Query($parameters); - - VideoScript::factory() - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $response = $this->get(route('api.videoscript.index', $parameters)); - - $scripts = $this->sort(VideoScript::query(), $query, $schema)->get(); - - $response->assertJson( - json_decode( - json_encode( - new ScriptCollection($scripts, $query) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Script Index Endpoint shall support filtering by created_at. - */ - public function testCreatedAtFilter(): void - { - $createdFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($createdFilter, function () { - VideoScript::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - Carbon::withTestNow($excludedDate, function () { - VideoScript::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - $script = VideoScript::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - - $response = $this->get(route('api.videoscript.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ScriptCollection($script, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Script Index Endpoint shall support filtering by updated_at. - */ - public function testUpdatedAtFilter(): void - { - $updatedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($updatedFilter, function () { - VideoScript::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - Carbon::withTestNow($excludedDate, function () { - VideoScript::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - $script = VideoScript::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - - $response = $this->get(route('api.videoscript.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ScriptCollection($script, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Script Index Endpoint shall support filtering by trashed. - */ - public function testWithoutTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITHOUT->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - VideoScript::factory()->count($this->faker->randomDigitNotNull())->create(); - - VideoScript::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - - $script = VideoScript::withoutTrashed()->get(); - - $response = $this->get(route('api.videoscript.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ScriptCollection($script, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Script Index Endpoint shall support filtering by trashed. - */ - public function testWithTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - VideoScript::factory()->count($this->faker->randomDigitNotNull())->create(); - - VideoScript::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - - $script = VideoScript::withTrashed()->get(); - - $response = $this->get(route('api.videoscript.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ScriptCollection($script, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Script Index Endpoint shall support filtering by trashed. - */ - public function testOnlyTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::ONLY->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - VideoScript::factory()->count($this->faker->randomDigitNotNull())->create(); - - VideoScript::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - - $script = VideoScript::onlyTrashed()->get(); - - $response = $this->get(route('api.videoscript.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ScriptCollection($script, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Script Index Endpoint shall support filtering by deleted_at. - */ - public function testDeletedAtFilter(): void - { - $deletedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - ModelConstants::ATTRIBUTE_DELETED_AT => $deletedFilter, - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($deletedFilter, function () { - VideoScript::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - }); - - Carbon::withTestNow($excludedDate, function () { - VideoScript::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - }); - - $script = VideoScript::withTrashed()->where(ModelConstants::ATTRIBUTE_DELETED_AT, $deletedFilter)->get(); - - $response = $this->get(route('api.videoscript.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ScriptCollection($script, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Script Index Endpoint shall support constrained eager loading of videos by lyrics. - */ - public function testVideosByLyrics(): void - { - $lyricsFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_LYRICS => $lyricsFilter, - ], - IncludeParser::param() => VideoScript::RELATION_VIDEO, - ]; - - VideoScript::factory() - ->count($this->faker->randomDigitNotNull()) - ->for(Video::factory()) - ->create(); - - $scripts = VideoScript::with([ - VideoScript::RELATION_VIDEO => function (BelongsTo $query) use ($lyricsFilter) { - $query->where(Video::ATTRIBUTE_LYRICS, $lyricsFilter); - }, - ]) - ->get(); - - $response = $this->get(route('api.videoscript.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ScriptCollection($scripts, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Script Index Endpoint shall support constrained eager loading of videos by nc. - */ - public function testVideosByNc(): void - { - $ncFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_NC => $ncFilter, - ], - IncludeParser::param() => VideoScript::RELATION_VIDEO, - ]; - - VideoScript::factory() - ->count($this->faker->randomDigitNotNull()) - ->for(Video::factory()) - ->create(); - - $scripts = VideoScript::with([ - VideoScript::RELATION_VIDEO => function (BelongsTo $query) use ($ncFilter) { - $query->where(Video::ATTRIBUTE_NC, $ncFilter); - }, - ]) - ->get(); - - $response = $this->get(route('api.videoscript.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ScriptCollection($scripts, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Script Index Endpoint shall support constrained eager loading of videos by overlap. - */ - public function testVideosByOverlap(): void - { - $overlapFilter = Arr::random(VideoOverlap::cases()); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_OVERLAP => $overlapFilter->localize(), - ], - IncludeParser::param() => VideoScript::RELATION_VIDEO, - ]; - - VideoScript::factory() - ->count($this->faker->randomDigitNotNull()) - ->for(Video::factory()) - ->create(); - - $scripts = VideoScript::with([ - VideoScript::RELATION_VIDEO => function (BelongsTo $query) use ($overlapFilter) { - $query->where(Video::ATTRIBUTE_OVERLAP, $overlapFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.videoscript.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ScriptCollection($scripts, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Script Index Endpoint shall support constrained eager loading of videos by resolution. - */ - public function testVideosByResolution(): void - { - $resolutionFilter = $this->faker->randomNumber(); - $excludedResolution = $resolutionFilter + 1; - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_RESOLUTION => $resolutionFilter, - ], - IncludeParser::param() => VideoScript::RELATION_VIDEO, - ]; - - VideoScript::factory() - ->count($this->faker->randomDigitNotNull()) - ->for( - Video::factory()->state([ - Video::ATTRIBUTE_RESOLUTION => $this->faker->boolean() ? $resolutionFilter : $excludedResolution, - ]) - ) - ->create(); - - $scripts = VideoScript::with([ - VideoScript::RELATION_VIDEO => function (BelongsTo $query) use ($resolutionFilter) { - $query->where(Video::ATTRIBUTE_RESOLUTION, $resolutionFilter); - }, - ]) - ->get(); - - $response = $this->get(route('api.videoscript.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ScriptCollection($scripts, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Script Index Endpoint shall support constrained eager loading of videos by source. - */ - public function testVideosBySource(): void - { - $sourceFilter = Arr::random(VideoSource::cases()); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_SOURCE => $sourceFilter->localize(), - ], - IncludeParser::param() => VideoScript::RELATION_VIDEO, - ]; - - VideoScript::factory() - ->count($this->faker->randomDigitNotNull()) - ->for(Video::factory()) - ->create(); - - $scripts = VideoScript::with([ - VideoScript::RELATION_VIDEO => function (BelongsTo $query) use ($sourceFilter) { - $query->where(Video::ATTRIBUTE_SOURCE, $sourceFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.videoscript.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ScriptCollection($scripts, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Script Index Endpoint shall support constrained eager loading of videos by subbed. - */ - public function testVideosBySubbed(): void - { - $subbedFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_SUBBED => $subbedFilter, - ], - IncludeParser::param() => VideoScript::RELATION_VIDEO, - ]; - - VideoScript::factory() - ->count($this->faker->randomDigitNotNull()) - ->for(Video::factory()) - ->create(); - - $scripts = VideoScript::with([ - VideoScript::RELATION_VIDEO => function (BelongsTo $query) use ($subbedFilter) { - $query->where(Video::ATTRIBUTE_SUBBED, $subbedFilter); - }, - ]) - ->get(); - - $response = $this->get(route('api.videoscript.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ScriptCollection($scripts, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Script Index Endpoint shall support constrained eager loading of videos by uncen. - */ - public function testVideosByUncen(): void - { - $uncenFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_UNCEN => $uncenFilter, - ], - IncludeParser::param() => VideoScript::RELATION_VIDEO, - ]; - - VideoScript::factory() - ->count($this->faker->randomDigitNotNull()) - ->for(Video::factory()) - ->create(); - - $scripts = VideoScript::with([ - VideoScript::RELATION_VIDEO => function (BelongsTo $query) use ($uncenFilter) { - $query->where(Video::ATTRIBUTE_UNCEN, $uncenFilter); - }, - ]) - ->get(); - - $response = $this->get(route('api.videoscript.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new ScriptCollection($scripts, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + +use function Pest\Laravel\get; + +uses(App\Concerns\Actions\Http\Api\SortsModels::class); + +uses(Illuminate\Foundation\Testing\WithFaker::class); + +test('default', function () { + $scripts = VideoScript::factory() + ->count(fake()->randomDigitNotNull()) + ->create(); + + $response = get(route('api.videoscript.index')); + + $response->assertJson( + json_decode( + json_encode( + new ScriptCollection($scripts, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('paginated', function () { + VideoScript::factory() + ->count(fake()->randomDigitNotNull()) + ->create(); + + $response = get(route('api.videoscript.index')); + + $response->assertJsonStructure([ + ScriptCollection::$wrap, + 'links', + 'meta', + ]); +}); + +test('allowed include paths', function () { + $schema = new ScriptSchema(); + + $allowedIncludes = collect($schema->allowedIncludes()); + + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); + + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; + + VideoScript::factory() + ->count(fake()->randomDigitNotNull()) + ->for(Video::factory()) + ->create(); + + $scripts = VideoScript::with($includedPaths->all())->get(); + + $response = get(route('api.videoscript.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ScriptCollection($scripts, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sparse fieldsets', function () { + $schema = new ScriptSchema(); + + $fields = collect($schema->fields()); + + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + ScriptResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + $scripts = VideoScript::factory() + ->count(fake()->randomDigitNotNull()) + ->create(); + + $response = get(route('api.videoscript.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ScriptCollection($scripts, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sorts', function () { + $schema = new ScriptSchema(); + + /** @var Sort $sort */ + $sort = collect($schema->fields()) + ->filter(fn (Field $field) => $field instanceof SortableField) + ->map(fn (SortableField $field) => $field->getSort()) + ->random(); + + $parameters = [ + SortParser::param() => $sort->format(Arr::random(Direction::cases())), + ]; + + $query = new Query($parameters); + + VideoScript::factory() + ->count(fake()->randomDigitNotNull()) + ->create(); + + $response = get(route('api.videoscript.index', $parameters)); + + $scripts = $this->sort(VideoScript::query(), $query, $schema)->get(); + + $response->assertJson( + json_decode( + json_encode( + new ScriptCollection($scripts, $query) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('created at filter', function () { + $createdFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($createdFilter, function () { + VideoScript::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + Carbon::withTestNow($excludedDate, function () { + VideoScript::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + $script = VideoScript::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); + + $response = get(route('api.videoscript.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ScriptCollection($script, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('updated at filter', function () { + $updatedFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($updatedFilter, function () { + VideoScript::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + Carbon::withTestNow($excludedDate, function () { + VideoScript::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + $script = VideoScript::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); + + $response = get(route('api.videoscript.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ScriptCollection($script, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('without trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITHOUT->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + VideoScript::factory()->count(fake()->randomDigitNotNull())->create(); + + VideoScript::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + + $script = VideoScript::withoutTrashed()->get(); + + $response = get(route('api.videoscript.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ScriptCollection($script, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('with trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + VideoScript::factory()->count(fake()->randomDigitNotNull())->create(); + + VideoScript::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + + $script = VideoScript::withTrashed()->get(); + + $response = get(route('api.videoscript.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ScriptCollection($script, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('only trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::ONLY->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + VideoScript::factory()->count(fake()->randomDigitNotNull())->create(); + + VideoScript::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + + $script = VideoScript::onlyTrashed()->get(); + + $response = get(route('api.videoscript.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ScriptCollection($script, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('deleted at filter', function () { + $deletedFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + ModelConstants::ATTRIBUTE_DELETED_AT => $deletedFilter, + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($deletedFilter, function () { + VideoScript::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + }); + + Carbon::withTestNow($excludedDate, function () { + VideoScript::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + }); + + $script = VideoScript::withTrashed()->where(ModelConstants::ATTRIBUTE_DELETED_AT, $deletedFilter)->get(); + + $response = get(route('api.videoscript.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ScriptCollection($script, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by lyrics', function () { + $lyricsFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_LYRICS => $lyricsFilter, + ], + IncludeParser::param() => VideoScript::RELATION_VIDEO, + ]; + + VideoScript::factory() + ->count(fake()->randomDigitNotNull()) + ->for(Video::factory()) + ->create(); + + $scripts = VideoScript::with([ + VideoScript::RELATION_VIDEO => function (BelongsTo $query) use ($lyricsFilter) { + $query->where(Video::ATTRIBUTE_LYRICS, $lyricsFilter); + }, + ]) + ->get(); + + $response = get(route('api.videoscript.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ScriptCollection($scripts, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by nc', function () { + $ncFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_NC => $ncFilter, + ], + IncludeParser::param() => VideoScript::RELATION_VIDEO, + ]; + + VideoScript::factory() + ->count(fake()->randomDigitNotNull()) + ->for(Video::factory()) + ->create(); + + $scripts = VideoScript::with([ + VideoScript::RELATION_VIDEO => function (BelongsTo $query) use ($ncFilter) { + $query->where(Video::ATTRIBUTE_NC, $ncFilter); + }, + ]) + ->get(); + + $response = get(route('api.videoscript.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ScriptCollection($scripts, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by overlap', function () { + $overlapFilter = Arr::random(VideoOverlap::cases()); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_OVERLAP => $overlapFilter->localize(), + ], + IncludeParser::param() => VideoScript::RELATION_VIDEO, + ]; + + VideoScript::factory() + ->count(fake()->randomDigitNotNull()) + ->for(Video::factory()) + ->create(); + + $scripts = VideoScript::with([ + VideoScript::RELATION_VIDEO => function (BelongsTo $query) use ($overlapFilter) { + $query->where(Video::ATTRIBUTE_OVERLAP, $overlapFilter->value); + }, + ]) + ->get(); + + $response = get(route('api.videoscript.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ScriptCollection($scripts, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by resolution', function () { + $resolutionFilter = fake()->randomNumber(); + $excludedResolution = $resolutionFilter + 1; + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_RESOLUTION => $resolutionFilter, + ], + IncludeParser::param() => VideoScript::RELATION_VIDEO, + ]; + + VideoScript::factory() + ->count(fake()->randomDigitNotNull()) + ->for( + Video::factory()->state([ + Video::ATTRIBUTE_RESOLUTION => fake()->boolean() ? $resolutionFilter : $excludedResolution, + ]) + ) + ->create(); + + $scripts = VideoScript::with([ + VideoScript::RELATION_VIDEO => function (BelongsTo $query) use ($resolutionFilter) { + $query->where(Video::ATTRIBUTE_RESOLUTION, $resolutionFilter); + }, + ]) + ->get(); + + $response = get(route('api.videoscript.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ScriptCollection($scripts, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by source', function () { + $sourceFilter = Arr::random(VideoSource::cases()); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_SOURCE => $sourceFilter->localize(), + ], + IncludeParser::param() => VideoScript::RELATION_VIDEO, + ]; + + VideoScript::factory() + ->count(fake()->randomDigitNotNull()) + ->for(Video::factory()) + ->create(); + + $scripts = VideoScript::with([ + VideoScript::RELATION_VIDEO => function (BelongsTo $query) use ($sourceFilter) { + $query->where(Video::ATTRIBUTE_SOURCE, $sourceFilter->value); + }, + ]) + ->get(); + + $response = get(route('api.videoscript.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ScriptCollection($scripts, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by subbed', function () { + $subbedFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_SUBBED => $subbedFilter, + ], + IncludeParser::param() => VideoScript::RELATION_VIDEO, + ]; + + VideoScript::factory() + ->count(fake()->randomDigitNotNull()) + ->for(Video::factory()) + ->create(); + + $scripts = VideoScript::with([ + VideoScript::RELATION_VIDEO => function (BelongsTo $query) use ($subbedFilter) { + $query->where(Video::ATTRIBUTE_SUBBED, $subbedFilter); + }, + ]) + ->get(); + + $response = get(route('api.videoscript.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ScriptCollection($scripts, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('videos by uncen', function () { + $uncenFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_UNCEN => $uncenFilter, + ], + IncludeParser::param() => VideoScript::RELATION_VIDEO, + ]; + + VideoScript::factory() + ->count(fake()->randomDigitNotNull()) + ->for(Video::factory()) + ->create(); + + $scripts = VideoScript::with([ + VideoScript::RELATION_VIDEO => function (BelongsTo $query) use ($uncenFilter) { + $query->where(Video::ATTRIBUTE_UNCEN, $uncenFilter); + }, + ]) + ->get(); + + $response = get(route('api.videoscript.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ScriptCollection($scripts, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Wiki/Video/Script/ScriptRestoreTest.php b/tests/Feature/Http/Api/Wiki/Video/Script/ScriptRestoreTest.php index 4fb204492..85a61b123 100644 --- a/tests/Feature/Http/Api/Wiki/Video/Script/ScriptRestoreTest.php +++ b/tests/Feature/Http/Api/Wiki/Video/Script/ScriptRestoreTest.php @@ -2,74 +2,54 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Video\Script; - use App\Enums\Auth\ExtendedCrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Video\VideoScript; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ScriptRestoreTest extends TestCase -{ - /** - * The Script Restore Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $script = VideoScript::factory()->trashed()->createOne(); +use function Pest\Laravel\patch; - $response = $this->patch(route('api.videoscript.restore', ['videoscript' => $script])); +test('protected', function () { + $script = VideoScript::factory()->trashed()->createOne(); - $response->assertUnauthorized(); - } + $response = patch(route('api.videoscript.restore', ['videoscript' => $script])); - /** - * The Script Restore Endpoint shall forbid users without the restore video script permission. - */ - public function testForbidden(): void - { - $script = VideoScript::factory()->trashed()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $script = VideoScript::factory()->trashed()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->patch(route('api.videoscript.restore', ['videoscript' => $script])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = patch(route('api.videoscript.restore', ['videoscript' => $script])); - /** - * The Script Restore Endpoint shall forbid users from restoring a script that isn't trashed. - */ - public function testTrashed(): void - { - $script = VideoScript::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(VideoScript::class))->createOne(); +test('trashed', function () { + $script = VideoScript::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(VideoScript::class))->createOne(); - $response = $this->patch(route('api.videoscript.restore', ['videoscript' => $script])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = patch(route('api.videoscript.restore', ['videoscript' => $script])); - /** - * The Script Restore Endpoint shall restore the script. - */ - public function testRestored(): void - { - $script = VideoScript::factory()->trashed()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(VideoScript::class))->createOne(); +test('restored', function () { + $script = VideoScript::factory()->trashed()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(VideoScript::class))->createOne(); - $response = $this->patch(route('api.videoscript.restore', ['videoscript' => $script])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertNotSoftDeleted($script); - } -} + $response = patch(route('api.videoscript.restore', ['videoscript' => $script])); + + $response->assertOk(); + $this->assertNotSoftDeleted($script); +}); diff --git a/tests/Feature/Http/Api/Wiki/Video/Script/ScriptShowTest.php b/tests/Feature/Http/Api/Wiki/Video/Script/ScriptShowTest.php index ddd2dc9d1..eff4ea0c0 100644 --- a/tests/Feature/Http/Api/Wiki/Video/Script/ScriptShowTest.php +++ b/tests/Feature/Http/Api/Wiki/Video/Script/ScriptShowTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Video\Script; - use App\Enums\Models\Wiki\VideoOverlap; use App\Enums\Models\Wiki\VideoSource; use App\Http\Api\Field\Field; @@ -17,392 +15,345 @@ use App\Http\Resources\Wiki\Video\Resource\ScriptResource; use App\Models\Wiki\Video; use App\Models\Wiki\Video\VideoScript; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; -use Tests\TestCase; -class ScriptShowTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the Script Show Endpoint shall return a Script Resource. - */ - public function testDefault(): void - { - $script = VideoScript::factory()->create(); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $response = $this->get(route('api.videoscript.show', ['videoscript' => $script])); +test('default', function () { + $script = VideoScript::factory()->create(); - $response->assertJson( - json_decode( - json_encode( - new ScriptResource($script, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.videoscript.show', ['videoscript' => $script])); - /** - * The Script Show Endpoint shall return a Script Resource for soft deleted scripts. - */ - public function testSoftDelete(): void - { - $script = VideoScript::factory()->trashed()->createOne(); + $response->assertJson( + json_decode( + json_encode( + new ScriptResource($script, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $response = $this->get(route('api.videoscript.show', ['videoscript' => $script])); +test('soft delete', function () { + $script = VideoScript::factory()->trashed()->createOne(); - $response->assertJson( - json_decode( - json_encode( - new ScriptResource($script, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.videoscript.show', ['videoscript' => $script])); - /** - * The Script Show Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new ScriptSchema(); + $response->assertJson( + json_decode( + json_encode( + new ScriptResource($script, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); - $allowedIncludes = collect($schema->allowedIncludes()); +test('allowed include paths', function () { + $schema = new ScriptSchema(); - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); + $allowedIncludes = collect($schema->allowedIncludes()); - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - $script = VideoScript::factory() - ->for(Video::factory()) - ->createOne(); + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; - $response = $this->get(route('api.videoscript.show', ['videoscript' => $script] + $parameters)); + $script = VideoScript::factory() + ->for(Video::factory()) + ->createOne(); - $response->assertJson( - json_decode( - json_encode( - new ScriptResource($script, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.videoscript.show', ['videoscript' => $script] + $parameters)); - /** - * The Script Show Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new ScriptSchema(); + $response->assertJson( + json_decode( + json_encode( + new ScriptResource($script, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $fields = collect($schema->fields()); +test('sparse fieldsets', function () { + $schema = new ScriptSchema(); - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); + $fields = collect($schema->fields()); - $parameters = [ - FieldParser::param() => [ - ScriptResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); - $script = VideoScript::factory()->create(); + $parameters = [ + FieldParser::param() => [ + ScriptResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; - $response = $this->get(route('api.videoscript.show', ['videoscript' => $script] + $parameters)); + $script = VideoScript::factory()->create(); - $response->assertJson( - json_decode( - json_encode( - new ScriptResource($script, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.videoscript.show', ['videoscript' => $script] + $parameters)); - /** - * The Script Show Endpoint shall support constrained eager loading of videos by lyrics. - */ - public function testVideosByLyrics(): void - { - $lyricsFilter = $this->faker->boolean(); + $response->assertJson( + json_decode( + json_encode( + new ScriptResource($script, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_LYRICS => $lyricsFilter, - ], - IncludeParser::param() => VideoScript::RELATION_VIDEO, - ]; +test('videos by lyrics', function () { + $lyricsFilter = fake()->boolean(); - $script = VideoScript::factory() - ->for(Video::factory()) - ->create(); + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_LYRICS => $lyricsFilter, + ], + IncludeParser::param() => VideoScript::RELATION_VIDEO, + ]; - $script->unsetRelations()->load([ - VideoScript::RELATION_VIDEO => function (BelongsTo $query) use ($lyricsFilter) { - $query->where(Video::ATTRIBUTE_LYRICS, $lyricsFilter); - }, - ]); + $script = VideoScript::factory() + ->for(Video::factory()) + ->create(); - $response = $this->get(route('api.videoscript.show', ['videoscript' => $script] + $parameters)); + $script->unsetRelations()->load([ + VideoScript::RELATION_VIDEO => function (BelongsTo $query) use ($lyricsFilter) { + $query->where(Video::ATTRIBUTE_LYRICS, $lyricsFilter); + }, + ]); - $response->assertJson( - json_decode( - json_encode( - new ScriptResource($script, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.videoscript.show', ['videoscript' => $script] + $parameters)); - /** - * The Script Show Endpoint shall support constrained eager loading of videos by nc. - */ - public function testVideosByNc(): void - { - $ncFilter = $this->faker->boolean(); + $response->assertJson( + json_decode( + json_encode( + new ScriptResource($script, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_NC => $ncFilter, - ], - IncludeParser::param() => VideoScript::RELATION_VIDEO, - ]; +test('videos by nc', function () { + $ncFilter = fake()->boolean(); - $script = VideoScript::factory() - ->for(Video::factory()) - ->create(); + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_NC => $ncFilter, + ], + IncludeParser::param() => VideoScript::RELATION_VIDEO, + ]; - $script->unsetRelations()->load([ - VideoScript::RELATION_VIDEO => function (BelongsTo $query) use ($ncFilter) { - $query->where(Video::ATTRIBUTE_NC, $ncFilter); - }, - ]); + $script = VideoScript::factory() + ->for(Video::factory()) + ->create(); - $response = $this->get(route('api.videoscript.show', ['videoscript' => $script] + $parameters)); + $script->unsetRelations()->load([ + VideoScript::RELATION_VIDEO => function (BelongsTo $query) use ($ncFilter) { + $query->where(Video::ATTRIBUTE_NC, $ncFilter); + }, + ]); - $response->assertJson( - json_decode( - json_encode( - new ScriptResource($script, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.videoscript.show', ['videoscript' => $script] + $parameters)); - /** - * The Script Show Endpoint shall support constrained eager loading of videos by overlap. - */ - public function testVideosByOverlap(): void - { - $overlapFilter = Arr::random(VideoOverlap::cases()); + $response->assertJson( + json_decode( + json_encode( + new ScriptResource($script, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_OVERLAP => $overlapFilter->localize(), - ], - IncludeParser::param() => VideoScript::RELATION_VIDEO, - ]; +test('videos by overlap', function () { + $overlapFilter = Arr::random(VideoOverlap::cases()); - $script = VideoScript::factory() - ->for(Video::factory()) - ->create(); + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_OVERLAP => $overlapFilter->localize(), + ], + IncludeParser::param() => VideoScript::RELATION_VIDEO, + ]; - $script->unsetRelations()->load([ - VideoScript::RELATION_VIDEO => function (BelongsTo $query) use ($overlapFilter) { - $query->where(Video::ATTRIBUTE_OVERLAP, $overlapFilter->value); - }, - ]); + $script = VideoScript::factory() + ->for(Video::factory()) + ->create(); - $response = $this->get(route('api.videoscript.show', ['videoscript' => $script] + $parameters)); + $script->unsetRelations()->load([ + VideoScript::RELATION_VIDEO => function (BelongsTo $query) use ($overlapFilter) { + $query->where(Video::ATTRIBUTE_OVERLAP, $overlapFilter->value); + }, + ]); - $response->assertJson( - json_decode( - json_encode( - new ScriptResource($script, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.videoscript.show', ['videoscript' => $script] + $parameters)); - /** - * The Script Show Endpoint shall support constrained eager loading of videos by resolution. - */ - public function testVideosByResolution(): void - { - $resolutionFilter = $this->faker->randomNumber(); - $excludedResolution = $resolutionFilter + 1; + $response->assertJson( + json_decode( + json_encode( + new ScriptResource($script, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_RESOLUTION => $resolutionFilter, - ], - IncludeParser::param() => VideoScript::RELATION_VIDEO, - ]; +test('videos by resolution', function () { + $resolutionFilter = fake()->randomNumber(); + $excludedResolution = $resolutionFilter + 1; - $script = VideoScript::factory() - ->for( - Video::factory()->state([ - Video::ATTRIBUTE_RESOLUTION => $this->faker->boolean() ? $resolutionFilter : $excludedResolution, - ]) - ) - ->create(); + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_RESOLUTION => $resolutionFilter, + ], + IncludeParser::param() => VideoScript::RELATION_VIDEO, + ]; - $script->unsetRelations()->load([ - VideoScript::RELATION_VIDEO => function (BelongsTo $query) use ($resolutionFilter) { - $query->where(Video::ATTRIBUTE_RESOLUTION, $resolutionFilter); - }, - ]); + $script = VideoScript::factory() + ->for( + Video::factory()->state([ + Video::ATTRIBUTE_RESOLUTION => fake()->boolean() ? $resolutionFilter : $excludedResolution, + ]) + ) + ->create(); - $response = $this->get(route('api.videoscript.show', ['videoscript' => $script] + $parameters)); + $script->unsetRelations()->load([ + VideoScript::RELATION_VIDEO => function (BelongsTo $query) use ($resolutionFilter) { + $query->where(Video::ATTRIBUTE_RESOLUTION, $resolutionFilter); + }, + ]); - $response->assertJson( - json_decode( - json_encode( - new ScriptResource($script, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.videoscript.show', ['videoscript' => $script] + $parameters)); - /** - * The Script Show Endpoint shall support constrained eager loading of videos by source. - */ - public function testVideosBySource(): void - { - $sourceFilter = Arr::random(VideoSource::cases()); + $response->assertJson( + json_decode( + json_encode( + new ScriptResource($script, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_SOURCE => $sourceFilter->localize(), - ], - IncludeParser::param() => VideoScript::RELATION_VIDEO, - ]; +test('videos by source', function () { + $sourceFilter = Arr::random(VideoSource::cases()); - $script = VideoScript::factory() - ->for(Video::factory()) - ->create(); + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_SOURCE => $sourceFilter->localize(), + ], + IncludeParser::param() => VideoScript::RELATION_VIDEO, + ]; - $script->unsetRelations()->load([ - VideoScript::RELATION_VIDEO => function (BelongsTo $query) use ($sourceFilter) { - $query->where(Video::ATTRIBUTE_SOURCE, $sourceFilter->value); - }, - ]); + $script = VideoScript::factory() + ->for(Video::factory()) + ->create(); - $response = $this->get(route('api.videoscript.show', ['videoscript' => $script] + $parameters)); + $script->unsetRelations()->load([ + VideoScript::RELATION_VIDEO => function (BelongsTo $query) use ($sourceFilter) { + $query->where(Video::ATTRIBUTE_SOURCE, $sourceFilter->value); + }, + ]); - $response->assertJson( - json_decode( - json_encode( - new ScriptResource($script, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.videoscript.show', ['videoscript' => $script] + $parameters)); - /** - * The Script Show Endpoint shall support constrained eager loading of videos by subbed. - */ - public function testVideosBySubbed(): void - { - $subbedFilter = $this->faker->boolean(); + $response->assertJson( + json_decode( + json_encode( + new ScriptResource($script, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_SUBBED => $subbedFilter, - ], - IncludeParser::param() => VideoScript::RELATION_VIDEO, - ]; +test('videos by subbed', function () { + $subbedFilter = fake()->boolean(); - $script = VideoScript::factory() - ->for(Video::factory()) - ->create(); + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_SUBBED => $subbedFilter, + ], + IncludeParser::param() => VideoScript::RELATION_VIDEO, + ]; - $script->unsetRelations()->load([ - VideoScript::RELATION_VIDEO => function (BelongsTo $query) use ($subbedFilter) { - $query->where(Video::ATTRIBUTE_SUBBED, $subbedFilter); - }, - ]); + $script = VideoScript::factory() + ->for(Video::factory()) + ->create(); - $response = $this->get(route('api.videoscript.show', ['videoscript' => $script] + $parameters)); + $script->unsetRelations()->load([ + VideoScript::RELATION_VIDEO => function (BelongsTo $query) use ($subbedFilter) { + $query->where(Video::ATTRIBUTE_SUBBED, $subbedFilter); + }, + ]); - $response->assertJson( - json_decode( - json_encode( - new ScriptResource($script, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } + $response = get(route('api.videoscript.show', ['videoscript' => $script] + $parameters)); - /** - * The Script Show Endpoint shall support constrained eager loading of videos by uncen. - */ - public function testVideosByUncen(): void - { - $uncenFilter = $this->faker->boolean(); + $response->assertJson( + json_decode( + json_encode( + new ScriptResource($script, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_UNCEN => $uncenFilter, - ], - IncludeParser::param() => VideoScript::RELATION_VIDEO, - ]; +test('videos by uncen', function () { + $uncenFilter = fake()->boolean(); - $script = VideoScript::factory() - ->for(Video::factory()) - ->create(); + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_UNCEN => $uncenFilter, + ], + IncludeParser::param() => VideoScript::RELATION_VIDEO, + ]; - $script->unsetRelations()->load([ - VideoScript::RELATION_VIDEO => function (BelongsTo $query) use ($uncenFilter) { - $query->where(Video::ATTRIBUTE_UNCEN, $uncenFilter); - }, - ]); + $script = VideoScript::factory() + ->for(Video::factory()) + ->create(); - $response = $this->get(route('api.videoscript.show', ['videoscript' => $script] + $parameters)); + $script->unsetRelations()->load([ + VideoScript::RELATION_VIDEO => function (BelongsTo $query) use ($uncenFilter) { + $query->where(Video::ATTRIBUTE_UNCEN, $uncenFilter); + }, + ]); - $response->assertJson( - json_decode( - json_encode( - new ScriptResource($script, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + $response = get(route('api.videoscript.show', ['videoscript' => $script] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new ScriptResource($script, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Wiki/Video/Script/ScriptStoreTest.php b/tests/Feature/Http/Api/Wiki/Video/Script/ScriptStoreTest.php index f604bdc9e..df839fe8d 100644 --- a/tests/Feature/Http/Api/Wiki/Video/Script/ScriptStoreTest.php +++ b/tests/Feature/Http/Api/Wiki/Video/Script/ScriptStoreTest.php @@ -2,74 +2,54 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Video\Script; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Video\VideoScript; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ScriptStoreTest extends TestCase -{ - /** - * The Script Store Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $script = VideoScript::factory()->makeOne(); +use function Pest\Laravel\post; - $response = $this->post(route('api.videoscript.store', $script->toArray())); +test('protected', function () { + $script = VideoScript::factory()->makeOne(); - $response->assertUnauthorized(); - } + $response = post(route('api.videoscript.store', $script->toArray())); - /** - * The Script Store Endpoint shall forbid users without the create video script permission. - */ - public function testForbidden(): void - { - $script = VideoScript::factory()->makeOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $script = VideoScript::factory()->makeOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->post(route('api.videoscript.store', $script->toArray())); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.videoscript.store', $script->toArray())); - /** - * The Script Store Endpoint shall require the path field. - */ - public function testRequiredFields(): void - { - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(VideoScript::class))->createOne(); + $response->assertForbidden(); +}); - Sanctum::actingAs($user); +test('required fields', function () { + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(VideoScript::class))->createOne(); - $response = $this->post(route('api.videoscript.store')); + Sanctum::actingAs($user); - $response->assertJsonValidationErrors([ - VideoScript::ATTRIBUTE_PATH, - ]); - } + $response = post(route('api.videoscript.store')); - /** - * The Script Store Endpoint shall create a script. - */ - public function testCreate(): void - { - $parameters = VideoScript::factory()->raw(); + $response->assertJsonValidationErrors([ + VideoScript::ATTRIBUTE_PATH, + ]); +}); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(VideoScript::class))->createOne(); +test('create', function () { + $parameters = VideoScript::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(VideoScript::class))->createOne(); - $response = $this->post(route('api.videoscript.store', $parameters)); + Sanctum::actingAs($user); - $response->assertCreated(); - static::assertDatabaseCount(VideoScript::class, 1); - } -} + $response = post(route('api.videoscript.store', $parameters)); + + $response->assertCreated(); + $this->assertDatabaseCount(VideoScript::class, 1); +}); diff --git a/tests/Feature/Http/Api/Wiki/Video/Script/ScriptUpdateTest.php b/tests/Feature/Http/Api/Wiki/Video/Script/ScriptUpdateTest.php index d0f88bf82..d21019f6a 100644 --- a/tests/Feature/Http/Api/Wiki/Video/Script/ScriptUpdateTest.php +++ b/tests/Feature/Http/Api/Wiki/Video/Script/ScriptUpdateTest.php @@ -2,81 +2,61 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Video\Script; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Video\VideoScript; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ScriptUpdateTest extends TestCase -{ - /** - * The Script Update Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $script = VideoScript::factory()->createOne(); +use function Pest\Laravel\put; - $parameters = VideoScript::factory()->raw(); +test('protected', function () { + $script = VideoScript::factory()->createOne(); - $response = $this->put(route('api.videoscript.update', ['videoscript' => $script] + $parameters)); + $parameters = VideoScript::factory()->raw(); - $response->assertUnauthorized(); - } + $response = put(route('api.videoscript.update', ['videoscript' => $script] + $parameters)); - /** - * The Script Update Endpoint shall forbid users without the update video script permission. - */ - public function testForbidden(): void - { - $script = VideoScript::factory()->createOne(); + $response->assertUnauthorized(); +}); - $parameters = VideoScript::factory()->raw(); +test('forbidden', function () { + $script = VideoScript::factory()->createOne(); - $user = User::factory()->createOne(); + $parameters = VideoScript::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->put(route('api.videoscript.update', ['videoscript' => $script] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.videoscript.update', ['videoscript' => $script] + $parameters)); - /** - * The Script Update Endpoint shall forbid users from updating a script that is trashed. - */ - public function testTrashed(): void - { - $script = VideoScript::factory()->trashed()->createOne(); + $response->assertForbidden(); +}); - $parameters = VideoScript::factory()->raw(); +test('trashed', function () { + $script = VideoScript::factory()->trashed()->createOne(); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(VideoScript::class))->createOne(); + $parameters = VideoScript::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(VideoScript::class))->createOne(); - $response = $this->put(route('api.videoscript.update', ['videoscript' => $script] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.videoscript.update', ['videoscript' => $script] + $parameters)); - /** - * The Script Update Endpoint shall update a script. - */ - public function testUpdate(): void - { - $script = VideoScript::factory()->createOne(); + $response->assertForbidden(); +}); - $parameters = VideoScript::factory()->raw(); +test('update', function () { + $script = VideoScript::factory()->createOne(); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(VideoScript::class))->createOne(); + $parameters = VideoScript::factory()->raw(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(VideoScript::class))->createOne(); - $response = $this->put(route('api.videoscript.update', ['videoscript' => $script] + $parameters)); + Sanctum::actingAs($user); - $response->assertOk(); - } -} + $response = put(route('api.videoscript.update', ['videoscript' => $script] + $parameters)); + + $response->assertOk(); +}); diff --git a/tests/Feature/Http/Api/Wiki/Video/VideoDestroyTest.php b/tests/Feature/Http/Api/Wiki/Video/VideoDestroyTest.php index 5fa635d55..e683cf278 100644 --- a/tests/Feature/Http/Api/Wiki/Video/VideoDestroyTest.php +++ b/tests/Feature/Http/Api/Wiki/Video/VideoDestroyTest.php @@ -2,74 +2,54 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Video; - use App\Enums\Auth\CrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Video; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class VideoDestroyTest extends TestCase -{ - /** - * The Video Destroy Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $video = Video::factory()->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.video.destroy', ['video' => $video])); +test('protected', function () { + $video = Video::factory()->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.video.destroy', ['video' => $video])); - /** - * The Video Destroy Endpoint shall forbid users without the delete video permission. - */ - public function testForbidden(): void - { - $video = Video::factory()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $video = Video::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.video.destroy', ['video' => $video])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.video.destroy', ['video' => $video])); - /** - * The Video Destroy Endpoint shall forbid users from updating a video that is trashed. - */ - public function testTrashed(): void - { - $video = Video::factory()->trashed()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Video::class))->createOne(); +test('trashed', function () { + $video = Video::factory()->trashed()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Video::class))->createOne(); - $response = $this->delete(route('api.video.destroy', ['video' => $video])); + Sanctum::actingAs($user); - $response->assertNotFound(); - } + $response = delete(route('api.video.destroy', ['video' => $video])); - /** - * The Video Destroy Endpoint shall delete the video. - */ - public function testDeleted(): void - { - $video = Video::factory()->createOne(); + $response->assertNotFound(); +}); - $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Video::class))->createOne(); +test('deleted', function () { + $video = Video::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::DELETE->format(Video::class))->createOne(); - $response = $this->delete(route('api.video.destroy', ['video' => $video])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertSoftDeleted($video); - } -} + $response = delete(route('api.video.destroy', ['video' => $video])); + + $response->assertOk(); + $this->assertSoftDeleted($video); +}); diff --git a/tests/Feature/Http/Api/Wiki/Video/VideoForceDeleteTest.php b/tests/Feature/Http/Api/Wiki/Video/VideoForceDeleteTest.php index b8d7da5c7..0d5f1e63d 100644 --- a/tests/Feature/Http/Api/Wiki/Video/VideoForceDeleteTest.php +++ b/tests/Feature/Http/Api/Wiki/Video/VideoForceDeleteTest.php @@ -2,58 +2,42 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Video; - use App\Enums\Auth\ExtendedCrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Video; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class VideoForceDeleteTest extends TestCase -{ - /** - * The Video Force Delete Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $video = Video::factory()->createOne(); +use function Pest\Laravel\delete; - $response = $this->delete(route('api.video.forceDelete', ['video' => $video])); +test('protected', function () { + $video = Video::factory()->createOne(); - $response->assertUnauthorized(); - } + $response = delete(route('api.video.forceDelete', ['video' => $video])); - /** - * The Video Force Delete Endpoint shall forbid users without the force delete video permission. - */ - public function testForbidden(): void - { - $video = Video::factory()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $video = Video::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->delete(route('api.video.forceDelete', ['video' => $video])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = delete(route('api.video.forceDelete', ['video' => $video])); - /** - * The Video Force Delete Endpoint shall force delete the video. - */ - public function testDeleted(): void - { - $video = Video::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::FORCE_DELETE->format(Video::class))->createOne(); +test('deleted', function () { + $video = Video::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::FORCE_DELETE->format(Video::class))->createOne(); - $response = $this->delete(route('api.video.forceDelete', ['video' => $video])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertModelMissing($video); - } -} + $response = delete(route('api.video.forceDelete', ['video' => $video])); + + $response->assertOk(); + $this->assertModelMissing($video); +}); diff --git a/tests/Feature/Http/Api/Wiki/Video/VideoIndexTest.php b/tests/Feature/Http/Api/Wiki/Video/VideoIndexTest.php index cabfbac98..42c52836f 100644 --- a/tests/Feature/Http/Api/Wiki/Video/VideoIndexTest.php +++ b/tests/Feature/Http/Api/Wiki/Video/VideoIndexTest.php @@ -2,9 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Video; - -use App\Concerns\Actions\Http\Api\SortsModels; use App\Constants\ModelConstants; use App\Contracts\Http\Api\Field\SortableField; use App\Enums\Http\Api\Filter\TrashedStatus; @@ -39,1007 +36,901 @@ use App\Models\Wiki\Video\VideoScript; use Illuminate\Database\Eloquent\Factories\Sequence; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsToMany; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; -use Tests\TestCase; - -class VideoIndexTest extends TestCase -{ - use SortsModels; - use WithFaker; - - /** - * By default, the Video Index Endpoint shall return a collection of Video Resources. - */ - public function testDefault(): void - { - $videos = Video::factory() - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $response = $this->get(route('api.video.index')); - - $response->assertJson( - json_decode( - json_encode( - new VideoCollection($videos, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Video Index Endpoint shall be paginated. - */ - public function testPaginated(): void - { - Video::factory() - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $response = $this->get(route('api.video.index')); - - $response->assertJsonStructure([ - VideoCollection::$wrap, - 'links', - 'meta', - ]); - } - - /** - * The Video Index Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new VideoSchema(); - - $allowedIncludes = collect($schema->allowedIncludes()); - - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); - - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; - - Video::factory() - ->count($this->faker->randomDigitNotNull()) - ->for(Audio::factory()) - ->has(VideoScript::factory(), Video::RELATION_SCRIPT) - ->has( - AnimeThemeEntry::factory() - ->count($this->faker->randomDigitNotNull()) - ->for(AnimeTheme::factory()->for(Anime::factory())) - ) - ->create(); - - $videos = Video::with($includedPaths->all())->get(); - - $response = $this->get(route('api.video.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new VideoCollection($videos, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Video Index Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new VideoSchema(); - - $fields = collect($schema->fields()); - - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); - - $parameters = [ - FieldParser::param() => [ - VideoResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; - - $videos = Video::factory() - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $response = $this->get(route('api.video.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new VideoCollection($videos, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Synonym Index Endpoint shall support sorting resources. - */ - public function testSorts(): void - { - $schema = new VideoSchema(); - - /** @var Sort $sort */ - $sort = collect($schema->fields()) - ->filter(fn (Field $field) => $field instanceof SortableField) - ->map(fn (SortableField $field) => $field->getSort()) - ->random(); - - $parameters = [ - SortParser::param() => $sort->format(Arr::random(Direction::cases())), - ]; - - $query = new Query($parameters); - - Video::factory() - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $response = $this->get(route('api.video.index', $parameters)); - - $videos = $this->sort(Video::query(), $query, $schema)->get(); - - $response->assertJson( - json_decode( - json_encode( - new VideoCollection($videos, $query) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Video Index Endpoint shall support filtering by created_at. - */ - public function testCreatedAtFilter(): void - { - $createdFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($createdFilter, function () { - Video::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - Carbon::withTestNow($excludedDate, function () { - Video::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - $video = Video::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); - - $response = $this->get(route('api.video.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new VideoCollection($video, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Video Index Endpoint shall support filtering by updated_at. - */ - public function testUpdatedAtFilter(): void - { - $updatedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($updatedFilter, function () { - Video::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - Carbon::withTestNow($excludedDate, function () { - Video::factory()->count($this->faker->randomDigitNotNull())->create(); - }); - - $video = Video::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); - - $response = $this->get(route('api.video.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new VideoCollection($video, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Video Index Endpoint shall support filtering by trashed. - */ - public function testWithoutTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITHOUT->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Video::factory()->count($this->faker->randomDigitNotNull())->create(); - - Video::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - - $video = Video::withoutTrashed()->get(); - - $response = $this->get(route('api.video.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new VideoCollection($video, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Video Index Endpoint shall support filtering by trashed. - */ - public function testWithTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Video::factory()->count($this->faker->randomDigitNotNull())->create(); - - Video::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - - $video = Video::withTrashed()->get(); - - $response = $this->get(route('api.video.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new VideoCollection($video, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Video Index Endpoint shall support filtering by trashed. - */ - public function testOnlyTrashedFilter(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => TrashedStatus::ONLY->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Video::factory()->count($this->faker->randomDigitNotNull())->create(); - - Video::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - - $video = Video::onlyTrashed()->get(); - - $response = $this->get(route('api.video.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new VideoCollection($video, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Video Index Endpoint shall support filtering by deleted_at. - */ - public function testDeletedAtFilter(): void - { - $deletedFilter = $this->faker->date(); - $excludedDate = $this->faker->date(); - - $parameters = [ - FilterParser::param() => [ - ModelConstants::ATTRIBUTE_DELETED_AT => $deletedFilter, - TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, - ], - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, - ], - ]; - - Carbon::withTestNow($deletedFilter, function () { - Video::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - }); - - Carbon::withTestNow($excludedDate, function () { - Video::factory()->trashed()->count($this->faker->randomDigitNotNull())->create(); - }); - - $video = Video::withTrashed()->where(ModelConstants::ATTRIBUTE_DELETED_AT, $deletedFilter)->get(); - - $response = $this->get(route('api.video.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new VideoCollection($video, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Video Index Endpoint shall support filtering by lyrics. - */ - public function testLyricsFilter(): void - { - $lyricsFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_LYRICS => $lyricsFilter, - ], - ]; - - Video::factory() - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $videos = Video::query()->where(Video::ATTRIBUTE_LYRICS, $lyricsFilter)->get(); - - $response = $this->get(route('api.video.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new VideoCollection($videos, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Video Index Endpoint shall support filtering by nc. - */ - public function testNcFilter(): void - { - $ncFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_NC => $ncFilter, - ], - ]; - - Video::factory() - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $videos = Video::query()->where(Video::ATTRIBUTE_NC, $ncFilter)->get(); - - $response = $this->get(route('api.video.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new VideoCollection($videos, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Video Index Endpoint shall support filtering by overlap. - */ - public function testOverlapFilter(): void - { - $overlapFilter = Arr::random(VideoOverlap::cases()); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_OVERLAP => $overlapFilter->localize(), - ], - ]; - - Video::factory() - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $videos = Video::query()->where(Video::ATTRIBUTE_OVERLAP, $overlapFilter->value)->get(); - - $response = $this->get(route('api.video.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new VideoCollection($videos, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Video Index Endpoint shall support filtering by resolution. - */ - public function testResolutionFilter(): void - { - $resolutionFilter = $this->faker->randomNumber(); - $excludedResolution = $resolutionFilter + 1; - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_RESOLUTION => $resolutionFilter, - ], - ]; - - Video::factory() - ->count($this->faker->randomDigitNotNull()) - ->state(new Sequence( - [Video::ATTRIBUTE_RESOLUTION => $resolutionFilter], - [Video::ATTRIBUTE_RESOLUTION => $excludedResolution], - )) - ->create(); - - $videos = Video::query()->where(Video::ATTRIBUTE_RESOLUTION, $resolutionFilter)->get(); - - $response = $this->get(route('api.video.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new VideoCollection($videos, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Video Index Endpoint shall support filtering by source. - */ - public function testSourceFilter(): void - { - $sourceFilter = Arr::random(VideoSource::cases()); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_SOURCE => $sourceFilter->localize(), - ], - ]; - - Video::factory() - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $videos = Video::query()->where(Video::ATTRIBUTE_SOURCE, $sourceFilter->value)->get(); - - $response = $this->get(route('api.video.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new VideoCollection($videos, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Video Index Endpoint shall support filtering by subbed. - */ - public function testSubbedFilter(): void - { - $subbedFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_SUBBED => $subbedFilter, - ], - ]; - - Video::factory() - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $videos = Video::query()->where(Video::ATTRIBUTE_SUBBED, $subbedFilter)->get(); - - $response = $this->get(route('api.video.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new VideoCollection($videos, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Video Index Endpoint shall support filtering by uncen. - */ - public function testUncenFilter(): void - { - $uncenFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - Video::ATTRIBUTE_UNCEN => $uncenFilter, - ], - ]; - - Video::factory() - ->count($this->faker->randomDigitNotNull()) - ->create(); - - $videos = Video::query()->where(Video::ATTRIBUTE_UNCEN, $uncenFilter)->get(); - - $response = $this->get(route('api.video.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new VideoCollection($videos, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Video Index Endpoint shall support constrained eager loading of entries by nsfw. - */ - public function testEntriesByNsfw(): void - { - $nsfwFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - AnimeThemeEntry::ATTRIBUTE_NSFW => $nsfwFilter, - ], - IncludeParser::param() => Video::RELATION_ANIMETHEMEENTRIES, - ]; - - Video::factory() - ->count($this->faker->randomDigitNotNull()) - ->has( - AnimeThemeEntry::factory() - ->count($this->faker->randomDigitNotNull()) - ->for(AnimeTheme::factory()->for(Anime::factory())) - ) - ->create(); - - $videos = Video::with([ - Video::RELATION_ANIMETHEMEENTRIES => function (BelongsToMany $query) use ($nsfwFilter) { - $query->where(AnimeThemeEntry::ATTRIBUTE_NSFW, $nsfwFilter); - }, - ]) - ->get(); - - $response = $this->get(route('api.video.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new VideoCollection($videos, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Video Index Endpoint shall support constrained eager loading of entries by spoiler. - */ - public function testEntriesBySpoiler(): void - { - $spoilerFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - AnimeThemeEntry::ATTRIBUTE_SPOILER => $spoilerFilter, - ], - IncludeParser::param() => Video::RELATION_ANIMETHEMEENTRIES, - ]; - - Video::factory() - ->count($this->faker->randomDigitNotNull()) - ->has( - AnimeThemeEntry::factory() - ->count($this->faker->randomDigitNotNull()) - ->for(AnimeTheme::factory()->for(Anime::factory())) - ) - ->create(); - - $videos = Video::with([ - Video::RELATION_ANIMETHEMEENTRIES => function (BelongsToMany $query) use ($spoilerFilter) { - $query->where(AnimeThemeEntry::ATTRIBUTE_SPOILER, $spoilerFilter); - }, - ]) - ->get(); - - $response = $this->get(route('api.video.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new VideoCollection($videos, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Video Index Endpoint shall support constrained eager loading of entries by version. - */ - public function testEntriesByVersion(): void - { - $versionFilter = $this->faker->randomDigitNotNull(); - $excludedVersion = $versionFilter + 1; - - $parameters = [ - FilterParser::param() => [ - AnimeThemeEntry::ATTRIBUTE_VERSION => $versionFilter, - ], - IncludeParser::param() => Video::RELATION_ANIMETHEMEENTRIES, - ]; - - Video::factory() - ->count($this->faker->randomDigitNotNull()) - ->has( - AnimeThemeEntry::factory() - ->count($this->faker->randomDigitNotNull()) - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->state(new Sequence( - [AnimeThemeEntry::ATTRIBUTE_VERSION => $versionFilter], - [AnimeThemeEntry::ATTRIBUTE_VERSION => $excludedVersion], - )) - ) - ->create(); - - $videos = Video::with([ - Video::RELATION_ANIMETHEMEENTRIES => function (BelongsToMany $query) use ($versionFilter) { - $query->where(AnimeThemeEntry::ATTRIBUTE_VERSION, $versionFilter); - }, - ]) - ->get(); - - $response = $this->get(route('api.video.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new VideoCollection($videos, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Video Index Endpoint shall support constrained eager loading of themes by sequence. - */ - public function testThemesBySequence(): void - { - $sequenceFilter = $this->faker->randomDigitNotNull(); - $excludedSequence = $sequenceFilter + 1; - - $parameters = [ - FilterParser::param() => [ - AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter, - ], - IncludeParser::param() => Video::RELATION_ANIMETHEME, - ]; - - Video::factory() - ->count($this->faker->randomDigitNotNull()) - ->has( - AnimeThemeEntry::factory() - ->count($this->faker->randomDigitNotNull()) - ->for( - AnimeTheme::factory() - ->for(Anime::factory()) - ->state([ - AnimeTheme::ATTRIBUTE_SEQUENCE => $this->faker->boolean() ? $sequenceFilter : $excludedSequence, - ]) - ) - ) - ->create(); - - $videos = Video::with([ - Video::RELATION_ANIMETHEME => function (BelongsTo $query) use ($sequenceFilter) { - $query->where(AnimeTheme::ATTRIBUTE_SEQUENCE, $sequenceFilter); - }, - ]) - ->get(); - - $response = $this->get(route('api.video.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new VideoCollection($videos, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Video Index Endpoint shall support constrained eager loading of themes by type. - */ - public function testThemesByType(): void - { - $typeFilter = Arr::random(ThemeType::cases()); - - $parameters = [ - FilterParser::param() => [ - AnimeTheme::ATTRIBUTE_TYPE => $typeFilter->localize(), - ], - IncludeParser::param() => Video::RELATION_ANIMETHEME, - ]; - - Video::factory() - ->count($this->faker->randomDigitNotNull()) - ->has( - AnimeThemeEntry::factory() - ->count($this->faker->randomDigitNotNull()) - ->for(AnimeTheme::factory()->for(Anime::factory())) - ) - ->create(); - - $videos = Video::with([ - Video::RELATION_ANIMETHEME => function (BelongsTo $query) use ($typeFilter) { - $query->where(AnimeTheme::ATTRIBUTE_TYPE, $typeFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.video.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new VideoCollection($videos, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Video Index Endpoint shall support constrained eager loading of anime by media format. - */ - public function testAnimeByMediaFormat(): void - { - $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), - ], - IncludeParser::param() => Video::RELATION_ANIME, - ]; - - Video::factory() - ->count($this->faker->randomDigitNotNull()) - ->has( - AnimeThemeEntry::factory() - ->count($this->faker->randomDigitNotNull()) - ->for(AnimeTheme::factory()->for(Anime::factory())) - ) - ->create(); - - $videos = Video::with([ - Video::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { - $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.video.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new VideoCollection($videos, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Video Index Endpoint shall support constrained eager loading of anime by season. - */ - public function testAnimeBySeason(): void - { - $seasonFilter = Arr::random(AnimeSeason::cases()); - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), - ], - IncludeParser::param() => Video::RELATION_ANIME, - ]; - - Video::factory() - ->count($this->faker->randomDigitNotNull()) - ->has( - AnimeThemeEntry::factory() - ->count($this->faker->randomDigitNotNull()) - ->for(AnimeTheme::factory()->for(Anime::factory())) - ) - ->create(); - - $videos = Video::with([ - Video::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { - $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); - }, - ]) - ->get(); - - $response = $this->get(route('api.video.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new VideoCollection($videos, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Video Index Endpoint shall support constrained eager loading of anime by year. - */ - public function testAnimeByYear(): void - { - $yearFilter = intval($this->faker->year()); - $excludedYear = $yearFilter + 1; - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_YEAR => $yearFilter, - ], - IncludeParser::param() => Video::RELATION_ANIME, - ]; - - Video::factory() - ->count($this->faker->randomDigitNotNull()) - ->has( - AnimeThemeEntry::factory() - ->count($this->faker->randomDigitNotNull()) - ->for( - AnimeTheme::factory() - ->for( - Anime::factory() - ->state([ - Anime::ATTRIBUTE_YEAR => $this->faker->boolean() ? $yearFilter : $excludedYear, - ]) - ) - ) - ) - ->create(); - - $videos = Video::with([ - Video::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { - $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); - }, - ]) - ->get(); - - $response = $this->get(route('api.video.index', $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new VideoCollection($videos, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + +use function Pest\Laravel\get; + +uses(App\Concerns\Actions\Http\Api\SortsModels::class); + +uses(Illuminate\Foundation\Testing\WithFaker::class); + +test('default', function () { + $videos = Video::factory() + ->count(fake()->randomDigitNotNull()) + ->create(); + + $response = get(route('api.video.index')); + + $response->assertJson( + json_decode( + json_encode( + new VideoCollection($videos, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('paginated', function () { + Video::factory() + ->count(fake()->randomDigitNotNull()) + ->create(); + + $response = get(route('api.video.index')); + + $response->assertJsonStructure([ + VideoCollection::$wrap, + 'links', + 'meta', + ]); +}); + +test('allowed include paths', function () { + $schema = new VideoSchema(); + + $allowedIncludes = collect($schema->allowedIncludes()); + + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); + + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; + + Video::factory() + ->count(fake()->randomDigitNotNull()) + ->for(Audio::factory()) + ->has(VideoScript::factory(), Video::RELATION_SCRIPT) + ->has( + AnimeThemeEntry::factory() + ->count(fake()->randomDigitNotNull()) + ->for(AnimeTheme::factory()->for(Anime::factory())) + ) + ->create(); + + $videos = Video::with($includedPaths->all())->get(); + + $response = get(route('api.video.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new VideoCollection($videos, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sparse fieldsets', function () { + $schema = new VideoSchema(); + + $fields = collect($schema->fields()); + + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + VideoResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + $videos = Video::factory() + ->count(fake()->randomDigitNotNull()) + ->create(); + + $response = get(route('api.video.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new VideoCollection($videos, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sorts', function () { + $schema = new VideoSchema(); + + /** @var Sort $sort */ + $sort = collect($schema->fields()) + ->filter(fn (Field $field) => $field instanceof SortableField) + ->map(fn (SortableField $field) => $field->getSort()) + ->random(); + + $parameters = [ + SortParser::param() => $sort->format(Arr::random(Direction::cases())), + ]; + + $query = new Query($parameters); + + Video::factory() + ->count(fake()->randomDigitNotNull()) + ->create(); + + $response = get(route('api.video.index', $parameters)); + + $videos = $this->sort(Video::query(), $query, $schema)->get(); + + $response->assertJson( + json_decode( + json_encode( + new VideoCollection($videos, $query) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('created at filter', function () { + $createdFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_CREATED_AT => $createdFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($createdFilter, function () { + Video::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + Carbon::withTestNow($excludedDate, function () { + Video::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + $video = Video::query()->where(BaseModel::ATTRIBUTE_CREATED_AT, $createdFilter)->get(); + + $response = get(route('api.video.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new VideoCollection($video, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('updated at filter', function () { + $updatedFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + BaseModel::ATTRIBUTE_UPDATED_AT => $updatedFilter, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($updatedFilter, function () { + Video::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + Carbon::withTestNow($excludedDate, function () { + Video::factory()->count(fake()->randomDigitNotNull())->create(); + }); + + $video = Video::query()->where(BaseModel::ATTRIBUTE_UPDATED_AT, $updatedFilter)->get(); + + $response = get(route('api.video.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new VideoCollection($video, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('without trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITHOUT->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Video::factory()->count(fake()->randomDigitNotNull())->create(); + + Video::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + + $video = Video::withoutTrashed()->get(); + + $response = get(route('api.video.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new VideoCollection($video, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('with trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Video::factory()->count(fake()->randomDigitNotNull())->create(); + + Video::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + + $video = Video::withTrashed()->get(); + + $response = get(route('api.video.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new VideoCollection($video, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('only trashed filter', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => TrashedStatus::ONLY->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Video::factory()->count(fake()->randomDigitNotNull())->create(); + + Video::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + + $video = Video::onlyTrashed()->get(); + + $response = get(route('api.video.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new VideoCollection($video, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('deleted at filter', function () { + $deletedFilter = fake()->date(); + $excludedDate = fake()->date(); + + $parameters = [ + FilterParser::param() => [ + ModelConstants::ATTRIBUTE_DELETED_AT => $deletedFilter, + TrashedCriteria::PARAM_VALUE => TrashedStatus::WITH->value, + ], + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => Criteria::MAX_RESULTS, + ], + ]; + + Carbon::withTestNow($deletedFilter, function () { + Video::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + }); + + Carbon::withTestNow($excludedDate, function () { + Video::factory()->trashed()->count(fake()->randomDigitNotNull())->create(); + }); + + $video = Video::withTrashed()->where(ModelConstants::ATTRIBUTE_DELETED_AT, $deletedFilter)->get(); + + $response = get(route('api.video.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new VideoCollection($video, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('lyrics filter', function () { + $lyricsFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_LYRICS => $lyricsFilter, + ], + ]; + + Video::factory() + ->count(fake()->randomDigitNotNull()) + ->create(); + + $videos = Video::query()->where(Video::ATTRIBUTE_LYRICS, $lyricsFilter)->get(); + + $response = get(route('api.video.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new VideoCollection($videos, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('nc filter', function () { + $ncFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_NC => $ncFilter, + ], + ]; + + Video::factory() + ->count(fake()->randomDigitNotNull()) + ->create(); + + $videos = Video::query()->where(Video::ATTRIBUTE_NC, $ncFilter)->get(); + + $response = get(route('api.video.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new VideoCollection($videos, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('overlap filter', function () { + $overlapFilter = Arr::random(VideoOverlap::cases()); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_OVERLAP => $overlapFilter->localize(), + ], + ]; + + Video::factory() + ->count(fake()->randomDigitNotNull()) + ->create(); + + $videos = Video::query()->where(Video::ATTRIBUTE_OVERLAP, $overlapFilter->value)->get(); + + $response = get(route('api.video.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new VideoCollection($videos, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('resolution filter', function () { + $resolutionFilter = fake()->randomNumber(); + $excludedResolution = $resolutionFilter + 1; + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_RESOLUTION => $resolutionFilter, + ], + ]; + + Video::factory() + ->count(fake()->randomDigitNotNull()) + ->state(new Sequence( + [Video::ATTRIBUTE_RESOLUTION => $resolutionFilter], + [Video::ATTRIBUTE_RESOLUTION => $excludedResolution], + )) + ->create(); + + $videos = Video::query()->where(Video::ATTRIBUTE_RESOLUTION, $resolutionFilter)->get(); + + $response = get(route('api.video.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new VideoCollection($videos, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('source filter', function () { + $sourceFilter = Arr::random(VideoSource::cases()); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_SOURCE => $sourceFilter->localize(), + ], + ]; + + Video::factory() + ->count(fake()->randomDigitNotNull()) + ->create(); + + $videos = Video::query()->where(Video::ATTRIBUTE_SOURCE, $sourceFilter->value)->get(); + + $response = get(route('api.video.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new VideoCollection($videos, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('subbed filter', function () { + $subbedFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_SUBBED => $subbedFilter, + ], + ]; + + Video::factory() + ->count(fake()->randomDigitNotNull()) + ->create(); + + $videos = Video::query()->where(Video::ATTRIBUTE_SUBBED, $subbedFilter)->get(); + + $response = get(route('api.video.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new VideoCollection($videos, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('uncen filter', function () { + $uncenFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + Video::ATTRIBUTE_UNCEN => $uncenFilter, + ], + ]; + + Video::factory() + ->count(fake()->randomDigitNotNull()) + ->create(); + + $videos = Video::query()->where(Video::ATTRIBUTE_UNCEN, $uncenFilter)->get(); + + $response = get(route('api.video.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new VideoCollection($videos, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('entries by nsfw', function () { + $nsfwFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + AnimeThemeEntry::ATTRIBUTE_NSFW => $nsfwFilter, + ], + IncludeParser::param() => Video::RELATION_ANIMETHEMEENTRIES, + ]; + + Video::factory() + ->count(fake()->randomDigitNotNull()) + ->has( + AnimeThemeEntry::factory() + ->count(fake()->randomDigitNotNull()) + ->for(AnimeTheme::factory()->for(Anime::factory())) + ) + ->create(); + + $videos = Video::with([ + Video::RELATION_ANIMETHEMEENTRIES => function (BelongsToMany $query) use ($nsfwFilter) { + $query->where(AnimeThemeEntry::ATTRIBUTE_NSFW, $nsfwFilter); + }, + ]) + ->get(); + + $response = get(route('api.video.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new VideoCollection($videos, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('entries by spoiler', function () { + $spoilerFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + AnimeThemeEntry::ATTRIBUTE_SPOILER => $spoilerFilter, + ], + IncludeParser::param() => Video::RELATION_ANIMETHEMEENTRIES, + ]; + + Video::factory() + ->count(fake()->randomDigitNotNull()) + ->has( + AnimeThemeEntry::factory() + ->count(fake()->randomDigitNotNull()) + ->for(AnimeTheme::factory()->for(Anime::factory())) + ) + ->create(); + + $videos = Video::with([ + Video::RELATION_ANIMETHEMEENTRIES => function (BelongsToMany $query) use ($spoilerFilter) { + $query->where(AnimeThemeEntry::ATTRIBUTE_SPOILER, $spoilerFilter); + }, + ]) + ->get(); + + $response = get(route('api.video.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new VideoCollection($videos, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('entries by version', function () { + $versionFilter = fake()->randomDigitNotNull(); + $excludedVersion = $versionFilter + 1; + + $parameters = [ + FilterParser::param() => [ + AnimeThemeEntry::ATTRIBUTE_VERSION => $versionFilter, + ], + IncludeParser::param() => Video::RELATION_ANIMETHEMEENTRIES, + ]; + + Video::factory() + ->count(fake()->randomDigitNotNull()) + ->has( + AnimeThemeEntry::factory() + ->count(fake()->randomDigitNotNull()) + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->state(new Sequence( + [AnimeThemeEntry::ATTRIBUTE_VERSION => $versionFilter], + [AnimeThemeEntry::ATTRIBUTE_VERSION => $excludedVersion], + )) + ) + ->create(); + + $videos = Video::with([ + Video::RELATION_ANIMETHEMEENTRIES => function (BelongsToMany $query) use ($versionFilter) { + $query->where(AnimeThemeEntry::ATTRIBUTE_VERSION, $versionFilter); + }, + ]) + ->get(); + + $response = get(route('api.video.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new VideoCollection($videos, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('themes by sequence', function () { + $sequenceFilter = fake()->randomDigitNotNull(); + $excludedSequence = $sequenceFilter + 1; + + $parameters = [ + FilterParser::param() => [ + AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter, + ], + IncludeParser::param() => Video::RELATION_ANIMETHEME, + ]; + + Video::factory() + ->count(fake()->randomDigitNotNull()) + ->has( + AnimeThemeEntry::factory() + ->count(fake()->randomDigitNotNull()) + ->for( + AnimeTheme::factory() + ->for(Anime::factory()) + ->state([ + AnimeTheme::ATTRIBUTE_SEQUENCE => fake()->boolean() ? $sequenceFilter : $excludedSequence, + ]) + ) + ) + ->create(); + + $videos = Video::with([ + Video::RELATION_ANIMETHEME => function (BelongsTo $query) use ($sequenceFilter) { + $query->where(AnimeTheme::ATTRIBUTE_SEQUENCE, $sequenceFilter); + }, + ]) + ->get(); + + $response = get(route('api.video.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new VideoCollection($videos, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('themes by type', function () { + $typeFilter = Arr::random(ThemeType::cases()); + + $parameters = [ + FilterParser::param() => [ + AnimeTheme::ATTRIBUTE_TYPE => $typeFilter->localize(), + ], + IncludeParser::param() => Video::RELATION_ANIMETHEME, + ]; + + Video::factory() + ->count(fake()->randomDigitNotNull()) + ->has( + AnimeThemeEntry::factory() + ->count(fake()->randomDigitNotNull()) + ->for(AnimeTheme::factory()->for(Anime::factory())) + ) + ->create(); + + $videos = Video::with([ + Video::RELATION_ANIMETHEME => function (BelongsTo $query) use ($typeFilter) { + $query->where(AnimeTheme::ATTRIBUTE_TYPE, $typeFilter->value); + }, + ]) + ->get(); + + $response = get(route('api.video.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new VideoCollection($videos, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by media format', function () { + $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), + ], + IncludeParser::param() => Video::RELATION_ANIME, + ]; + + Video::factory() + ->count(fake()->randomDigitNotNull()) + ->has( + AnimeThemeEntry::factory() + ->count(fake()->randomDigitNotNull()) + ->for(AnimeTheme::factory()->for(Anime::factory())) + ) + ->create(); + + $videos = Video::with([ + Video::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { + $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); + }, + ]) + ->get(); + + $response = get(route('api.video.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new VideoCollection($videos, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by season', function () { + $seasonFilter = Arr::random(AnimeSeason::cases()); + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), + ], + IncludeParser::param() => Video::RELATION_ANIME, + ]; + + Video::factory() + ->count(fake()->randomDigitNotNull()) + ->has( + AnimeThemeEntry::factory() + ->count(fake()->randomDigitNotNull()) + ->for(AnimeTheme::factory()->for(Anime::factory())) + ) + ->create(); + + $videos = Video::with([ + Video::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { + $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); + }, + ]) + ->get(); + + $response = get(route('api.video.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new VideoCollection($videos, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by year', function () { + $yearFilter = intval(fake()->year()); + $excludedYear = $yearFilter + 1; + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_YEAR => $yearFilter, + ], + IncludeParser::param() => Video::RELATION_ANIME, + ]; + + Video::factory() + ->count(fake()->randomDigitNotNull()) + ->has( + AnimeThemeEntry::factory() + ->count(fake()->randomDigitNotNull()) + ->for( + AnimeTheme::factory() + ->for( + Anime::factory() + ->state([ + Anime::ATTRIBUTE_YEAR => fake()->boolean() ? $yearFilter : $excludedYear, + ]) + ) + ) + ) + ->create(); + + $videos = Video::with([ + Video::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { + $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); + }, + ]) + ->get(); + + $response = get(route('api.video.index', $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new VideoCollection($videos, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Wiki/Video/VideoRestoreTest.php b/tests/Feature/Http/Api/Wiki/Video/VideoRestoreTest.php index 4f6b0dca6..d1facc9af 100644 --- a/tests/Feature/Http/Api/Wiki/Video/VideoRestoreTest.php +++ b/tests/Feature/Http/Api/Wiki/Video/VideoRestoreTest.php @@ -2,74 +2,54 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Video; - use App\Enums\Auth\ExtendedCrudPermission; use App\Models\Auth\User; use App\Models\Wiki\Video; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class VideoRestoreTest extends TestCase -{ - /** - * The Video Restore Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $video = Video::factory()->trashed()->createOne(); +use function Pest\Laravel\patch; - $response = $this->patch(route('api.video.restore', ['video' => $video])); +test('protected', function () { + $video = Video::factory()->trashed()->createOne(); - $response->assertUnauthorized(); - } + $response = patch(route('api.video.restore', ['video' => $video])); - /** - * The Video Restore Endpoint shall forbid users without the restore video permission. - */ - public function testForbidden(): void - { - $video = Video::factory()->trashed()->createOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $video = Video::factory()->trashed()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->patch(route('api.video.restore', ['video' => $video])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = patch(route('api.video.restore', ['video' => $video])); - /** - * The Video Restore Endpoint shall forbid users from restoring a video that isn't trashed. - */ - public function testTrashed(): void - { - $video = Video::factory()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(Video::class))->createOne(); +test('trashed', function () { + $video = Video::factory()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(Video::class))->createOne(); - $response = $this->patch(route('api.video.restore', ['video' => $video])); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = patch(route('api.video.restore', ['video' => $video])); - /** - * The Video Restore Endpoint shall restore the video. - */ - public function testRestored(): void - { - $video = Video::factory()->trashed()->createOne(); + $response->assertForbidden(); +}); - $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(Video::class))->createOne(); +test('restored', function () { + $video = Video::factory()->trashed()->createOne(); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(ExtendedCrudPermission::RESTORE->format(Video::class))->createOne(); - $response = $this->patch(route('api.video.restore', ['video' => $video])); + Sanctum::actingAs($user); - $response->assertOk(); - static::assertNotSoftDeleted($video); - } -} + $response = patch(route('api.video.restore', ['video' => $video])); + + $response->assertOk(); + $this->assertNotSoftDeleted($video); +}); diff --git a/tests/Feature/Http/Api/Wiki/Video/VideoShowTest.php b/tests/Feature/Http/Api/Wiki/Video/VideoShowTest.php index 5c04ec240..15d69c79a 100644 --- a/tests/Feature/Http/Api/Wiki/Video/VideoShowTest.php +++ b/tests/Feature/Http/Api/Wiki/Video/VideoShowTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Video; - use App\Enums\Models\Wiki\AnimeMediaFormat; use App\Enums\Models\Wiki\AnimeSeason; use App\Enums\Models\Wiki\ThemeType; @@ -24,484 +22,433 @@ use App\Models\Wiki\Video\VideoScript; use Illuminate\Database\Eloquent\Factories\Sequence; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsToMany; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; -use Tests\TestCase; - -class VideoShowTest extends TestCase -{ - use WithFaker; - - /** - * By default, the Video Show Endpoint shall return a Video Resource. - */ - public function testDefault(): void - { - $video = Video::factory()->create(); - - $response = $this->get(route('api.video.show', ['video' => $video])); - - $response->assertJson( - json_decode( - json_encode( - new VideoResource($video, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Video Show Endpoint shall return a Video Resource for soft deleted videos. - */ - public function testSoftDelete(): void - { - $video = Video::factory()->trashed()->createOne(); - - $response = $this->get(route('api.video.show', ['video' => $video])); - - $response->assertJson( - json_decode( - json_encode( - new VideoResource($video, new Query()) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Video Show Endpoint shall allow inclusion of related resources. - */ - public function testAllowedIncludePaths(): void - { - $schema = new VideoSchema(); - - $allowedIncludes = collect($schema->allowedIncludes()); - - $selectedIncludes = $allowedIncludes->random($this->faker->numberBetween(1, $allowedIncludes->count())); - - $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); - - $parameters = [ - IncludeParser::param() => $includedPaths->join(','), - ]; - - $video = Video::factory() - ->for(Audio::factory()) - ->has(VideoScript::factory(), Video::RELATION_SCRIPT) - ->has( - AnimeThemeEntry::factory() - ->count($this->faker->randomDigitNotNull()) - ->for(AnimeTheme::factory()->for(Anime::factory())) - ) - ->createOne(); - - $response = $this->get(route('api.video.show', ['video' => $video] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new VideoResource($video, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Video Show Endpoint shall implement sparse fieldsets. - */ - public function testSparseFieldsets(): void - { - $schema = new VideoSchema(); - - $fields = collect($schema->fields()); - - $includedFields = $fields->random($this->faker->numberBetween(1, $fields->count())); - - $parameters = [ - FieldParser::param() => [ - VideoResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), - ], - ]; - - $video = Video::factory()->create(); - - $response = $this->get(route('api.video.show', ['video' => $video] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new VideoResource($video, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Video Show Endpoint shall support constrained eager loading of entries by nsfw. - */ - public function testEntriesByNsfw(): void - { - $nsfwFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - AnimeThemeEntry::ATTRIBUTE_NSFW => $nsfwFilter, - ], - IncludeParser::param() => Video::RELATION_ANIMETHEMEENTRIES, - ]; - - $video = Video::factory() - ->has( - AnimeThemeEntry::factory() - ->count($this->faker->randomDigitNotNull()) - ->for(AnimeTheme::factory()->for(Anime::factory())) - ) - ->createOne(); - - $video->unsetRelations()->load([ - Video::RELATION_ANIMETHEMEENTRIES => function (BelongsToMany $query) use ($nsfwFilter) { - $query->where(AnimeThemeEntry::ATTRIBUTE_NSFW, $nsfwFilter); - }, - ]); - - $response = $this->get(route('api.video.show', ['video' => $video] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new VideoResource($video, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Video Show Endpoint shall support constrained eager loading of entries by spoiler. - */ - public function testEntriesBySpoiler(): void - { - $spoilerFilter = $this->faker->boolean(); - - $parameters = [ - FilterParser::param() => [ - AnimeThemeEntry::ATTRIBUTE_SPOILER => $spoilerFilter, - ], - IncludeParser::param() => Video::RELATION_ANIMETHEMEENTRIES, - ]; - - $video = Video::factory() - ->has( - AnimeThemeEntry::factory() - ->count($this->faker->randomDigitNotNull()) - ->for(AnimeTheme::factory()->for(Anime::factory())) - ) - ->createOne(); - - $video->unsetRelations()->load([ - Video::RELATION_ANIMETHEMEENTRIES => function (BelongsToMany $query) use ($spoilerFilter) { - $query->where(AnimeThemeEntry::ATTRIBUTE_SPOILER, $spoilerFilter); - }, - ]); - - $response = $this->get(route('api.video.show', ['video' => $video] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new VideoResource($video, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Video Show Endpoint shall support constrained eager loading of entries by version. - */ - public function testEntriesByVersion(): void - { - $versionFilter = $this->faker->randomDigitNotNull(); - $excludedVersion = $versionFilter + 1; - - $parameters = [ - FilterParser::param() => [ - AnimeThemeEntry::ATTRIBUTE_VERSION => $versionFilter, - ], - IncludeParser::param() => Video::RELATION_ANIMETHEMEENTRIES, - ]; - - $video = Video::factory() - ->has( - AnimeThemeEntry::factory() - ->count($this->faker->randomDigitNotNull()) - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->state(new Sequence( - [AnimeThemeEntry::ATTRIBUTE_VERSION => $versionFilter], - [AnimeThemeEntry::ATTRIBUTE_VERSION => $excludedVersion], - )) - ) - ->createOne(); - - $video->unsetRelations()->load([ - Video::RELATION_ANIMETHEMEENTRIES => function (BelongsToMany $query) use ($versionFilter) { - $query->where(AnimeThemeEntry::ATTRIBUTE_VERSION, $versionFilter); - }, - ]); - - $response = $this->get(route('api.video.show', ['video' => $video] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new VideoResource($video, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Video Show Endpoint shall support constrained eager loading of themes by sequence. - */ - public function testThemesBySequence(): void - { - $sequenceFilter = $this->faker->randomDigitNotNull(); - $excludedSequence = $sequenceFilter + 1; - - $parameters = [ - FilterParser::param() => [ - AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter, - ], - IncludeParser::param() => Video::RELATION_ANIMETHEME, - ]; - - $video = Video::factory() - ->has( - AnimeThemeEntry::factory() - ->count($this->faker->randomDigitNotNull()) - ->for( - AnimeTheme::factory() - ->for(Anime::factory()) - ->state([ - AnimeTheme::ATTRIBUTE_SEQUENCE => $this->faker->boolean() ? $sequenceFilter : $excludedSequence, - ]) - ) - ) - ->createOne(); - - $video->unsetRelations()->load([ - Video::RELATION_ANIMETHEME => function (BelongsTo $query) use ($sequenceFilter) { - $query->where(AnimeTheme::ATTRIBUTE_SEQUENCE, $sequenceFilter); - }, - ]); - - $response = $this->get(route('api.video.show', ['video' => $video] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new VideoResource($video, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Video Show Endpoint shall support constrained eager loading of themes by type. - */ - public function testThemesByType(): void - { - $typeFilter = Arr::random(ThemeType::cases()); - - $parameters = [ - FilterParser::param() => [ - AnimeTheme::ATTRIBUTE_TYPE => $typeFilter->localize(), - ], - IncludeParser::param() => Video::RELATION_ANIMETHEME, - ]; - - $video = Video::factory() - ->has( - AnimeThemeEntry::factory() - ->count($this->faker->randomDigitNotNull()) - ->for(AnimeTheme::factory()->for(Anime::factory())) - ) - ->createOne(); - - $video->unsetRelations()->load([ - Video::RELATION_ANIMETHEME => function (BelongsTo $query) use ($typeFilter) { - $query->where(AnimeTheme::ATTRIBUTE_TYPE, $typeFilter->value); - }, - ]); - - $response = $this->get(route('api.video.show', ['video' => $video] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new VideoResource($video, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Video Show Endpoint shall support constrained eager loading of anime by media format. - */ - public function testAnimeByMediaFormat(): void - { - $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), - ], - IncludeParser::param() => Video::RELATION_ANIME, - ]; - - $video = Video::factory() - ->has( - AnimeThemeEntry::factory() - ->count($this->faker->randomDigitNotNull()) - ->for(AnimeTheme::factory()->for(Anime::factory())) - ) - ->createOne(); - - $video->unsetRelations()->load([ - Video::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { - $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); - }, - ]); - - $response = $this->get(route('api.video.show', ['video' => $video] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new VideoResource($video, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Video Show Endpoint shall support constrained eager loading of anime by season. - */ - public function testAnimeBySeason(): void - { - $seasonFilter = Arr::random(AnimeSeason::cases()); - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), - ], - IncludeParser::param() => Video::RELATION_ANIME, - ]; - - $video = Video::factory() - ->has( - AnimeThemeEntry::factory() - ->count($this->faker->randomDigitNotNull()) - ->for(AnimeTheme::factory()->for(Anime::factory())) - ) - ->createOne(); - - $video->unsetRelations()->load([ - Video::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { - $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); - }, - ]); - - $response = $this->get(route('api.video.show', ['video' => $video] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new VideoResource($video, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } - - /** - * The Video Show Endpoint shall support constrained eager loading of anime by year. - */ - public function testAnimeByYear(): void - { - $yearFilter = intval($this->faker->year()); - $excludedYear = $yearFilter + 1; - - $parameters = [ - FilterParser::param() => [ - Anime::ATTRIBUTE_YEAR => $yearFilter, - ], - IncludeParser::param() => Video::RELATION_ANIME, - ]; - - $video = Video::factory() - ->has( - AnimeThemeEntry::factory() - ->count($this->faker->randomDigitNotNull()) - ->for( - AnimeTheme::factory() - ->for( - Anime::factory() - ->state([ - Anime::ATTRIBUTE_YEAR => $this->faker->boolean() ? $yearFilter : $excludedYear, - ]) - ) - ) - ) - ->createOne(); - - $video->unsetRelations()->load([ - Video::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { - $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); - }, - ]); - - $response = $this->get(route('api.video.show', ['video' => $video] + $parameters)); - - $response->assertJson( - json_decode( - json_encode( - new VideoResource($video, new Query($parameters)) - ->response() - ->getData() - ), - true - ) - ); - } -} + +use function Pest\Laravel\get; + +uses(Illuminate\Foundation\Testing\WithFaker::class); + +test('default', function () { + $video = Video::factory()->create(); + + $response = get(route('api.video.show', ['video' => $video])); + + $response->assertJson( + json_decode( + json_encode( + new VideoResource($video, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('soft delete', function () { + $video = Video::factory()->trashed()->createOne(); + + $response = get(route('api.video.show', ['video' => $video])); + + $response->assertJson( + json_decode( + json_encode( + new VideoResource($video, new Query()) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('allowed include paths', function () { + $schema = new VideoSchema(); + + $allowedIncludes = collect($schema->allowedIncludes()); + + $selectedIncludes = $allowedIncludes->random(fake()->numberBetween(1, $allowedIncludes->count())); + + $includedPaths = $selectedIncludes->map(fn (AllowedInclude $include) => $include->path()); + + $parameters = [ + IncludeParser::param() => $includedPaths->join(','), + ]; + + $video = Video::factory() + ->for(Audio::factory()) + ->has(VideoScript::factory(), Video::RELATION_SCRIPT) + ->has( + AnimeThemeEntry::factory() + ->count(fake()->randomDigitNotNull()) + ->for(AnimeTheme::factory()->for(Anime::factory())) + ) + ->createOne(); + + $response = get(route('api.video.show', ['video' => $video] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new VideoResource($video, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('sparse fieldsets', function () { + $schema = new VideoSchema(); + + $fields = collect($schema->fields()); + + $includedFields = $fields->random(fake()->numberBetween(1, $fields->count())); + + $parameters = [ + FieldParser::param() => [ + VideoResource::$wrap => $includedFields->map(fn (Field $field) => $field->getKey())->join(','), + ], + ]; + + $video = Video::factory()->create(); + + $response = get(route('api.video.show', ['video' => $video] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new VideoResource($video, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('entries by nsfw', function () { + $nsfwFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + AnimeThemeEntry::ATTRIBUTE_NSFW => $nsfwFilter, + ], + IncludeParser::param() => Video::RELATION_ANIMETHEMEENTRIES, + ]; + + $video = Video::factory() + ->has( + AnimeThemeEntry::factory() + ->count(fake()->randomDigitNotNull()) + ->for(AnimeTheme::factory()->for(Anime::factory())) + ) + ->createOne(); + + $video->unsetRelations()->load([ + Video::RELATION_ANIMETHEMEENTRIES => function (BelongsToMany $query) use ($nsfwFilter) { + $query->where(AnimeThemeEntry::ATTRIBUTE_NSFW, $nsfwFilter); + }, + ]); + + $response = get(route('api.video.show', ['video' => $video] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new VideoResource($video, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('entries by spoiler', function () { + $spoilerFilter = fake()->boolean(); + + $parameters = [ + FilterParser::param() => [ + AnimeThemeEntry::ATTRIBUTE_SPOILER => $spoilerFilter, + ], + IncludeParser::param() => Video::RELATION_ANIMETHEMEENTRIES, + ]; + + $video = Video::factory() + ->has( + AnimeThemeEntry::factory() + ->count(fake()->randomDigitNotNull()) + ->for(AnimeTheme::factory()->for(Anime::factory())) + ) + ->createOne(); + + $video->unsetRelations()->load([ + Video::RELATION_ANIMETHEMEENTRIES => function (BelongsToMany $query) use ($spoilerFilter) { + $query->where(AnimeThemeEntry::ATTRIBUTE_SPOILER, $spoilerFilter); + }, + ]); + + $response = get(route('api.video.show', ['video' => $video] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new VideoResource($video, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('entries by version', function () { + $versionFilter = fake()->randomDigitNotNull(); + $excludedVersion = $versionFilter + 1; + + $parameters = [ + FilterParser::param() => [ + AnimeThemeEntry::ATTRIBUTE_VERSION => $versionFilter, + ], + IncludeParser::param() => Video::RELATION_ANIMETHEMEENTRIES, + ]; + + $video = Video::factory() + ->has( + AnimeThemeEntry::factory() + ->count(fake()->randomDigitNotNull()) + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->state(new Sequence( + [AnimeThemeEntry::ATTRIBUTE_VERSION => $versionFilter], + [AnimeThemeEntry::ATTRIBUTE_VERSION => $excludedVersion], + )) + ) + ->createOne(); + + $video->unsetRelations()->load([ + Video::RELATION_ANIMETHEMEENTRIES => function (BelongsToMany $query) use ($versionFilter) { + $query->where(AnimeThemeEntry::ATTRIBUTE_VERSION, $versionFilter); + }, + ]); + + $response = get(route('api.video.show', ['video' => $video] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new VideoResource($video, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('themes by sequence', function () { + $sequenceFilter = fake()->randomDigitNotNull(); + $excludedSequence = $sequenceFilter + 1; + + $parameters = [ + FilterParser::param() => [ + AnimeTheme::ATTRIBUTE_SEQUENCE => $sequenceFilter, + ], + IncludeParser::param() => Video::RELATION_ANIMETHEME, + ]; + + $video = Video::factory() + ->has( + AnimeThemeEntry::factory() + ->count(fake()->randomDigitNotNull()) + ->for( + AnimeTheme::factory() + ->for(Anime::factory()) + ->state([ + AnimeTheme::ATTRIBUTE_SEQUENCE => fake()->boolean() ? $sequenceFilter : $excludedSequence, + ]) + ) + ) + ->createOne(); + + $video->unsetRelations()->load([ + Video::RELATION_ANIMETHEME => function (BelongsTo $query) use ($sequenceFilter) { + $query->where(AnimeTheme::ATTRIBUTE_SEQUENCE, $sequenceFilter); + }, + ]); + + $response = get(route('api.video.show', ['video' => $video] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new VideoResource($video, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('themes by type', function () { + $typeFilter = Arr::random(ThemeType::cases()); + + $parameters = [ + FilterParser::param() => [ + AnimeTheme::ATTRIBUTE_TYPE => $typeFilter->localize(), + ], + IncludeParser::param() => Video::RELATION_ANIMETHEME, + ]; + + $video = Video::factory() + ->has( + AnimeThemeEntry::factory() + ->count(fake()->randomDigitNotNull()) + ->for(AnimeTheme::factory()->for(Anime::factory())) + ) + ->createOne(); + + $video->unsetRelations()->load([ + Video::RELATION_ANIMETHEME => function (BelongsTo $query) use ($typeFilter) { + $query->where(AnimeTheme::ATTRIBUTE_TYPE, $typeFilter->value); + }, + ]); + + $response = get(route('api.video.show', ['video' => $video] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new VideoResource($video, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by media format', function () { + $mediaFormatFilter = Arr::random(AnimeMediaFormat::cases()); + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_MEDIA_FORMAT => $mediaFormatFilter->localize(), + ], + IncludeParser::param() => Video::RELATION_ANIME, + ]; + + $video = Video::factory() + ->has( + AnimeThemeEntry::factory() + ->count(fake()->randomDigitNotNull()) + ->for(AnimeTheme::factory()->for(Anime::factory())) + ) + ->createOne(); + + $video->unsetRelations()->load([ + Video::RELATION_ANIME => function (BelongsTo $query) use ($mediaFormatFilter) { + $query->where(Anime::ATTRIBUTE_MEDIA_FORMAT, $mediaFormatFilter->value); + }, + ]); + + $response = get(route('api.video.show', ['video' => $video] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new VideoResource($video, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by season', function () { + $seasonFilter = Arr::random(AnimeSeason::cases()); + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_SEASON => $seasonFilter->localize(), + ], + IncludeParser::param() => Video::RELATION_ANIME, + ]; + + $video = Video::factory() + ->has( + AnimeThemeEntry::factory() + ->count(fake()->randomDigitNotNull()) + ->for(AnimeTheme::factory()->for(Anime::factory())) + ) + ->createOne(); + + $video->unsetRelations()->load([ + Video::RELATION_ANIME => function (BelongsTo $query) use ($seasonFilter) { + $query->where(Anime::ATTRIBUTE_SEASON, $seasonFilter->value); + }, + ]); + + $response = get(route('api.video.show', ['video' => $video] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new VideoResource($video, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); + +test('anime by year', function () { + $yearFilter = intval(fake()->year()); + $excludedYear = $yearFilter + 1; + + $parameters = [ + FilterParser::param() => [ + Anime::ATTRIBUTE_YEAR => $yearFilter, + ], + IncludeParser::param() => Video::RELATION_ANIME, + ]; + + $video = Video::factory() + ->has( + AnimeThemeEntry::factory() + ->count(fake()->randomDigitNotNull()) + ->for( + AnimeTheme::factory() + ->for( + Anime::factory() + ->state([ + Anime::ATTRIBUTE_YEAR => fake()->boolean() ? $yearFilter : $excludedYear, + ]) + ) + ) + ) + ->createOne(); + + $video->unsetRelations()->load([ + Video::RELATION_ANIME => function (BelongsTo $query) use ($yearFilter) { + $query->where(Anime::ATTRIBUTE_YEAR, $yearFilter); + }, + ]); + + $response = get(route('api.video.show', ['video' => $video] + $parameters)); + + $response->assertJson( + json_decode( + json_encode( + new VideoResource($video, new Query($parameters)) + ->response() + ->getData() + ), + true + ) + ); +}); diff --git a/tests/Feature/Http/Api/Wiki/Video/VideoStoreTest.php b/tests/Feature/Http/Api/Wiki/Video/VideoStoreTest.php index 57cb1926a..28c98ce44 100644 --- a/tests/Feature/Http/Api/Wiki/Video/VideoStoreTest.php +++ b/tests/Feature/Http/Api/Wiki/Video/VideoStoreTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Video; - use App\Enums\Auth\CrudPermission; use App\Enums\Models\Wiki\VideoOverlap; use App\Enums\Models\Wiki\VideoSource; @@ -11,81 +9,63 @@ use App\Models\Auth\User; use App\Models\Wiki\Video; use Illuminate\Support\Arr; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class VideoStoreTest extends TestCase -{ - /** - * The Video Store Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $video = Video::factory()->makeOne(); +use function Pest\Laravel\post; - $response = $this->post(route('api.video.store', $video->toArray())); +test('protected', function () { + $video = Video::factory()->makeOne(); - $response->assertUnauthorized(); - } + $response = post(route('api.video.store', $video->toArray())); - /** - * The Video Store Endpoint shall forbid users without the create video permission. - */ - public function testForbidden(): void - { - $video = Video::factory()->makeOne(); + $response->assertUnauthorized(); +}); - $user = User::factory()->createOne(); +test('forbidden', function () { + $video = Video::factory()->makeOne(); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->post(route('api.video.store', $video->toArray())); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = post(route('api.video.store', $video->toArray())); - /** - * The Video Store Endpoint shall require basename, filename, mimetype, path & size fields. - */ - public function testRequiredFields(): void - { - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Video::class))->createOne(); + $response->assertForbidden(); +}); - Sanctum::actingAs($user); +test('required fields', function () { + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Video::class))->createOne(); - $response = $this->post(route('api.video.store')); + Sanctum::actingAs($user); - $response->assertJsonValidationErrors([ - Video::ATTRIBUTE_BASENAME, - Video::ATTRIBUTE_FILENAME, - Video::ATTRIBUTE_MIMETYPE, - Video::ATTRIBUTE_PATH, - Video::ATTRIBUTE_SIZE, - ]); - } + $response = post(route('api.video.store')); - /** - * The Video Store Endpoint shall create a video. - */ - public function testCreate(): void - { - $overlap = Arr::random(VideoOverlap::cases()); - $source = Arr::random(VideoSource::cases()); + $response->assertJsonValidationErrors([ + Video::ATTRIBUTE_BASENAME, + Video::ATTRIBUTE_FILENAME, + Video::ATTRIBUTE_MIMETYPE, + Video::ATTRIBUTE_PATH, + Video::ATTRIBUTE_SIZE, + ]); +}); - $parameters = array_merge( - Video::factory()->raw(), - [ - Video::ATTRIBUTE_OVERLAP => $overlap->localize(), - Video::ATTRIBUTE_SOURCE => $source->localize(), - ] - ); +test('create', function () { + $overlap = Arr::random(VideoOverlap::cases()); + $source = Arr::random(VideoSource::cases()); - $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Video::class))->createOne(); + $parameters = array_merge( + Video::factory()->raw(), + [ + Video::ATTRIBUTE_OVERLAP => $overlap->localize(), + Video::ATTRIBUTE_SOURCE => $source->localize(), + ] + ); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::CREATE->format(Video::class))->createOne(); - $response = $this->post(route('api.video.store', $parameters)); + Sanctum::actingAs($user); - $response->assertCreated(); - static::assertDatabaseCount(Video::class, 1); - } -} + $response = post(route('api.video.store', $parameters)); + + $response->assertCreated(); + $this->assertDatabaseCount(Video::class, 1); +}); diff --git a/tests/Feature/Http/Api/Wiki/Video/VideoUpdateTest.php b/tests/Feature/Http/Api/Wiki/Video/VideoUpdateTest.php index c2495c4d0..5609aaa26 100644 --- a/tests/Feature/Http/Api/Wiki/Video/VideoUpdateTest.php +++ b/tests/Feature/Http/Api/Wiki/Video/VideoUpdateTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Api\Wiki\Video; - use App\Enums\Auth\CrudPermission; use App\Enums\Models\Wiki\VideoOverlap; use App\Enums\Models\Wiki\VideoSource; @@ -11,111 +9,93 @@ use App\Models\Auth\User; use App\Models\Wiki\Video; use Illuminate\Support\Arr; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class VideoUpdateTest extends TestCase -{ - /** - * The Video Update Endpoint shall be protected by sanctum. - */ - public function testProtected(): void - { - $video = Video::factory()->createOne(); +use function Pest\Laravel\put; - $overlap = Arr::random(VideoOverlap::cases()); - $source = Arr::random(VideoSource::cases()); +test('protected', function () { + $video = Video::factory()->createOne(); - $parameters = array_merge( - Video::factory()->raw(), - [ - Video::ATTRIBUTE_OVERLAP => $overlap->localize(), - Video::ATTRIBUTE_SOURCE => $source->localize(), - ] - ); + $overlap = Arr::random(VideoOverlap::cases()); + $source = Arr::random(VideoSource::cases()); - $response = $this->put(route('api.video.update', ['video' => $video] + $parameters)); + $parameters = array_merge( + Video::factory()->raw(), + [ + Video::ATTRIBUTE_OVERLAP => $overlap->localize(), + Video::ATTRIBUTE_SOURCE => $source->localize(), + ] + ); - $response->assertUnauthorized(); - } + $response = put(route('api.video.update', ['video' => $video] + $parameters)); - /** - * The Video Update Endpoint shall forbid users without the update video permission. - */ - public function testForbidden(): void - { - $video = Video::factory()->createOne(); + $response->assertUnauthorized(); +}); - $overlap = Arr::random(VideoOverlap::cases()); - $source = Arr::random(VideoSource::cases()); +test('forbidden', function () { + $video = Video::factory()->createOne(); - $parameters = array_merge( - Video::factory()->raw(), - [ - Video::ATTRIBUTE_OVERLAP => $overlap->localize(), - Video::ATTRIBUTE_SOURCE => $source->localize(), - ] - ); + $overlap = Arr::random(VideoOverlap::cases()); + $source = Arr::random(VideoSource::cases()); - $user = User::factory()->createOne(); + $parameters = array_merge( + Video::factory()->raw(), + [ + Video::ATTRIBUTE_OVERLAP => $overlap->localize(), + Video::ATTRIBUTE_SOURCE => $source->localize(), + ] + ); - Sanctum::actingAs($user); + $user = User::factory()->createOne(); - $response = $this->put(route('api.video.update', ['video' => $video] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.video.update', ['video' => $video] + $parameters)); - /** - * The Video Update Endpoint shall forbid users from updating a video that is trashed. - */ - public function testTrashed(): void - { - $video = Video::factory()->trashed()->createOne(); + $response->assertForbidden(); +}); - $overlap = Arr::random(VideoOverlap::cases()); - $source = Arr::random(VideoSource::cases()); +test('trashed', function () { + $video = Video::factory()->trashed()->createOne(); - $parameters = array_merge( - Video::factory()->raw(), - [ - Video::ATTRIBUTE_OVERLAP => $overlap->localize(), - Video::ATTRIBUTE_SOURCE => $source->localize(), - ] - ); + $overlap = Arr::random(VideoOverlap::cases()); + $source = Arr::random(VideoSource::cases()); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Video::class))->createOne(); + $parameters = array_merge( + Video::factory()->raw(), + [ + Video::ATTRIBUTE_OVERLAP => $overlap->localize(), + Video::ATTRIBUTE_SOURCE => $source->localize(), + ] + ); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Video::class))->createOne(); - $response = $this->put(route('api.video.update', ['video' => $video] + $parameters)); + Sanctum::actingAs($user); - $response->assertForbidden(); - } + $response = put(route('api.video.update', ['video' => $video] + $parameters)); - /** - * The Video Update Endpoint shall update a video. - */ - public function testUpdate(): void - { - $video = Video::factory()->createOne(); + $response->assertForbidden(); +}); - $overlap = Arr::random(VideoOverlap::cases()); - $source = Arr::random(VideoSource::cases()); +test('update', function () { + $video = Video::factory()->createOne(); - $parameters = array_merge( - Video::factory()->raw(), - [ - Video::ATTRIBUTE_OVERLAP => $overlap->localize(), - Video::ATTRIBUTE_SOURCE => $source->localize(), - ] - ); + $overlap = Arr::random(VideoOverlap::cases()); + $source = Arr::random(VideoSource::cases()); - $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Video::class))->createOne(); + $parameters = array_merge( + Video::factory()->raw(), + [ + Video::ATTRIBUTE_OVERLAP => $overlap->localize(), + Video::ATTRIBUTE_SOURCE => $source->localize(), + ] + ); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(CrudPermission::UPDATE->format(Video::class))->createOne(); - $response = $this->put(route('api.video.update', ['video' => $video] + $parameters)); + Sanctum::actingAs($user); - $response->assertOk(); - } -} + $response = put(route('api.video.update', ['video' => $video] + $parameters)); + + $response->assertOk(); +}); diff --git a/tests/Feature/Http/Auth/EmailVerificationTest.php b/tests/Feature/Http/Auth/EmailVerificationTest.php index 6d545d1b9..57dfc7791 100644 --- a/tests/Feature/Http/Auth/EmailVerificationTest.php +++ b/tests/Feature/Http/Auth/EmailVerificationTest.php @@ -2,62 +2,54 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Auth; - use App\Models\Auth\Role; use App\Models\Auth\User; use Illuminate\Auth\Events\Verified; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Collection; use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\URL; use Illuminate\Support\Str; + +use function Pest\Laravel\actingAs; + use Spatie\Permission\PermissionRegistrar; -use Tests\TestCase; -class EmailVerificationTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Email Verification route shall assign default roles. - */ - public function testAssignsDefaultRoles(): void - { - Event::fakeExcept(Verified::class); +test('assigns default roles', function () { + Event::fakeExcept(Verified::class); - Collection::times($this->faker->randomDigitNotNull, function () { - Role::findOrCreate(Str::random()); - }); + Collection::times(fake()->randomDigitNotNull, function () { + Role::findOrCreate(Str::random()); + }); - $defaultRoleCount = $this->faker->randomDigitNotNull(); + $defaultRoleCount = fake()->randomDigitNotNull(); - Collection::times($defaultRoleCount, function () { - /** @var Role $role */ - $role = Role::findOrCreate(Str::random()); + Collection::times($defaultRoleCount, function () { + /** @var Role $role */ + $role = Role::findOrCreate(Str::random()); - $role->default = true; - $role->save(); - }); + $role->default = true; + $role->save(); + }); - App::make(PermissionRegistrar::class)->forgetCachedPermissions(); + App::make(PermissionRegistrar::class)->forgetCachedPermissions(); - $user = User::factory()->createOne([ - User::ATTRIBUTE_EMAIL_VERIFIED_AT => null, - ]); + $user = User::factory()->createOne([ + User::ATTRIBUTE_EMAIL_VERIFIED_AT => null, + ]); - $url = URL::temporarySignedRoute( - 'verification.verify', - now()->addMinutes(60), - [ - 'id' => $user->getKey(), - 'hash' => sha1($user->email), - ] - ); + $url = URL::temporarySignedRoute( + 'verification.verify', + now()->addMinutes(60), + [ + 'id' => $user->getKey(), + 'hash' => sha1($user->email), + ] + ); - $this->actingAs($user)->get($url); + actingAs($user)->get($url); - static::assertCount($defaultRoleCount, $user->roles()->get()); - } -} + $this->assertCount($defaultRoleCount, $user->roles()->get()); +}); diff --git a/tests/Feature/Http/Wiki/Audio/AudioTest.php b/tests/Feature/Http/Wiki/Audio/AudioTest.php index 9b07813ab..aa601c951 100644 --- a/tests/Feature/Http/Wiki/Audio/AudioTest.php +++ b/tests/Feature/Http/Wiki/Audio/AudioTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Wiki\Audio; - use App\Constants\Config\AudioConstants; use App\Constants\FeatureConstants; use App\Enums\Auth\SpecialPermission; @@ -11,179 +9,139 @@ use App\Enums\Http\StreamingMethod; use App\Features\AllowAudioStreams; use App\Models\Auth\User; use App\Models\Wiki\Audio; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Storage; use Laravel\Pennant\Feature; use Laravel\Sanctum\Sanctum; + +use function Pest\Laravel\get; + use Symfony\Component\HttpFoundation\StreamedResponse; -use Tests\TestCase; -class AudioTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * If audio streaming is disabled through the Allow Audio Streams feature, - * the user shall receive a forbidden exception. - */ - public function testAudioStreamingNotAllowedForbidden(): void - { - Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); +test('audio streaming not allowed forbidden', function () { + Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); - Feature::deactivate(AllowAudioStreams::class); + Feature::deactivate(AllowAudioStreams::class); - $audio = Audio::factory()->createOne(); + $audio = Audio::factory()->createOne(); - $response = $this->get(route('audio.show', ['audio' => $audio])); + $response = get(route('audio.show', ['audio' => $audio])); - $response->assertForbidden(); - } + $response->assertForbidden(); +}); - /** - * Users with the bypass feature flag permission shall be permitted to stream audio - * even if the Allow Audio Streams feature is disabled. - */ - public function testAudioStreamingPermittedForBypass(): void - { - Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); +test('audio streaming permitted for bypass', function () { + Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); - Feature::activate(AllowAudioStreams::class, $this->faker->boolean()); + Feature::activate(AllowAudioStreams::class, fake()->boolean()); - /** @var StreamingMethod $streamingMethod */ - $streamingMethod = Arr::random(StreamingMethod::cases()); - Config::set(AudioConstants::STREAMING_METHOD_QUALIFIED, $streamingMethod->value); + /** @var StreamingMethod $streamingMethod */ + $streamingMethod = Arr::random(StreamingMethod::cases()); + Config::set(AudioConstants::STREAMING_METHOD_QUALIFIED, $streamingMethod->value); - $audio = Audio::factory()->createOne(); + $audio = Audio::factory()->createOne(); - $user = User::factory()->withPermissions(SpecialPermission::BYPASS_FEATURE_FLAGS->value)->createOne(); + $user = User::factory()->withPermissions(SpecialPermission::BYPASS_FEATURE_FLAGS->value)->createOne(); - Sanctum::actingAs($user); + Sanctum::actingAs($user); - $response = $this->get(route('audio.show', ['audio' => $audio])); + $response = get(route('audio.show', ['audio' => $audio])); - $response->assertSuccessful(); - } + $response->assertSuccessful(); +}); - /** - * If the audio is soft-deleted, the user shall receive a not found exception. - */ - public function testCannotStreamSoftDeletedAudio(): void - { - Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); +test('cannot stream soft deleted audio', function () { + Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); - Feature::activate(AllowAudioStreams::class); + Feature::activate(AllowAudioStreams::class); - $audio = Audio::factory()->trashed()->createOne(); + $audio = Audio::factory()->trashed()->createOne(); - $response = $this->get(route('audio.show', ['audio' => $audio])); + $response = get(route('audio.show', ['audio' => $audio])); - $response->assertNotFound(); - } + $response->assertNotFound(); +}); - /** - * If view recording is disabled, the audio show route shall not record a view for the audio. - */ - public function testViewRecordingNotAllowed(): void - { - Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); +test('view recording not allowed', function () { + Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); - Feature::activate(AllowAudioStreams::class); - Feature::deactivate(FeatureConstants::ALLOW_VIEW_RECORDING); + Feature::activate(AllowAudioStreams::class); + Feature::deactivate(FeatureConstants::ALLOW_VIEW_RECORDING); - $audio = Audio::factory()->createOne(); + $audio = Audio::factory()->createOne(); - $this->get(route('audio.show', ['audio' => $audio])); + get(route('audio.show', ['audio' => $audio])); - static::assertEquals(0, $audio->views()->count()); - } + $this->assertEquals(0, $audio->views()->count()); +}); - /** - * If view recording is enabled, the audio show route shall record a view for the audio. - */ - public function testViewRecordingIsAllowed(): void - { - Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); +test('view recording is allowed', function () { + Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); - Feature::activate(AllowAudioStreams::class); - Feature::activate(FeatureConstants::ALLOW_VIEW_RECORDING); + Feature::activate(AllowAudioStreams::class); + Feature::activate(FeatureConstants::ALLOW_VIEW_RECORDING); - $audio = Audio::factory()->createOne(); + $audio = Audio::factory()->createOne(); - $this->get(route('audio.show', ['audio' => $audio])); + get(route('audio.show', ['audio' => $audio])); - static::assertEquals(1, $audio->views()->count()); - } + $this->assertEquals(1, $audio->views()->count()); +}); - /** - * If view recording is enabled, the audio show route shall record a view for the audio. - */ - public function testViewRecordingCooldown(): void - { - Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); +test('view recording cooldown', function () { + Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); - Feature::activate(AllowAudioStreams::class); - Feature::activate(FeatureConstants::ALLOW_VIEW_RECORDING); + Feature::activate(AllowAudioStreams::class); + Feature::activate(FeatureConstants::ALLOW_VIEW_RECORDING); - $audio = Audio::factory()->createOne(); + $audio = Audio::factory()->createOne(); - Collection::times($this->faker->randomDigitNotNull(), function () use ($audio) { - $this->get(route('audio.show', ['audio' => $audio])); - }); + Collection::times(fake()->randomDigitNotNull(), function () use ($audio) { + get(route('audio.show', ['audio' => $audio])); + }); - static::assertEquals(1, $audio->views()->count()); - } + $this->assertEquals(1, $audio->views()->count()); +}); - /** - * If the streaming method is set to an unexpected value, the user shall receive an error. - */ - public function testInvalidStreamingMethodError(): void - { - Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); +test('invalid streaming method error', function () { + Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); - Feature::activate(AllowAudioStreams::class); - Config::set(AudioConstants::STREAMING_METHOD_QUALIFIED, $this->faker->word()); + Feature::activate(AllowAudioStreams::class); + Config::set(AudioConstants::STREAMING_METHOD_QUALIFIED, fake()->word()); - $audio = Audio::factory()->createOne(); + $audio = Audio::factory()->createOne(); - $response = $this->get(route('audio.show', ['audio' => $audio])); + $response = get(route('audio.show', ['audio' => $audio])); - $response->assertServerError(); - } + $response->assertServerError(); +}); - /** - * If the streaming method is set to 'response', the audio shall be streamed through a Symfony StreamedResponse. - */ - public function testStreamedThroughResponse(): void - { - Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); +test('streamed through response', function () { + Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); - Feature::activate(AllowAudioStreams::class); - Config::set(AudioConstants::STREAMING_METHOD_QUALIFIED, StreamingMethod::RESPONSE->value); + Feature::activate(AllowAudioStreams::class); + Config::set(AudioConstants::STREAMING_METHOD_QUALIFIED, StreamingMethod::RESPONSE->value); - $audio = Audio::factory()->createOne(); + $audio = Audio::factory()->createOne(); - $response = $this->get(route('audio.show', ['audio' => $audio])); + $response = get(route('audio.show', ['audio' => $audio])); - static::assertInstanceOf(StreamedResponse::class, $response->baseResponse); - } + $this->assertInstanceOf(StreamedResponse::class, $response->baseResponse); +}); - /** - * If the streaming method is set to 'nginx', the audio shall be streamed through a nginx internal redirect. - */ - public function testStreamedThroughNginxRedirect(): void - { - Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); +test('streamed through nginx redirect', function () { + Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); - Feature::activate(AllowAudioStreams::class); - Config::set(AudioConstants::STREAMING_METHOD_QUALIFIED, StreamingMethod::NGINX->value); + Feature::activate(AllowAudioStreams::class); + Config::set(AudioConstants::STREAMING_METHOD_QUALIFIED, StreamingMethod::NGINX->value); - $audio = Audio::factory()->createOne(); + $audio = Audio::factory()->createOne(); - $response = $this->get(route('audio.show', ['audio' => $audio])); + $response = get(route('audio.show', ['audio' => $audio])); - $response->assertHeader('X-Accel-Redirect'); - } -} + $response->assertHeader('X-Accel-Redirect'); +}); diff --git a/tests/Feature/Http/Wiki/Video/Script/ScriptTest.php b/tests/Feature/Http/Wiki/Video/Script/ScriptTest.php index 7a55f2768..3466f49c4 100644 --- a/tests/Feature/Http/Wiki/Video/Script/ScriptTest.php +++ b/tests/Feature/Http/Wiki/Video/Script/ScriptTest.php @@ -2,96 +2,73 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Wiki\Video\Script; - use App\Constants\Config\VideoConstants; use App\Enums\Auth\SpecialPermission; use App\Features\AllowScriptDownloading; use App\Models\Auth\User; use App\Models\Wiki\Video\VideoScript; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Http\Testing\File; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Storage; use Laravel\Pennant\Feature; use Laravel\Sanctum\Sanctum; -use Tests\TestCase; -class ScriptTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * If script downloading is disabled through the Allow Script Downloading feature, - * the user shall receive a forbidden exception. - */ - public function testScriptDownloadingNotAllowedForbidden(): void - { - Feature::deactivate(AllowScriptDownloading::class); +uses(Illuminate\Foundation\Testing\WithFaker::class); - $script = VideoScript::factory()->createOne(); +test('script downloading not allowed forbidden', function () { + Feature::deactivate(AllowScriptDownloading::class); - $response = $this->get(route('videoscript.show', ['videoscript' => $script])); + $script = VideoScript::factory()->createOne(); - $response->assertForbidden(); - } + $response = get(route('videoscript.show', ['videoscript' => $script])); - /** - * Users with the bypass feature flag permission shall be permitted to download scripts - * even if the Allow Script Downloading feature is disabled. - */ - public function testVideoStreamingPermittedForBypass(): void - { - Feature::activate(AllowScriptDownloading::class, $this->faker->boolean()); + $response->assertForbidden(); +}); - $fs = Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); - $file = File::fake()->create($this->faker->word().'.txt'); - $fsFile = $fs->putFile('', $file); +test('video streaming permitted for bypass', function () { + Feature::activate(AllowScriptDownloading::class, fake()->boolean()); - $script = VideoScript::factory()->createOne([ - VideoScript::ATTRIBUTE_PATH => $fsFile, - ]); + $fs = Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); + $file = File::fake()->create(fake()->word().'.txt'); + $fsFile = $fs->putFile('', $file); - $user = User::factory()->withPermissions(SpecialPermission::BYPASS_FEATURE_FLAGS->value)->createOne(); + $script = VideoScript::factory()->createOne([ + VideoScript::ATTRIBUTE_PATH => $fsFile, + ]); - Sanctum::actingAs($user); + $user = User::factory()->withPermissions(SpecialPermission::BYPASS_FEATURE_FLAGS->value)->createOne(); - $response = $this->get(route('videoscript.show', ['videoscript' => $script])); + Sanctum::actingAs($user); - $response->assertDownload($script->path); - } + $response = get(route('videoscript.show', ['videoscript' => $script])); - /** - * If the script is soft-deleted, the user shall receive a not found exception. - */ - public function testCannotStreamSoftDeletedVideo(): void - { - Feature::activate(AllowScriptDownloading::class); + $response->assertDownload($script->path); +}); - $script = VideoScript::factory()->trashed()->createOne(); +test('cannot stream soft deleted video', function () { + Feature::activate(AllowScriptDownloading::class); - $response = $this->get(route('videoscript.show', ['videoscript' => $script])); + $script = VideoScript::factory()->trashed()->createOne(); - $response->assertNotFound(); - } + $response = get(route('videoscript.show', ['videoscript' => $script])); - /** - * If script downloading is enabled, the script is downloaded from storage through the response. - */ - public function testDownloadedThroughResponse(): void - { - Feature::activate(AllowScriptDownloading::class); + $response->assertNotFound(); +}); - $fs = Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); - $file = File::fake()->create($this->faker->word().'.txt'); - $fsFile = $fs->putFile('', $file); +test('downloaded through response', function () { + Feature::activate(AllowScriptDownloading::class); - $script = VideoScript::factory()->createOne([ - VideoScript::ATTRIBUTE_PATH => $fsFile, - ]); + $fs = Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); + $file = File::fake()->create(fake()->word().'.txt'); + $fsFile = $fs->putFile('', $file); - $response = $this->get(route('videoscript.show', ['videoscript' => $script])); + $script = VideoScript::factory()->createOne([ + VideoScript::ATTRIBUTE_PATH => $fsFile, + ]); - $response->assertDownload($script->path); - } -} + $response = get(route('videoscript.show', ['videoscript' => $script])); + + $response->assertDownload($script->path); +}); diff --git a/tests/Feature/Http/Wiki/Video/VideoTest.php b/tests/Feature/Http/Wiki/Video/VideoTest.php index 6ad2f0690..65fedbd29 100644 --- a/tests/Feature/Http/Wiki/Video/VideoTest.php +++ b/tests/Feature/Http/Wiki/Video/VideoTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Http\Wiki\Video; - use App\Constants\Config\VideoConstants; use App\Constants\FeatureConstants; use App\Enums\Auth\SpecialPermission; @@ -13,7 +11,6 @@ use App\Features\AllowVideoStreams; use App\Jobs\SendDiscordNotificationJob; use App\Models\Auth\User; use App\Models\Wiki\Video; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Bus; @@ -22,260 +19,205 @@ use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Storage; use Laravel\Pennant\Feature; use Laravel\Sanctum\Sanctum; + +use function Pest\Laravel\get; + use Symfony\Component\HttpFoundation\StreamedResponse; -use Tests\TestCase; -class VideoTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * If video streaming is disabled through the Allow Video Streams feature, - * the user shall receive a forbidden exception. - */ - public function testVideoStreamingNotAllowedForbidden(): void - { - Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); +test('video streaming not allowed forbidden', function () { + Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); - Feature::deactivate(AllowVideoStreams::class); + Feature::deactivate(AllowVideoStreams::class); - $video = Video::factory()->createOne(); + $video = Video::factory()->createOne(); - $response = $this->get(route('video.show', ['video' => $video])); + $response = get(route('video.show', ['video' => $video])); - $response->assertForbidden(); - } + $response->assertForbidden(); +}); - /** - * If the video is soft-deleted, the user shall receive a not found exception. - */ - public function testCannotStreamSoftDeletedVideo(): void - { - Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); +test('cannot stream soft deleted video', function () { + Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); - Feature::activate(AllowVideoStreams::class); + Feature::activate(AllowVideoStreams::class); - $video = Video::factory()->trashed()->createOne(); + $video = Video::factory()->trashed()->createOne(); - $response = $this->get(route('video.show', ['video' => $video])); + $response = get(route('video.show', ['video' => $video])); - $response->assertNotFound(); - } + $response->assertNotFound(); +}); - /** - * If view recording is disabled, the video show route shall not record a view for the video. - */ - public function testViewRecordingNotAllowed(): void - { - Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); +test('view recording not allowed', function () { + Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); - Feature::activate(AllowVideoStreams::class); - Feature::deactivate(FeatureConstants::ALLOW_VIEW_RECORDING); + Feature::activate(AllowVideoStreams::class); + Feature::deactivate(FeatureConstants::ALLOW_VIEW_RECORDING); - $video = Video::factory()->createOne(); + $video = Video::factory()->createOne(); - $this->get(route('video.show', ['video' => $video])); + get(route('video.show', ['video' => $video])); - static::assertEquals(0, $video->views()->count()); - } + $this->assertEquals(0, $video->views()->count()); +}); - /** - * Users with the bypass feature flag permission shall be permitted to stream video - * even if the Allow Video Streams feature is disabled. - */ - public function testVideoStreamingPermittedForBypass(): void - { - Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); +test('video streaming permitted for bypass', function () { + Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); - Feature::activate(AllowVideoStreams::class, $this->faker->boolean()); + Feature::activate(AllowVideoStreams::class, fake()->boolean()); - /** @var StreamingMethod $streamingMethod */ - $streamingMethod = Arr::random(StreamingMethod::cases()); - Config::set(VideoConstants::STREAMING_METHOD_QUALIFIED, $streamingMethod->value); + /** @var StreamingMethod $streamingMethod */ + $streamingMethod = Arr::random(StreamingMethod::cases()); + Config::set(VideoConstants::STREAMING_METHOD_QUALIFIED, $streamingMethod->value); - $video = Video::factory()->createOne(); + $video = Video::factory()->createOne(); - $user = User::factory()->withPermissions(SpecialPermission::BYPASS_FEATURE_FLAGS->value)->createOne(); + $user = User::factory()->withPermissions(SpecialPermission::BYPASS_FEATURE_FLAGS->value)->createOne(); - Sanctum::actingAs($user); + Sanctum::actingAs($user); - $response = $this->get(route('video.show', ['video' => $video])); + $response = get(route('video.show', ['video' => $video])); - $response->assertSuccessful(); - } + $response->assertSuccessful(); +}); - /** - * If view recording is enabled, the video show route shall record a view for the video. - */ - public function testViewRecordingIsAllowed(): void - { - Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); +test('view recording is allowed', function () { + Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); - Feature::activate(AllowVideoStreams::class); - Feature::activate(FeatureConstants::ALLOW_VIEW_RECORDING); + Feature::activate(AllowVideoStreams::class); + Feature::activate(FeatureConstants::ALLOW_VIEW_RECORDING); - $video = Video::factory()->createOne(); + $video = Video::factory()->createOne(); - $this->get(route('video.show', ['video' => $video])); + get(route('video.show', ['video' => $video])); - static::assertEquals(1, $video->views()->count()); - } + $this->assertEquals(1, $video->views()->count()); +}); - /** - * If view recording is enabled, the video show route shall record a view for the video. - */ - public function testViewRecordingCooldown(): void - { - Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); +test('view recording cooldown', function () { + Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); - Feature::activate(AllowVideoStreams::class); - Feature::activate(FeatureConstants::ALLOW_VIEW_RECORDING); + Feature::activate(AllowVideoStreams::class); + Feature::activate(FeatureConstants::ALLOW_VIEW_RECORDING); - $video = Video::factory()->createOne(); + $video = Video::factory()->createOne(); - Collection::times($this->faker->randomDigitNotNull(), function () use ($video) { - $this->get(route('video.show', ['video' => $video])); - }); + Collection::times(fake()->randomDigitNotNull(), function () use ($video) { + get(route('video.show', ['video' => $video])); + }); - static::assertEquals(1, $video->views()->count()); - } + $this->assertEquals(1, $video->views()->count()); +}); - /** - * If the streaming method is set to an unexpected value, the user shall receive an error. - */ - public function testInvalidStreamingMethodError(): void - { - Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); +test('invalid streaming method error', function () { + Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); - Feature::activate(AllowVideoStreams::class); - Config::set(VideoConstants::STREAMING_METHOD_QUALIFIED, $this->faker->word()); + Feature::activate(AllowVideoStreams::class); + Config::set(VideoConstants::STREAMING_METHOD_QUALIFIED, fake()->word()); - $video = Video::factory()->createOne(); + $video = Video::factory()->createOne(); - $response = $this->get(route('video.show', ['video' => $video])); + $response = get(route('video.show', ['video' => $video])); - $response->assertServerError(); - } + $response->assertServerError(); +}); - /** - * If the streaming method is set to 'response', the video shall be streamed through a Symfony StreamedResponse. - */ - public function testStreamedThroughResponse(): void - { - Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); +test('streamed through response', function () { + Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); - Feature::activate(AllowVideoStreams::class); - Config::set(VideoConstants::STREAMING_METHOD_QUALIFIED, StreamingMethod::RESPONSE->value); + Feature::activate(AllowVideoStreams::class); + Config::set(VideoConstants::STREAMING_METHOD_QUALIFIED, StreamingMethod::RESPONSE->value); - $video = Video::factory()->createOne(); + $video = Video::factory()->createOne(); - $response = $this->get(route('video.show', ['video' => $video])); + $response = get(route('video.show', ['video' => $video])); - static::assertInstanceOf(StreamedResponse::class, $response->baseResponse); - } + $this->assertInstanceOf(StreamedResponse::class, $response->baseResponse); +}); - /** - * If the streaming method is set to 'nginx', the video shall be streamed through a nginx internal redirect. - */ - public function testStreamedThroughNginxRedirect(): void - { - Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); +test('streamed through nginx redirect', function () { + Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); - Feature::activate(AllowVideoStreams::class); - Config::set(VideoConstants::STREAMING_METHOD_QUALIFIED, StreamingMethod::NGINX->value); + Feature::activate(AllowVideoStreams::class); + Config::set(VideoConstants::STREAMING_METHOD_QUALIFIED, StreamingMethod::NGINX->value); - $video = Video::factory()->createOne(); + $video = Video::factory()->createOne(); - $response = $this->get(route('video.show', ['video' => $video])); + $response = get(route('video.show', ['video' => $video])); - $response->assertHeader('X-Accel-Redirect'); - } + $response->assertHeader('X-Accel-Redirect'); +}); - /** - * If the video rate limit is less than or equal to zero, videos shall not be throttled. - */ - public function testNotThrottled(): void - { - Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); +test('not throttled', function () { + Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); - Feature::activate(AllowVideoStreams::class); - Config::set(VideoConstants::STREAMING_METHOD_QUALIFIED, Arr::random(StreamingMethod::cases())->value); - Config::set(VideoConstants::RATE_LIMITER_QUALIFIED, -1); + Feature::activate(AllowVideoStreams::class); + Config::set(VideoConstants::STREAMING_METHOD_QUALIFIED, Arr::random(StreamingMethod::cases())->value); + Config::set(VideoConstants::RATE_LIMITER_QUALIFIED, -1); - $video = Video::factory()->createOne(); + $video = Video::factory()->createOne(); - $response = $this->get(route('video.show', ['video' => $video])); + $response = get(route('video.show', ['video' => $video])); - $response->assertHeaderMissing('X-RateLimit-Limit'); - $response->assertHeaderMissing('X-RateLimit-Remaining'); - } + $response->assertHeaderMissing('X-RateLimit-Limit'); + $response->assertHeaderMissing('X-RateLimit-Remaining'); +}); - /** - * If the video rate limit is greater than or equal to zero, videos shall be throttled. - */ - public function testRateLimited(): void - { - Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); +test('rate limited', function () { + Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); - Feature::activate(AllowVideoStreams::class); - Config::set(VideoConstants::STREAMING_METHOD_QUALIFIED, Arr::random(StreamingMethod::cases())->value); - Config::set(VideoConstants::RATE_LIMITER_QUALIFIED, $this->faker->randomDigitNotNull()); + Feature::activate(AllowVideoStreams::class); + Config::set(VideoConstants::STREAMING_METHOD_QUALIFIED, Arr::random(StreamingMethod::cases())->value); + Config::set(VideoConstants::RATE_LIMITER_QUALIFIED, fake()->randomDigitNotNull()); - $video = Video::factory()->createOne(); + $video = Video::factory()->createOne(); - $response = $this->get(route('video.show', ['video' => $video])); + $response = get(route('video.show', ['video' => $video])); - $response->assertHeader('X-RateLimit-Limit'); - $response->assertHeader('X-RateLimit-Remaining'); - } + $response->assertHeader('X-RateLimit-Limit'); + $response->assertHeader('X-RateLimit-Remaining'); +}); - /** - * If the video rate limit attempt is exceeded, a VideoThrottled event shall be dispatched. - */ - public function testThrottledEvent(): void - { - $limit = $this->faker->randomDigitNotNull(); +test('throttled event', function () { + $limit = fake()->randomDigitNotNull(); - Event::fake(); + Event::fake(); - Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); + Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); - Feature::activate(AllowVideoStreams::class); - Config::set(VideoConstants::STREAMING_METHOD_QUALIFIED, Arr::random(StreamingMethod::cases())->value); - Config::set(VideoConstants::RATE_LIMITER_QUALIFIED, $limit); + Feature::activate(AllowVideoStreams::class); + Config::set(VideoConstants::STREAMING_METHOD_QUALIFIED, Arr::random(StreamingMethod::cases())->value); + Config::set(VideoConstants::RATE_LIMITER_QUALIFIED, $limit); - $video = Video::factory()->createOne(); + $video = Video::factory()->createOne(); - Collection::times($limit + 1, function () use ($video) { - $this->get(route('video.show', ['video' => $video])); - }); + Collection::times($limit + 1, function () use ($video) { + get(route('video.show', ['video' => $video])); + }); - Event::assertDispatched(VideoThrottled::class); - } + Event::assertDispatched(VideoThrottled::class); +}); - /** - * If the video rate limit attempt is exceeded, a SendDiscordNotification job shall be dispatched. - */ - public function testThrottledNotification(): void - { - $limit = $this->faker->randomDigitNotNull(); +test('throttled notification', function () { + $limit = fake()->randomDigitNotNull(); - Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); + Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); - Bus::fake(SendDiscordNotificationJob::class); + Bus::fake(SendDiscordNotificationJob::class); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Feature::activate(AllowVideoStreams::class); - Config::set(VideoConstants::STREAMING_METHOD_QUALIFIED, Arr::random(StreamingMethod::cases())->value); - Config::set(VideoConstants::RATE_LIMITER_QUALIFIED, $limit); - Event::fakeExcept(VideoThrottled::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Feature::activate(AllowVideoStreams::class); + Config::set(VideoConstants::STREAMING_METHOD_QUALIFIED, Arr::random(StreamingMethod::cases())->value); + Config::set(VideoConstants::RATE_LIMITER_QUALIFIED, $limit); + Event::fakeExcept(VideoThrottled::class); - $video = Video::factory()->createOne(); + $video = Video::factory()->createOne(); - Collection::times($limit + 1, function () use ($video) { - $this->get(route('video.show', ['video' => $video])); - }); + Collection::times($limit + 1, function () use ($video) { + get(route('video.show', ['video' => $video])); + }); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } -} + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); diff --git a/tests/Feature/Jobs/Admin/AnnouncementTest.php b/tests/Feature/Jobs/Admin/AnnouncementTest.php index 3e5ceffe0..4730ae6e4 100644 --- a/tests/Feature/Jobs/Admin/AnnouncementTest.php +++ b/tests/Feature/Jobs/Admin/AnnouncementTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Jobs\Admin; - use App\Constants\FeatureConstants; use App\Events\Admin\Announcement\AnnouncementCreated; use App\Events\Admin\Announcement\AnnouncementDeleted; @@ -13,56 +11,40 @@ use App\Models\Admin\Announcement; use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; -use Tests\TestCase; -class AnnouncementTest extends TestCase -{ - /** - * When an announcement is created, a SendDiscordNotification job shall be dispatched. - */ - public function testAnnouncementCreatedSendsDiscordNotification(): void - { - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(AnnouncementCreated::class); +test('announcement created sends discord notification', function () { + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(AnnouncementCreated::class); - Announcement::factory()->createOne(); + Announcement::factory()->createOne(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When an announcement is deleted, a SendDiscordNotification job shall be dispatched. - */ - public function testAnnouncementDeletedSendsDiscordNotification(): void - { - $announcement = Announcement::factory()->createOne(); +test('announcement deleted sends discord notification', function () { + $announcement = Announcement::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(AnnouncementDeleted::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(AnnouncementDeleted::class); - $announcement->delete(); + $announcement->delete(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When an announcement is updated, a SendDiscordNotification job shall be dispatched. - */ - public function testAnnouncementUpdatedSendsDiscordNotification(): void - { - $announcement = Announcement::factory()->createOne(); +test('announcement updated sends discord notification', function () { + $announcement = Announcement::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(AnnouncementUpdated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(AnnouncementUpdated::class); - $changes = Announcement::factory()->makeOne(); + $changes = Announcement::factory()->makeOne(); - $announcement->fill($changes->getAttributes()); - $announcement->save(); + $announcement->fill($changes->getAttributes()); + $announcement->save(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } -} + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); diff --git a/tests/Feature/Jobs/Admin/DumpTest.php b/tests/Feature/Jobs/Admin/DumpTest.php index 023bbbda9..30709fe8e 100644 --- a/tests/Feature/Jobs/Admin/DumpTest.php +++ b/tests/Feature/Jobs/Admin/DumpTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Jobs\Admin; - use App\Constants\FeatureConstants; use App\Events\Admin\Dump\DumpCreated; use App\Events\Admin\Dump\DumpDeleted; @@ -13,56 +11,40 @@ use App\Models\Admin\Dump; use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; -use Tests\TestCase; -class DumpTest extends TestCase -{ - /** - * When a dump is created, a SendDiscordNotification job shall be dispatched. - */ - public function testDumpCreatedSendsDiscordNotification(): void - { - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(DumpCreated::class); +test('dump created sends discord notification', function () { + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(DumpCreated::class); - Dump::factory()->createOne(); + Dump::factory()->createOne(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a dump is deleted, a SendDiscordNotification job shall be dispatched. - */ - public function testDumpDeletedSendsDiscordNotification(): void - { - $dump = Dump::factory()->createOne(); +test('dump deleted sends discord notification', function () { + $dump = Dump::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(DumpDeleted::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(DumpDeleted::class); - $dump->delete(); + $dump->delete(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a dump is updated, a SendDiscordNotification job shall be dispatched. - */ - public function testDumpUpdatedSendsDiscordNotification(): void - { - $dump = Dump::factory()->createOne(); +test('dump updated sends discord notification', function () { + $dump = Dump::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(DumpUpdated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(DumpUpdated::class); - $changes = Dump::factory()->makeOne(); + $changes = Dump::factory()->makeOne(); - $dump->fill($changes->getAttributes()); - $dump->save(); + $dump->fill($changes->getAttributes()); + $dump->save(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } -} + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); diff --git a/tests/Feature/Jobs/Admin/FeatureTest.php b/tests/Feature/Jobs/Admin/FeatureTest.php index 33bc77e3d..51cd45ae2 100644 --- a/tests/Feature/Jobs/Admin/FeatureTest.php +++ b/tests/Feature/Jobs/Admin/FeatureTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Jobs\Admin; - use App\Constants\FeatureConstants; use App\Events\Admin\Feature\FeatureCreated; use App\Events\Admin\Feature\FeatureDeleted; @@ -13,55 +11,39 @@ use App\Models\Admin\Feature as FeatureModel; use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; -use Tests\TestCase; -class FeatureTest extends TestCase -{ - /** - * When a feature is created, a SendDiscordNotification job shall be dispatched. - */ - public function testFeatureCreatedSendsDiscordNotification(): void - { - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(FeatureCreated::class); +test('feature created sends discord notification', function () { + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(FeatureCreated::class); - FeatureModel::factory()->createOne(); + FeatureModel::factory()->createOne(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a feature is deleted, a SendDiscordNotification job shall be dispatched. - */ - public function testFeatureDeletedSendsDiscordNotification(): void - { - $feature = FeatureModel::factory()->createOne(); +test('feature deleted sends discord notification', function () { + $feature = FeatureModel::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(FeatureDeleted::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(FeatureDeleted::class); - $feature->delete(); + $feature->delete(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a feature is updated, a SendDiscordNotification job shall be dispatched. - */ - public function testFeatureUpdatedSendsDiscordNotification(): void - { - $feature = FeatureModel::factory()->createOne(); +test('feature updated sends discord notification', function () { + $feature = FeatureModel::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(FeatureUpdated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(FeatureUpdated::class); - $feature->update([ - FeatureModel::ATTRIBUTE_VALUE => ! $feature->value, - ]); + $feature->update([ + FeatureModel::ATTRIBUTE_VALUE => ! $feature->value, + ]); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } -} + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); diff --git a/tests/Feature/Jobs/Admin/FeaturedThemeTest.php b/tests/Feature/Jobs/Admin/FeaturedThemeTest.php index 5340da51d..3b6d502cd 100644 --- a/tests/Feature/Jobs/Admin/FeaturedThemeTest.php +++ b/tests/Feature/Jobs/Admin/FeaturedThemeTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Jobs\Admin; - use App\Constants\FeatureConstants; use App\Events\Admin\FeaturedTheme\FeaturedThemeCreated; use App\Events\Admin\FeaturedTheme\FeaturedThemeDeleted; @@ -13,56 +11,40 @@ use App\Models\Admin\FeaturedTheme; use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; -use Tests\TestCase; -class FeaturedThemeTest extends TestCase -{ - /** - * When a featured theme is created, a SendDiscordNotification job shall be dispatched. - */ - public function testFeaturedThemeCreatedSendsDiscordNotification(): void - { - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(FeaturedThemeCreated::class); +test('featured theme created sends discord notification', function () { + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(FeaturedThemeCreated::class); - FeaturedTheme::factory()->createOne(); + FeaturedTheme::factory()->createOne(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a featured theme is deleted, a SendDiscordNotification job shall be dispatched. - */ - public function testFeaturedThemeDeletedSendsDiscordNotification(): void - { - $featuredTheme = FeaturedTheme::factory()->createOne(); +test('featured theme deleted sends discord notification', function () { + $featuredTheme = FeaturedTheme::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(FeaturedThemeDeleted::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(FeaturedThemeDeleted::class); - $featuredTheme->delete(); + $featuredTheme->delete(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a featured theme is updated, a SendDiscordNotification job shall be dispatched. - */ - public function testFeaturedThemeUpdatedSendsDiscordNotification(): void - { - $featuredTheme = FeaturedTheme::factory()->createOne(); +test('featured theme updated sends discord notification', function () { + $featuredTheme = FeaturedTheme::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(FeaturedThemeUpdated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(FeaturedThemeUpdated::class); - $changes = FeaturedTheme::factory()->makeOne(); + $changes = FeaturedTheme::factory()->makeOne(); - $featuredTheme->fill($changes->getAttributes()); - $featuredTheme->save(); + $featuredTheme->fill($changes->getAttributes()); + $featuredTheme->save(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } -} + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); diff --git a/tests/Feature/Jobs/Auth/UserTest.php b/tests/Feature/Jobs/Auth/UserTest.php index 2bd87217e..cb6578c35 100644 --- a/tests/Feature/Jobs/Auth/UserTest.php +++ b/tests/Feature/Jobs/Auth/UserTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Jobs\Auth; - use App\Constants\FeatureConstants; use App\Events\Auth\User\UserCreated; use App\Events\Auth\User\UserDeleted; @@ -14,72 +12,52 @@ use App\Models\Auth\User; use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; -use Tests\TestCase; -class UserTest extends TestCase -{ - /** - * When a user is created, a SendDiscordNotification job shall be dispatched. - */ - public function testUserCreatedSendsDiscordNotification(): void - { - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(UserCreated::class); +test('user created sends discord notification', function () { + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(UserCreated::class); - User::factory()->createOne(); + User::factory()->createOne(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a user is deleted, a SendDiscordNotification job shall be dispatched. - */ - public function testUserDeletedSendsDiscordNotification(): void - { - $user = User::factory()->createOne(); +test('user deleted sends discord notification', function () { + $user = User::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(UserDeleted::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(UserDeleted::class); - $user->delete(); + $user->delete(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a user is restored, a SendDiscordNotification job shall be dispatched. - */ - public function testUserRestoredSendsDiscordNotification(): void - { - $user = User::factory()->createOne(); +test('user restored sends discord notification', function () { + $user = User::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(UserRestored::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(UserRestored::class); - $user->restore(); + $user->restore(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a user is updated, a SendDiscordNotification job shall be dispatched. - */ - public function testUserUpdatedSendsDiscordNotification(): void - { - $user = User::factory()->createOne(); +test('user updated sends discord notification', function () { + $user = User::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(UserUpdated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(UserUpdated::class); - $changes = User::factory()->makeOne(); + $changes = User::factory()->makeOne(); - $user->fill($changes->getAttributes()); - $user->save(); + $user->fill($changes->getAttributes()); + $user->save(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } -} + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); diff --git a/tests/Feature/Jobs/Discord/DiscordThreadTest.php b/tests/Feature/Jobs/Discord/DiscordThreadTest.php index caacea6f2..c3fb0511a 100644 --- a/tests/Feature/Jobs/Discord/DiscordThreadTest.php +++ b/tests/Feature/Jobs/Discord/DiscordThreadTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Jobs\Discord; - use App\Constants\FeatureConstants; use App\Events\Discord\DiscordThread\DiscordThreadDeleted; use App\Events\Discord\DiscordThread\DiscordThreadUpdated; @@ -14,50 +12,38 @@ use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Http; use Laravel\Pennant\Feature; -use Tests\TestCase; -class DiscordThreadTest extends TestCase -{ - /** - * When a thread is deleted, a SendDiscordNotification job shall be dispatched. - */ - public function testThreadDeletedSendsDiscordNotification(): void - { - $thread = DiscordThread::factory() - ->for(Anime::factory()) - ->createOne(); +test('thread deleted sends discord notification', function () { + $thread = DiscordThread::factory() + ->for(Anime::factory()) + ->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Http::fake(); - Event::fakeExcept(DiscordThreadDeleted::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Http::fake(); + Event::fakeExcept(DiscordThreadDeleted::class); - $thread->delete(); + $thread->delete(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a thread is updated, a SendDiscordNotification job shall be dispatched. - */ - public function testThreadUpdatedSendsDiscordNotification(): void - { - $thread = DiscordThread::factory() - ->for(Anime::factory()) - ->createOne(); +test('thread updated sends discord notification', function () { + $thread = DiscordThread::factory() + ->for(Anime::factory()) + ->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Http::fake(); - Event::fakeExcept(DiscordThreadUpdated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Http::fake(); + Event::fakeExcept(DiscordThreadUpdated::class); - $changes = DiscordThread::factory() - ->for(Anime::factory()) - ->makeOne(); + $changes = DiscordThread::factory() + ->for(Anime::factory()) + ->makeOne(); - $thread->fill($changes->getAttributes()); - $thread->save(); + $thread->fill($changes->getAttributes()); + $thread->save(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } -} + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); diff --git a/tests/Feature/Jobs/Document/PageTest.php b/tests/Feature/Jobs/Document/PageTest.php index 3f693bfe7..e54523f9d 100644 --- a/tests/Feature/Jobs/Document/PageTest.php +++ b/tests/Feature/Jobs/Document/PageTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Jobs\Document; - use App\Constants\FeatureConstants; use App\Events\Document\Page\PageCreated; use App\Events\Document\Page\PageDeleted; @@ -14,72 +12,52 @@ use App\Models\Document\Page; use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; -use Tests\TestCase; -class PageTest extends TestCase -{ - /** - * When n page is created, a SendDiscordNotification job shall be dispatched. - */ - public function testPageCreatedSendsDiscordNotification(): void - { - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(PageCreated::class); +test('page created sends discord notification', function () { + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(PageCreated::class); - Page::factory()->createOne(); + Page::factory()->createOne(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a page is deleted, a SendDiscordNotification job shall be dispatched. - */ - public function testPageDeletedSendsDiscordNotification(): void - { - $page = Page::factory()->createOne(); +test('page deleted sends discord notification', function () { + $page = Page::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(PageDeleted::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(PageDeleted::class); - $page->delete(); + $page->delete(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a page is restored, a SendDiscordNotification job shall be dispatched. - */ - public function testPageRestoredSendsDiscordNotification(): void - { - $page = Page::factory()->createOne(); +test('page restored sends discord notification', function () { + $page = Page::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(PageRestored::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(PageRestored::class); - $page->restore(); + $page->restore(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a page is updated, a SendDiscordNotification job shall be dispatched. - */ - public function testPageUpdatedSendsDiscordNotification(): void - { - $page = Page::factory()->createOne(); +test('page updated sends discord notification', function () { + $page = Page::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(PageUpdated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(PageUpdated::class); - $changes = Page::factory()->makeOne(); + $changes = Page::factory()->makeOne(); - $page->fill($changes->getAttributes()); - $page->save(); + $page->fill($changes->getAttributes()); + $page->save(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } -} + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); diff --git a/tests/Feature/Jobs/List/ExternalProfileTest.php b/tests/Feature/Jobs/List/ExternalProfileTest.php index e96e7e842..43087f252 100644 --- a/tests/Feature/Jobs/List/ExternalProfileTest.php +++ b/tests/Feature/Jobs/List/ExternalProfileTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Jobs\List; - use App\Constants\FeatureConstants; use App\Events\List\ExternalProfile\ExternalProfileCreated; use App\Events\List\ExternalProfile\ExternalProfileDeleted; @@ -13,56 +11,40 @@ use App\Models\List\ExternalProfile; use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; -use Tests\TestCase; -class ExternalProfileTest extends TestCase -{ - /** - * When a profile is created, a SendDiscordNotification job shall be dispatched. - */ - public function testExternalProfileCreatedSendsDiscordNotification(): void - { - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(ExternalProfileCreated::class); +test('external profile created sends discord notification', function () { + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(ExternalProfileCreated::class); - ExternalProfile::factory()->createOne(); + ExternalProfile::factory()->createOne(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a profile is deleted, a SendDiscordNotification job shall not be dispatched. - */ - public function testExternalProfileDeletedSendsDiscordNotification(): void - { - $profile = ExternalProfile::factory()->createOne(); +test('external profile deleted sends discord notification', function () { + $profile = ExternalProfile::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(ExternalProfileDeleted::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(ExternalProfileDeleted::class); - $profile->delete(); + $profile->delete(); - Bus::assertNotDispatched(SendDiscordNotificationJob::class); - } + Bus::assertNotDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a profile is updated, a SendDiscordNotification job shall not be dispatched. - */ - public function testExternalProfileUpdatedSendsDiscordNotification(): void - { - $profile = ExternalProfile::factory()->createOne(); +test('external profile updated sends discord notification', function () { + $profile = ExternalProfile::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(ExternalProfileUpdated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(ExternalProfileUpdated::class); - $changes = ExternalProfile::factory()->makeOne(); + $changes = ExternalProfile::factory()->makeOne(); - $profile->fill($changes->getAttributes()); - $profile->save(); + $profile->fill($changes->getAttributes()); + $profile->save(); - Bus::assertNotDispatched(SendDiscordNotificationJob::class); - } -} + Bus::assertNotDispatched(SendDiscordNotificationJob::class); +}); diff --git a/tests/Feature/Jobs/List/Playlist/TrackTest.php b/tests/Feature/Jobs/List/Playlist/TrackTest.php index f39f907df..44a15024b 100644 --- a/tests/Feature/Jobs/List/Playlist/TrackTest.php +++ b/tests/Feature/Jobs/List/Playlist/TrackTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Jobs\List\Playlist; - use App\Constants\FeatureConstants; use App\Events\List\Playlist\Track\TrackCreated; use App\Events\List\Playlist\Track\TrackDeleted; @@ -15,71 +13,55 @@ use App\Models\Wiki\Video; use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; -use Tests\TestCase; -class TrackTest extends TestCase -{ - /** - * When a track is created, a SendDiscordNotification job shall not be dispatched. - */ - public function testPlaylistCreatedSendsDiscordNotification(): void - { - $playlist = Playlist::factory()->createOne(); +test('playlist created sends discord notification', function () { + $playlist = Playlist::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(TrackCreated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(TrackCreated::class); - PlaylistTrack::factory() - ->for($playlist) - ->createOne(); + PlaylistTrack::factory() + ->for($playlist) + ->createOne(); - Bus::assertNotDispatched(SendDiscordNotificationJob::class); - } + Bus::assertNotDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a track is deleted, a SendDiscordNotification job shall not be dispatched. - */ - public function testPlaylistDeletedSendsDiscordNotification(): void - { - $playlist = Playlist::factory()->createOne(); +test('playlist deleted sends discord notification', function () { + $playlist = Playlist::factory()->createOne(); - $track = PlaylistTrack::factory() - ->for($playlist) - ->createOne(); + $track = PlaylistTrack::factory() + ->for($playlist) + ->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(TrackDeleted::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(TrackDeleted::class); - $track->delete(); + $track->delete(); - Bus::assertNotDispatched(SendDiscordNotificationJob::class); - } + Bus::assertNotDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a track is updated, a SendDiscordNotification job shall not be dispatched. - */ - public function testPlaylistUpdatedSendsDiscordNotification(): void - { - $playlist = Playlist::factory()->createOne(); +test('playlist updated sends discord notification', function () { + $playlist = Playlist::factory()->createOne(); - $track = PlaylistTrack::factory() - ->for($playlist) - ->createOne(); + $track = PlaylistTrack::factory() + ->for($playlist) + ->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(TrackUpdated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(TrackUpdated::class); - $changes = array_merge( - PlaylistTrack::factory()->raw(), - [PlaylistTrack::ATTRIBUTE_VIDEO => Video::factory()->createOne()->getKey()], - ); + $changes = array_merge( + PlaylistTrack::factory()->raw(), + [PlaylistTrack::ATTRIBUTE_VIDEO => Video::factory()->createOne()->getKey()], + ); - $track->fill($changes); - $track->save(); + $track->fill($changes); + $track->save(); - Bus::assertNotDispatched(SendDiscordNotificationJob::class); - } -} + Bus::assertNotDispatched(SendDiscordNotificationJob::class); +}); diff --git a/tests/Feature/Jobs/List/PlaylistTest.php b/tests/Feature/Jobs/List/PlaylistTest.php index d906d6f61..c6e8fd1f8 100644 --- a/tests/Feature/Jobs/List/PlaylistTest.php +++ b/tests/Feature/Jobs/List/PlaylistTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Jobs\List; - use App\Constants\FeatureConstants; use App\Events\List\Playlist\PlaylistCreated; use App\Events\List\Playlist\PlaylistDeleted; @@ -13,56 +11,40 @@ use App\Models\List\Playlist; use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; -use Tests\TestCase; -class PlaylistTest extends TestCase -{ - /** - * When a playlist is created, a SendDiscordNotification job shall be dispatched. - */ - public function testPlaylistCreatedSendsDiscordNotification(): void - { - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(PlaylistCreated::class); +test('playlist created sends discord notification', function () { + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(PlaylistCreated::class); - Playlist::factory()->createOne(); + Playlist::factory()->createOne(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a playlist is deleted, a SendDiscordNotification job shall not be dispatched. - */ - public function testPlaylistDeletedSendsDiscordNotification(): void - { - $playlist = Playlist::factory()->createOne(); +test('playlist deleted sends discord notification', function () { + $playlist = Playlist::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(PlaylistDeleted::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(PlaylistDeleted::class); - $playlist->delete(); + $playlist->delete(); - Bus::assertNotDispatched(SendDiscordNotificationJob::class); - } + Bus::assertNotDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a playlist is updated, a SendDiscordNotification job shall not be dispatched. - */ - public function testPlaylistUpdatedSendsDiscordNotification(): void - { - $playlist = Playlist::factory()->createOne(); +test('playlist updated sends discord notification', function () { + $playlist = Playlist::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(PlaylistUpdated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(PlaylistUpdated::class); - $changes = Playlist::factory()->makeOne(); + $changes = Playlist::factory()->makeOne(); - $playlist->fill($changes->getAttributes()); - $playlist->save(); + $playlist->fill($changes->getAttributes()); + $playlist->save(); - Bus::assertNotDispatched(SendDiscordNotificationJob::class); - } -} + Bus::assertNotDispatched(SendDiscordNotificationJob::class); +}); diff --git a/tests/Feature/Jobs/Pivot/List/PlaylistImageTest.php b/tests/Feature/Jobs/Pivot/List/PlaylistImageTest.php index 2eecd939e..689cdb7b3 100644 --- a/tests/Feature/Jobs/Pivot/List/PlaylistImageTest.php +++ b/tests/Feature/Jobs/Pivot/List/PlaylistImageTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Jobs\Pivot\List; - use App\Constants\FeatureConstants; use App\Events\Pivot\List\PlaylistImage\PlaylistImageCreated; use App\Events\Pivot\List\PlaylistImage\PlaylistImageDeleted; @@ -13,43 +11,31 @@ use App\Models\Wiki\Image; use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; -use Tests\TestCase; -class PlaylistImageTest extends TestCase -{ - /** - * When a Playlist is attached to an Image or vice versa, a SendDiscordNotification job shall be dispatched. - */ - public function testPlaylistImageCreatedSendsDiscordNotification(): void - { - $playlist = Playlist::factory()->createOne(); - $image = Image::factory()->createOne(); +test('playlist image created sends discord notification', function () { + $playlist = Playlist::factory()->createOne(); + $image = Image::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(PlaylistImageCreated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(PlaylistImageCreated::class); - $playlist->images()->attach($image); + $playlist->images()->attach($image); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a Playlist is detached from an Image or vice versa, a SendDiscordNotification job shall be dispatched. - */ - public function testPlaylistImageDeletedSendsDiscordNotification(): void - { - $playlist = Playlist::factory()->createOne(); - $image = Image::factory()->createOne(); +test('playlist image deleted sends discord notification', function () { + $playlist = Playlist::factory()->createOne(); + $image = Image::factory()->createOne(); - $playlist->images()->attach($image); + $playlist->images()->attach($image); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(PlaylistImageDeleted::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(PlaylistImageDeleted::class); - $playlist->images()->detach($image); + $playlist->images()->detach($image); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } -} + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); diff --git a/tests/Feature/Jobs/Pivot/Wiki/AnimeImageTest.php b/tests/Feature/Jobs/Pivot/Wiki/AnimeImageTest.php index 3b8134778..6d8ee99f1 100644 --- a/tests/Feature/Jobs/Pivot/Wiki/AnimeImageTest.php +++ b/tests/Feature/Jobs/Pivot/Wiki/AnimeImageTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Jobs\Pivot\Wiki; - use App\Constants\FeatureConstants; use App\Events\Pivot\Wiki\AnimeImage\AnimeImageCreated; use App\Events\Pivot\Wiki\AnimeImage\AnimeImageDeleted; @@ -13,43 +11,31 @@ use App\Models\Wiki\Image; use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; -use Tests\TestCase; -class AnimeImageTest extends TestCase -{ - /** - * When an Anime is attached to an Image or vice versa, a SendDiscordNotification job shall be dispatched. - */ - public function testAnimeImageCreatedSendsDiscordNotification(): void - { - $anime = Anime::factory()->createOne(); - $image = Image::factory()->createOne(); +test('anime image created sends discord notification', function () { + $anime = Anime::factory()->createOne(); + $image = Image::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(AnimeImageCreated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(AnimeImageCreated::class); - $anime->images()->attach($image); + $anime->images()->attach($image); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When an Anime is detached from an Image or vice versa, a SendDiscordNotification job shall be dispatched. - */ - public function testAnimeImageDeletedSendsDiscordNotification(): void - { - $anime = Anime::factory()->createOne(); - $image = Image::factory()->createOne(); +test('anime image deleted sends discord notification', function () { + $anime = Anime::factory()->createOne(); + $image = Image::factory()->createOne(); - $anime->images()->attach($image); + $anime->images()->attach($image); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(AnimeImageDeleted::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(AnimeImageDeleted::class); - $anime->images()->detach($image); + $anime->images()->detach($image); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } -} + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); diff --git a/tests/Feature/Jobs/Pivot/Wiki/AnimeResourceTest.php b/tests/Feature/Jobs/Pivot/Wiki/AnimeResourceTest.php index e32251197..abd5a1a0b 100644 --- a/tests/Feature/Jobs/Pivot/Wiki/AnimeResourceTest.php +++ b/tests/Feature/Jobs/Pivot/Wiki/AnimeResourceTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Jobs\Pivot\Wiki; - use App\Constants\FeatureConstants; use App\Events\Pivot\Wiki\AnimeResource\AnimeResourceCreated; use App\Events\Pivot\Wiki\AnimeResource\AnimeResourceDeleted; @@ -15,71 +13,55 @@ use App\Pivots\Wiki\AnimeResource; use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; -use Tests\TestCase; -class AnimeResourceTest extends TestCase -{ - /** - * When an Anime is attached to a Resource or vice versa, a SendDiscordNotification job shall be dispatched. - */ - public function testAnimeResourceCreatedSendsDiscordNotification(): void - { - $anime = Anime::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); +test('anime resource created sends discord notification', function () { + $anime = Anime::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(AnimeResourceCreated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(AnimeResourceCreated::class); - $anime->resources()->attach($resource); + $anime->resources()->attach($resource); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When an Anime is detached from a Resource or vice versa, a SendDiscordNotification job shall be dispatched. - */ - public function testAnimeResourceDeletedSendsDiscordNotification(): void - { - $anime = Anime::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); +test('anime resource deleted sends discord notification', function () { + $anime = Anime::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - $anime->resources()->attach($resource); + $anime->resources()->attach($resource); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(AnimeResourceDeleted::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(AnimeResourceDeleted::class); - $anime->resources()->detach($resource); + $anime->resources()->detach($resource); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When an Anime Resource pivot is updated, a SendDiscordNotification job shall be dispatched. - */ - public function testAnimeResourceUpdatedSendsDiscordNotification(): void - { - $anime = Anime::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); +test('anime resource updated sends discord notification', function () { + $anime = Anime::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - $animeResource = AnimeResource::factory() - ->for($anime, 'anime') - ->for($resource, 'resource') - ->createOne(); + $animeResource = AnimeResource::factory() + ->for($anime, 'anime') + ->for($resource, 'resource') + ->createOne(); - $changes = AnimeResource::factory() - ->for($anime, 'anime') - ->for($resource, 'resource') - ->makeOne(); + $changes = AnimeResource::factory() + ->for($anime, 'anime') + ->for($resource, 'resource') + ->makeOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(AnimeResourceUpdated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(AnimeResourceUpdated::class); - $animeResource->fill($changes->getAttributes()); - $animeResource->save(); + $animeResource->fill($changes->getAttributes()); + $animeResource->save(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } -} + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); diff --git a/tests/Feature/Jobs/Pivot/Wiki/AnimeSeriesTest.php b/tests/Feature/Jobs/Pivot/Wiki/AnimeSeriesTest.php index 135fcf280..c71f28255 100644 --- a/tests/Feature/Jobs/Pivot/Wiki/AnimeSeriesTest.php +++ b/tests/Feature/Jobs/Pivot/Wiki/AnimeSeriesTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Jobs\Pivot\Wiki; - use App\Constants\FeatureConstants; use App\Events\Pivot\Wiki\AnimeSeries\AnimeSeriesCreated; use App\Events\Pivot\Wiki\AnimeSeries\AnimeSeriesDeleted; @@ -13,43 +11,31 @@ use App\Models\Wiki\Series; use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; -use Tests\TestCase; -class AnimeSeriesTest extends TestCase -{ - /** - * When an Anime is attached to a Series or vice versa, a SendDiscordNotification job shall be dispatched. - */ - public function testAnimeSeriesCreatedSendsDiscordNotification(): void - { - $anime = Anime::factory()->createOne(); - $series = Series::factory()->createOne(); +test('anime series created sends discord notification', function () { + $anime = Anime::factory()->createOne(); + $series = Series::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(AnimeSeriesCreated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(AnimeSeriesCreated::class); - $anime->series()->attach($series); + $anime->series()->attach($series); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When an Anime is detached from a Series or vice versa, a SendDiscordNotification job shall be dispatched. - */ - public function testAnimeSeriesDeletedSendsDiscordNotification(): void - { - $anime = Anime::factory()->createOne(); - $series = Series::factory()->createOne(); +test('anime series deleted sends discord notification', function () { + $anime = Anime::factory()->createOne(); + $series = Series::factory()->createOne(); - $anime->series()->attach($series); + $anime->series()->attach($series); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(AnimeSeriesDeleted::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(AnimeSeriesDeleted::class); - $anime->series()->detach($series); + $anime->series()->detach($series); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } -} + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); diff --git a/tests/Feature/Jobs/Pivot/Wiki/AnimeStudioTest.php b/tests/Feature/Jobs/Pivot/Wiki/AnimeStudioTest.php index 533018036..6473430ff 100644 --- a/tests/Feature/Jobs/Pivot/Wiki/AnimeStudioTest.php +++ b/tests/Feature/Jobs/Pivot/Wiki/AnimeStudioTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Jobs\Pivot\Wiki; - use App\Constants\FeatureConstants; use App\Events\Pivot\Wiki\AnimeStudio\AnimeStudioCreated; use App\Events\Pivot\Wiki\AnimeStudio\AnimeStudioDeleted; @@ -13,43 +11,31 @@ use App\Models\Wiki\Studio; use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; -use Tests\TestCase; -class AnimeStudioTest extends TestCase -{ - /** - * When an Anime is attached to a Studio or vice versa, a SendDiscordNotification job shall be dispatched. - */ - public function testAnimeStudioCreatedSendsDiscordNotification(): void - { - $anime = Anime::factory()->createOne(); - $studio = Studio::factory()->createOne(); +test('anime studio created sends discord notification', function () { + $anime = Anime::factory()->createOne(); + $studio = Studio::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(AnimeStudioCreated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(AnimeStudioCreated::class); - $anime->studios()->attach($studio); + $anime->studios()->attach($studio); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When an Anime is detached from a Studio or vice versa, a SendDiscordNotification job shall be dispatched. - */ - public function testAnimeStudioDeletedSendsDiscordNotification(): void - { - $anime = Anime::factory()->createOne(); - $studio = Studio::factory()->createOne(); +test('anime studio deleted sends discord notification', function () { + $anime = Anime::factory()->createOne(); + $studio = Studio::factory()->createOne(); - $anime->studios()->attach($studio); + $anime->studios()->attach($studio); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(AnimeStudioDeleted::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(AnimeStudioDeleted::class); - $anime->studios()->detach($studio); + $anime->studios()->detach($studio); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } -} + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); diff --git a/tests/Feature/Jobs/Pivot/Wiki/AnimeThemeEntryVideoTest.php b/tests/Feature/Jobs/Pivot/Wiki/AnimeThemeEntryVideoTest.php index 34f101e7b..6c52d7a47 100644 --- a/tests/Feature/Jobs/Pivot/Wiki/AnimeThemeEntryVideoTest.php +++ b/tests/Feature/Jobs/Pivot/Wiki/AnimeThemeEntryVideoTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Jobs\Pivot\Wiki; - use App\Constants\FeatureConstants; use App\Events\Pivot\Wiki\AnimeThemeEntryVideo\AnimeThemeEntryVideoCreated; use App\Events\Pivot\Wiki\AnimeThemeEntryVideo\AnimeThemeEntryVideoDeleted; @@ -15,47 +13,35 @@ use App\Models\Wiki\Video; use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; -use Tests\TestCase; -class AnimeThemeEntryVideoTest extends TestCase -{ - /** - * When a Video is attached to an AnimeThemeEntry or vice versa, a SendDiscordNotification job shall be dispatched. - */ - public function testAnimeThemeEntryVideoCreatedSendsDiscordNotification(): void - { - $video = Video::factory()->createOne(); - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); +test('anime theme entry video created sends discord notification', function () { + $video = Video::factory()->createOne(); + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(AnimeThemeEntryVideoCreated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(AnimeThemeEntryVideoCreated::class); - $video->animethemeentries()->attach($entry); + $video->animethemeentries()->attach($entry); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a Video is detached from an AnimeThemeEntry or vice versa, a SendDiscordNotification job shall be dispatched. - */ - public function testAnimeThemeEntryVideoDeletedSendsDiscordNotification(): void - { - $video = Video::factory()->createOne(); - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); +test('anime theme entry video deleted sends discord notification', function () { + $video = Video::factory()->createOne(); + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - $video->animethemeentries()->attach($entry); + $video->animethemeentries()->attach($entry); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(AnimeThemeEntryVideoDeleted::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(AnimeThemeEntryVideoDeleted::class); - $video->animethemeentries()->detach($entry); + $video->animethemeentries()->detach($entry); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } -} + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); diff --git a/tests/Feature/Jobs/Pivot/Wiki/ArtistImageTest.php b/tests/Feature/Jobs/Pivot/Wiki/ArtistImageTest.php index 969de258c..8ec62e0bc 100644 --- a/tests/Feature/Jobs/Pivot/Wiki/ArtistImageTest.php +++ b/tests/Feature/Jobs/Pivot/Wiki/ArtistImageTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Jobs\Pivot\Wiki; - use App\Constants\FeatureConstants; use App\Events\Pivot\Wiki\ArtistImage\ArtistImageCreated; use App\Events\Pivot\Wiki\ArtistImage\ArtistImageDeleted; @@ -13,43 +11,31 @@ use App\Models\Wiki\Image; use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; -use Tests\TestCase; -class ArtistImageTest extends TestCase -{ - /** - * When an Artist is attached to an Image or vice versa, a SendDiscordNotification job shall be dispatched. - */ - public function testArtistImageCreatedSendsDiscordNotification(): void - { - $artist = Artist::factory()->createOne(); - $image = Image::factory()->createOne(); +test('artist image created sends discord notification', function () { + $artist = Artist::factory()->createOne(); + $image = Image::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(ArtistImageCreated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(ArtistImageCreated::class); - $artist->images()->attach($image); + $artist->images()->attach($image); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When an Artist is detached from an Image or vice versa, a SendDiscordNotification job shall be dispatched. - */ - public function testArtistImageDeletedSendsDiscordNotification(): void - { - $artist = Artist::factory()->createOne(); - $image = Image::factory()->createOne(); +test('artist image deleted sends discord notification', function () { + $artist = Artist::factory()->createOne(); + $image = Image::factory()->createOne(); - $artist->images()->attach($image); + $artist->images()->attach($image); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(ArtistImageDeleted::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(ArtistImageDeleted::class); - $artist->images()->detach($image); + $artist->images()->detach($image); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } -} + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); diff --git a/tests/Feature/Jobs/Pivot/Wiki/ArtistMemberTest.php b/tests/Feature/Jobs/Pivot/Wiki/ArtistMemberTest.php index 47aff996f..6b7e9ec21 100644 --- a/tests/Feature/Jobs/Pivot/Wiki/ArtistMemberTest.php +++ b/tests/Feature/Jobs/Pivot/Wiki/ArtistMemberTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Jobs\Pivot\Wiki; - use App\Constants\FeatureConstants; use App\Events\Pivot\Wiki\ArtistMember\ArtistMemberCreated; use App\Events\Pivot\Wiki\ArtistMember\ArtistMemberDeleted; @@ -14,71 +12,55 @@ use App\Pivots\Wiki\ArtistMember; use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; -use Tests\TestCase; -class ArtistMemberTest extends TestCase -{ - /** - * When an Artist is attached to a Member or vice versa, a SendDiscordNotification job shall be dispatched. - */ - public function testArtistMemberCreatedSendsDiscordNotification(): void - { - $artist = Artist::factory()->createOne(); - $member = Artist::factory()->createOne(); +test('artist member created sends discord notification', function () { + $artist = Artist::factory()->createOne(); + $member = Artist::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(ArtistMemberCreated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(ArtistMemberCreated::class); - $artist->members()->attach($member); + $artist->members()->attach($member); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When an Artist is detached from a Member or vice versa, a SendDiscordNotification job shall be dispatched. - */ - public function testArtistMemberDeletedSendsDiscordNotification(): void - { - $artist = Artist::factory()->createOne(); - $member = Artist::factory()->createOne(); +test('artist member deleted sends discord notification', function () { + $artist = Artist::factory()->createOne(); + $member = Artist::factory()->createOne(); - $artist->members()->attach($member); + $artist->members()->attach($member); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(ArtistMemberDeleted::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(ArtistMemberDeleted::class); - $artist->members()->detach($member); + $artist->members()->detach($member); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When an Artist Member pivot is updated, a SendDiscordNotification job shall be dispatched. - */ - public function testArtistMemberUpdatedSendsDiscordNotification(): void - { - $artist = Artist::factory()->createOne(); - $member = Artist::factory()->createOne(); +test('artist member updated sends discord notification', function () { + $artist = Artist::factory()->createOne(); + $member = Artist::factory()->createOne(); - $artistMember = ArtistMember::factory() - ->for($artist, 'artist') - ->for($member, 'member') - ->createOne(); + $artistMember = ArtistMember::factory() + ->for($artist, 'artist') + ->for($member, 'member') + ->createOne(); - $changes = ArtistMember::factory() - ->for($artist, 'artist') - ->for($member, 'member') - ->makeOne(); + $changes = ArtistMember::factory() + ->for($artist, 'artist') + ->for($member, 'member') + ->makeOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(ArtistMemberUpdated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(ArtistMemberUpdated::class); - $artistMember->fill($changes->getAttributes()); - $artistMember->save(); + $artistMember->fill($changes->getAttributes()); + $artistMember->save(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } -} + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); diff --git a/tests/Feature/Jobs/Pivot/Wiki/ArtistResourceTest.php b/tests/Feature/Jobs/Pivot/Wiki/ArtistResourceTest.php index 612e56ceb..b855990ee 100644 --- a/tests/Feature/Jobs/Pivot/Wiki/ArtistResourceTest.php +++ b/tests/Feature/Jobs/Pivot/Wiki/ArtistResourceTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Jobs\Pivot\Wiki; - use App\Constants\FeatureConstants; use App\Events\Pivot\Wiki\ArtistResource\ArtistResourceCreated; use App\Events\Pivot\Wiki\ArtistResource\ArtistResourceDeleted; @@ -15,71 +13,55 @@ use App\Pivots\Wiki\ArtistResource; use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; -use Tests\TestCase; -class ArtistResourceTest extends TestCase -{ - /** - * When an Artist is attached to a Resource or vice versa, a SendDiscordNotification job shall be dispatched. - */ - public function testArtistResourceCreatedSendsDiscordNotification(): void - { - $artist = Artist::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); +test('artist resource created sends discord notification', function () { + $artist = Artist::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(ArtistResourceCreated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(ArtistResourceCreated::class); - $artist->resources()->attach($resource); + $artist->resources()->attach($resource); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When an Artist is detached from a Resource or vice versa, a SendDiscordNotification job shall be dispatched. - */ - public function testArtistResourceDeletedSendsDiscordNotification(): void - { - $artist = Artist::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); +test('artist resource deleted sends discord notification', function () { + $artist = Artist::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - $artist->resources()->attach($resource); + $artist->resources()->attach($resource); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(ArtistResourceDeleted::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(ArtistResourceDeleted::class); - $artist->resources()->detach($resource); + $artist->resources()->detach($resource); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When an Artist Resource pivot is updated, a SendDiscordNotification job shall be dispatched. - */ - public function testArtistResourceUpdatedSendsDiscordNotification(): void - { - $artist = Artist::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); +test('artist resource updated sends discord notification', function () { + $artist = Artist::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - $artistResource = ArtistResource::factory() - ->for($artist, 'artist') - ->for($resource, 'resource') - ->createOne(); + $artistResource = ArtistResource::factory() + ->for($artist, 'artist') + ->for($resource, 'resource') + ->createOne(); - $changes = ArtistResource::factory() - ->for($artist, 'artist') - ->for($resource, 'resource') - ->makeOne(); + $changes = ArtistResource::factory() + ->for($artist, 'artist') + ->for($resource, 'resource') + ->makeOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(ArtistResourceUpdated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(ArtistResourceUpdated::class); - $artistResource->fill($changes->getAttributes()); - $artistResource->save(); + $artistResource->fill($changes->getAttributes()); + $artistResource->save(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } -} + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); diff --git a/tests/Feature/Jobs/Pivot/Wiki/ArtistSongTest.php b/tests/Feature/Jobs/Pivot/Wiki/ArtistSongTest.php index 01f9d8860..ed5063068 100644 --- a/tests/Feature/Jobs/Pivot/Wiki/ArtistSongTest.php +++ b/tests/Feature/Jobs/Pivot/Wiki/ArtistSongTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Jobs\Pivot\Wiki; - use App\Constants\FeatureConstants; use App\Events\Pivot\Wiki\ArtistSong\ArtistSongCreated; use App\Events\Pivot\Wiki\ArtistSong\ArtistSongDeleted; @@ -15,71 +13,55 @@ use App\Pivots\Wiki\ArtistSong; use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; -use Tests\TestCase; -class ArtistSongTest extends TestCase -{ - /** - * When an Artist is attached to a Song or vice versa, a SendDiscordNotification job shall be dispatched. - */ - public function testArtistSongCreatedSendsDiscordNotification(): void - { - $artist = Artist::factory()->createOne(); - $song = Song::factory()->createOne(); +test('artist song created sends discord notification', function () { + $artist = Artist::factory()->createOne(); + $song = Song::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(ArtistSongCreated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(ArtistSongCreated::class); - $artist->songs()->attach($song); + $artist->songs()->attach($song); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When an Artist is detached from a Song or vice versa, a SendDiscordNotification job shall be dispatched. - */ - public function testArtistSongDeletedSendsDiscordNotification(): void - { - $artist = Artist::factory()->createOne(); - $song = Song::factory()->createOne(); +test('artist song deleted sends discord notification', function () { + $artist = Artist::factory()->createOne(); + $song = Song::factory()->createOne(); - $artist->songs()->attach($song); + $artist->songs()->attach($song); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(ArtistSongDeleted::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(ArtistSongDeleted::class); - $artist->songs()->detach($song); + $artist->songs()->detach($song); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When an Artist Song pivot is updated, a SendDiscordNotification job shall be dispatched. - */ - public function testArtistSongUpdatedSendsDiscordNotification(): void - { - $artist = Artist::factory()->createOne(); - $song = Song::factory()->createOne(); +test('artist song updated sends discord notification', function () { + $artist = Artist::factory()->createOne(); + $song = Song::factory()->createOne(); - $artistSong = ArtistSong::factory() - ->for($artist, 'artist') - ->for($song, 'song') - ->createOne(); + $artistSong = ArtistSong::factory() + ->for($artist, 'artist') + ->for($song, 'song') + ->createOne(); - $changes = ArtistSong::factory() - ->for($artist, 'artist') - ->for($song, 'song') - ->makeOne(); + $changes = ArtistSong::factory() + ->for($artist, 'artist') + ->for($song, 'song') + ->makeOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(ArtistSongUpdated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(ArtistSongUpdated::class); - $artistSong->fill($changes->getAttributes()); - $artistSong->save(); + $artistSong->fill($changes->getAttributes()); + $artistSong->save(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } -} + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); diff --git a/tests/Feature/Jobs/Pivot/Wiki/SongResourceTest.php b/tests/Feature/Jobs/Pivot/Wiki/SongResourceTest.php index 862c8e0e9..7adce2595 100644 --- a/tests/Feature/Jobs/Pivot/Wiki/SongResourceTest.php +++ b/tests/Feature/Jobs/Pivot/Wiki/SongResourceTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Jobs\Pivot\Wiki; - use App\Constants\FeatureConstants; use App\Events\Pivot\Wiki\SongResource\SongResourceCreated; use App\Events\Pivot\Wiki\SongResource\SongResourceDeleted; @@ -15,71 +13,55 @@ use App\Pivots\Wiki\SongResource; use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; -use Tests\TestCase; -class SongResourceTest extends TestCase -{ - /** - * When an Song is attached to a Resource or vice versa, a SendDiscordNotification job shall be dispatched. - */ - public function testSongResourceCreatedSendsDiscordNotification(): void - { - $song = Song::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); +test('song resource created sends discord notification', function () { + $song = Song::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(SongResourceCreated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(SongResourceCreated::class); - $song->resources()->attach($resource); + $song->resources()->attach($resource); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When an Song is detached from a Resource or vice versa, a SendDiscordNotification job shall be dispatched. - */ - public function testSongResourceDeletedSendsDiscordNotification(): void - { - $song = Song::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); +test('song resource deleted sends discord notification', function () { + $song = Song::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - $song->resources()->attach($resource); + $song->resources()->attach($resource); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(SongResourceDeleted::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(SongResourceDeleted::class); - $song->resources()->detach($resource); + $song->resources()->detach($resource); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When an Song Resource pivot is updated, a SendDiscordNotification job shall be dispatched. - */ - public function testSongResourceUpdatedSendsDiscordNotification(): void - { - $song = Song::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); +test('song resource updated sends discord notification', function () { + $song = Song::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - $songResource = SongResource::factory() - ->for($song, 'song') - ->for($resource, 'resource') - ->createOne(); + $songResource = SongResource::factory() + ->for($song, 'song') + ->for($resource, 'resource') + ->createOne(); - $changes = SongResource::factory() - ->for($song, 'song') - ->for($resource, 'resource') - ->makeOne(); + $changes = SongResource::factory() + ->for($song, 'song') + ->for($resource, 'resource') + ->makeOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(SongResourceUpdated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(SongResourceUpdated::class); - $songResource->fill($changes->getAttributes()); - $songResource->save(); + $songResource->fill($changes->getAttributes()); + $songResource->save(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } -} + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); diff --git a/tests/Feature/Jobs/Pivot/Wiki/StudioImageTest.php b/tests/Feature/Jobs/Pivot/Wiki/StudioImageTest.php index 5edb23c16..8ab114e06 100644 --- a/tests/Feature/Jobs/Pivot/Wiki/StudioImageTest.php +++ b/tests/Feature/Jobs/Pivot/Wiki/StudioImageTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Jobs\Pivot\Wiki; - use App\Constants\FeatureConstants; use App\Events\Pivot\Wiki\StudioImage\StudioImageCreated; use App\Events\Pivot\Wiki\StudioImage\StudioImageDeleted; @@ -13,43 +11,31 @@ use App\Models\Wiki\Studio; use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; -use Tests\TestCase; -class StudioImageTest extends TestCase -{ - /** - * When a Studio is attached to an Image or vice versa, a SendDiscordNotification job shall be dispatched. - */ - public function testStudioImageCreatedSendsDiscordNotification(): void - { - $studio = Studio::factory()->createOne(); - $image = Image::factory()->createOne(); +test('studio image created sends discord notification', function () { + $studio = Studio::factory()->createOne(); + $image = Image::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(StudioImageCreated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(StudioImageCreated::class); - $studio->images()->attach($image); + $studio->images()->attach($image); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a Studio is detached from an Image or vice versa, a SendDiscordNotification job shall be dispatched. - */ - public function testStudioImageDeletedSendsDiscordNotification(): void - { - $studio = Studio::factory()->createOne(); - $image = Image::factory()->createOne(); +test('studio image deleted sends discord notification', function () { + $studio = Studio::factory()->createOne(); + $image = Image::factory()->createOne(); - $studio->images()->attach($image); + $studio->images()->attach($image); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(StudioImageDeleted::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(StudioImageDeleted::class); - $studio->images()->detach($image); + $studio->images()->detach($image); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } -} + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); diff --git a/tests/Feature/Jobs/Pivot/Wiki/StudioResourceTest.php b/tests/Feature/Jobs/Pivot/Wiki/StudioResourceTest.php index b7daa2492..c3f126e46 100644 --- a/tests/Feature/Jobs/Pivot/Wiki/StudioResourceTest.php +++ b/tests/Feature/Jobs/Pivot/Wiki/StudioResourceTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Jobs\Pivot\Wiki; - use App\Constants\FeatureConstants; use App\Events\Pivot\Wiki\StudioResource\StudioResourceCreated; use App\Events\Pivot\Wiki\StudioResource\StudioResourceDeleted; @@ -15,71 +13,55 @@ use App\Pivots\Wiki\StudioResource; use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; -use Tests\TestCase; -class StudioResourceTest extends TestCase -{ - /** - * When a Studio is attached to a Resource or vice versa, a SendDiscordNotification job shall be dispatched. - */ - public function testStudioResourceCreatedSendsDiscordNotification(): void - { - $studio = Studio::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); +test('studio resource created sends discord notification', function () { + $studio = Studio::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(StudioResourceCreated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(StudioResourceCreated::class); - $studio->resources()->attach($resource); + $studio->resources()->attach($resource); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a Studio is detached from a Resource or vice versa, a SendDiscordNotification job shall be dispatched. - */ - public function testStudioResourceDeletedSendsDiscordNotification(): void - { - $studio = Studio::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); +test('studio resource deleted sends discord notification', function () { + $studio = Studio::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - $studio->resources()->attach($resource); + $studio->resources()->attach($resource); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(StudioResourceDeleted::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(StudioResourceDeleted::class); - $studio->resources()->detach($resource); + $studio->resources()->detach($resource); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a Studio Resource pivot is updated, a SendDiscordNotification job will be dispatched. - */ - public function testStudioResourceUpdatedSendsDiscordNotification(): void - { - $studio = Studio::factory()->createOne(); - $resource = ExternalResource::factory()->createOne(); +test('studio resource updated sends discord notification', function () { + $studio = Studio::factory()->createOne(); + $resource = ExternalResource::factory()->createOne(); - $studioResource = StudioResource::factory() - ->for($studio, 'studio') - ->for($resource, 'resource') - ->createOne(); + $studioResource = StudioResource::factory() + ->for($studio, 'studio') + ->for($resource, 'resource') + ->createOne(); - $changes = StudioResource::factory() - ->for($studio, 'studio') - ->for($resource, 'resource') - ->makeOne(); + $changes = StudioResource::factory() + ->for($studio, 'studio') + ->for($resource, 'resource') + ->makeOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(StudioResourceUpdated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(StudioResourceUpdated::class); - $studioResource->fill($changes->getAttributes()); - $studioResource->save(); + $studioResource->fill($changes->getAttributes()); + $studioResource->save(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } -} + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); diff --git a/tests/Feature/Jobs/SendDiscordNotificationTest.php b/tests/Feature/Jobs/SendDiscordNotificationTest.php index 4f3889453..c5e54a3ed 100644 --- a/tests/Feature/Jobs/SendDiscordNotificationTest.php +++ b/tests/Feature/Jobs/SendDiscordNotificationTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Jobs; - use App\Constants\FeatureConstants; use App\Contracts\Events\DiscordMessageEvent; use App\Jobs\Middleware\RateLimited; @@ -14,97 +12,85 @@ use Illuminate\Notifications\AnonymousNotifiable; use Illuminate\Support\Facades\Notification; use Laravel\Pennant\Feature; use NotificationChannels\Discord\DiscordMessage; -use Tests\TestCase; -class SendDiscordNotificationTest extends TestCase -{ - /** - * The Send Discord Notification Job shall send a DiscordNotification. - */ - public function testSendDiscordNotificationJobSendsNotification(): void +use function Pest\Laravel\get; + +test('send discord notification job sends notification', function () { + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Notification::fake(); + + $event = new class implements DiscordMessageEvent { - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Notification::fake(); + use Dispatchable; - $event = new class implements DiscordMessageEvent + /** + * Get Discord message payload. + * + * @return DiscordMessage + */ + public function getDiscordMessage(): DiscordMessage { - use Dispatchable; + return DiscordMessage::create(); + } - /** - * Get Discord message payload. - * - * @return DiscordMessage - */ - public function getDiscordMessage(): DiscordMessage - { - return DiscordMessage::create(); - } + /** + * Get Discord channel the message will be sent to. + */ + public function getDiscordChannel(): string + { + return ''; + } - /** - * Get Discord channel the message will be sent to. - */ - public function getDiscordChannel(): string - { - return ''; - } + /** + * Determine if the message should be sent. + */ + public function shouldSendDiscordMessage(): bool + { + return true; + } + }; + $job = new SendDiscordNotificationJob($event); - /** - * Determine if the message should be sent. - */ - public function shouldSendDiscordMessage(): bool - { - return true; - } - }; + $job->handle(); - $job = new SendDiscordNotificationJob($event); + Notification::assertSentTo( + new AnonymousNotifiable(), + DiscordNotification::class, + ); +}); - $job->handle(); - - Notification::assertSentTo( - new AnonymousNotifiable(), - DiscordNotification::class, - ); - } - - /** - * The Send Discord Notification Job shall use the RateLimited middleware. - */ - public function testRateLimited(): void +test('rate limited', function () { + $event = new class implements DiscordMessageEvent { - $event = new class implements DiscordMessageEvent + use Dispatchable; + + /** + * Get Discord message payload. + */ + public function getDiscordMessage(): DiscordMessage { - use Dispatchable; + return DiscordMessage::create(); + } - /** - * Get Discord message payload. - */ - public function getDiscordMessage(): DiscordMessage - { - return DiscordMessage::create(); - } + /** + * Get Discord channel the message will be sent to. + */ + public function getDiscordChannel(): string + { + return ''; + } - /** - * Get Discord channel the message will be sent to. - */ - public function getDiscordChannel(): string - { - return ''; - } + /** + * Determine if the message should be sent. + */ + public function shouldSendDiscordMessage(): bool + { + return true; + } + }; + $job = new SendDiscordNotificationJob($event); - /** - * Determine if the message should be sent. - */ - public function shouldSendDiscordMessage(): bool - { - return true; - } - }; + $middleware = collect($job->middleware())->first(); - $job = new SendDiscordNotificationJob($event); - - $middleware = collect($job->middleware())->first(); - - static::assertInstanceOf(RateLimited::class, $middleware); - } -} + $this->assertInstanceOf(RateLimited::class, $middleware); +}); diff --git a/tests/Feature/Jobs/Wiki/Anime/SynonymTest.php b/tests/Feature/Jobs/Wiki/Anime/SynonymTest.php index cf7d31ddf..e5af6758d 100644 --- a/tests/Feature/Jobs/Wiki/Anime/SynonymTest.php +++ b/tests/Feature/Jobs/Wiki/Anime/SynonymTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Jobs\Wiki\Anime; - use App\Constants\FeatureConstants; use App\Events\Wiki\Anime\Synonym\SynonymCreated; use App\Events\Wiki\Anime\Synonym\SynonymDeleted; @@ -15,82 +13,62 @@ use App\Models\Wiki\Anime\AnimeSynonym; use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; -use Tests\TestCase; -class SynonymTest extends TestCase -{ - /** - * When a synonym is created, a SendDiscordNotification job shall be dispatched. - */ - public function testSynonymCreatedSendsDiscordNotification(): void - { - $anime = Anime::factory()->createOne(); +test('synonym created sends discord notification', function () { + $anime = Anime::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(SynonymCreated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(SynonymCreated::class); - AnimeSynonym::factory()->for($anime)->createOne(); + AnimeSynonym::factory()->for($anime)->createOne(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a synonym is deleted, a SendDiscordNotification job shall be dispatched. - */ - public function testSynonymDeletedSendsDiscordNotification(): void - { - $synonym = AnimeSynonym::factory() - ->for(Anime::factory()) - ->createOne(); +test('synonym deleted sends discord notification', function () { + $synonym = AnimeSynonym::factory() + ->for(Anime::factory()) + ->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(SynonymDeleted::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(SynonymDeleted::class); - $synonym->delete(); + $synonym->delete(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a synonym is restored, a SendDiscordNotification job shall be dispatched. - */ - public function testSynonymRestoredSendsDiscordNotification(): void - { - $synonym = AnimeSynonym::factory() - ->for(Anime::factory()) - ->createOne(); +test('synonym restored sends discord notification', function () { + $synonym = AnimeSynonym::factory() + ->for(Anime::factory()) + ->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(SynonymRestored::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(SynonymRestored::class); - $synonym->restore(); + $synonym->restore(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a synonym is updated, a SendDiscordNotification job shall be dispatched. - */ - public function testSynonymUpdatedSendsDiscordNotification(): void - { - $synonym = AnimeSynonym::factory() - ->for(Anime::factory()) - ->createOne(); +test('synonym updated sends discord notification', function () { + $synonym = AnimeSynonym::factory() + ->for(Anime::factory()) + ->createOne(); - $changes = AnimeSynonym::factory() - ->for(Anime::factory()) - ->makeOne(); + $changes = AnimeSynonym::factory() + ->for(Anime::factory()) + ->makeOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(SynonymUpdated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(SynonymUpdated::class); - $synonym->fill($changes->getAttributes()); - $synonym->save(); + $synonym->fill($changes->getAttributes()); + $synonym->save(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } -} + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); diff --git a/tests/Feature/Jobs/Wiki/Anime/Theme/EntryTest.php b/tests/Feature/Jobs/Wiki/Anime/Theme/EntryTest.php index 785ef1a51..41b583ffc 100644 --- a/tests/Feature/Jobs/Wiki/Anime/Theme/EntryTest.php +++ b/tests/Feature/Jobs/Wiki/Anime/Theme/EntryTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Jobs\Wiki\Anime\Theme; - use App\Constants\FeatureConstants; use App\Events\Wiki\Anime\Theme\Entry\EntryCreated; use App\Events\Wiki\Anime\Theme\Entry\EntryDeleted; @@ -16,84 +14,64 @@ use App\Models\Wiki\Anime\Theme\AnimeThemeEntry; use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; -use Tests\TestCase; -class EntryTest extends TestCase -{ - /** - * When an entry is created, a SendDiscordNotification job shall be dispatched. - */ - public function testEntryCreatedSendsDiscordNotification(): void - { - $theme = AnimeTheme::factory() - ->for(Anime::factory()) - ->createOne(); +test('entry created sends discord notification', function () { + $theme = AnimeTheme::factory() + ->for(Anime::factory()) + ->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(EntryCreated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(EntryCreated::class); - AnimeThemeEntry::factory()->for($theme)->createOne(); + AnimeThemeEntry::factory()->for($theme)->createOne(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When an entry is deleted, a SendDiscordNotification job shall be dispatched. - */ - public function testEntryDeletedSendsDiscordNotification(): void - { - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); +test('entry deleted sends discord notification', function () { + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(EntryDeleted::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(EntryDeleted::class); - $entry->delete(); + $entry->delete(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When an entry is restored, a SendDiscordNotification job shall be dispatched. - */ - public function testEntryRestoredSendsDiscordNotification(): void - { - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); +test('entry restored sends discord notification', function () { + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(EntryRestored::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(EntryRestored::class); - $entry->restore(); + $entry->restore(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When an entry is updated, a SendDiscordNotification job shall be dispatched. - */ - public function testEntryUpdatedSendsDiscordNotification(): void - { - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); +test('entry updated sends discord notification', function () { + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - $changes = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->makeOne(); + $changes = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->makeOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(EntryUpdated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(EntryUpdated::class); - $entry->fill($changes->getAttributes()); - $entry->save(); + $entry->fill($changes->getAttributes()); + $entry->save(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } -} + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); diff --git a/tests/Feature/Jobs/Wiki/Anime/ThemeTest.php b/tests/Feature/Jobs/Wiki/Anime/ThemeTest.php index ae4ba2050..93bff804d 100644 --- a/tests/Feature/Jobs/Wiki/Anime/ThemeTest.php +++ b/tests/Feature/Jobs/Wiki/Anime/ThemeTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Jobs\Wiki\Anime; - use App\Constants\FeatureConstants; use App\Events\Wiki\Anime\Theme\ThemeCreated; use App\Events\Wiki\Anime\Theme\ThemeDeleted; @@ -15,82 +13,62 @@ use App\Models\Wiki\Anime\AnimeTheme; use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; -use Tests\TestCase; -class ThemeTest extends TestCase -{ - /** - * When a theme is created, a SendDiscordNotification job shall be dispatched. - */ - public function testThemeCreatedSendsDiscordNotification(): void - { - $anime = Anime::factory()->createOne(); +test('theme created sends discord notification', function () { + $anime = Anime::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(ThemeCreated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(ThemeCreated::class); - AnimeTheme::factory()->for($anime)->createOne(); + AnimeTheme::factory()->for($anime)->createOne(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a theme is deleted, a SendDiscordNotification job shall be dispatched. - */ - public function testThemeDeletedSendsDiscordNotification(): void - { - $theme = AnimeTheme::factory() - ->for(Anime::factory()) - ->createOne(); +test('theme deleted sends discord notification', function () { + $theme = AnimeTheme::factory() + ->for(Anime::factory()) + ->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(ThemeDeleted::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(ThemeDeleted::class); - $theme->delete(); + $theme->delete(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a theme is restored, a SendDiscordNotification job shall be dispatched. - */ - public function testThemeRestoredSendsDiscordNotification(): void - { - $theme = AnimeTheme::factory() - ->for(Anime::factory()) - ->createOne(); +test('theme restored sends discord notification', function () { + $theme = AnimeTheme::factory() + ->for(Anime::factory()) + ->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(ThemeRestored::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(ThemeRestored::class); - $theme->restore(); + $theme->restore(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a theme is updated, a SendDiscordNotification job shall be dispatched. - */ - public function testThemeUpdatedSendsDiscordNotification(): void - { - $theme = AnimeTheme::factory() - ->for(Anime::factory()) - ->createOne(); +test('theme updated sends discord notification', function () { + $theme = AnimeTheme::factory() + ->for(Anime::factory()) + ->createOne(); - $changes = AnimeTheme::factory() - ->for(Anime::factory()) - ->makeOne(); + $changes = AnimeTheme::factory() + ->for(Anime::factory()) + ->makeOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(ThemeUpdated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(ThemeUpdated::class); - $theme->fill($changes->getAttributes()); - $theme->save(); + $theme->fill($changes->getAttributes()); + $theme->save(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } -} + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); diff --git a/tests/Feature/Jobs/Wiki/AnimeTest.php b/tests/Feature/Jobs/Wiki/AnimeTest.php index 5c9c3343e..5c19c1189 100644 --- a/tests/Feature/Jobs/Wiki/AnimeTest.php +++ b/tests/Feature/Jobs/Wiki/AnimeTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Jobs\Wiki; - use App\Constants\FeatureConstants; use App\Events\Wiki\Anime\AnimeCreated; use App\Events\Wiki\Anime\AnimeDeleted; @@ -14,72 +12,52 @@ use App\Models\Wiki\Anime; use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; -use Tests\TestCase; -class AnimeTest extends TestCase -{ - /** - * When an anime is created, a SendDiscordNotification job shall be dispatched. - */ - public function testAnimeCreatedSendsDiscordNotification(): void - { - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(AnimeCreated::class); +test('anime created sends discord notification', function () { + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(AnimeCreated::class); - Anime::factory()->createOne(); + Anime::factory()->createOne(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When an anime is deleted, a SendDiscordNotification job shall be dispatched. - */ - public function testAnimeDeletedSendsDiscordNotification(): void - { - $anime = Anime::factory()->createOne(); +test('anime deleted sends discord notification', function () { + $anime = Anime::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(AnimeDeleted::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(AnimeDeleted::class); - $anime->delete(); + $anime->delete(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When an anime is restored, a SendDiscordNotification job shall be dispatched. - */ - public function testAnimeRestoredSendsDiscordNotification(): void - { - $anime = Anime::factory()->createOne(); +test('anime restored sends discord notification', function () { + $anime = Anime::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(AnimeRestored::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(AnimeRestored::class); - $anime->restore(); + $anime->restore(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When an anime is updated, a SendDiscordNotification job shall be dispatched. - */ - public function testAnimeUpdatedSendsDiscordNotification(): void - { - $anime = Anime::factory()->createOne(); +test('anime updated sends discord notification', function () { + $anime = Anime::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(AnimeUpdated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(AnimeUpdated::class); - $changes = Anime::factory()->makeOne(); + $changes = Anime::factory()->makeOne(); - $anime->fill($changes->getAttributes()); - $anime->save(); + $anime->fill($changes->getAttributes()); + $anime->save(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } -} + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); diff --git a/tests/Feature/Jobs/Wiki/ArtistTest.php b/tests/Feature/Jobs/Wiki/ArtistTest.php index 2787ba7f7..495c7fa23 100644 --- a/tests/Feature/Jobs/Wiki/ArtistTest.php +++ b/tests/Feature/Jobs/Wiki/ArtistTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Jobs\Wiki; - use App\Constants\FeatureConstants; use App\Events\Wiki\Artist\ArtistCreated; use App\Events\Wiki\Artist\ArtistDeleted; @@ -14,72 +12,52 @@ use App\Models\Wiki\Artist; use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; -use Tests\TestCase; -class ArtistTest extends TestCase -{ - /** - * When an artist is created, a SendDiscordNotification job shall be dispatched. - */ - public function testArtistCreatedSendsDiscordNotification(): void - { - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(ArtistCreated::class); +test('artist created sends discord notification', function () { + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(ArtistCreated::class); - Artist::factory()->createOne(); + Artist::factory()->createOne(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When an artist is deleted, a SendDiscordNotification job shall be dispatched. - */ - public function testArtistDeletedSendsDiscordNotification(): void - { - $artist = Artist::factory()->createOne(); +test('artist deleted sends discord notification', function () { + $artist = Artist::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(ArtistDeleted::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(ArtistDeleted::class); - $artist->delete(); + $artist->delete(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When an artist is restored, a SendDiscordNotification job shall be dispatched. - */ - public function testArtistRestoredSendsDiscordNotification(): void - { - $artist = Artist::factory()->createOne(); +test('artist restored sends discord notification', function () { + $artist = Artist::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(ArtistRestored::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(ArtistRestored::class); - $artist->restore(); + $artist->restore(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When an artist is updated, a SendDiscordNotification job shall be dispatched. - */ - public function testArtistUpdatedSendsDiscordNotification(): void - { - $artist = Artist::factory()->createOne(); +test('artist updated sends discord notification', function () { + $artist = Artist::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(ArtistUpdated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(ArtistUpdated::class); - $changes = Artist::factory()->makeOne(); + $changes = Artist::factory()->makeOne(); - $artist->fill($changes->getAttributes()); - $artist->save(); + $artist->fill($changes->getAttributes()); + $artist->save(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } -} + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); diff --git a/tests/Feature/Jobs/Wiki/AudioTest.php b/tests/Feature/Jobs/Wiki/AudioTest.php index a104296cc..20345d9ee 100644 --- a/tests/Feature/Jobs/Wiki/AudioTest.php +++ b/tests/Feature/Jobs/Wiki/AudioTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Jobs\Wiki; - use App\Constants\FeatureConstants; use App\Events\Wiki\Audio\AudioCreated; use App\Events\Wiki\Audio\AudioDeleted; @@ -14,72 +12,52 @@ use App\Models\Wiki\Audio; use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; -use Tests\TestCase; -class AudioTest extends TestCase -{ - /** - * When an audio is created, a SendDiscordNotification job shall be dispatched. - */ - public function testAudioCreatedSendsDiscordNotification(): void - { - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(AudioCreated::class); +test('audio created sends discord notification', function () { + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(AudioCreated::class); - Audio::factory()->createOne(); + Audio::factory()->createOne(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When an audio is deleted, a SendDiscordNotification job shall be dispatched. - */ - public function testAudioDeletedSendsDiscordNotification(): void - { - $audio = Audio::factory()->createOne(); +test('audio deleted sends discord notification', function () { + $audio = Audio::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(AudioDeleted::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(AudioDeleted::class); - $audio->delete(); + $audio->delete(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When an audio is restored, a SendDiscordNotification job shall be dispatched. - */ - public function testAudioRestoredSendsDiscordNotification(): void - { - $audio = Audio::factory()->createOne(); +test('audio restored sends discord notification', function () { + $audio = Audio::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(AudioRestored::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(AudioRestored::class); - $audio->restore(); + $audio->restore(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When an audio is updated, a SendDiscordNotification job shall be dispatched. - */ - public function testAudioUpdatedSendsDiscordNotification(): void - { - $audio = Audio::factory()->createOne(); +test('audio updated sends discord notification', function () { + $audio = Audio::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(AudioUpdated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(AudioUpdated::class); - $changes = Audio::factory()->makeOne(); + $changes = Audio::factory()->makeOne(); - $audio->fill($changes->getAttributes()); - $audio->save(); + $audio->fill($changes->getAttributes()); + $audio->save(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } -} + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); diff --git a/tests/Feature/Jobs/Wiki/ExternalResourceTest.php b/tests/Feature/Jobs/Wiki/ExternalResourceTest.php index dc58368ae..cbb67aff9 100644 --- a/tests/Feature/Jobs/Wiki/ExternalResourceTest.php +++ b/tests/Feature/Jobs/Wiki/ExternalResourceTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Jobs\Wiki; - use App\Constants\FeatureConstants; use App\Events\Wiki\ExternalResource\ExternalResourceCreated; use App\Events\Wiki\ExternalResource\ExternalResourceDeleted; @@ -14,72 +12,52 @@ use App\Models\Wiki\ExternalResource; use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; -use Tests\TestCase; -class ExternalResourceTest extends TestCase -{ - /** - * When a resource is created, a SendDiscordNotification job shall be dispatched. - */ - public function testResourceCreatedSendsDiscordNotification(): void - { - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(ExternalResourceCreated::class); +test('resource created sends discord notification', function () { + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(ExternalResourceCreated::class); - ExternalResource::factory()->createOne(); + ExternalResource::factory()->createOne(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a resource is deleted, a SendDiscordNotification job shall be dispatched. - */ - public function testResourceDeletedSendsDiscordNotification(): void - { - $resource = ExternalResource::factory()->createOne(); +test('resource deleted sends discord notification', function () { + $resource = ExternalResource::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(ExternalResourceDeleted::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(ExternalResourceDeleted::class); - $resource->delete(); + $resource->delete(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a resource is restored, a SendDiscordNotification job shall be dispatched. - */ - public function testResourceRestoredSendsDiscordNotification(): void - { - $resource = ExternalResource::factory()->createOne(); +test('resource restored sends discord notification', function () { + $resource = ExternalResource::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(ExternalResourceRestored::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(ExternalResourceRestored::class); - $resource->restore(); + $resource->restore(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a resource is updated, a SendDiscordNotification job shall be dispatched. - */ - public function testResourceUpdatedSendsDiscordNotification(): void - { - $resource = ExternalResource::factory()->createOne(); +test('resource updated sends discord notification', function () { + $resource = ExternalResource::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(ExternalResourceUpdated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(ExternalResourceUpdated::class); - $changes = ExternalResource::factory()->makeOne(); + $changes = ExternalResource::factory()->makeOne(); - $resource->fill($changes->getAttributes()); - $resource->save(); + $resource->fill($changes->getAttributes()); + $resource->save(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } -} + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); diff --git a/tests/Feature/Jobs/Wiki/GroupTest.php b/tests/Feature/Jobs/Wiki/GroupTest.php index 974a3c0bb..e9b7fa566 100644 --- a/tests/Feature/Jobs/Wiki/GroupTest.php +++ b/tests/Feature/Jobs/Wiki/GroupTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Jobs\Wiki; - use App\Constants\FeatureConstants; use App\Events\Wiki\Group\GroupCreated; use App\Events\Wiki\Group\GroupDeleted; @@ -14,72 +12,52 @@ use App\Models\Wiki\Group; use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; -use Tests\TestCase; -class GroupTest extends TestCase -{ - /** - * When a group is created, a SendDiscordNotification job shall be dispatched. - */ - public function testGroupCreatedSendsDiscordNotification(): void - { - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(GroupCreated::class); +test('group created sends discord notification', function () { + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(GroupCreated::class); - Group::factory()->createOne(); + Group::factory()->createOne(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a group is deleted, a SendDiscordNotification job shall be dispatched. - */ - public function testGroupDeletedSendsDiscordNotification(): void - { - $group = Group::factory()->createOne(); +test('group deleted sends discord notification', function () { + $group = Group::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(GroupDeleted::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(GroupDeleted::class); - $group->delete(); + $group->delete(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a group is restored, a SendDiscordNotification job shall be dispatched. - */ - public function testGroupRestoredSendsDiscordNotification(): void - { - $group = Group::factory()->createOne(); +test('group restored sends discord notification', function () { + $group = Group::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(GroupRestored::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(GroupRestored::class); - $group->restore(); + $group->restore(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a group is updated, a SendDiscordNotification job shall be dispatched. - */ - public function testGroupUpdatedSendsDiscordNotification(): void - { - $group = Group::factory()->createOne(); +test('group updated sends discord notification', function () { + $group = Group::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(GroupUpdated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(GroupUpdated::class); - $changes = Group::factory()->makeOne(); + $changes = Group::factory()->makeOne(); - $group->fill($changes->getAttributes()); - $group->save(); + $group->fill($changes->getAttributes()); + $group->save(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } -} + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); diff --git a/tests/Feature/Jobs/Wiki/ImageTest.php b/tests/Feature/Jobs/Wiki/ImageTest.php index c90d44d4f..4b68ac356 100644 --- a/tests/Feature/Jobs/Wiki/ImageTest.php +++ b/tests/Feature/Jobs/Wiki/ImageTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Jobs\Wiki; - use App\Constants\FeatureConstants; use App\Events\Wiki\Image\ImageCreated; use App\Events\Wiki\Image\ImageDeleted; @@ -14,72 +12,52 @@ use App\Models\Wiki\Image; use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; -use Tests\TestCase; -class ImageTest extends TestCase -{ - /** - * When an image is created, a SendDiscordNotification job shall be dispatched. - */ - public function testImageCreatedSendsDiscordNotification(): void - { - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(ImageCreated::class); +test('image created sends discord notification', function () { + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(ImageCreated::class); - Image::factory()->createOne(); + Image::factory()->createOne(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When an image is deleted, a SendDiscordNotification job shall be dispatched. - */ - public function testImageDeletedSendsDiscordNotification(): void - { - $image = Image::factory()->createOne(); +test('image deleted sends discord notification', function () { + $image = Image::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(ImageDeleted::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(ImageDeleted::class); - $image->delete(); + $image->delete(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When an image is restored, a SendDiscordNotification job shall be dispatched. - */ - public function testImageRestoredSendsDiscordNotification(): void - { - $image = Image::factory()->createOne(); +test('image restored sends discord notification', function () { + $image = Image::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(ImageRestored::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(ImageRestored::class); - $image->restore(); + $image->restore(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When an image is updated, a SendDiscordNotification job shall be dispatched. - */ - public function testImageUpdatedSendsDiscordNotification(): void - { - $image = Image::factory()->createOne(); +test('image updated sends discord notification', function () { + $image = Image::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(ImageUpdated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(ImageUpdated::class); - $changes = Image::factory()->makeOne(); + $changes = Image::factory()->makeOne(); - $image->fill($changes->getAttributes()); - $image->save(); + $image->fill($changes->getAttributes()); + $image->save(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } -} + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); diff --git a/tests/Feature/Jobs/Wiki/SeriesTest.php b/tests/Feature/Jobs/Wiki/SeriesTest.php index c00af69d6..99192334a 100644 --- a/tests/Feature/Jobs/Wiki/SeriesTest.php +++ b/tests/Feature/Jobs/Wiki/SeriesTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Jobs\Wiki; - use App\Constants\FeatureConstants; use App\Events\Wiki\Series\SeriesCreated; use App\Events\Wiki\Series\SeriesDeleted; @@ -14,72 +12,52 @@ use App\Models\Wiki\Series; use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; -use Tests\TestCase; -class SeriesTest extends TestCase -{ - /** - * When a series is created, a SendDiscordNotification job shall be dispatched. - */ - public function testSeriesCreatedSendsDiscordNotification(): void - { - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(SeriesCreated::class); +test('series created sends discord notification', function () { + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(SeriesCreated::class); - Series::factory()->createOne(); + Series::factory()->createOne(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a series is deleted, a SendDiscordNotification job shall be dispatched. - */ - public function testSeriesDeletedSendsDiscordNotification(): void - { - $series = Series::factory()->createOne(); +test('series deleted sends discord notification', function () { + $series = Series::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(SeriesDeleted::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(SeriesDeleted::class); - $series->delete(); + $series->delete(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a series is restored, a SendDiscordNotification job shall be dispatched. - */ - public function testSeriesRestoredSendsDiscordNotification(): void - { - $series = Series::factory()->createOne(); +test('series restored sends discord notification', function () { + $series = Series::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(SeriesRestored::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(SeriesRestored::class); - $series->restore(); + $series->restore(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a series is updated, a SendDiscordNotification job shall be dispatched. - */ - public function testSeriesUpdatedSendsDiscordNotification(): void - { - $series = Series::factory()->createOne(); +test('series updated sends discord notification', function () { + $series = Series::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(SeriesUpdated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(SeriesUpdated::class); - $changes = Series::factory()->makeOne(); + $changes = Series::factory()->makeOne(); - $series->fill($changes->getAttributes()); - $series->save(); + $series->fill($changes->getAttributes()); + $series->save(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } -} + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); diff --git a/tests/Feature/Jobs/Wiki/SongTest.php b/tests/Feature/Jobs/Wiki/SongTest.php index dcaec389e..1ef129b19 100644 --- a/tests/Feature/Jobs/Wiki/SongTest.php +++ b/tests/Feature/Jobs/Wiki/SongTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Jobs\Wiki; - use App\Constants\FeatureConstants; use App\Events\Wiki\Song\SongCreated; use App\Events\Wiki\Song\SongDeleted; @@ -14,72 +12,52 @@ use App\Models\Wiki\Song; use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; -use Tests\TestCase; -class SongTest extends TestCase -{ - /** - * When a song is created, a SendDiscordNotification job shall be dispatched. - */ - public function testSongCreatedSendsDiscordNotification(): void - { - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(SongCreated::class); +test('song created sends discord notification', function () { + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(SongCreated::class); - Song::factory()->createOne(); + Song::factory()->createOne(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a song is deleted, a SendDiscordNotification job shall be dispatched. - */ - public function testSongDeletedSendsDiscordNotification(): void - { - $song = Song::factory()->createOne(); +test('song deleted sends discord notification', function () { + $song = Song::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(SongDeleted::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(SongDeleted::class); - $song->delete(); + $song->delete(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a song is restored, a SendDiscordNotification job shall be dispatched. - */ - public function testSongRestoredSendsDiscordNotification(): void - { - $song = Song::factory()->createOne(); +test('song restored sends discord notification', function () { + $song = Song::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(SongRestored::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(SongRestored::class); - $song->restore(); + $song->restore(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a song is updated, a SendDiscordNotification job shall be dispatched. - */ - public function testSongUpdatedSendsDiscordNotification(): void - { - $song = Song::factory()->createOne(); +test('song updated sends discord notification', function () { + $song = Song::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(SongUpdated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(SongUpdated::class); - $changes = Song::factory()->makeOne(); + $changes = Song::factory()->makeOne(); - $song->fill($changes->getAttributes()); - $song->save(); + $song->fill($changes->getAttributes()); + $song->save(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } -} + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); diff --git a/tests/Feature/Jobs/Wiki/StudioTest.php b/tests/Feature/Jobs/Wiki/StudioTest.php index 893be9973..24af1c8a6 100644 --- a/tests/Feature/Jobs/Wiki/StudioTest.php +++ b/tests/Feature/Jobs/Wiki/StudioTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Jobs\Wiki; - use App\Constants\FeatureConstants; use App\Events\Wiki\Studio\StudioCreated; use App\Events\Wiki\Studio\StudioDeleted; @@ -14,72 +12,52 @@ use App\Models\Wiki\Studio; use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; -use Tests\TestCase; -class StudioTest extends TestCase -{ - /** - * When a studio is created, a SendDiscordNotification job shall be dispatched. - */ - public function testStudioCreatedSendsDiscordNotification(): void - { - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(StudioCreated::class); +test('studio created sends discord notification', function () { + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(StudioCreated::class); - Studio::factory()->createOne(); + Studio::factory()->createOne(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a studio is deleted, a SendDiscordNotification job shall be dispatched. - */ - public function testStudioDeletedSendsDiscordNotification(): void - { - $studio = Studio::factory()->createOne(); +test('studio deleted sends discord notification', function () { + $studio = Studio::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(StudioDeleted::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(StudioDeleted::class); - $studio->delete(); + $studio->delete(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a studio is restored, a SendDiscordNotification job shall be dispatched. - */ - public function testStudioRestoredSendsDiscordNotification(): void - { - $studio = Studio::factory()->createOne(); +test('studio restored sends discord notification', function () { + $studio = Studio::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(StudioRestored::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(StudioRestored::class); - $studio->restore(); + $studio->restore(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a studio is updated, a SendDiscordNotification job shall be dispatched. - */ - public function testStudioUpdatedSendsDiscordNotification(): void - { - $studio = Studio::factory()->createOne(); +test('studio updated sends discord notification', function () { + $studio = Studio::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(StudioUpdated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(StudioUpdated::class); - $changes = Studio::factory()->makeOne(); + $changes = Studio::factory()->makeOne(); - $studio->fill($changes->getAttributes()); - $studio->save(); + $studio->fill($changes->getAttributes()); + $studio->save(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } -} + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); diff --git a/tests/Feature/Jobs/Wiki/Video/ScriptTest.php b/tests/Feature/Jobs/Wiki/Video/ScriptTest.php index 6337076b0..a95903ccf 100644 --- a/tests/Feature/Jobs/Wiki/Video/ScriptTest.php +++ b/tests/Feature/Jobs/Wiki/Video/ScriptTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Jobs\Wiki\Video; - use App\Constants\FeatureConstants; use App\Events\Wiki\Video\Script\VideoScriptCreated; use App\Events\Wiki\Video\Script\VideoScriptDeleted; @@ -14,72 +12,52 @@ use App\Models\Wiki\Video\VideoScript; use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; -use Tests\TestCase; -class ScriptTest extends TestCase -{ - /** - * When a script is created, a SendDiscordNotification job shall be dispatched. - */ - public function testVideoCreatedSendsDiscordNotification(): void - { - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(VideoScriptCreated::class); +test('video created sends discord notification', function () { + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(VideoScriptCreated::class); - VideoScript::factory()->createOne(); + VideoScript::factory()->createOne(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a script is deleted, a SendDiscordNotification job shall be dispatched. - */ - public function testVideoDeletedSendsDiscordNotification(): void - { - $script = VideoScript::factory()->createOne(); +test('video deleted sends discord notification', function () { + $script = VideoScript::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(VideoScriptDeleted::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(VideoScriptDeleted::class); - $script->delete(); + $script->delete(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a script is restored, a SendDiscordNotification job shall be dispatched. - */ - public function testVideoRestoredSendsDiscordNotification(): void - { - $script = VideoScript::factory()->createOne(); +test('video restored sends discord notification', function () { + $script = VideoScript::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(VideoScriptRestored::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(VideoScriptRestored::class); - $script->restore(); + $script->restore(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a script is updated, a SendDiscordNotification job shall be dispatched. - */ - public function testVideoUpdatedSendsDiscordNotification(): void - { - $script = VideoScript::factory()->createOne(); +test('video updated sends discord notification', function () { + $script = VideoScript::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(VideoScriptUpdated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(VideoScriptUpdated::class); - $changes = VideoScript::factory()->makeOne(); + $changes = VideoScript::factory()->makeOne(); - $script->fill($changes->getAttributes()); - $script->save(); + $script->fill($changes->getAttributes()); + $script->save(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } -} + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); diff --git a/tests/Feature/Jobs/Wiki/VideoTest.php b/tests/Feature/Jobs/Wiki/VideoTest.php index f71f0f347..209cb277b 100644 --- a/tests/Feature/Jobs/Wiki/VideoTest.php +++ b/tests/Feature/Jobs/Wiki/VideoTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Jobs\Wiki; - use App\Constants\FeatureConstants; use App\Events\Wiki\Video\VideoCreated; use App\Events\Wiki\Video\VideoDeleted; @@ -14,72 +12,52 @@ use App\Models\Wiki\Video; use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Event; use Laravel\Pennant\Feature; -use Tests\TestCase; -class VideoTest extends TestCase -{ - /** - * When a video is created, a SendDiscordNotification job shall be dispatched. - */ - public function testVideoCreatedSendsDiscordNotification(): void - { - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(VideoCreated::class); +test('video created sends discord notification', function () { + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(VideoCreated::class); - Video::factory()->createOne(); + Video::factory()->createOne(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a video is deleted, a SendDiscordNotification job shall be dispatched. - */ - public function testVideoDeletedSendsDiscordNotification(): void - { - $video = Video::factory()->createOne(); +test('video deleted sends discord notification', function () { + $video = Video::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(VideoDeleted::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(VideoDeleted::class); - $video->delete(); + $video->delete(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a video is restored, a SendDiscordNotification job shall be dispatched. - */ - public function testVideoRestoredSendsDiscordNotification(): void - { - $video = Video::factory()->createOne(); +test('video restored sends discord notification', function () { + $video = Video::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(VideoRestored::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(VideoRestored::class); - $video->restore(); + $video->restore(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); - /** - * When a video is updated, a SendDiscordNotification job shall be dispatched. - */ - public function testVideoUpdatedSendsDiscordNotification(): void - { - $video = Video::factory()->createOne(); +test('video updated sends discord notification', function () { + $video = Video::factory()->createOne(); - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); - Event::fakeExcept(VideoUpdated::class); + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + Event::fakeExcept(VideoUpdated::class); - $changes = Video::factory()->makeOne(); + $changes = Video::factory()->makeOne(); - $video->fill($changes->getAttributes()); - $video->save(); + $video->fill($changes->getAttributes()); + $video->save(); - Bus::assertDispatched(SendDiscordNotificationJob::class); - } -} + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); diff --git a/tests/Feature/Listeners/SendDiscordNotificationTest.php b/tests/Feature/Listeners/SendDiscordNotificationTest.php index 4046be26e..98f83cfdc 100644 --- a/tests/Feature/Listeners/SendDiscordNotificationTest.php +++ b/tests/Feature/Listeners/SendDiscordNotificationTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Feature\Listeners; - use App\Constants\FeatureConstants; use App\Contracts\Events\DiscordMessageEvent; use App\Jobs\SendDiscordNotificationJob; @@ -12,97 +10,83 @@ use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Support\Facades\Bus; use Laravel\Pennant\Feature; use NotificationChannels\Discord\DiscordMessage; -use Tests\TestCase; -class SendDiscordNotificationTest extends TestCase -{ - /** - * If discord notifications are disabled through the Allow Discord Notifications feature, - * discord notification jobs shall not be dispatched. - */ - public function testDiscordNotificationsNotAllowed(): void +use function Pest\Laravel\get; + +test('discord notifications not allowed', function () { + Feature::deactivate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); + + $event = new class implements DiscordMessageEvent { - Feature::deactivate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); + use Dispatchable; - $event = new class implements DiscordMessageEvent + /** + * Get Discord message payload. + */ + public function getDiscordMessage(): DiscordMessage { - use Dispatchable; + return DiscordMessage::create(); + } - /** - * Get Discord message payload. - */ - public function getDiscordMessage(): DiscordMessage - { - return DiscordMessage::create(); - } + /** + * Get Discord channel the message will be sent to. + */ + public function getDiscordChannel(): string + { + return ''; + } - /** - * Get Discord channel the message will be sent to. - */ - public function getDiscordChannel(): string - { - return ''; - } + /** + * Determine if the message should be sent. + */ + public function shouldSendDiscordMessage(): bool + { + return true; + } + }; + $listener = new SendDiscordNotification(); - /** - * Determine if the message should be sent. - */ - public function shouldSendDiscordMessage(): bool - { - return true; - } - }; + $listener->handle($event); - $listener = new SendDiscordNotification(); + Bus::assertNotDispatched(SendDiscordNotificationJob::class); +}); - $listener->handle($event); +test('discord notifications allowed', function () { + Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); + Bus::fake(SendDiscordNotificationJob::class); - Bus::assertNotDispatched(SendDiscordNotificationJob::class); - } - - /** - * If discord notifications are enabled through the Allow Discord Notifications feature, - * discord notification jobs shall be dispatched. - */ - public function testDiscordNotificationsAllowed(): void + $event = new class implements DiscordMessageEvent { - Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS); - Bus::fake(SendDiscordNotificationJob::class); + use Dispatchable; - $event = new class implements DiscordMessageEvent + /** + * Get Discord message payload. + */ + public function getDiscordMessage(): DiscordMessage { - use Dispatchable; + return DiscordMessage::create(); + } - /** - * Get Discord message payload. - */ - public function getDiscordMessage(): DiscordMessage - { - return DiscordMessage::create(); - } + /** + * Get Discord channel the message will be sent to. + */ + public function getDiscordChannel(): string + { + return ''; + } - /** - * Get Discord channel the message will be sent to. - */ - public function getDiscordChannel(): string - { - return ''; - } + /** + * Determine if the message should be sent. + */ + public function shouldSendDiscordMessage(): bool + { + return true; + } + }; + $listener = new SendDiscordNotification(); - /** - * Determine if the message should be sent. - */ - public function shouldSendDiscordMessage(): bool - { - return true; - } - }; + $listener->handle($event); - $listener = new SendDiscordNotification(); - - $listener->handle($event); - - Bus::assertDispatched(SendDiscordNotificationJob::class); - } -} + Bus::assertDispatched(SendDiscordNotificationJob::class); +}); diff --git a/tests/Pest.php b/tests/Pest.php new file mode 100644 index 000000000..166038c31 --- /dev/null +++ b/tests/Pest.php @@ -0,0 +1,83 @@ +extend(Tests\TestCase::class) + ->use(Illuminate\Foundation\Testing\RefreshDatabase::class) + ->in('Feature', 'Unit'); + +pest() + ->in('Unit/Filament/Resources') + ->beforeEach(function () { + $this->markTestIncomplete(); + + /** @phpstan-ignore-next-line */ + $user = User::factory() + ->withPermissions(SpecialPermission::VIEW_FILAMENT->value) + ->createOne(); + + actingAs($user); + }); + +/* +|-------------------------------------------------------------------------- +| Expectations +|-------------------------------------------------------------------------- +| +| When you're writing tests, you often need to check that values meet certain conditions. The +| "expect()" function gives you access to a set of "expectations" methods that you can use +| to assert different things. Of course, you may extend the Expectation API at any time. +| +*/ + +expect()->extend('toBeOne', function () { + return $this->toBe(1); +}); + +/* +|-------------------------------------------------------------------------- +| Functions +|-------------------------------------------------------------------------- +| +| While Pest is very powerful out-of-the-box, you may have some testing code specific to your +| project that you don't want to repeat in every file. Here you can also expose helpers as +| global functions to help you to reduce the number of lines of code in your test files. +| +*/ + +// Filament +/** + * @param class-string $resource + */ +function getIndexPage(string $resource): string +{ + $pages = $resource::getPages(); + + return $pages['index']->getPage(); +} + +/** + * @param class-string $resource + */ +function getViewPage(string $resource): string +{ + $pages = $resource::getPages(); + + return $pages['view']->getPage(); +} diff --git a/tests/TestCase.php b/tests/TestCase.php index 6315bfa51..a8b0ef709 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -6,6 +6,7 @@ namespace Tests; use Illuminate\Foundation\Testing\LazilyRefreshDatabase; use Illuminate\Foundation\Testing\TestCase as BaseTestCase; +use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Mail; @@ -22,6 +23,7 @@ abstract class TestCase extends BaseTestCase use LazilyRefreshDatabase; use MakesGraphQLRequests; use RefreshesSchemaCache; + use WithFaker; /** * Setup the test environment. diff --git a/tests/Unit/Actions/ActionResultTest.php b/tests/Unit/Actions/ActionResultTest.php index 9e5ab34ec..7fe91a359 100644 --- a/tests/Unit/Actions/ActionResultTest.php +++ b/tests/Unit/Actions/ActionResultTest.php @@ -2,41 +2,27 @@ declare(strict_types=1); -namespace Tests\Unit\Actions; - use App\Actions\ActionResult; use App\Enums\Actions\ActionStatus; use Illuminate\Support\Arr; -use Tests\TestCase; -class ActionResultTest extends TestCase -{ - /** - * The Action Result has failed if the status is Failed. - */ - public function testHasFailed(): void - { - $result = new ActionResult(ActionStatus::FAILED); +test('has failed', function () { + $result = new ActionResult(ActionStatus::FAILED); - static::assertTrue($result->hasFailed()); - } + $this->assertTrue($result->hasFailed()); +}); - /** - * The Action Result has not failed if the status is not Failed. - */ - public function testHasNotFailed(): void - { - $status = null; +test('has not failed', function () { + $status = null; - while ($status === null) { - $statusCandidate = Arr::random(ActionStatus::cases()); - if ($statusCandidate !== ActionStatus::FAILED) { - $status = $statusCandidate; - } + while ($status === null) { + $statusCandidate = Arr::random(ActionStatus::cases()); + if ($statusCandidate !== ActionStatus::FAILED) { + $status = $statusCandidate; } - - $result = new ActionResult($status); - - static::assertFalse($result->hasFailed()); } -} + + $result = new ActionResult($status); + + $this->assertFalse($result->hasFailed()); +}); diff --git a/tests/Unit/Actions/Repositories/ReconcileResultsTest.php b/tests/Unit/Actions/Repositories/ReconcileResultsTest.php index 36b52e444..97542dd61 100644 --- a/tests/Unit/Actions/Repositories/ReconcileResultsTest.php +++ b/tests/Unit/Actions/Repositories/ReconcileResultsTest.php @@ -2,33 +2,25 @@ declare(strict_types=1); -namespace Tests\Unit\Actions\Repositories; - use App\Actions\Repositories\ReconcileResults; use App\Enums\Actions\ActionStatus; use Illuminate\Database\Eloquent\Model; -use Tests\TestCase; -class ReconcileResultsTest extends TestCase -{ - /** - * The Reconcile Results shall always return true. - */ - public function testDefault(): void +use function Pest\Laravel\get; + +test('default', function () { + $reconcileResults = new class extends ReconcileResults { - $reconcileResults = new class extends ReconcileResults + /** + * Get the model of the reconciliation results. + * + * @return class-string + */ + public function model(): string { - /** - * Get the model of the reconciliation results. - * - * @return class-string - */ - protected function model(): string - { - return Model::class; - } - }; + return Model::class; + } + }; - static::assertTrue($reconcileResults->getStatus() === ActionStatus::PASSED); - } -} + $this->assertTrue($reconcileResults->getStatus() === ActionStatus::PASSED); +}); diff --git a/tests/Unit/Actions/Storage/Base/DeleteResultsTest.php b/tests/Unit/Actions/Storage/Base/DeleteResultsTest.php index 1acda979d..4508fd0c9 100644 --- a/tests/Unit/Actions/Storage/Base/DeleteResultsTest.php +++ b/tests/Unit/Actions/Storage/Base/DeleteResultsTest.php @@ -2,73 +2,54 @@ declare(strict_types=1); -namespace Tests\Unit\Actions\Storage\Base; - use App\Actions\Storage\Base\DeleteResults; use App\Enums\Actions\ActionStatus; use App\Models\Wiki\Video; -use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; -class DeleteResultsTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Action result has failed if there are no deletions. - */ - public function testDefault(): void - { - $video = Video::factory()->createOne(); +test('default', function () { + $video = Video::factory()->createOne(); - $deleteResults = new DeleteResults($video); + $deleteResults = new DeleteResults($video); - $result = $deleteResults->toActionResult(); + $result = $deleteResults->toActionResult(); - static::assertTrue($result->hasFailed()); + $this->assertTrue($result->hasFailed()); +}); + +test('failed', function () { + $video = Video::factory()->createOne(); + + $deletions = []; + + foreach (range(0, fake()->randomDigitNotNull()) as $ignored) { + $deletions[fake()->word()] = true; } - /** - * The Action result has failed if any deletions have returned false. - */ - public function testFailed(): void - { - $video = Video::factory()->createOne(); - - $deletions = []; - - foreach (range(0, $this->faker->randomDigitNotNull()) as $ignored) { - $deletions[$this->faker->word()] = true; - } - - foreach (range(0, $this->faker->randomDigitNotNull()) as $ignored) { - $deletions[$this->faker->word()] = false; - } - - $deleteResults = new DeleteResults($video, $deletions); - - $result = $deleteResults->toActionResult(); - - static::assertTrue($result->hasFailed()); + foreach (range(0, fake()->randomDigitNotNull()) as $ignored) { + $deletions[fake()->word()] = false; } - /** - * The Action result has passed if all deletions have returned true. - */ - public function testPassed(): void - { - $video = Video::factory()->createOne(); + $deleteResults = new DeleteResults($video, $deletions); - $deletions = []; + $result = $deleteResults->toActionResult(); - foreach (range(0, $this->faker->randomDigitNotNull()) as $ignored) { - $deletions[$this->faker->word()] = true; - } + $this->assertTrue($result->hasFailed()); +}); - $deleteResults = new DeleteResults($video, $deletions); +test('passed', function () { + $video = Video::factory()->createOne(); - $result = $deleteResults->toActionResult(); + $deletions = []; - static::assertTrue($result->getStatus() === ActionStatus::PASSED); + foreach (range(0, fake()->randomDigitNotNull()) as $ignored) { + $deletions[fake()->word()] = true; } -} + + $deleteResults = new DeleteResults($video, $deletions); + + $result = $deleteResults->toActionResult(); + + $this->assertTrue($result->getStatus() === ActionStatus::PASSED); +}); diff --git a/tests/Unit/Actions/Storage/Base/MoveResultsTest.php b/tests/Unit/Actions/Storage/Base/MoveResultsTest.php index b343074c2..232142496 100644 --- a/tests/Unit/Actions/Storage/Base/MoveResultsTest.php +++ b/tests/Unit/Actions/Storage/Base/MoveResultsTest.php @@ -2,73 +2,54 @@ declare(strict_types=1); -namespace Tests\Unit\Actions\Storage\Base; - use App\Actions\Storage\Base\MoveResults; use App\Enums\Actions\ActionStatus; use App\Models\Wiki\Video; -use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; -class MoveResultsTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Action result has failed if there are no moves. - */ - public function testDefault(): void - { - $video = Video::factory()->createOne(); +test('default', function () { + $video = Video::factory()->createOne(); - $moveResults = new MoveResults($video, $this->faker->word(), $this->faker->word()); + $moveResults = new MoveResults($video, fake()->word(), fake()->word()); - $result = $moveResults->toActionResult(); + $result = $moveResults->toActionResult(); - static::assertTrue($result->hasFailed()); + $this->assertTrue($result->hasFailed()); +}); + +test('failed', function () { + $video = Video::factory()->createOne(); + + $moves = []; + + foreach (range(0, fake()->randomDigitNotNull()) as $ignored) { + $moves[fake()->word()] = true; } - /** - * The Action result has failed if any moves have returned false. - */ - public function testFailed(): void - { - $video = Video::factory()->createOne(); - - $moves = []; - - foreach (range(0, $this->faker->randomDigitNotNull()) as $ignored) { - $moves[$this->faker->word()] = true; - } - - foreach (range(0, $this->faker->randomDigitNotNull()) as $ignored) { - $moves[$this->faker->word()] = false; - } - - $moveResults = new MoveResults($video, $this->faker->word(), $this->faker->word(), $moves); - - $result = $moveResults->toActionResult(); - - static::assertTrue($result->hasFailed()); + foreach (range(0, fake()->randomDigitNotNull()) as $ignored) { + $moves[fake()->word()] = false; } - /** - * The Action result has passed if all moves have returned true. - */ - public function testPassed(): void - { - $video = Video::factory()->createOne(); + $moveResults = new MoveResults($video, fake()->word(), fake()->word(), $moves); - $moves = []; + $result = $moveResults->toActionResult(); - foreach (range(0, $this->faker->randomDigitNotNull()) as $ignored) { - $moves[$this->faker->word()] = true; - } + $this->assertTrue($result->hasFailed()); +}); - $moveResults = new MoveResults($video, $this->faker->word(), $this->faker->word(), $moves); +test('passed', function () { + $video = Video::factory()->createOne(); - $result = $moveResults->toActionResult(); + $moves = []; - static::assertTrue($result->getStatus() === ActionStatus::PASSED); + foreach (range(0, fake()->randomDigitNotNull()) as $ignored) { + $moves[fake()->word()] = true; } -} + + $moveResults = new MoveResults($video, fake()->word(), fake()->word(), $moves); + + $result = $moveResults->toActionResult(); + + $this->assertTrue($result->getStatus() === ActionStatus::PASSED); +}); diff --git a/tests/Unit/Actions/Storage/Base/PruneResultsTest.php b/tests/Unit/Actions/Storage/Base/PruneResultsTest.php index b38b0ce30..73f237fe1 100644 --- a/tests/Unit/Actions/Storage/Base/PruneResultsTest.php +++ b/tests/Unit/Actions/Storage/Base/PruneResultsTest.php @@ -2,66 +2,47 @@ declare(strict_types=1); -namespace Tests\Unit\Actions\Storage\Base; - use App\Actions\Storage\Base\PruneResults; use App\Enums\Actions\ActionStatus; -use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; -class PruneResultsTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Action result has failed if there are no prunings. - */ - public function testDefault(): void - { - $pruneResults = new PruneResults($this->faker->word()); +test('default', function () { + $pruneResults = new PruneResults(fake()->word()); - $result = $pruneResults->toActionResult(); + $result = $pruneResults->toActionResult(); - static::assertTrue($result->hasFailed()); + $this->assertTrue($result->hasFailed()); +}); + +test('failed', function () { + $prunings = []; + + foreach (range(0, fake()->randomDigitNotNull()) as $ignored) { + $prunings[fake()->word()] = true; } - /** - * The Action result has failed if any prunings have returned false. - */ - public function testFailed(): void - { - $prunings = []; - - foreach (range(0, $this->faker->randomDigitNotNull()) as $ignored) { - $prunings[$this->faker->word()] = true; - } - - foreach (range(0, $this->faker->randomDigitNotNull()) as $ignored) { - $prunings[$this->faker->word()] = false; - } - - $pruneResults = new PruneResults($this->faker->word(), $prunings); - - $result = $pruneResults->toActionResult(); - - static::assertTrue($result->hasFailed()); + foreach (range(0, fake()->randomDigitNotNull()) as $ignored) { + $prunings[fake()->word()] = false; } - /** - * The Action result has passed if all prunings have returned true. - */ - public function testPassed(): void - { - $prunings = []; + $pruneResults = new PruneResults(fake()->word(), $prunings); - foreach (range(0, $this->faker->randomDigitNotNull()) as $ignored) { - $prunings[$this->faker->word()] = true; - } + $result = $pruneResults->toActionResult(); - $pruneResults = new PruneResults($this->faker->word(), $prunings); + $this->assertTrue($result->hasFailed()); +}); - $result = $pruneResults->toActionResult(); +test('passed', function () { + $prunings = []; - static::assertTrue($result->getStatus() === ActionStatus::PASSED); + foreach (range(0, fake()->randomDigitNotNull()) as $ignored) { + $prunings[fake()->word()] = true; } -} + + $pruneResults = new PruneResults(fake()->word(), $prunings); + + $result = $pruneResults->toActionResult(); + + $this->assertTrue($result->getStatus() === ActionStatus::PASSED); +}); diff --git a/tests/Unit/Actions/Storage/Base/UploadResultsTest.php b/tests/Unit/Actions/Storage/Base/UploadResultsTest.php index 747301212..17474a172 100644 --- a/tests/Unit/Actions/Storage/Base/UploadResultsTest.php +++ b/tests/Unit/Actions/Storage/Base/UploadResultsTest.php @@ -2,66 +2,47 @@ declare(strict_types=1); -namespace Tests\Unit\Actions\Storage\Base; - use App\Actions\Storage\Base\UploadResults; use App\Enums\Actions\ActionStatus; -use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; -class UploadResultsTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Action result has failed if there are no uploads. - */ - public function testDefault(): void - { - $uploadResults = new UploadResults(); +test('default', function () { + $uploadResults = new UploadResults(); - $result = $uploadResults->toActionResult(); + $result = $uploadResults->toActionResult(); - static::assertTrue($result->hasFailed()); + $this->assertTrue($result->hasFailed()); +}); + +test('failed', function () { + $uploads = []; + + foreach (range(0, fake()->randomDigitNotNull()) as $ignored) { + $uploads[fake()->word()] = fake()->filePath(); } - /** - * The Action result has failed if any uploads have returned false. - */ - public function testFailed(): void - { - $uploads = []; - - foreach (range(0, $this->faker->randomDigitNotNull()) as $ignored) { - $uploads[$this->faker->word()] = $this->faker->filePath(); - } - - foreach (range(0, $this->faker->randomDigitNotNull()) as $ignored) { - $uploads[$this->faker->word()] = false; - } - - $uploadResults = new UploadResults($uploads); - - $result = $uploadResults->toActionResult(); - - static::assertTrue($result->hasFailed()); + foreach (range(0, fake()->randomDigitNotNull()) as $ignored) { + $uploads[fake()->word()] = false; } - /** - * The Action result has passed if all uploads have returned the file path. - */ - public function testPassed(): void - { - $uploads = []; + $uploadResults = new UploadResults($uploads); - foreach (range(0, $this->faker->randomDigitNotNull()) as $ignored) { - $uploads[$this->faker->word()] = $this->faker->filePath(); - } + $result = $uploadResults->toActionResult(); - $uploadResults = new UploadResults($uploads); + $this->assertTrue($result->hasFailed()); +}); - $result = $uploadResults->toActionResult(); +test('passed', function () { + $uploads = []; - static::assertTrue($result->getStatus() === ActionStatus::PASSED); + foreach (range(0, fake()->randomDigitNotNull()) as $ignored) { + $uploads[fake()->word()] = fake()->filePath(); } -} + + $uploadResults = new UploadResults($uploads); + + $result = $uploadResults->toActionResult(); + + $this->assertTrue($result->getStatus() === ActionStatus::PASSED); +}); diff --git a/tests/Unit/ArchTest.php b/tests/Unit/ArchTest.php new file mode 100644 index 000000000..351044faa --- /dev/null +++ b/tests/Unit/ArchTest.php @@ -0,0 +1,106 @@ +expect('App') + ->toUseStrictTypes() + ->not->toUse(['die', 'dd', 'dump', 'var_dump']); + +arch() + ->expect('App\Concerns') + ->toBeTraits(); + +arch() + ->expect('App\Contracts') + ->toBeInterfaces(); + +arch() + ->expect('App\Enums') + ->toBeEnums(); + +arch() + ->expect('App\Features') + ->toBeClasses() + ->toHaveMethod('resolve'); + +arch() + ->expect('App\Jobs') + ->toBeClasses() + ->toHaveMethod('handle') + ->toImplement(ShouldQueue::class) + ->ignoring('App\Jobs\Middleware'); + +arch() + ->expect('App\*\Middleware') + ->toBeClasses() + ->toHaveMethod('handle'); + +arch() + ->expect('App\Listeners') + ->toBeClasses() + ->toHaveMethod('handle'); + +arch() + ->expect('App\Models') + ->toBeClasses() + ->toExtend(Model::class); + +arch() + ->expect('App\Pivots') + ->toBeClasses() + ->toExtend(Pivot::class); + +arch() + ->expect('App\Providers') + ->toBeClasses() + ->toExtend(ServiceProvider::class); + +describe('filament', function () { + arch() + ->expect('App\Filament\Actions') + ->toBeClasses() + ->toExtend(Action::class); + + arch() + ->expect('App\Filament\BulkActions') + ->toBeClasses() + ->toExtend(BulkAction::class); + + arch() + ->expect('App\Filament\Dashboards') + ->toBeClasses() + ->toExtend(Dashboard::class); + + arch() + ->expect('App\Filament\RelationManagers') + ->toBeClasses() + ->toExtend(RelationManager::class); + + arch() + ->expect('App\Filament\StateCasts') + ->toBeClasses() + ->toImplement(StateCast::class); + + arch() + ->expect('App\Filament\Tabs') + ->toBeClasses() + ->toExtend(Tab::class); + + arch() + ->expect('App\Filament\Widgets') + ->toBeClasses() + ->toExtend(Widget::class); +}); diff --git a/tests/Unit/Discord/DiscordEmbedFieldTest.php b/tests/Unit/Discord/DiscordEmbedFieldTest.php index 92959433e..04ac9be21 100644 --- a/tests/Unit/Discord/DiscordEmbedFieldTest.php +++ b/tests/Unit/Discord/DiscordEmbedFieldTest.php @@ -2,130 +2,82 @@ declare(strict_types=1); -namespace Tests\Unit\Discord; - use App\Discord\DiscordEmbedField; use App\Enums\Http\Api\Filter\AllowedDateFormat; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Date; -use stdClass; -use Tests\TestCase; use Tests\Unit\Enums\LocalizedEnum; -class DiscordEmbedFieldTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * Discord Embed Fields shall format an Enum value by its description. - */ - public function testDiscordEmbedFormatEnum(): void - { - $enum = Arr::random(LocalizedEnum::cases()); +test('discord embed format enum', function () { + $enum = Arr::random(LocalizedEnum::cases()); - $field = new DiscordEmbedField($this->faker->word(), $enum); + $field = new DiscordEmbedField(fake()->word(), $enum); - static::assertEquals($enum->localize(), Arr::get($field->toArray(), 'value')); - } + $this->assertEquals($enum->localize(), Arr::get($field->toArray(), 'value')); +}); - /** - * Discord Embed Fields shall format a date value by the Y-m-d date format. - */ - public function testDiscordEmbedFormatDate(): void - { - $date = Date::now()->subDays($this->faker->randomDigitNotNull()); +test('discord embed format date', function () { + $date = Date::now()->subDays(fake()->randomDigitNotNull()); - $field = new DiscordEmbedField($this->faker->word(), $date); + $field = new DiscordEmbedField(fake()->word(), $date); - static::assertEquals($date->format(AllowedDateFormat::YMD->value), Arr::get($field->toArray(), 'value')); - } + $this->assertEquals($date->format(AllowedDateFormat::YMD->value), Arr::get($field->toArray(), 'value')); +}); - /** - * Discord Embed Fields shall format a boolean value by pretty printing. - */ - public function testDiscordEmbedFormatBoolean(): void - { - $boolean = $this->faker->boolean(); +test('discord embed format boolean', function () { + $boolean = fake()->boolean(); - $field = new DiscordEmbedField($this->faker->word(), $boolean); + $field = new DiscordEmbedField(fake()->word(), $boolean); - static::assertEquals($boolean ? 'true' : 'false', Arr::get($field->toArray(), 'value')); - } + $this->assertEquals($boolean ? 'true' : 'false', Arr::get($field->toArray(), 'value')); +}); - /** - * Discord Embed Fields shall format numbers by their string value. - */ - public function testDiscordEmbedFormatNumber(): void - { - $number = $this->faker->randomNumber(); +test('discord embed format number', function () { + $number = fake()->randomNumber(); - $field = new DiscordEmbedField($this->faker->word(), $number); + $field = new DiscordEmbedField(fake()->word(), $number); - static::assertEquals(strval($number), Arr::get($field->toArray(), 'value')); - } + $this->assertEquals(strval($number), Arr::get($field->toArray(), 'value')); +}); - /** - * Discord Embed Fields shall format floats by their string value. - */ - public function testDiscordEmbedFormatFloat(): void - { - $float = $this->faker->randomFloat(); +test('discord embed format float', function () { + $float = fake()->randomFloat(); - $field = new DiscordEmbedField($this->faker->word(), $float); + $field = new DiscordEmbedField(fake()->word(), $float); - static::assertEquals(strval($float), Arr::get($field->toArray(), 'value')); - } + $this->assertEquals(strval($float), Arr::get($field->toArray(), 'value')); +}); - /** - * Discord Embed Fields shall format non-empty string by their string value. - */ - public function testDiscordEmbedFormatString(): void - { - $string = $this->faker->word(); +test('discord embed format string', function () { + $string = fake()->word(); - $field = new DiscordEmbedField($this->faker->word(), $string); + $field = new DiscordEmbedField(fake()->word(), $string); - static::assertEquals($string, Arr::get($field->toArray(), 'value')); - } + $this->assertEquals($string, Arr::get($field->toArray(), 'value')); +}); - /** - * Discord Embed Fields shall use a default value for empty string values. - */ - public function testDiscordEmbedFormatEmptyString(): void - { - $field = new DiscordEmbedField($this->faker->word(), ''); +test('discord embed format empty string', function () { + $field = new DiscordEmbedField(fake()->word(), ''); - static::assertEquals(DiscordEmbedField::DEFAULT_FIELD_VALUE, Arr::get($field->toArray(), 'value')); - } + $this->assertEquals(DiscordEmbedField::DEFAULT_FIELD_VALUE, Arr::get($field->toArray(), 'value')); +}); - /** - * Discord Embed Fields shall use a default value for null values. - */ - public function testDiscordEmbedFormatNull(): void - { - $field = new DiscordEmbedField($this->faker->word(), null); +test('discord embed format null', function () { + $field = new DiscordEmbedField(fake()->word(), null); - static::assertEquals(DiscordEmbedField::DEFAULT_FIELD_VALUE, Arr::get($field->toArray(), 'value')); - } + $this->assertEquals(DiscordEmbedField::DEFAULT_FIELD_VALUE, Arr::get($field->toArray(), 'value')); +}); - /** - * Discord Embed Fields shall use a default value for arrays. - */ - public function testDiscordEmbedFormatArray(): void - { - $field = new DiscordEmbedField($this->faker->word(), []); +test('discord embed format array', function () { + $field = new DiscordEmbedField(fake()->word(), []); - static::assertEquals(DiscordEmbedField::DEFAULT_FIELD_VALUE, Arr::get($field->toArray(), 'value')); - } + $this->assertEquals(DiscordEmbedField::DEFAULT_FIELD_VALUE, Arr::get($field->toArray(), 'value')); +}); - /** - * Discord Embed Fields shall use a default value for objects. - */ - public function testDiscordEmbedFormatObject(): void - { - $field = new DiscordEmbedField($this->faker->word(), new stdClass()); +test('discord embed format object', function () { + $field = new DiscordEmbedField(fake()->word(), new stdClass()); - static::assertEquals(DiscordEmbedField::DEFAULT_FIELD_VALUE, Arr::get($field->toArray(), 'value')); - } -} + $this->assertEquals(DiscordEmbedField::DEFAULT_FIELD_VALUE, Arr::get($field->toArray(), 'value')); +}); diff --git a/tests/Unit/Enums/Models/Wiki/ResourceSiteTest.php b/tests/Unit/Enums/Models/Wiki/ResourceSiteTest.php index 3106e60e7..20a22f09c 100644 --- a/tests/Unit/Enums/Models/Wiki/ResourceSiteTest.php +++ b/tests/Unit/Enums/Models/Wiki/ResourceSiteTest.php @@ -2,162 +2,127 @@ declare(strict_types=1); -namespace Tests\Unit\Enums\Models\Wiki; - use App\Enums\Models\Wiki\ResourceSite; use App\Models\Wiki\Anime; use App\Models\Wiki\Studio; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Http; use Illuminate\Support\Str; -use Tests\TestCase; -class ResourceSiteTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Resource Site shall parse the ID from URLs that contain the Anime ID. - */ - public function testParseIdFromAnimeResource(): void - { - $animeId = $this->faker->randomDigitNotNull(); +test('parse id from anime resource', function () { + $animeId = fake()->randomDigitNotNull(); - /** @var ResourceSite $site */ - $site = Arr::random([ - ResourceSite::ANIDB, - ResourceSite::ANILIST, - ResourceSite::ANN, - ResourceSite::MAL, - ResourceSite::NETFLIX, - ]); + /** @var ResourceSite $site */ + $site = Arr::random([ + ResourceSite::ANIDB, + ResourceSite::ANILIST, + ResourceSite::ANN, + ResourceSite::MAL, + ResourceSite::NETFLIX, + ]); - $link = $site->formatResourceLink(Anime::class, $animeId); + $link = $site->formatResourceLink(Anime::class, $animeId); - static::assertEquals(strval($animeId), ResourceSite::parseIdFromLink($link)); - } + $this->assertEquals(strval($animeId), ResourceSite::parseIdFromLink($link)); +}); - /** - * The Resource Site shall parse the ID from URLs that contain the Studio ID. - */ - public function testParseIdFromStudioResource(): void - { - $studioId = $this->faker->randomDigitNotNull(); +test('parse id from studio resource', function () { + $studioId = fake()->randomDigitNotNull(); - /** @var ResourceSite $site */ - $site = Arr::random([ - ResourceSite::ANIDB, - ResourceSite::ANILIST, - ResourceSite::ANN, - ResourceSite::MAL, - ]); + /** @var ResourceSite $site */ + $site = Arr::random([ + ResourceSite::ANIDB, + ResourceSite::ANILIST, + ResourceSite::ANN, + ResourceSite::MAL, + ]); - $link = $site->formatResourceLink(Studio::class, $studioId); + $link = $site->formatResourceLink(Studio::class, $studioId); - static::assertEquals(strval($studioId), ResourceSite::parseIdFromLink($link)); - } + $this->assertEquals(strval($studioId), ResourceSite::parseIdFromLink($link)); +}); - /** - * The Resource Site shall fail to parse the ID from Anime-Planet for studio resources. - */ - public function testFailParseAnimePlanetIdFromStudioResource(): void - { - $link = ResourceSite::ANIME_PLANET->formatResourceLink( - Studio::class, - $this->faker->randomDigitNotNull(), - $this->faker->slug() - ); +test('fail parse anime planet id from studio resource', function () { + $link = ResourceSite::ANIME_PLANET->formatResourceLink( + Studio::class, + fake()->randomDigitNotNull(), + fake()->slug() + ); - static::assertEmpty(ResourceSite::parseIdFromLink($link)); - Http::assertNothingSent(); - } + $this->assertEmpty(ResourceSite::parseIdFromLink($link)); + Http::assertNothingSent(); +}); - /** - * The Resource Site shall fail to parse the ID from Anime-Planet if the response is not expected. - */ - public function testFailParseAnimePlanetIdFromAnimeResource(): void - { - Http::fake([ - 'https://www.anime-planet.com/anime/*' => Http::response([ - $this->faker->word() => $this->faker->word(), - ]), - ]); +test('fail parse anime planet id from anime resource', function () { + Http::fake([ + 'https://www.anime-planet.com/anime/*' => Http::response([ + fake()->word() => fake()->word(), + ]), + ]); - $link = ResourceSite::ANIME_PLANET->formatResourceLink( - Anime::class, - $this->faker->randomDigitNotNull(), - $this->faker->slug() - ); + $link = ResourceSite::ANIME_PLANET->formatResourceLink( + Anime::class, + fake()->randomDigitNotNull(), + fake()->slug() + ); - static::assertEmpty(ResourceSite::parseIdFromLink($link)); - Http::assertSentCount(1); - } + $this->assertEmpty(ResourceSite::parseIdFromLink($link)); + Http::assertSentCount(1); +}); - /** - * The Resource Site shall parse the ID from Anime-Planet if the response is expected. - */ - public function testParseAnimePlanetIdFromAnimeResource(): void - { - $id = $this->faker->randomDigitNotNull(); +test('parse anime planet id from anime resource', function () { + $id = fake()->randomDigitNotNull(); - Http::fake([ - 'https://www.anime-planet.com/anime/*' => Http::response( - " + Http::fake([ + 'https://www.anime-planet.com/anime/*' => Http::response( + " $(function() { window.AP_VARS = $.extend(true, {}, window.AP_VARS, { ENTRY_INFO: { type: \"anime\", id: \"$id\", - url: \"{$this->faker->word()}\" + url: \"{fake()->word()}\" } } }); " - ), - ]); + ), + ]); - $link = ResourceSite::ANIME_PLANET->formatResourceLink(Anime::class, $id, $this->faker->slug()); + $link = ResourceSite::ANIME_PLANET->formatResourceLink(Anime::class, $id, fake()->slug()); - static::assertEquals(strval($id), ResourceSite::parseIdFromLink($link)); - Http::assertSentCount(1); - } + $this->assertEquals(strval($id), ResourceSite::parseIdFromLink($link)); + Http::assertSentCount(1); +}); - /** - * The Resource Site shall parse the ID from Kitsu if the link contains an integer. - */ - public function testParseKitsuIdForIdFromAnimeResource(): void - { - $id = $this->faker->randomDigitNotNull(); +test('parse kitsu id for id from anime resource', function () { + $id = fake()->randomDigitNotNull(); - $link = ResourceSite::KITSU->formatResourceLink(Anime::class, $id); + $link = ResourceSite::KITSU->formatResourceLink(Anime::class, $id); - static::assertEquals($id, ResourceSite::parseIdFromLink($link)); - } + $this->assertEquals($id, ResourceSite::parseIdFromLink($link)); +}); - /** - * The Resource Site shall parse the ID from Kitsu if the link contains a slug. - */ - public function testParseKitsuIdForSlugFromAnimeResource(): void - { - $id = $this->faker->randomDigitNotNull(); - $slug = $this->faker->slug(); +test('parse kitsu id for slug from anime resource', function () { + $id = fake()->randomDigitNotNull(); + $slug = fake()->slug(); - $linkWithSlug = Str::of(ResourceSite::KITSU->formatResourceLink(Anime::class, $id)) - ->replace(strval($id), $slug) - ->__toString(); + $linkWithSlug = Str::of(ResourceSite::KITSU->formatResourceLink(Anime::class, $id)) + ->replace(strval($id), $slug) + ->__toString(); - Http::fake([ - 'https://kitsu.io/api/graphql' => Http::response([ - 'data' => [ - 'findAnimeBySlug' => [ - 'id' => strval($id), - ], + Http::fake([ + 'https://kitsu.io/api/graphql' => Http::response([ + 'data' => [ + 'findAnimeBySlug' => [ + 'id' => strval($id), ], - ]), - ]); + ], + ]), + ]); - static::assertEquals(strval($id), ResourceSite::parseIdFromLink($linkWithSlug)); - Http::assertSentCount(1); - } -} + $this->assertEquals(strval($id), ResourceSite::parseIdFromLink($linkWithSlug)); + Http::assertSentCount(1); +}); diff --git a/tests/Unit/Events/AssignHashidsTest.php b/tests/Unit/Events/AssignHashidsTest.php index 2c779ad6d..2dc4162ab 100644 --- a/tests/Unit/Events/AssignHashidsTest.php +++ b/tests/Unit/Events/AssignHashidsTest.php @@ -2,20 +2,10 @@ declare(strict_types=1); -namespace Tests\Unit\Events; - use App\Contracts\Events\AssignHashidsEvent; use App\Listeners\AssignHashids; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class AssignHashidsTest extends TestCase -{ - /** - * AssignHashids shall listen to AssignHashidsEvent. - */ - public function testListening(): void - { - Event::assertListening(AssignHashidsEvent::class, AssignHashids::class); - } -} +test('listening', function () { + Event::assertListening(AssignHashidsEvent::class, AssignHashids::class); +}); diff --git a/tests/Unit/Events/CascadesDeletesTest.php b/tests/Unit/Events/CascadesDeletesTest.php index 76dbcfb93..aecd0fe25 100644 --- a/tests/Unit/Events/CascadesDeletesTest.php +++ b/tests/Unit/Events/CascadesDeletesTest.php @@ -2,20 +2,10 @@ declare(strict_types=1); -namespace Tests\Unit\Events; - use App\Contracts\Events\CascadesDeletesEvent; use App\Listeners\CascadesDeletes; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class CascadesDeletesTest extends TestCase -{ - /** - * CascadesDeletes shall listen to CascadesDeletesEvent. - */ - public function testListening(): void - { - Event::assertListening(CascadesDeletesEvent::class, CascadesDeletes::class); - } -} +test('listening', function () { + Event::assertListening(CascadesDeletesEvent::class, CascadesDeletes::class); +}); diff --git a/tests/Unit/Events/CascadesRestoresTest.php b/tests/Unit/Events/CascadesRestoresTest.php index 174b59030..10f0e112c 100644 --- a/tests/Unit/Events/CascadesRestoresTest.php +++ b/tests/Unit/Events/CascadesRestoresTest.php @@ -2,20 +2,10 @@ declare(strict_types=1); -namespace Tests\Unit\Events; - use App\Contracts\Events\CascadesRestoresEvent; use App\Listeners\CascadesRestores; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class CascadesRestoresTest extends TestCase -{ - /** - * CascadesRestores shall listen to CascadesRestoresEvent. - */ - public function testListening(): void - { - Event::assertListening(CascadesRestoresEvent::class, CascadesRestores::class); - } -} +test('listening', function () { + Event::assertListening(CascadesRestoresEvent::class, CascadesRestores::class); +}); diff --git a/tests/Unit/Events/ManagesTrackTest.php b/tests/Unit/Events/ManagesTrackTest.php index b24552bd3..8819638ce 100644 --- a/tests/Unit/Events/ManagesTrackTest.php +++ b/tests/Unit/Events/ManagesTrackTest.php @@ -2,20 +2,10 @@ declare(strict_types=1); -namespace Tests\Unit\Events; - use App\Contracts\Events\ManagesTrackEvent; use App\Listeners\ManagesTrack; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class ManagesTrackTest extends TestCase -{ - /** - * ManagesTrack shall listen to ManagesTrackEvent. - */ - public function testListening(): void - { - Event::assertListening(ManagesTrackEvent::class, ManagesTrack::class); - } -} +test('listening', function () { + Event::assertListening(ManagesTrackEvent::class, ManagesTrack::class); +}); diff --git a/tests/Unit/Events/NotifiesFilamentUsersTest.php b/tests/Unit/Events/NotifiesFilamentUsersTest.php index 0356ddf92..e55eb6cb9 100644 --- a/tests/Unit/Events/NotifiesFilamentUsersTest.php +++ b/tests/Unit/Events/NotifiesFilamentUsersTest.php @@ -2,20 +2,10 @@ declare(strict_types=1); -namespace Tests\Unit\Events; - use App\Contracts\Events\FilamentNotificationEvent; use App\Listeners\NotifiesFilamentUsers; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class NotifiesFilamentUsersTest extends TestCase -{ - /** - * NotifiesFilamentUsers shall listen to FilamentNotificationEvent. - */ - public function testListening(): void - { - Event::assertListening(FilamentNotificationEvent::class, NotifiesFilamentUsers::class); - } -} +test('listening', function () { + Event::assertListening(FilamentNotificationEvent::class, NotifiesFilamentUsers::class); +}); diff --git a/tests/Unit/Events/NotifiesUsersTest.php b/tests/Unit/Events/NotifiesUsersTest.php index 40e253ad6..ea157bf80 100644 --- a/tests/Unit/Events/NotifiesUsersTest.php +++ b/tests/Unit/Events/NotifiesUsersTest.php @@ -2,20 +2,10 @@ declare(strict_types=1); -namespace Tests\Unit\Events; - use App\Contracts\Events\NotifiesUsersEvent; use App\Listeners\NotifiesUsers; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class NotifiesUsersTest extends TestCase -{ - /** - * NotifiesUsers shall listen to NotifiesUsersEvent. - */ - public function testListening(): void - { - Event::assertListening(NotifiesUsersEvent::class, NotifiesUsers::class); - } -} +test('listening', function () { + Event::assertListening(NotifiesUsersEvent::class, NotifiesUsers::class); +}); diff --git a/tests/Unit/Events/RemoveFromStorageTest.php b/tests/Unit/Events/RemoveFromStorageTest.php index ddd4a179b..5ce6bc7ca 100644 --- a/tests/Unit/Events/RemoveFromStorageTest.php +++ b/tests/Unit/Events/RemoveFromStorageTest.php @@ -2,20 +2,10 @@ declare(strict_types=1); -namespace Tests\Unit\Events; - use App\Contracts\Events\RemoveFromStorageEvent; use App\Listeners\Storage\RemoveFromStorage; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class RemoveFromStorageTest extends TestCase -{ - /** - * RemoveFromStorage shall listen to RemoveFromStorageEvent. - */ - public function testListening(): void - { - Event::assertListening(RemoveFromStorageEvent::class, RemoveFromStorage::class); - } -} +test('listening', function () { + Event::assertListening(RemoveFromStorageEvent::class, RemoveFromStorage::class); +}); diff --git a/tests/Unit/Events/SyncArtistSongTest.php b/tests/Unit/Events/SyncArtistSongTest.php index 0374308f9..8b08bdfb7 100644 --- a/tests/Unit/Events/SyncArtistSongTest.php +++ b/tests/Unit/Events/SyncArtistSongTest.php @@ -2,20 +2,10 @@ declare(strict_types=1); -namespace Tests\Unit\Events; - use App\Contracts\Events\SyncArtistSongEvent; use App\Listeners\SyncArtistSong; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class SyncArtistSongTest extends TestCase -{ - /** - * SyncArtistSong shall listen to SyncArtistSongEvent. - */ - public function testListening(): void - { - Event::assertListening(SyncArtistSongEvent::class, SyncArtistSong::class); - } -} +test('listening', function () { + Event::assertListening(SyncArtistSongEvent::class, SyncArtistSong::class); +}); diff --git a/tests/Unit/Events/UpdatePlaylistTracksTest.php b/tests/Unit/Events/UpdatePlaylistTracksTest.php index f595be7e2..7685e606c 100644 --- a/tests/Unit/Events/UpdatePlaylistTracksTest.php +++ b/tests/Unit/Events/UpdatePlaylistTracksTest.php @@ -2,20 +2,10 @@ declare(strict_types=1); -namespace Tests\Unit\Events; - use App\Contracts\Events\UpdatePlaylistTracksEvent; use App\Listeners\List\UpdatePlaylistTracks; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class UpdatePlaylistTracksTest extends TestCase -{ - /** - * UpdatePlaylistTracks shall listen to UpdatePlaylistTracksEvent. - */ - public function testListening(): void - { - Event::assertListening(UpdatePlaylistTracksEvent::class, UpdatePlaylistTracks::class); - } -} +test('listening', function () { + Event::assertListening(UpdatePlaylistTracksEvent::class, UpdatePlaylistTracks::class); +}); diff --git a/tests/Unit/Events/UpdateRelatedIndicesTest.php b/tests/Unit/Events/UpdateRelatedIndicesTest.php index aa763e6e7..3e9934841 100644 --- a/tests/Unit/Events/UpdateRelatedIndicesTest.php +++ b/tests/Unit/Events/UpdateRelatedIndicesTest.php @@ -2,20 +2,10 @@ declare(strict_types=1); -namespace Tests\Unit\Events; - use App\Contracts\Events\UpdateRelatedIndicesEvent; use App\Listeners\UpdateRelatedIndices; use Illuminate\Support\Facades\Event; -use Tests\TestCase; -class UpdateRelatedIndicesTest extends TestCase -{ - /** - * UpdateRelatedIndices shall listen to UpdateRelatedIndicesEvent. - */ - public function testListening(): void - { - Event::assertListening(UpdateRelatedIndicesEvent::class, UpdateRelatedIndices::class); - } -} +test('listening', function () { + Event::assertListening(UpdateRelatedIndicesEvent::class, UpdateRelatedIndices::class); +}); diff --git a/tests/Unit/Filament/BaseResourceTestCase.php b/tests/Unit/Filament/BaseResourceTestCase.php deleted file mode 100644 index aa2bad6b7..000000000 --- a/tests/Unit/Filament/BaseResourceTestCase.php +++ /dev/null @@ -1,28 +0,0 @@ -withPermissions(SpecialPermission::VIEW_FILAMENT->value) - ->createOne(); - - $this->actingAs($user); - } -} diff --git a/tests/Unit/Filament/Resources/Admin/AnnouncementTest.php b/tests/Unit/Filament/Resources/Admin/AnnouncementTest.php index 633e37977..ab0b314d5 100644 --- a/tests/Unit/Filament/Resources/Admin/AnnouncementTest.php +++ b/tests/Unit/Filament/Resources/Admin/AnnouncementTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Filament\Resources\Admin; - use App\Enums\Auth\CrudPermission; use App\Enums\Auth\SpecialPermission; use App\Filament\Actions\Base\CreateAction; @@ -15,93 +13,58 @@ use App\Filament\Resources\Admin\Announcement; use App\Models\Admin\Announcement as AnnouncementModel; use App\Models\Auth\User; use Livewire\Livewire; -use Tests\Unit\Filament\BaseResourceTestCase; -class AnnouncementTest extends BaseResourceTestCase -{ - /** - * Get the index page class of the resource. - */ - protected static function getIndexPage(): string - { - $pages = Announcement::getPages(); +use function Pest\Laravel\actingAs; +use function Pest\Laravel\get; - return $pages['index']->getPage(); - } +test('render index page', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(AnnouncementModel::class) + ) + ->createOne(); - /** - * The index page of the resource shall be rendered. - */ - public function testRenderIndexPage(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(AnnouncementModel::class) - ) - ->createOne(); + actingAs($user); - $this->actingAs($user); + $records = AnnouncementModel::factory()->count(10)->create(); - $records = AnnouncementModel::factory()->count(10)->create(); + get(Announcement::getUrl('index')) + ->assertSuccessful(); - $this->get(Announcement::getUrl('index')) - ->assertSuccessful(); + Livewire::test(getIndexPage(Announcement::class)) + ->assertCanSeeTableRecords($records); +}); - Livewire::test(static::getIndexPage()) - ->assertCanSeeTableRecords($records); - } +test('user cannot create record', function () { + Livewire::test(getIndexPage(Announcement::class)) + ->assertActionHidden(CreateAction::class); +}); - /** - * The user with no permissions cannot create a record. - */ - public function testUserCannotCreateRecord(): void - { - Livewire::test(static::getIndexPage()) - ->assertActionHidden(CreateAction::class); - } +test('user cannot edit record', function () { + $record = AnnouncementModel::factory()->createOne(); - /** - * The user with no permissions cannot edit a record. - */ - public function testUserCannotEditRecord(): void - { - $record = AnnouncementModel::factory()->createOne(); + Livewire::test(getIndexPage(Announcement::class)) + ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); +}); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); - } +test('user cannot delete record', function () { + $record = AnnouncementModel::factory()->createOne(); - /** - * The user with no permissions cannot delete a record. - */ - public function testUserCannotDeleteRecord(): void - { - $record = AnnouncementModel::factory()->createOne(); + Livewire::test(getIndexPage(Announcement::class)) + ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); +}); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); - } +test('user cannot restore record', function () { + $record = AnnouncementModel::factory()->createOne(); - /** - * The user with no permissions cannot restore a record. - */ - public function testUserCannotRestoreRecord(): void - { - $record = AnnouncementModel::factory()->createOne(); + Livewire::test(getIndexPage(Announcement::class)) + ->assertActionHidden(RestoreAction::class, ['record' => $record->getKey()]); +}); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(RestoreAction::class, ['record' => $record->getKey()]); - } +test('user cannot force delete record', function () { + $record = AnnouncementModel::factory()->createOne(); - /** - * The user with no permissions cannot force delete a record. - */ - public function testUserCannotForceDeleteRecord(): void - { - $record = AnnouncementModel::factory()->createOne(); - - Livewire::test(static::getIndexPage()) - ->assertActionHidden(ForceDeleteAction::class, ['record' => $record->getKey()]); - } -} + Livewire::test(getIndexPage(Announcement::class)) + ->assertActionHidden(ForceDeleteAction::class, ['record' => $record->getKey()]); +}); diff --git a/tests/Unit/Filament/Resources/Admin/DumpTest.php b/tests/Unit/Filament/Resources/Admin/DumpTest.php index 201086cb3..e32f4f650 100644 --- a/tests/Unit/Filament/Resources/Admin/DumpTest.php +++ b/tests/Unit/Filament/Resources/Admin/DumpTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Filament\Resources\Admin; - use App\Enums\Auth\CrudPermission; use App\Enums\Auth\SpecialPermission; use App\Filament\Actions\Base\DeleteAction; @@ -14,84 +12,53 @@ use App\Filament\Resources\Admin\Dump; use App\Models\Admin\Dump as DumpModel; use App\Models\Auth\User; use Livewire\Livewire; -use Tests\Unit\Filament\BaseResourceTestCase; -class DumpTest extends BaseResourceTestCase -{ - /** - * Get the index page class of the resource. - */ - protected static function getIndexPage(): string - { - $pages = Dump::getPages(); +use function Pest\Laravel\actingAs; +use function Pest\Laravel\get; - return $pages['index']->getPage(); - } +test('render index page', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(DumpModel::class) + ) + ->createOne(); - /** - * The index page of the resource shall be rendered. - */ - public function testRenderIndexPage(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(DumpModel::class) - ) - ->createOne(); + actingAs($user); - $this->actingAs($user); + $records = DumpModel::factory()->count(10)->create(); - $records = DumpModel::factory()->count(10)->create(); + get(Dump::getUrl('index')) + ->assertSuccessful(); - $this->get(Dump::getUrl('index')) - ->assertSuccessful(); + Livewire::test(getIndexPage(Dump::class)) + ->assertCanSeeTableRecords($records); +}); - Livewire::test(static::getIndexPage()) - ->assertCanSeeTableRecords($records); - } +test('user cannot edit record', function () { + $record = DumpModel::factory()->createOne(); - /** - * The user with no permissions cannot edit a record. - */ - public function testUserCannotEditRecord(): void - { - $record = DumpModel::factory()->createOne(); + Livewire::test(getIndexPage(Dump::class)) + ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); +}); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); - } +test('user cannot delete record', function () { + $record = DumpModel::factory()->createOne(); - /** - * The user with no permissions cannot delete a record. - */ - public function testUserCannotDeleteRecord(): void - { - $record = DumpModel::factory()->createOne(); + Livewire::test(getIndexPage(Dump::class)) + ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); +}); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); - } +test('user cannot restore record', function () { + $record = DumpModel::factory()->createOne(); - /** - * The user with no permissions cannot restore a record. - */ - public function testUserCannotRestoreRecord(): void - { - $record = DumpModel::factory()->createOne(); + Livewire::test(getIndexPage(Dump::class)) + ->assertActionHidden(RestoreAction::class, ['record' => $record->getKey()]); +}); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(RestoreAction::class, ['record' => $record->getKey()]); - } +test('user cannot force delete record', function () { + $record = DumpModel::factory()->createOne(); - /** - * The user with no permissions cannot force delete a record. - */ - public function testUserCannotForceDeleteRecord(): void - { - $record = DumpModel::factory()->createOne(); - - Livewire::test(static::getIndexPage()) - ->assertActionHidden(ForceDeleteAction::class, ['record' => $record->getKey()]); - } -} + Livewire::test(getIndexPage(Dump::class)) + ->assertActionHidden(ForceDeleteAction::class, ['record' => $record->getKey()]); +}); diff --git a/tests/Unit/Filament/Resources/Admin/FeatureTest.php b/tests/Unit/Filament/Resources/Admin/FeatureTest.php index 49e885237..babb6538d 100644 --- a/tests/Unit/Filament/Resources/Admin/FeatureTest.php +++ b/tests/Unit/Filament/Resources/Admin/FeatureTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Filament\Resources\Admin; - use App\Enums\Auth\CrudPermission; use App\Enums\Auth\SpecialPermission; use App\Filament\Actions\Base\DeleteAction; @@ -14,84 +12,53 @@ use App\Filament\Resources\Admin\Feature; use App\Models\Admin\Feature as FeatureModel; use App\Models\Auth\User; use Livewire\Livewire; -use Tests\Unit\Filament\BaseResourceTestCase; -class FeatureTest extends BaseResourceTestCase -{ - /** - * Get the index page class of the resource. - */ - protected static function getIndexPage(): string - { - $pages = Feature::getPages(); +use function Pest\Laravel\actingAs; +use function Pest\Laravel\get; - return $pages['index']->getPage(); - } +test('render index page', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(FeatureModel::class) + ) + ->createOne(); - /** - * The index page of the resource shall be rendered. - */ - public function testRenderIndexPage(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(FeatureModel::class) - ) - ->createOne(); + actingAs($user); - $this->actingAs($user); + $records = FeatureModel::factory()->count(10)->create(); - $records = FeatureModel::factory()->count(10)->create(); + get(Feature::getUrl('index')) + ->assertSuccessful(); - $this->get(Feature::getUrl('index')) - ->assertSuccessful(); + Livewire::test(getIndexPage(Feature::class)) + ->assertCanSeeTableRecords($records); +}); - Livewire::test(static::getIndexPage()) - ->assertCanSeeTableRecords($records); - } +test('user cannot edit record', function () { + $record = FeatureModel::factory()->createOne(); - /** - * The user with no permissions cannot edit a record. - */ - public function testUserCannotEditRecord(): void - { - $record = FeatureModel::factory()->createOne(); + Livewire::test(getIndexPage(Feature::class)) + ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); +}); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); - } +test('user cannot delete record', function () { + $record = FeatureModel::factory()->createOne(); - /** - * The user with no permissions cannot delete a record. - */ - public function testUserCannotDeleteRecord(): void - { - $record = FeatureModel::factory()->createOne(); + Livewire::test(getIndexPage(Feature::class)) + ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); +}); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); - } +test('user cannot restore record', function () { + $record = FeatureModel::factory()->createOne(); - /** - * The user with no permissions cannot restore a record. - */ - public function testUserCannotRestoreRecord(): void - { - $record = FeatureModel::factory()->createOne(); + Livewire::test(getIndexPage(Feature::class)) + ->assertActionHidden(RestoreAction::class, ['record' => $record->getKey()]); +}); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(RestoreAction::class, ['record' => $record->getKey()]); - } +test('user cannot force delete record', function () { + $record = FeatureModel::factory()->createOne(); - /** - * The user with no permissions cannot force delete a record. - */ - public function testUserCannotForceDeleteRecord(): void - { - $record = FeatureModel::factory()->createOne(); - - Livewire::test(static::getIndexPage()) - ->assertActionHidden(ForceDeleteAction::class, ['record' => $record->getKey()]); - } -} + Livewire::test(getIndexPage(Feature::class)) + ->assertActionHidden(ForceDeleteAction::class, ['record' => $record->getKey()]); +}); diff --git a/tests/Unit/Filament/Resources/Admin/FeaturedThemeTest.php b/tests/Unit/Filament/Resources/Admin/FeaturedThemeTest.php index 699540cd6..26900d816 100644 --- a/tests/Unit/Filament/Resources/Admin/FeaturedThemeTest.php +++ b/tests/Unit/Filament/Resources/Admin/FeaturedThemeTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Filament\Resources\Admin; - use App\Enums\Auth\CrudPermission; use App\Enums\Auth\SpecialPermission; use App\Filament\Actions\Base\CreateAction; @@ -15,174 +13,117 @@ use App\Filament\Resources\Admin\FeaturedTheme; use App\Models\Admin\FeaturedTheme as FeaturedThemeModel; use App\Models\Auth\User; use Livewire\Livewire; -use Tests\Unit\Filament\BaseResourceTestCase; -class FeaturedThemeTest extends BaseResourceTestCase -{ - /** - * Get the index page class of the resource. - */ - protected static function getIndexPage(): string - { - $pages = FeaturedTheme::getPages(); +use function Pest\Laravel\actingAs; +use function Pest\Laravel\get; - return $pages['index']->getPage(); - } +test('render index page', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(FeaturedThemeModel::class) + ) + ->createOne(); - /** - * Get the view page class of the resource. - */ - protected static function getViewPage(): string - { - $pages = FeaturedTheme::getPages(); + actingAs($user); - return $pages['view']->getPage(); - } + $records = FeaturedThemeModel::factory()->count(10)->create(); - /** - * The index page of the resource shall be rendered. - */ - public function testRenderIndexPage(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(FeaturedThemeModel::class) - ) - ->createOne(); + get(FeaturedTheme::getUrl('index')) + ->assertSuccessful(); - $this->actingAs($user); + Livewire::test(getIndexPage(FeaturedTheme::class)) + ->assertCanSeeTableRecords($records); +}); - $records = FeaturedThemeModel::factory()->count(10)->create(); +test('render view page', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(FeaturedThemeModel::class) + ) + ->createOne(); - $this->get(FeaturedTheme::getUrl('index')) - ->assertSuccessful(); + actingAs($user); - Livewire::test(static::getIndexPage()) - ->assertCanSeeTableRecords($records); - } + $record = FeaturedThemeModel::factory()->createOne(); - /** - * The view page of the resource shall be rendered. - */ - public function testRenderViewPage(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(FeaturedThemeModel::class) - ) - ->createOne(); + get(FeaturedTheme::getUrl('view', ['record' => $record])) + ->assertSuccessful(); +}); - $this->actingAs($user); +test('mount create action', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::CREATE->format(FeaturedThemeModel::class) + ) + ->createOne(); - $record = FeaturedThemeModel::factory()->createOne(); + actingAs($user); - $this->get(FeaturedTheme::getUrl('view', ['record' => $record])) - ->assertSuccessful(); - } + Livewire::test(getIndexPage(FeaturedTheme::class)) + ->mountAction(CreateAction::class) + ->assertActionMounted(CreateAction::class); +}); - /** - * The create action of the resource shall be mounted. - */ - public function testMountCreateAction(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::CREATE->format(FeaturedThemeModel::class) - ) - ->createOne(); +test('mount edit action', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::UPDATE->format(FeaturedThemeModel::class) + ) + ->createOne(); - $this->actingAs($user); + actingAs($user); - Livewire::test(static::getIndexPage()) - ->mountAction(CreateAction::class) - ->assertActionMounted(CreateAction::class); - } + $record = FeaturedThemeModel::factory()->createOne(); - /** - * The create action of the resource shall be mounted. - */ - public function testMountEditAction(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::UPDATE->format(FeaturedThemeModel::class) - ) - ->createOne(); + Livewire::test(getIndexPage(FeaturedTheme::class)) + ->mountAction(EditAction::class, ['record' => $record]) + ->assertActionMounted(EditAction::class); +}); - $this->actingAs($user); +test('user cannot create record', function () { + Livewire::test(getIndexPage(FeaturedTheme::class)) + ->assertActionHidden(CreateAction::class); +}); - $record = FeaturedThemeModel::factory()->createOne(); +test('user cannot edit record', function () { + $record = FeaturedThemeModel::factory()->createOne(); - Livewire::test(static::getIndexPage()) - ->mountAction(EditAction::class, ['record' => $record]) - ->assertActionMounted(EditAction::class); - } + Livewire::test(getIndexPage(FeaturedTheme::class)) + ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); +}); - /** - * The user with no permissions cannot create a record. - */ - public function testUserCannotCreateRecord(): void - { - Livewire::test(static::getIndexPage()) - ->assertActionHidden(CreateAction::class); - } +test('user cannot delete record', function () { + $record = FeaturedThemeModel::factory()->createOne(); - /** - * The user with no permissions cannot edit a record. - */ - public function testUserCannotEditRecord(): void - { - $record = FeaturedThemeModel::factory()->createOne(); + Livewire::test(getViewPage(FeaturedTheme::class), ['record' => $record->getKey()]) + ->assertActionHidden(DeleteAction::class); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); - } + Livewire::test(getIndexPage(FeaturedTheme::class)) + ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); +}); - /** - * The user with no permissions cannot delete a record. - */ - public function testUserCannotDeleteRecord(): void - { - $record = FeaturedThemeModel::factory()->createOne(); +test('user cannot restore record', function () { + $record = FeaturedThemeModel::factory()->createOne(); - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(DeleteAction::class); + $record->delete(); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); - } + Livewire::test(getViewPage(FeaturedTheme::class), ['record' => $record->getKey()]) + ->assertActionHidden(RestoreAction::class); - /** - * The user with no permissions cannot restore a record. - */ - public function testUserCannotRestoreRecord(): void - { - $record = FeaturedThemeModel::factory()->createOne(); + Livewire::test(getIndexPage(FeaturedTheme::class)) + ->assertActionHidden(RestoreAction::class, ['record' => $record->getKey()]); +}); - $record->delete(); +test('user cannot force delete record', function () { + $record = FeaturedThemeModel::factory()->createOne(); - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(RestoreAction::class); + Livewire::test(getViewPage(FeaturedTheme::class), ['record' => $record->getKey()]) + ->assertActionHidden(ForceDeleteAction::class); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(RestoreAction::class, ['record' => $record->getKey()]); - } - - /** - * The user with no permissions cannot force delete a record. - */ - public function testUserCannotForceDeleteRecord(): void - { - $record = FeaturedThemeModel::factory()->createOne(); - - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(ForceDeleteAction::class); - - Livewire::test(static::getIndexPage()) - ->assertActionHidden(ForceDeleteAction::class, ['record' => $record->getKey()]); - } -} + Livewire::test(getIndexPage(FeaturedTheme::class)) + ->assertActionHidden(ForceDeleteAction::class, ['record' => $record->getKey()]); +}); diff --git a/tests/Unit/Filament/Resources/Discord/DiscordThreadTest.php b/tests/Unit/Filament/Resources/Discord/DiscordThreadTest.php index 45ab4483c..5c69386fb 100644 --- a/tests/Unit/Filament/Resources/Discord/DiscordThreadTest.php +++ b/tests/Unit/Filament/Resources/Discord/DiscordThreadTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Filament\Resources\Discord; - use App\Enums\Auth\CrudPermission; use App\Enums\Auth\SpecialPermission; use App\Filament\Actions\Base\CreateAction; @@ -14,155 +12,106 @@ use App\Models\Auth\User; use App\Models\Discord\DiscordThread as DiscordThreadModel; use App\Models\Wiki\Anime; use Livewire\Livewire; -use Tests\Unit\Filament\BaseResourceTestCase; -class DiscordThreadTest extends BaseResourceTestCase -{ - /** - * Get the index page class of the resource. - */ - protected static function getIndexPage(): string - { - $pages = DiscordThread::getPages(); +use function Pest\Laravel\actingAs; +use function Pest\Laravel\get; - return $pages['index']->getPage(); - } +test('render index page', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(DiscordThreadModel::class) + ) + ->createOne(); - /** - * Get the view page class of the resource. - */ - protected static function getViewPage(): string - { - $pages = DiscordThread::getPages(); + actingAs($user); - return $pages['view']->getPage(); - } + $records = DiscordThreadModel::factory() + ->for(Anime::factory()) + ->count(10) + ->create(); - /** - * The index page of the resource shall be rendered. - */ - public function testRenderIndexPage(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(DiscordThreadModel::class) - ) - ->createOne(); + get(DiscordThread::getUrl('index')) + ->assertSuccessful(); - $this->actingAs($user); + Livewire::test(getIndexPage(DiscordThread::class)) + ->assertCanSeeTableRecords($records); +}); - $records = DiscordThreadModel::factory() - ->for(Anime::factory()) - ->count(10) - ->create(); +test('render view page', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(DiscordThreadModel::class) + ) + ->createOne(); - $this->get(DiscordThread::getUrl('index')) - ->assertSuccessful(); + actingAs($user); - Livewire::test(static::getIndexPage()) - ->assertCanSeeTableRecords($records); - } + $record = DiscordThreadModel::factory() + ->for(Anime::factory()) + ->createOne(); - /** - * The view page of the resource shall be rendered. - */ - public function testRenderViewPage(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(DiscordThreadModel::class) - ) - ->createOne(); + get(DiscordThread::getUrl('view', ['record' => $record])) + ->assertSuccessful(); +}); - $this->actingAs($user); +test('mount create action', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::CREATE->format(DiscordThreadModel::class) + ) + ->createOne(); - $record = DiscordThreadModel::factory() - ->for(Anime::factory()) - ->createOne(); + actingAs($user); - $this->get(DiscordThread::getUrl('view', ['record' => $record])) - ->assertSuccessful(); - } + Livewire::test(getIndexPage(DiscordThread::class)) + ->mountAction(CreateAction::class) + ->assertActionMounted(CreateAction::class); +}); - /** - * The create action of the resource shall be mounted. - */ - public function testMountCreateAction(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::CREATE->format(DiscordThreadModel::class) - ) - ->createOne(); +test('mount edit action', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::UPDATE->format(DiscordThreadModel::class) + ) + ->createOne(); - $this->actingAs($user); + actingAs($user); - Livewire::test(static::getIndexPage()) - ->mountAction(CreateAction::class) - ->assertActionMounted(CreateAction::class); - } + $record = DiscordThreadModel::factory() + ->for(Anime::factory()) + ->createOne(); - /** - * The create action of the resource shall be mounted. - */ - public function testMountEditAction(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::UPDATE->format(DiscordThreadModel::class) - ) - ->createOne(); + Livewire::test(getIndexPage(DiscordThread::class)) + ->mountAction(EditAction::class, ['record' => $record]) + ->assertActionMounted(EditAction::class); +}); - $this->actingAs($user); +test('user cannot create record', function () { + Livewire::test(getIndexPage(DiscordThread::class)) + ->assertActionHidden(CreateAction::class); +}); - $record = DiscordThreadModel::factory() - ->for(Anime::factory()) - ->createOne(); +test('user cannot edit record', function () { + $record = DiscordThreadModel::factory() + ->for(Anime::factory()) + ->createOne(); - Livewire::test(static::getIndexPage()) - ->mountAction(EditAction::class, ['record' => $record]) - ->assertActionMounted(EditAction::class); - } + Livewire::test(getIndexPage(DiscordThread::class)) + ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); +}); - /** - * The user with no permissions cannot create a record. - */ - public function testUserCannotCreateRecord(): void - { - Livewire::test(static::getIndexPage()) - ->assertActionHidden(CreateAction::class); - } +test('user cannot delete record', function () { + $record = DiscordThreadModel::factory() + ->for(Anime::factory()) + ->createOne(); - /** - * The user with no permissions cannot edit a record. - */ - public function testUserCannotEditRecord(): void - { - $record = DiscordThreadModel::factory() - ->for(Anime::factory()) - ->createOne(); + Livewire::test(getViewPage(DiscordThread::class), ['record' => $record->getKey()]) + ->assertActionHidden(DeleteAction::class); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); - } - - /** - * The user with no permissions cannot delete a record. - */ - public function testUserCannotDeleteRecord(): void - { - $record = DiscordThreadModel::factory() - ->for(Anime::factory()) - ->createOne(); - - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(DeleteAction::class); - - Livewire::test(static::getIndexPage()) - ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); - } -} + Livewire::test(getIndexPage(DiscordThread::class)) + ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); +}); diff --git a/tests/Unit/Filament/Resources/Document/PageTest.php b/tests/Unit/Filament/Resources/Document/PageTest.php index a48e82afa..2c9132b55 100644 --- a/tests/Unit/Filament/Resources/Document/PageTest.php +++ b/tests/Unit/Filament/Resources/Document/PageTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Filament\Resources\Document; - use App\Enums\Auth\CrudPermission; use App\Enums\Auth\SpecialPermission; use App\Filament\Actions\Base\CreateAction; @@ -15,174 +13,117 @@ use App\Filament\Resources\Document\Page; use App\Models\Auth\User; use App\Models\Document\Page as PageModel; use Livewire\Livewire; -use Tests\Unit\Filament\BaseResourceTestCase; -class PageTest extends BaseResourceTestCase -{ - /** - * Get the index page class of the resource. - */ - protected static function getIndexPage(): string - { - $pages = Page::getPages(); +use function Pest\Laravel\actingAs; +use function Pest\Laravel\get; - return $pages['index']->getPage(); - } +test('render index page', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(PageModel::class) + ) + ->createOne(); - /** - * Get the view page class of the resource. - */ - protected static function getViewPage(): string - { - $pages = Page::getPages(); + actingAs($user); - return $pages['view']->getPage(); - } + $records = PageModel::factory()->count(10)->create(); - /** - * The index page of the resource shall be rendered. - */ - public function testRenderIndexPage(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(PageModel::class) - ) - ->createOne(); + get(Page::getUrl('index')) + ->assertSuccessful(); - $this->actingAs($user); + Livewire::test(getIndexPage(Page::class)) + ->assertCanSeeTableRecords($records); +}); - $records = PageModel::factory()->count(10)->create(); +test('render view page', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(PageModel::class) + ) + ->createOne(); - $this->get(Page::getUrl('index')) - ->assertSuccessful(); + actingAs($user); - Livewire::test(static::getIndexPage()) - ->assertCanSeeTableRecords($records); - } + $record = PageModel::factory()->createOne(); - /** - * The view page of the resource shall be rendered. - */ - public function testRenderViewPage(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(PageModel::class) - ) - ->createOne(); + get(Page::getUrl('view', ['record' => $record])) + ->assertSuccessful(); +}); - $this->actingAs($user); +test('mount create action', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::CREATE->format(PageModel::class) + ) + ->createOne(); - $record = PageModel::factory()->createOne(); + actingAs($user); - $this->get(Page::getUrl('view', ['record' => $record])) - ->assertSuccessful(); - } + Livewire::test(getIndexPage(Page::class)) + ->mountAction(CreateAction::class) + ->assertActionMounted(CreateAction::class); +}); - /** - * The create action of the resource shall be mounted. - */ - public function testMountCreateAction(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::CREATE->format(PageModel::class) - ) - ->createOne(); +test('mount edit action', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::UPDATE->format(PageModel::class) + ) + ->createOne(); - $this->actingAs($user); + actingAs($user); - Livewire::test(static::getIndexPage()) - ->mountAction(CreateAction::class) - ->assertActionMounted(CreateAction::class); - } + $record = PageModel::factory()->createOne(); - /** - * The create action of the resource shall be mounted. - */ - public function testMountEditAction(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::UPDATE->format(PageModel::class) - ) - ->createOne(); + Livewire::test(getIndexPage(Page::class)) + ->mountAction(EditAction::class, ['record' => $record]) + ->assertActionMounted(EditAction::class); +}); - $this->actingAs($user); +test('user cannot create record', function () { + Livewire::test(getIndexPage(Page::class)) + ->assertActionHidden(CreateAction::class); +}); - $record = PageModel::factory()->createOne(); +test('user cannot edit record', function () { + $record = PageModel::factory()->createOne(); - Livewire::test(static::getIndexPage()) - ->mountAction(EditAction::class, ['record' => $record]) - ->assertActionMounted(EditAction::class); - } + Livewire::test(getIndexPage(Page::class)) + ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); +}); - /** - * The user with no permissions cannot create a record. - */ - public function testUserCannotCreateRecord(): void - { - Livewire::test(static::getIndexPage()) - ->assertActionHidden(CreateAction::class); - } +test('user cannot delete record', function () { + $record = PageModel::factory()->createOne(); - /** - * The user with no permissions cannot edit a record. - */ - public function testUserCannotEditRecord(): void - { - $record = PageModel::factory()->createOne(); + Livewire::test(getViewPage(Page::class), ['record' => $record->getKey()]) + ->assertActionHidden(DeleteAction::class); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); - } + Livewire::test(getIndexPage(Page::class)) + ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); +}); - /** - * The user with no permissions cannot delete a record. - */ - public function testUserCannotDeleteRecord(): void - { - $record = PageModel::factory()->createOne(); +test('user cannot restore record', function () { + $record = PageModel::factory()->createOne(); - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(DeleteAction::class); + $record->delete(); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); - } + Livewire::test(getViewPage(Page::class), ['record' => $record->getKey()]) + ->assertActionHidden(RestoreAction::class); - /** - * The user with no permissions cannot restore a record. - */ - public function testUserCannotRestoreRecord(): void - { - $record = PageModel::factory()->createOne(); + Livewire::test(getIndexPage(Page::class)) + ->assertActionHidden(RestoreAction::class, ['record' => $record->getKey()]); +}); - $record->delete(); +test('user cannot force delete record', function () { + $record = PageModel::factory()->createOne(); - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(RestoreAction::class); + Livewire::test(getViewPage(Page::class), ['record' => $record->getKey()]) + ->assertActionHidden(ForceDeleteAction::class); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(RestoreAction::class, ['record' => $record->getKey()]); - } - - /** - * The user with no permissions cannot force delete a record. - */ - public function testUserCannotForceDeleteRecord(): void - { - $record = PageModel::factory()->createOne(); - - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(ForceDeleteAction::class); - - Livewire::test(static::getIndexPage()) - ->assertActionHidden(ForceDeleteAction::class, ['record' => $record->getKey()]); - } -} + Livewire::test(getIndexPage(Page::class)) + ->assertActionHidden(ForceDeleteAction::class, ['record' => $record->getKey()]); +}); diff --git a/tests/Unit/Filament/Resources/List/External/ExternalEntryTest.php b/tests/Unit/Filament/Resources/List/External/ExternalEntryTest.php index 5c9b42c7a..e84bdf98e 100644 --- a/tests/Unit/Filament/Resources/List/External/ExternalEntryTest.php +++ b/tests/Unit/Filament/Resources/List/External/ExternalEntryTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Filament\Resources\List\External; - use App\Enums\Auth\CrudPermission; use App\Enums\Auth\SpecialPermission; use App\Filament\Actions\Base\EditAction; @@ -13,110 +11,74 @@ use App\Models\List\External\ExternalEntry as ExternalEntryModel; use App\Models\List\ExternalProfile; use Filament\Facades\Filament; use Livewire\Livewire; -use Tests\Unit\Filament\BaseResourceTestCase; -class ExternalEntryTest extends BaseResourceTestCase -{ - /** - * Initial setup for the tests. - */ - protected function setUp(): void - { - parent::setUp(); +use function Pest\Laravel\actingAs; +use function Pest\Laravel\get; - Filament::setServingStatus(); - } +/** + * Initial setup for the tests. + */ +beforeEach(function () { + Filament::setServingStatus(); +}); - /** - * Get the index page class of the resource. - */ - protected static function getIndexPage(): string - { - $pages = ExternalEntry::getPages(); +test('render index page', function () { + $user = User::factory() + ->withAdmin() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(ExternalEntryModel::class) + ) + ->createOne(); - return $pages['index']->getPage(); - } + actingAs($user); - /** - * Get the view page class of the resource. - */ - protected static function getViewPage(): string - { - $pages = ExternalEntry::getPages(); + $profile = ExternalProfile::factory()->entries(3)->createOne(); - return $pages['view']->getPage(); - } + $records = $profile->externalentries; - /** - * The index page of the resource shall be rendered. - */ - public function testRenderIndexPage(): void - { - $user = User::factory() - ->withAdmin() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(ExternalEntryModel::class) - ) - ->createOne(); + get(ExternalEntry::getUrl('index')) + ->assertSuccessful(); - $this->actingAs($user); + Livewire::test(getIndexPage(ExternalEntry::class)) + ->assertCanSeeTableRecords($records); +}); - $profile = ExternalProfile::factory()->entries(3)->createOne(); +test('render view page', function () { + $user = User::factory() + ->withAdmin() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(ExternalEntryModel::class) + ) + ->createOne(); - $records = $profile->externalentries; + actingAs($user); - $this->get(ExternalEntry::getUrl('index')) - ->assertSuccessful(); + $profile = ExternalProfile::factory()->entries(3)->createOne(); - Livewire::test(static::getIndexPage()) - ->assertCanSeeTableRecords($records); - } + $record = $profile->externalentries->first(); - /** - * The view page of the resource shall be rendered. - */ - public function testRenderViewPage(): void - { - $user = User::factory() - ->withAdmin() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(ExternalEntryModel::class) - ) - ->createOne(); + get(ExternalEntry::getUrl('view', ['record' => $record])) + ->assertSuccessful(); +}); - $this->actingAs($user); +test('mount edit action', function () { + $user = User::factory() + ->withAdmin() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::UPDATE->format(ExternalEntryModel::class), + ) + ->createOne(); - $profile = ExternalProfile::factory()->entries(3)->createOne(); + actingAs($user); - $record = $profile->externalentries->first(); + $profile = ExternalProfile::factory()->entries(3)->createOne(); - $this->get(ExternalEntry::getUrl('view', ['record' => $record])) - ->assertSuccessful(); - } + $record = $profile->externalentries->first(); - /** - * The create action of the resource shall be mounted. - */ - public function testMountEditAction(): void - { - $user = User::factory() - ->withAdmin() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::UPDATE->format(ExternalEntryModel::class), - ) - ->createOne(); - - $this->actingAs($user); - - $profile = ExternalProfile::factory()->entries(3)->createOne(); - - $record = $profile->externalentries->first(); - - Livewire::test(static::getIndexPage()) - ->mountAction(EditAction::class, ['record' => $record]) - ->assertActionMounted(EditAction::class); - } -} + Livewire::test(getIndexPage(ExternalEntry::class)) + ->mountAction(EditAction::class, ['record' => $record]) + ->assertActionMounted(EditAction::class); +}); diff --git a/tests/Unit/Filament/Resources/List/ExternalProfileTest.php b/tests/Unit/Filament/Resources/List/ExternalProfileTest.php index 4471afb44..41ed13597 100644 --- a/tests/Unit/Filament/Resources/List/ExternalProfileTest.php +++ b/tests/Unit/Filament/Resources/List/ExternalProfileTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Filament\Resources\List; - use App\Enums\Auth\CrudPermission; use App\Enums\Auth\SpecialPermission; use App\Filament\Actions\Base\CreateAction; @@ -13,124 +11,84 @@ use App\Models\Auth\User; use App\Models\List\ExternalProfile as ExternalProfileModel; use Filament\Facades\Filament; use Livewire\Livewire; -use Tests\Unit\Filament\BaseResourceTestCase; -class ExternalProfileTest extends BaseResourceTestCase -{ - /** - * Initial setup for the tests. - */ - protected function setUp(): void - { - parent::setUp(); +use function Pest\Laravel\actingAs; +use function Pest\Laravel\get; - Filament::setServingStatus(); - } +/** + * Initial setup for the tests. + */ +beforeEach(function () { + Filament::setServingStatus(); +}); - /** - * Get the index page class of the resource. - */ - protected static function getIndexPage(): string - { - $pages = ExternalProfile::getPages(); +test('render view page', function () { + $user = User::factory() + ->withAdmin() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(ExternalProfileModel::class) + ) + ->createOne(); - return $pages['index']->getPage(); - } + actingAs($user); - /** - * Get the view page class of the resource. - */ - protected static function getViewPage(): string - { - $pages = ExternalProfile::getPages(); + $record = ExternalProfileModel::factory()->createOne(); - return $pages['view']->getPage(); - } + get(ExternalProfile::getUrl('view', ['record' => $record])) + ->assertSuccessful(); +}); - /** - * The view page of the resource shall be rendered. - */ - public function testRenderViewPage(): void - { - $user = User::factory() - ->withAdmin() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(ExternalProfileModel::class) - ) - ->createOne(); +test('render index page', function () { + $user = User::factory() + ->withAdmin() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(ExternalProfileModel::class) + ) + ->createOne(); - $this->actingAs($user); + actingAs($user); - $record = ExternalProfileModel::factory()->createOne(); + $records = ExternalProfileModel::factory()->count(10)->create(); - $this->get(ExternalProfile::getUrl('view', ['record' => $record])) - ->assertSuccessful(); - } + get(ExternalProfile::getUrl('index')) + ->assertSuccessful(); - /** - * The index page of the resource shall be rendered. - */ - public function testRenderIndexPage(): void - { - $user = User::factory() - ->withAdmin() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(ExternalProfileModel::class) - ) - ->createOne(); + Livewire::test(getIndexPage(ExternalProfile::class)) + ->assertCanSeeTableRecords($records); +}); - $this->actingAs($user); +test('mount create action', function () { + $user = User::factory() + ->withAdmin() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::CREATE->format(ExternalProfileModel::class) + ) + ->createOne(); - $records = ExternalProfileModel::factory()->count(10)->create(); + actingAs($user); - $this->get(ExternalProfile::getUrl('index')) - ->assertSuccessful(); + Livewire::test(getIndexPage(ExternalProfile::class)) + ->mountAction(CreateAction::class) + ->assertActionMounted(CreateAction::class); +}); - Livewire::test(static::getIndexPage()) - ->assertCanSeeTableRecords($records); - } +test('mount edit action', function () { + $user = User::factory() + ->withAdmin() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::UPDATE->format(ExternalProfileModel::class), + ) + ->createOne(); - /** - * The create action of the resource shall be mounted. - */ - public function testMountCreateAction(): void - { - $user = User::factory() - ->withAdmin() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::CREATE->format(ExternalProfileModel::class) - ) - ->createOne(); + actingAs($user); - $this->actingAs($user); + $record = ExternalProfileModel::factory()->createOne(); - Livewire::test(static::getIndexPage()) - ->mountAction(CreateAction::class) - ->assertActionMounted(CreateAction::class); - } - - /** - * The create action of the resource shall be mounted. - */ - public function testMountEditAction(): void - { - $user = User::factory() - ->withAdmin() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::UPDATE->format(ExternalProfileModel::class), - ) - ->createOne(); - - $this->actingAs($user); - - $record = ExternalProfileModel::factory()->createOne(); - - Livewire::test(static::getIndexPage()) - ->mountAction(EditAction::class, ['record' => $record]) - ->assertActionMounted(EditAction::class); - } -} + Livewire::test(getIndexPage(ExternalProfile::class)) + ->mountAction(EditAction::class, ['record' => $record]) + ->assertActionMounted(EditAction::class); +}); diff --git a/tests/Unit/Filament/Resources/List/Playlist/TrackTest.php b/tests/Unit/Filament/Resources/List/Playlist/TrackTest.php index f1331e492..2b18d5688 100644 --- a/tests/Unit/Filament/Resources/List/Playlist/TrackTest.php +++ b/tests/Unit/Filament/Resources/List/Playlist/TrackTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Filament\Resources\List\Playlist; - use App\Enums\Auth\CrudPermission; use App\Enums\Auth\SpecialPermission; use App\Filament\Actions\Base\CreateAction; @@ -14,130 +12,90 @@ use App\Models\List\Playlist; use App\Models\List\Playlist\PlaylistTrack as PlaylistTrackModel; use Filament\Facades\Filament; use Livewire\Livewire; -use Tests\Unit\Filament\BaseResourceTestCase; -class TrackTest extends BaseResourceTestCase -{ - /** - * Initial setup for the tests. - */ - protected function setUp(): void - { - parent::setUp(); +use function Pest\Laravel\actingAs; +use function Pest\Laravel\get; - Filament::setServingStatus(); - } +/** + * Initial setup for the tests. + */ +beforeEach(function () { + Filament::setServingStatus(); +}); - /** - * Get the index page class of the resource. - */ - protected static function getIndexPage(): string - { - $pages = Track::getPages(); +test('render index page', function () { + $user = User::factory() + ->withAdmin() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(PlaylistTrackModel::class) + ) + ->createOne(); - return $pages['index']->getPage(); - } + actingAs($user); - /** - * Get the view page class of the resource. - */ - protected static function getViewPage(): string - { - $pages = Track::getPages(); + $playlist = Playlist::factory()->tracks(3)->create(); - return $pages['view']->getPage(); - } + $records = $playlist->tracks; - /** - * The index page of the resource shall be rendered. - */ - public function testRenderIndexPage(): void - { - $user = User::factory() - ->withAdmin() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(PlaylistTrackModel::class) - ) - ->createOne(); + get(Track::getUrl('index')) + ->assertSuccessful(); - $this->actingAs($user); + Livewire::test(getIndexPage(Track::class)) + ->assertCanSeeTableRecords($records); +}); - $playlist = Playlist::factory()->tracks(3)->create(); +test('render view page', function () { + $user = User::factory() + ->withAdmin() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(PlaylistTrackModel::class) + ) + ->createOne(); - $records = $playlist->tracks; + actingAs($user); - $this->get(Track::getUrl('index')) - ->assertSuccessful(); + $playlist = Playlist::factory()->tracks(3)->create(); - Livewire::test(static::getIndexPage()) - ->assertCanSeeTableRecords($records); - } + $record = $playlist->tracks->first(); - /** - * The view page of the resource shall be rendered. - */ - public function testRenderViewPage(): void - { - $user = User::factory() - ->withAdmin() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(PlaylistTrackModel::class) - ) - ->createOne(); + get(Track::getUrl('view', ['record' => $record])) + ->assertSuccessful(); +}); - $this->actingAs($user); +test('mount create action', function () { + $user = User::factory() + ->withAdmin() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::CREATE->format(PlaylistTrackModel::class) + ) + ->createOne(); - $playlist = Playlist::factory()->tracks(3)->create(); + actingAs($user); - $record = $playlist->tracks->first(); + Livewire::test(getIndexPage(Track::class)) + ->mountAction(CreateAction::class) + ->assertActionMounted(CreateAction::class); +}); - $this->get(Track::getUrl('view', ['record' => $record])) - ->assertSuccessful(); - } +test('mount edit action', function () { + $user = User::factory() + ->withAdmin() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::UPDATE->format(PlaylistTrackModel::class), + ) + ->createOne(); - /** - * The create action of the resource shall be mounted. - */ - public function testMountCreateAction(): void - { - $user = User::factory() - ->withAdmin() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::CREATE->format(PlaylistTrackModel::class) - ) - ->createOne(); + actingAs($user); - $this->actingAs($user); + $playlist = Playlist::factory()->tracks(3)->create(); - Livewire::test(static::getIndexPage()) - ->mountAction(CreateAction::class) - ->assertActionMounted(CreateAction::class); - } + $record = $playlist->tracks->first(); - /** - * The create action of the resource shall be mounted. - */ - public function testMountEditAction(): void - { - $user = User::factory() - ->withAdmin() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::UPDATE->format(PlaylistTrackModel::class), - ) - ->createOne(); - - $this->actingAs($user); - - $playlist = Playlist::factory()->tracks(3)->create(); - - $record = $playlist->tracks->first(); - - Livewire::test(static::getIndexPage()) - ->mountAction(EditAction::class, ['record' => $record]) - ->assertActionMounted(EditAction::class); - } -} + Livewire::test(getIndexPage(Track::class)) + ->mountAction(EditAction::class, ['record' => $record]) + ->assertActionMounted(EditAction::class); +}); diff --git a/tests/Unit/Filament/Resources/List/PlaylistTest.php b/tests/Unit/Filament/Resources/List/PlaylistTest.php index 6059ee658..678d7ca9a 100644 --- a/tests/Unit/Filament/Resources/List/PlaylistTest.php +++ b/tests/Unit/Filament/Resources/List/PlaylistTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Filament\Resources\List; - use App\Enums\Auth\CrudPermission; use App\Enums\Auth\SpecialPermission; use App\Filament\Actions\Base\CreateAction; @@ -13,124 +11,84 @@ use App\Models\Auth\User; use App\Models\List\Playlist as PlaylistModel; use Filament\Facades\Filament; use Livewire\Livewire; -use Tests\Unit\Filament\BaseResourceTestCase; -class PlaylistTest extends BaseResourceTestCase -{ - /** - * Initial setup for the tests. - */ - protected function setUp(): void - { - parent::setUp(); +use function Pest\Laravel\actingAs; +use function Pest\Laravel\get; - Filament::setServingStatus(); - } +/** + * Initial setup for the tests. + */ +beforeEach(function () { + Filament::setServingStatus(); +}); - /** - * Get the index page class of the resource. - */ - protected static function getIndexPage(): string - { - $pages = Playlist::getPages(); +test('render index page', function () { + $user = User::factory() + ->withAdmin() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(PlaylistModel::class) + ) + ->createOne(); - return $pages['index']->getPage(); - } + actingAs($user); - /** - * Get the view page class of the resource. - */ - protected static function getViewPage(): string - { - $pages = Playlist::getPages(); + $records = PlaylistModel::factory()->count(10)->create(); - return $pages['view']->getPage(); - } + get(Playlist::getUrl('index')) + ->assertSuccessful(); - /** - * The index page of the resource shall be rendered. - */ - public function testRenderIndexPage(): void - { - $user = User::factory() - ->withAdmin() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(PlaylistModel::class) - ) - ->createOne(); + Livewire::test(getIndexPage(Playlist::class)) + ->assertCanSeeTableRecords($records); +}); - $this->actingAs($user); +test('render view page', function () { + $user = User::factory() + ->withAdmin() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(PlaylistModel::class) + ) + ->createOne(); - $records = PlaylistModel::factory()->count(10)->create(); + actingAs($user); - $this->get(Playlist::getUrl('index')) - ->assertSuccessful(); + $record = PlaylistModel::factory()->createOne(); - Livewire::test(static::getIndexPage()) - ->assertCanSeeTableRecords($records); - } + get(Playlist::getUrl('view', ['record' => $record])) + ->assertSuccessful(); +}); - /** - * The view page of the resource shall be rendered. - */ - public function testRenderViewPage(): void - { - $user = User::factory() - ->withAdmin() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(PlaylistModel::class) - ) - ->createOne(); +test('mount create action', function () { + $user = User::factory() + ->withAdmin() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::CREATE->format(PlaylistModel::class) + ) + ->createOne(); - $this->actingAs($user); + actingAs($user); - $record = PlaylistModel::factory()->createOne(); + Livewire::test(getIndexPage(Playlist::class)) + ->mountAction(CreateAction::class) + ->assertActionMounted(CreateAction::class); +}); - $this->get(Playlist::getUrl('view', ['record' => $record])) - ->assertSuccessful(); - } +test('mount edit action', function () { + $user = User::factory() + ->withAdmin() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::UPDATE->format(PlaylistModel::class), + ) + ->createOne(); - /** - * The create action of the resource shall be mounted. - */ - public function testMountCreateAction(): void - { - $user = User::factory() - ->withAdmin() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::CREATE->format(PlaylistModel::class) - ) - ->createOne(); + actingAs($user); - $this->actingAs($user); + $record = PlaylistModel::factory()->createOne(); - Livewire::test(static::getIndexPage()) - ->mountAction(CreateAction::class) - ->assertActionMounted(CreateAction::class); - } - - /** - * The create action of the resource shall be mounted. - */ - public function testMountEditAction(): void - { - $user = User::factory() - ->withAdmin() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::UPDATE->format(PlaylistModel::class), - ) - ->createOne(); - - $this->actingAs($user); - - $record = PlaylistModel::factory()->createOne(); - - Livewire::test(static::getIndexPage()) - ->mountAction(EditAction::class, ['record' => $record]) - ->assertActionMounted(EditAction::class); - } -} + Livewire::test(getIndexPage(Playlist::class)) + ->mountAction(EditAction::class, ['record' => $record]) + ->assertActionMounted(EditAction::class); +}); diff --git a/tests/Unit/Filament/Resources/Wiki/Anime/Theme/EntryTest.php b/tests/Unit/Filament/Resources/Wiki/Anime/Theme/EntryTest.php index d750b766d..eed5243fd 100644 --- a/tests/Unit/Filament/Resources/Wiki/Anime/Theme/EntryTest.php +++ b/tests/Unit/Filament/Resources/Wiki/Anime/Theme/EntryTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Filament\Resources\Wiki\Anime\Theme; - use App\Enums\Auth\CrudPermission; use App\Enums\Auth\SpecialPermission; use App\Filament\Actions\Base\CreateAction; @@ -15,188 +13,131 @@ use App\Filament\Resources\Wiki\Anime\Theme\Entry; use App\Models\Auth\User; use App\Models\Wiki\Anime\Theme\AnimeThemeEntry as AnimeThemeEntryModel; use Livewire\Livewire; -use Tests\Unit\Filament\BaseResourceTestCase; -class EntryTest extends BaseResourceTestCase -{ - /** - * Get the index page class of the resource. - */ - protected static function getIndexPage(): string - { - $pages = Entry::getPages(); +use function Pest\Laravel\actingAs; +use function Pest\Laravel\get; - return $pages['index']->getPage(); - } +test('render index page', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(AnimeThemeEntryModel::class) + ) + ->createOne(); - /** - * Get the view page class of the resource. - */ - protected static function getViewPage(): string - { - $pages = Entry::getPages(); + actingAs($user); - return $pages['view']->getPage(); - } + $records = AnimeThemeEntryModel::factory() + ->forAnime() + ->count(10)->create(); - /** - * The index page of the resource shall be rendered. - */ - public function testRenderIndexPage(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(AnimeThemeEntryModel::class) - ) - ->createOne(); + get(Entry::getUrl('index')) + ->assertSuccessful(); - $this->actingAs($user); + Livewire::test(getIndexPage(Entry::class)) + ->assertCanSeeTableRecords($records); +}); - $records = AnimeThemeEntryModel::factory() - ->forAnime() - ->count(10)->create(); +test('render view page', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(AnimeThemeEntryModel::class) + ) + ->createOne(); - $this->get(Entry::getUrl('index')) - ->assertSuccessful(); + actingAs($user); - Livewire::test(static::getIndexPage()) - ->assertCanSeeTableRecords($records); - } + $record = AnimeThemeEntryModel::factory() + ->forAnime() + ->createOne(); - /** - * The view page of the resource shall be rendered. - */ - public function testRenderViewPage(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(AnimeThemeEntryModel::class) - ) - ->createOne(); + get(Entry::getUrl('view', ['record' => $record])) + ->assertSuccessful(); +}); - $this->actingAs($user); +test('mount create action', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::CREATE->format(AnimeThemeEntryModel::class) + ) + ->createOne(); - $record = AnimeThemeEntryModel::factory() - ->forAnime() - ->createOne(); + actingAs($user); - $this->get(Entry::getUrl('view', ['record' => $record])) - ->assertSuccessful(); - } + Livewire::test(getIndexPage(Entry::class)) + ->mountAction(CreateAction::class) + ->assertActionMounted(CreateAction::class); +}); - /** - * The create action of the resource shall be mounted. - */ - public function testMountCreateAction(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::CREATE->format(AnimeThemeEntryModel::class) - ) - ->createOne(); +test('mount edit action', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::UPDATE->format(AnimeThemeEntryModel::class) + ) + ->createOne(); - $this->actingAs($user); + actingAs($user); - Livewire::test(static::getIndexPage()) - ->mountAction(CreateAction::class) - ->assertActionMounted(CreateAction::class); - } + $record = AnimeThemeEntryModel::factory() + ->forAnime() + ->createOne(); - /** - * The create action of the resource shall be mounted. - */ - public function testMountEditAction(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::UPDATE->format(AnimeThemeEntryModel::class) - ) - ->createOne(); + Livewire::test(getIndexPage(Entry::class)) + ->mountAction(EditAction::class, ['record' => $record]) + ->assertActionMounted(EditAction::class); +}); - $this->actingAs($user); +test('user cannot create record', function () { + Livewire::test(getIndexPage(Entry::class)) + ->assertActionHidden(CreateAction::class); +}); - $record = AnimeThemeEntryModel::factory() - ->forAnime() - ->createOne(); +test('user cannot edit record', function () { + $record = AnimeThemeEntryModel::factory() + ->forAnime() + ->createOne(); - Livewire::test(static::getIndexPage()) - ->mountAction(EditAction::class, ['record' => $record]) - ->assertActionMounted(EditAction::class); - } + Livewire::test(getIndexPage(Entry::class)) + ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); +}); - /** - * The user with no permissions cannot create a record. - */ - public function testUserCannotCreateRecord(): void - { - Livewire::test(static::getIndexPage()) - ->assertActionHidden(CreateAction::class); - } +test('user cannot delete record', function () { + $record = AnimeThemeEntryModel::factory() + ->forAnime() + ->createOne(); - /** - * The user with no permissions cannot edit a record. - */ - public function testUserCannotEditRecord(): void - { - $record = AnimeThemeEntryModel::factory() - ->forAnime() - ->createOne(); + Livewire::test(getViewPage(Entry::class), ['record' => $record->getKey()]) + ->assertActionHidden(DeleteAction::class); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); - } + Livewire::test(getIndexPage(Entry::class)) + ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); +}); - /** - * The user with no permissions cannot delete a record. - */ - public function testUserCannotDeleteRecord(): void - { - $record = AnimeThemeEntryModel::factory() - ->forAnime() - ->createOne(); +test('user cannot restore record', function () { + $record = AnimeThemeEntryModel::factory() + ->forAnime() + ->createOne(); - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(DeleteAction::class); + $record->delete(); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); - } + Livewire::test(getViewPage(Entry::class), ['record' => $record->getKey()]) + ->assertActionHidden(RestoreAction::class); - /** - * The user with no permissions cannot restore a record. - */ - public function testUserCannotRestoreRecord(): void - { - $record = AnimeThemeEntryModel::factory() - ->forAnime() - ->createOne(); + Livewire::test(getIndexPage(Entry::class)) + ->assertActionHidden(RestoreAction::class, ['record' => $record->getKey()]); +}); - $record->delete(); +test('user cannot force delete record', function () { + $record = AnimeThemeEntryModel::factory() + ->forAnime() + ->createOne(); - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(RestoreAction::class); + Livewire::test(getViewPage(Entry::class), ['record' => $record->getKey()]) + ->assertActionHidden(ForceDeleteAction::class); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(RestoreAction::class, ['record' => $record->getKey()]); - } - - /** - * The user with no permissions cannot force delete a record. - */ - public function testUserCannotForceDeleteRecord(): void - { - $record = AnimeThemeEntryModel::factory() - ->forAnime() - ->createOne(); - - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(ForceDeleteAction::class); - - Livewire::test(static::getIndexPage()) - ->assertActionHidden(ForceDeleteAction::class, ['record' => $record->getKey()]); - } -} + Livewire::test(getIndexPage(Entry::class)) + ->assertActionHidden(ForceDeleteAction::class, ['record' => $record->getKey()]); +}); diff --git a/tests/Unit/Filament/Resources/Wiki/Anime/ThemeTest.php b/tests/Unit/Filament/Resources/Wiki/Anime/ThemeTest.php index b8ec0c524..855e36ee5 100644 --- a/tests/Unit/Filament/Resources/Wiki/Anime/ThemeTest.php +++ b/tests/Unit/Filament/Resources/Wiki/Anime/ThemeTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Filament\Resources\Wiki\Anime; - use App\Enums\Auth\CrudPermission; use App\Enums\Auth\SpecialPermission; use App\Filament\Actions\Base\CreateAction; @@ -16,188 +14,131 @@ use App\Models\Auth\User; use App\Models\Wiki\Anime; use App\Models\Wiki\Anime\AnimeTheme as AnimeThemeModel; use Livewire\Livewire; -use Tests\Unit\Filament\BaseResourceTestCase; -class ThemeTest extends BaseResourceTestCase -{ - /** - * Get the index page class of the resource. - */ - protected static function getIndexPage(): string - { - $pages = Theme::getPages(); +use function Pest\Laravel\actingAs; +use function Pest\Laravel\get; - return $pages['index']->getPage(); - } +test('render index page', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(AnimeThemeModel::class) + ) + ->createOne(); - /** - * Get the view page class of the resource. - */ - protected static function getViewPage(): string - { - $pages = Theme::getPages(); + actingAs($user); - return $pages['view']->getPage(); - } + $records = AnimeThemeModel::factory() + ->for(Anime::factory()) + ->count(10)->create(); - /** - * The index page of the resource shall be rendered. - */ - public function testRenderIndexPage(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(AnimeThemeModel::class) - ) - ->createOne(); + get(Theme::getUrl('index')) + ->assertSuccessful(); - $this->actingAs($user); + Livewire::test(getIndexPage(Theme::class)) + ->assertCanSeeTableRecords($records); +}); - $records = AnimeThemeModel::factory() - ->for(Anime::factory()) - ->count(10)->create(); +test('render view page', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(AnimeThemeModel::class) + ) + ->createOne(); - $this->get(Theme::getUrl('index')) - ->assertSuccessful(); + actingAs($user); - Livewire::test(static::getIndexPage()) - ->assertCanSeeTableRecords($records); - } + $record = AnimeThemeModel::factory() + ->for(Anime::factory()) + ->createOne(); - /** - * The view page of the resource shall be rendered. - */ - public function testRenderViewPage(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(AnimeThemeModel::class) - ) - ->createOne(); + get(Theme::getUrl('view', ['record' => $record])) + ->assertSuccessful(); +}); - $this->actingAs($user); +test('mount create action', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::CREATE->format(AnimeThemeModel::class) + ) + ->createOne(); - $record = AnimeThemeModel::factory() - ->for(Anime::factory()) - ->createOne(); + actingAs($user); - $this->get(Theme::getUrl('view', ['record' => $record])) - ->assertSuccessful(); - } + Livewire::test(getIndexPage(Theme::class)) + ->mountAction(CreateAction::class) + ->assertActionMounted(CreateAction::class); +}); - /** - * The create action of the resource shall be mounted. - */ - public function testMountCreateAction(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::CREATE->format(AnimeThemeModel::class) - ) - ->createOne(); +test('mount edit action', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::UPDATE->format(AnimeThemeModel::class) + ) + ->createOne(); - $this->actingAs($user); + actingAs($user); - Livewire::test(static::getIndexPage()) - ->mountAction(CreateAction::class) - ->assertActionMounted(CreateAction::class); - } + $record = AnimeThemeModel::factory() + ->for(Anime::factory()) + ->createOne(); - /** - * The create action of the resource shall be mounted. - */ - public function testMountEditAction(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::UPDATE->format(AnimeThemeModel::class) - ) - ->createOne(); + Livewire::test(getIndexPage(Theme::class)) + ->mountAction(EditAction::class, ['record' => $record]) + ->assertActionMounted(EditAction::class); +}); - $this->actingAs($user); +test('user cannot create record', function () { + Livewire::test(getIndexPage(Theme::class)) + ->assertActionHidden(CreateAction::class); +}); - $record = AnimeThemeModel::factory() - ->for(Anime::factory()) - ->createOne(); +test('user cannot edit record', function () { + $record = AnimeThemeModel::factory() + ->for(Anime::factory()) + ->createOne(); - Livewire::test(static::getIndexPage()) - ->mountAction(EditAction::class, ['record' => $record]) - ->assertActionMounted(EditAction::class); - } + Livewire::test(getIndexPage(Theme::class)) + ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); +}); - /** - * The user with no permissions cannot create a record. - */ - public function testUserCannotCreateRecord(): void - { - Livewire::test(static::getIndexPage()) - ->assertActionHidden(CreateAction::class); - } +test('user cannot delete record', function () { + $record = AnimeThemeModel::factory() + ->for(Anime::factory()) + ->createOne(); - /** - * The user with no permissions cannot edit a record. - */ - public function testUserCannotEditRecord(): void - { - $record = AnimeThemeModel::factory() - ->for(Anime::factory()) - ->createOne(); + Livewire::test(getViewPage(Theme::class), ['record' => $record->getKey()]) + ->assertActionHidden(DeleteAction::class); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); - } + Livewire::test(getIndexPage(Theme::class)) + ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); +}); - /** - * The user with no permissions cannot delete a record. - */ - public function testUserCannotDeleteRecord(): void - { - $record = AnimeThemeModel::factory() - ->for(Anime::factory()) - ->createOne(); +test('user cannot restore record', function () { + $record = AnimeThemeModel::factory() + ->for(Anime::factory()) + ->createOne(); - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(DeleteAction::class); + $record->delete(); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); - } + Livewire::test(getViewPage(Theme::class), ['record' => $record->getKey()]) + ->assertActionHidden(RestoreAction::class); - /** - * The user with no permissions cannot restore a record. - */ - public function testUserCannotRestoreRecord(): void - { - $record = AnimeThemeModel::factory() - ->for(Anime::factory()) - ->createOne(); + Livewire::test(getIndexPage(Theme::class)) + ->assertActionHidden(RestoreAction::class, ['record' => $record->getKey()]); +}); - $record->delete(); +test('user cannot force delete record', function () { + $record = AnimeThemeModel::factory() + ->for(Anime::factory()) + ->createOne(); - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(RestoreAction::class); + Livewire::test(getViewPage(Theme::class), ['record' => $record->getKey()]) + ->assertActionHidden(ForceDeleteAction::class); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(RestoreAction::class, ['record' => $record->getKey()]); - } - - /** - * The user with no permissions cannot force delete a record. - */ - public function testUserCannotForceDeleteRecord(): void - { - $record = AnimeThemeModel::factory() - ->for(Anime::factory()) - ->createOne(); - - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(ForceDeleteAction::class); - - Livewire::test(static::getIndexPage()) - ->assertActionHidden(ForceDeleteAction::class, ['record' => $record->getKey()]); - } -} + Livewire::test(getIndexPage(Theme::class)) + ->assertActionHidden(ForceDeleteAction::class, ['record' => $record->getKey()]); +}); diff --git a/tests/Unit/Filament/Resources/Wiki/AnimeTest.php b/tests/Unit/Filament/Resources/Wiki/AnimeTest.php index 7726c77c1..c70650f5c 100644 --- a/tests/Unit/Filament/Resources/Wiki/AnimeTest.php +++ b/tests/Unit/Filament/Resources/Wiki/AnimeTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Filament\Resources\Wiki; - use App\Enums\Auth\CrudPermission; use App\Enums\Auth\SpecialPermission; use App\Filament\Actions\Base\CreateAction; @@ -15,174 +13,117 @@ use App\Filament\Resources\Wiki\Anime; use App\Models\Auth\User; use App\Models\Wiki\Anime as AnimeModel; use Livewire\Livewire; -use Tests\Unit\Filament\BaseResourceTestCase; -class AnimeTest extends BaseResourceTestCase -{ - /** - * Get the index page class of the resource. - */ - protected static function getIndexPage(): string - { - $pages = Anime::getPages(); +use function Pest\Laravel\actingAs; +use function Pest\Laravel\get; - return $pages['index']->getPage(); - } +test('render index page', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(AnimeModel::class) + ) + ->createOne(); - /** - * Get the view page class of the resource. - */ - protected static function getViewPage(): string - { - $pages = Anime::getPages(); + actingAs($user); - return $pages['view']->getPage(); - } + $records = AnimeModel::factory()->count(10)->create(); - /** - * The index page of the resource shall be rendered. - */ - public function testRenderIndexPage(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(AnimeModel::class) - ) - ->createOne(); + get(Anime::getUrl('index')) + ->assertSuccessful(); - $this->actingAs($user); + Livewire::test(getIndexPage(Anime::class)) + ->assertCanSeeTableRecords($records); +}); - $records = AnimeModel::factory()->count(10)->create(); +test('render view page', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(AnimeModel::class) + ) + ->createOne(); - $this->get(Anime::getUrl('index')) - ->assertSuccessful(); + actingAs($user); - Livewire::test(static::getIndexPage()) - ->assertCanSeeTableRecords($records); - } + $record = AnimeModel::factory()->createOne(); - /** - * The view page of the resource shall be rendered. - */ - public function testRenderViewPage(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(AnimeModel::class) - ) - ->createOne(); + get(Anime::getUrl('view', ['record' => $record])) + ->assertSuccessful(); +}); - $this->actingAs($user); +test('mount create action', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::CREATE->format(AnimeModel::class) + ) + ->createOne(); - $record = AnimeModel::factory()->createOne(); + actingAs($user); - $this->get(Anime::getUrl('view', ['record' => $record])) - ->assertSuccessful(); - } + Livewire::test(getIndexPage(Anime::class)) + ->mountAction(CreateAction::class) + ->assertActionMounted(CreateAction::class); +}); - /** - * The create action of the resource shall be mounted. - */ - public function testMountCreateAction(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::CREATE->format(AnimeModel::class) - ) - ->createOne(); +test('mount edit action', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::UPDATE->format(AnimeModel::class) + ) + ->createOne(); - $this->actingAs($user); + actingAs($user); - Livewire::test(static::getIndexPage()) - ->mountAction(CreateAction::class) - ->assertActionMounted(CreateAction::class); - } + $record = AnimeModel::factory()->createOne(); - /** - * The create action of the resource shall be mounted. - */ - public function testMountEditAction(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::UPDATE->format(AnimeModel::class) - ) - ->createOne(); + Livewire::test(getIndexPage(Anime::class)) + ->mountAction(EditAction::class, ['record' => $record]) + ->assertActionMounted(EditAction::class); +}); - $this->actingAs($user); +test('user cannot create record', function () { + Livewire::test(getIndexPage(Anime::class)) + ->assertActionHidden(CreateAction::class); +}); - $record = AnimeModel::factory()->createOne(); +test('user cannot edit record', function () { + $record = AnimeModel::factory()->createOne(); - Livewire::test(static::getIndexPage()) - ->mountAction(EditAction::class, ['record' => $record]) - ->assertActionMounted(EditAction::class); - } + Livewire::test(getIndexPage(Anime::class)) + ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); +}); - /** - * The user with no permissions cannot create a record. - */ - public function testUserCannotCreateRecord(): void - { - Livewire::test(static::getIndexPage()) - ->assertActionHidden(CreateAction::class); - } +test('user cannot delete record', function () { + $record = AnimeModel::factory()->createOne(); - /** - * The user with no permissions cannot edit a record. - */ - public function testUserCannotEditRecord(): void - { - $record = AnimeModel::factory()->createOne(); + Livewire::test(getViewPage(Anime::class), ['record' => $record->getKey()]) + ->assertActionHidden(DeleteAction::class); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); - } + Livewire::test(getIndexPage(Anime::class)) + ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); +}); - /** - * The user with no permissions cannot delete a record. - */ - public function testUserCannotDeleteRecord(): void - { - $record = AnimeModel::factory()->createOne(); +test('user cannot restore record', function () { + $record = AnimeModel::factory()->createOne(); - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(DeleteAction::class); + $record->delete(); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); - } + Livewire::test(getViewPage(Anime::class), ['record' => $record->getKey()]) + ->assertActionHidden(RestoreAction::class); - /** - * The user with no permissions cannot restore a record. - */ - public function testUserCannotRestoreRecord(): void - { - $record = AnimeModel::factory()->createOne(); + Livewire::test(getIndexPage(Anime::class)) + ->assertActionHidden(RestoreAction::class, ['record' => $record->getKey()]); +}); - $record->delete(); +test('user cannot force delete record', function () { + $record = AnimeModel::factory()->createOne(); - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(RestoreAction::class); + Livewire::test(getViewPage(Anime::class), ['record' => $record->getKey()]) + ->assertActionHidden(ForceDeleteAction::class); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(RestoreAction::class, ['record' => $record->getKey()]); - } - - /** - * The user with no permissions cannot force delete a record. - */ - public function testUserCannotForceDeleteRecord(): void - { - $record = AnimeModel::factory()->createOne(); - - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(ForceDeleteAction::class); - - Livewire::test(static::getIndexPage()) - ->assertActionHidden(ForceDeleteAction::class, ['record' => $record->getKey()]); - } -} + Livewire::test(getIndexPage(Anime::class)) + ->assertActionHidden(ForceDeleteAction::class, ['record' => $record->getKey()]); +}); diff --git a/tests/Unit/Filament/Resources/Wiki/ArtistTest.php b/tests/Unit/Filament/Resources/Wiki/ArtistTest.php index eec2a91a6..f6793a632 100644 --- a/tests/Unit/Filament/Resources/Wiki/ArtistTest.php +++ b/tests/Unit/Filament/Resources/Wiki/ArtistTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Filament\Resources\Wiki; - use App\Enums\Auth\CrudPermission; use App\Enums\Auth\SpecialPermission; use App\Filament\Actions\Base\CreateAction; @@ -15,174 +13,117 @@ use App\Filament\Resources\Wiki\Artist; use App\Models\Auth\User; use App\Models\Wiki\Artist as ArtistModel; use Livewire\Livewire; -use Tests\Unit\Filament\BaseResourceTestCase; -class ArtistTest extends BaseResourceTestCase -{ - /** - * Get the index page class of the resource. - */ - protected static function getIndexPage(): string - { - $pages = Artist::getPages(); +use function Pest\Laravel\actingAs; +use function Pest\Laravel\get; - return $pages['index']->getPage(); - } +test('render index page', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(ArtistModel::class) + ) + ->createOne(); - /** - * Get the view page class of the resource. - */ - protected static function getViewPage(): string - { - $pages = Artist::getPages(); + actingAs($user); - return $pages['view']->getPage(); - } + $records = ArtistModel::factory()->count(10)->create(); - /** - * The index page of the resource shall be rendered. - */ - public function testRenderIndexPage(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(ArtistModel::class) - ) - ->createOne(); + get(Artist::getUrl('index')) + ->assertSuccessful(); - $this->actingAs($user); + Livewire::test(getIndexPage(Artist::class)) + ->assertCanSeeTableRecords($records); +}); - $records = ArtistModel::factory()->count(10)->create(); +test('render view page', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(ArtistModel::class) + ) + ->createOne(); - $this->get(Artist::getUrl('index')) - ->assertSuccessful(); + actingAs($user); - Livewire::test(static::getIndexPage()) - ->assertCanSeeTableRecords($records); - } + $record = ArtistModel::factory()->createOne(); - /** - * The view page of the resource shall be rendered. - */ - public function testRenderViewPage(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(ArtistModel::class) - ) - ->createOne(); + get(Artist::getUrl('view', ['record' => $record])) + ->assertSuccessful(); +}); - $this->actingAs($user); +test('mount create action', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::CREATE->format(ArtistModel::class) + ) + ->createOne(); - $record = ArtistModel::factory()->createOne(); + actingAs($user); - $this->get(Artist::getUrl('view', ['record' => $record])) - ->assertSuccessful(); - } + Livewire::test(getIndexPage(Artist::class)) + ->mountAction(CreateAction::class) + ->assertActionMounted(CreateAction::class); +}); - /** - * The create action of the resource shall be mounted. - */ - public function testMountCreateAction(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::CREATE->format(ArtistModel::class) - ) - ->createOne(); +test('mount edit action', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::UPDATE->format(ArtistModel::class) + ) + ->createOne(); - $this->actingAs($user); + actingAs($user); - Livewire::test(static::getIndexPage()) - ->mountAction(CreateAction::class) - ->assertActionMounted(CreateAction::class); - } + $record = ArtistModel::factory()->createOne(); - /** - * The create action of the resource shall be mounted. - */ - public function testMountEditAction(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::UPDATE->format(ArtistModel::class) - ) - ->createOne(); + Livewire::test(getIndexPage(Artist::class)) + ->mountAction(EditAction::class, ['record' => $record]) + ->assertActionMounted(EditAction::class); +}); - $this->actingAs($user); +test('user cannot create record', function () { + Livewire::test(getIndexPage(Artist::class)) + ->assertActionHidden(CreateAction::class); +}); - $record = ArtistModel::factory()->createOne(); +test('user cannot edit record', function () { + $record = ArtistModel::factory()->createOne(); - Livewire::test(static::getIndexPage()) - ->mountAction(EditAction::class, ['record' => $record]) - ->assertActionMounted(EditAction::class); - } + Livewire::test(getIndexPage(Artist::class)) + ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); +}); - /** - * The user with no permissions cannot create a record. - */ - public function testUserCannotCreateRecord(): void - { - Livewire::test(static::getIndexPage()) - ->assertActionHidden(CreateAction::class); - } +test('user cannot delete record', function () { + $record = ArtistModel::factory()->createOne(); - /** - * The user with no permissions cannot edit a record. - */ - public function testUserCannotEditRecord(): void - { - $record = ArtistModel::factory()->createOne(); + Livewire::test(getViewPage(Artist::class), ['record' => $record->getKey()]) + ->assertActionHidden(DeleteAction::class); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); - } + Livewire::test(getIndexPage(Artist::class)) + ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); +}); - /** - * The user with no permissions cannot delete a record. - */ - public function testUserCannotDeleteRecord(): void - { - $record = ArtistModel::factory()->createOne(); +test('user cannot restore record', function () { + $record = ArtistModel::factory()->createOne(); - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(DeleteAction::class); + $record->delete(); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); - } + Livewire::test(getViewPage(Artist::class), ['record' => $record->getKey()]) + ->assertActionHidden(RestoreAction::class); - /** - * The user with no permissions cannot restore a record. - */ - public function testUserCannotRestoreRecord(): void - { - $record = ArtistModel::factory()->createOne(); + Livewire::test(getIndexPage(Artist::class)) + ->assertActionHidden(RestoreAction::class, ['record' => $record->getKey()]); +}); - $record->delete(); +test('user cannot force delete record', function () { + $record = ArtistModel::factory()->createOne(); - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(RestoreAction::class); + Livewire::test(getViewPage(Artist::class), ['record' => $record->getKey()]) + ->assertActionHidden(ForceDeleteAction::class); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(RestoreAction::class, ['record' => $record->getKey()]); - } - - /** - * The user with no permissions cannot force delete a record. - */ - public function testUserCannotForceDeleteRecord(): void - { - $record = ArtistModel::factory()->createOne(); - - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(ForceDeleteAction::class); - - Livewire::test(static::getIndexPage()) - ->assertActionHidden(ForceDeleteAction::class, ['record' => $record->getKey()]); - } -} + Livewire::test(getIndexPage(Artist::class)) + ->assertActionHidden(ForceDeleteAction::class, ['record' => $record->getKey()]); +}); diff --git a/tests/Unit/Filament/Resources/Wiki/AudioTest.php b/tests/Unit/Filament/Resources/Wiki/AudioTest.php index 86a139b7e..b1c8e438b 100644 --- a/tests/Unit/Filament/Resources/Wiki/AudioTest.php +++ b/tests/Unit/Filament/Resources/Wiki/AudioTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Filament\Resources\Wiki; - use App\Enums\Auth\CrudPermission; use App\Enums\Auth\SpecialPermission; use App\Filament\Actions\Base\DeleteAction; @@ -14,146 +12,97 @@ use App\Filament\Resources\Wiki\Audio; use App\Models\Auth\User; use App\Models\Wiki\Audio as AudioModel; use Livewire\Livewire; -use Tests\Unit\Filament\BaseResourceTestCase; -class AudioTest extends BaseResourceTestCase -{ - /** - * Get the index page class of the resource. - */ - protected static function getIndexPage(): string - { - $pages = Audio::getPages(); +use function Pest\Laravel\actingAs; +use function Pest\Laravel\get; - return $pages['index']->getPage(); - } +test('render index page', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(AudioModel::class) + ) + ->createOne(); - /** - * Get the view page class of the resource. - */ - protected static function getViewPage(): string - { - $pages = Audio::getPages(); + actingAs($user); - return $pages['view']->getPage(); - } + $records = AudioModel::factory()->count(10)->create(); - /** - * The index page of the resource shall be rendered. - */ - public function testRenderIndexPage(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(AudioModel::class) - ) - ->createOne(); + get(Audio::getUrl('index')) + ->assertSuccessful(); - $this->actingAs($user); + Livewire::test(getIndexPage(Audio::class)) + ->assertCanSeeTableRecords($records); +}); - $records = AudioModel::factory()->count(10)->create(); +test('render view page', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(AudioModel::class) + ) + ->createOne(); - $this->get(Audio::getUrl('index')) - ->assertSuccessful(); + actingAs($user); - Livewire::test(static::getIndexPage()) - ->assertCanSeeTableRecords($records); - } + $record = AudioModel::factory()->createOne(); - /** - * The view page of the resource shall be rendered. - */ - public function testRenderViewPage(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(AudioModel::class) - ) - ->createOne(); + get(Audio::getUrl('view', ['record' => $record])) + ->assertSuccessful(); +}); - $this->actingAs($user); +test('mount edit action', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::UPDATE->format(AudioModel::class) + ) + ->createOne(); - $record = AudioModel::factory()->createOne(); + actingAs($user); - $this->get(Audio::getUrl('view', ['record' => $record])) - ->assertSuccessful(); - } + $record = AudioModel::factory()->createOne(); - /** - * The create action of the resource shall be mounted. - */ - public function testMountEditAction(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::UPDATE->format(AudioModel::class) - ) - ->createOne(); + Livewire::test(getIndexPage(Audio::class)) + ->mountAction(EditAction::class, ['record' => $record]) + ->assertActionMounted(EditAction::class); +}); - $this->actingAs($user); +test('user cannot edit record', function () { + $record = AudioModel::factory()->createOne(); - $record = AudioModel::factory()->createOne(); + Livewire::test(getIndexPage(Audio::class)) + ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); +}); - Livewire::test(static::getIndexPage()) - ->mountAction(EditAction::class, ['record' => $record]) - ->assertActionMounted(EditAction::class); - } +test('user cannot delete record', function () { + $record = AudioModel::factory()->createOne(); - /** - * The user with no permissions cannot edit a record. - */ - public function testUserCannotEditRecord(): void - { - $record = AudioModel::factory()->createOne(); + Livewire::test(getViewPage(Audio::class), ['record' => $record->getKey()]) + ->assertActionHidden(DeleteAction::class); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); - } + Livewire::test(getIndexPage(Audio::class)) + ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); +}); - /** - * The user with no permissions cannot delete a record. - */ - public function testUserCannotDeleteRecord(): void - { - $record = AudioModel::factory()->createOne(); +test('user cannot restore record', function () { + $record = AudioModel::factory()->createOne(); - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(DeleteAction::class); + $record->delete(); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); - } + Livewire::test(getViewPage(Audio::class), ['record' => $record->getKey()]) + ->assertActionHidden(RestoreAction::class); - /** - * The user with no permissions cannot restore a record. - */ - public function testUserCannotRestoreRecord(): void - { - $record = AudioModel::factory()->createOne(); + Livewire::test(getIndexPage(Audio::class)) + ->assertActionHidden(RestoreAction::class, ['record' => $record->getKey()]); +}); - $record->delete(); +test('user cannot force delete record', function () { + $record = AudioModel::factory()->createOne(); - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(RestoreAction::class); + Livewire::test(getViewPage(Audio::class), ['record' => $record->getKey()]) + ->assertActionHidden(ForceDeleteAction::class); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(RestoreAction::class, ['record' => $record->getKey()]); - } - - /** - * The user with no permissions cannot force delete a record. - */ - public function testUserCannotForceDeleteRecord(): void - { - $record = AudioModel::factory()->createOne(); - - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(ForceDeleteAction::class); - - Livewire::test(static::getIndexPage()) - ->assertActionHidden(ForceDeleteAction::class, ['record' => $record->getKey()]); - } -} + Livewire::test(getIndexPage(Audio::class)) + ->assertActionHidden(ForceDeleteAction::class, ['record' => $record->getKey()]); +}); diff --git a/tests/Unit/Filament/Resources/Wiki/ExternalResourceTest.php b/tests/Unit/Filament/Resources/Wiki/ExternalResourceTest.php index d57437284..fc3d0709d 100644 --- a/tests/Unit/Filament/Resources/Wiki/ExternalResourceTest.php +++ b/tests/Unit/Filament/Resources/Wiki/ExternalResourceTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Filament\Resources\Wiki; - use App\Enums\Auth\CrudPermission; use App\Enums\Auth\SpecialPermission; use App\Filament\Actions\Base\DeleteAction; @@ -14,146 +12,97 @@ use App\Filament\Resources\Wiki\ExternalResource; use App\Models\Auth\User; use App\Models\Wiki\ExternalResource as ExternalResourceModel; use Livewire\Livewire; -use Tests\Unit\Filament\BaseResourceTestCase; -class ExternalResourceTest extends BaseResourceTestCase -{ - /** - * Get the index page class of the resource. - */ - protected static function getIndexPage(): string - { - $pages = ExternalResource::getPages(); +use function Pest\Laravel\actingAs; +use function Pest\Laravel\get; - return $pages['index']->getPage(); - } +test('render index page', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(ExternalResourceModel::class) + ) + ->createOne(); - /** - * Get the view page class of the resource. - */ - protected static function getViewPage(): string - { - $pages = ExternalResource::getPages(); + actingAs($user); - return $pages['view']->getPage(); - } + $records = ExternalResourceModel::factory()->count(10)->create(); - /** - * The index page of the resource shall be rendered. - */ - public function testRenderIndexPage(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(ExternalResourceModel::class) - ) - ->createOne(); + get(ExternalResource::getUrl('index')) + ->assertSuccessful(); - $this->actingAs($user); + Livewire::test(getIndexPage(ExternalResource::class)) + ->assertCanSeeTableRecords($records); +}); - $records = ExternalResourceModel::factory()->count(10)->create(); +test('render view page', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(ExternalResourceModel::class) + ) + ->createOne(); - $this->get(ExternalResource::getUrl('index')) - ->assertSuccessful(); + actingAs($user); - Livewire::test(static::getIndexPage()) - ->assertCanSeeTableRecords($records); - } + $record = ExternalResourceModel::factory()->createOne(); - /** - * The view page of the resource shall be rendered. - */ - public function testRenderViewPage(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(ExternalResourceModel::class) - ) - ->createOne(); + get(ExternalResource::getUrl('view', ['record' => $record])) + ->assertSuccessful(); +}); - $this->actingAs($user); +test('mount edit action', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::UPDATE->format(ExternalResourceModel::class) + ) + ->createOne(); - $record = ExternalResourceModel::factory()->createOne(); + actingAs($user); - $this->get(ExternalResource::getUrl('view', ['record' => $record])) - ->assertSuccessful(); - } + $record = ExternalResourceModel::factory()->createOne(); - /** - * The create action of the resource shall be mounted. - */ - public function testMountEditAction(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::UPDATE->format(ExternalResourceModel::class) - ) - ->createOne(); + Livewire::test(getIndexPage(ExternalResource::class)) + ->mountAction(EditAction::class, ['record' => $record]) + ->assertActionMounted(EditAction::class); +}); - $this->actingAs($user); +test('user cannot edit record', function () { + $record = ExternalResourceModel::factory()->createOne(); - $record = ExternalResourceModel::factory()->createOne(); + Livewire::test(getIndexPage(ExternalResource::class)) + ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); +}); - Livewire::test(static::getIndexPage()) - ->mountAction(EditAction::class, ['record' => $record]) - ->assertActionMounted(EditAction::class); - } +test('user cannot delete record', function () { + $record = ExternalResourceModel::factory()->createOne(); - /** - * The user with no permissions cannot edit a record. - */ - public function testUserCannotEditRecord(): void - { - $record = ExternalResourceModel::factory()->createOne(); + Livewire::test(getViewPage(ExternalResource::class), ['record' => $record->getKey()]) + ->assertActionHidden(DeleteAction::class); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); - } + Livewire::test(getIndexPage(ExternalResource::class)) + ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); +}); - /** - * The user with no permissions cannot delete a record. - */ - public function testUserCannotDeleteRecord(): void - { - $record = ExternalResourceModel::factory()->createOne(); +test('user cannot restore record', function () { + $record = ExternalResourceModel::factory()->createOne(); - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(DeleteAction::class); + $record->delete(); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); - } + Livewire::test(getViewPage(ExternalResource::class), ['record' => $record->getKey()]) + ->assertActionHidden(RestoreAction::class); - /** - * The user with no permissions cannot restore a record. - */ - public function testUserCannotRestoreRecord(): void - { - $record = ExternalResourceModel::factory()->createOne(); + Livewire::test(getIndexPage(ExternalResource::class)) + ->assertActionHidden(RestoreAction::class, ['record' => $record->getKey()]); +}); - $record->delete(); +test('user cannot force delete record', function () { + $record = ExternalResourceModel::factory()->createOne(); - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(RestoreAction::class); + Livewire::test(getViewPage(ExternalResource::class), ['record' => $record->getKey()]) + ->assertActionHidden(ForceDeleteAction::class); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(RestoreAction::class, ['record' => $record->getKey()]); - } - - /** - * The user with no permissions cannot force delete a record. - */ - public function testUserCannotForceDeleteRecord(): void - { - $record = ExternalResourceModel::factory()->createOne(); - - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(ForceDeleteAction::class); - - Livewire::test(static::getIndexPage()) - ->assertActionHidden(ForceDeleteAction::class, ['record' => $record->getKey()]); - } -} + Livewire::test(getIndexPage(ExternalResource::class)) + ->assertActionHidden(ForceDeleteAction::class, ['record' => $record->getKey()]); +}); diff --git a/tests/Unit/Filament/Resources/Wiki/GroupTest.php b/tests/Unit/Filament/Resources/Wiki/GroupTest.php index 4a47afb7e..d0fa969ef 100644 --- a/tests/Unit/Filament/Resources/Wiki/GroupTest.php +++ b/tests/Unit/Filament/Resources/Wiki/GroupTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Filament\Resources\Wiki; - use App\Enums\Auth\CrudPermission; use App\Enums\Auth\SpecialPermission; use App\Filament\Actions\Base\CreateAction; @@ -15,174 +13,117 @@ use App\Filament\Resources\Wiki\Group; use App\Models\Auth\User; use App\Models\Wiki\Group as GroupModel; use Livewire\Livewire; -use Tests\Unit\Filament\BaseResourceTestCase; -class GroupTest extends BaseResourceTestCase -{ - /** - * Get the index page class of the resource. - */ - protected static function getIndexPage(): string - { - $pages = Group::getPages(); +use function Pest\Laravel\actingAs; +use function Pest\Laravel\get; - return $pages['index']->getPage(); - } +test('render index page', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(GroupModel::class) + ) + ->createOne(); - /** - * Get the view page class of the resource. - */ - protected static function getViewPage(): string - { - $pages = Group::getPages(); + actingAs($user); - return $pages['view']->getPage(); - } + $records = GroupModel::factory()->count(10)->create(); - /** - * The index page of the resource shall be rendered. - */ - public function testRenderIndexPage(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(GroupModel::class) - ) - ->createOne(); + get(Group::getUrl('index')) + ->assertSuccessful(); - $this->actingAs($user); + Livewire::test(getIndexPage(Group::class)) + ->assertCanSeeTableRecords($records); +}); - $records = GroupModel::factory()->count(10)->create(); +test('render view page', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(GroupModel::class) + ) + ->createOne(); - $this->get(Group::getUrl('index')) - ->assertSuccessful(); + actingAs($user); - Livewire::test(static::getIndexPage()) - ->assertCanSeeTableRecords($records); - } + $record = GroupModel::factory()->createOne(); - /** - * The view page of the resource shall be rendered. - */ - public function testRenderViewPage(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(GroupModel::class) - ) - ->createOne(); + get(Group::getUrl('view', ['record' => $record])) + ->assertSuccessful(); +}); - $this->actingAs($user); +test('mount create action', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::CREATE->format(GroupModel::class) + ) + ->createOne(); - $record = GroupModel::factory()->createOne(); + actingAs($user); - $this->get(Group::getUrl('view', ['record' => $record])) - ->assertSuccessful(); - } + Livewire::test(getIndexPage(Group::class)) + ->mountAction(CreateAction::class) + ->assertActionMounted(CreateAction::class); +}); - /** - * The create action of the resource shall be mounted. - */ - public function testMountCreateAction(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::CREATE->format(GroupModel::class) - ) - ->createOne(); +test('mount edit action', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::UPDATE->format(GroupModel::class) + ) + ->createOne(); - $this->actingAs($user); + actingAs($user); - Livewire::test(static::getIndexPage()) - ->mountAction(CreateAction::class) - ->assertActionMounted(CreateAction::class); - } + $record = GroupModel::factory()->createOne(); - /** - * The create action of the resource shall be mounted. - */ - public function testMountEditAction(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::UPDATE->format(GroupModel::class) - ) - ->createOne(); + Livewire::test(getIndexPage(Group::class)) + ->mountAction(EditAction::class, ['record' => $record]) + ->assertActionMounted(EditAction::class); +}); - $this->actingAs($user); +test('user cannot create record', function () { + Livewire::test(getIndexPage(Group::class)) + ->assertActionHidden(CreateAction::class); +}); - $record = GroupModel::factory()->createOne(); +test('user cannot edit record', function () { + $record = GroupModel::factory()->createOne(); - Livewire::test(static::getIndexPage()) - ->mountAction(EditAction::class, ['record' => $record]) - ->assertActionMounted(EditAction::class); - } + Livewire::test(getIndexPage(Group::class)) + ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); +}); - /** - * The user with no permissions cannot create a record. - */ - public function testUserCannotCreateRecord(): void - { - Livewire::test(static::getIndexPage()) - ->assertActionHidden(CreateAction::class); - } +test('user cannot delete record', function () { + $record = GroupModel::factory()->createOne(); - /** - * The user with no permissions cannot edit a record. - */ - public function testUserCannotEditRecord(): void - { - $record = GroupModel::factory()->createOne(); + Livewire::test(getViewPage(Group::class), ['record' => $record->getKey()]) + ->assertActionHidden(DeleteAction::class); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); - } + Livewire::test(getIndexPage(Group::class)) + ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); +}); - /** - * The user with no permissions cannot delete a record. - */ - public function testUserCannotDeleteRecord(): void - { - $record = GroupModel::factory()->createOne(); +test('user cannot restore record', function () { + $record = GroupModel::factory()->createOne(); - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(DeleteAction::class); + $record->delete(); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); - } + Livewire::test(getViewPage(Group::class), ['record' => $record->getKey()]) + ->assertActionHidden(RestoreAction::class); - /** - * The user with no permissions cannot restore a record. - */ - public function testUserCannotRestoreRecord(): void - { - $record = GroupModel::factory()->createOne(); + Livewire::test(getIndexPage(Group::class)) + ->assertActionHidden(RestoreAction::class, ['record' => $record->getKey()]); +}); - $record->delete(); +test('user cannot force delete record', function () { + $record = GroupModel::factory()->createOne(); - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(RestoreAction::class); + Livewire::test(getViewPage(Group::class), ['record' => $record->getKey()]) + ->assertActionHidden(ForceDeleteAction::class); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(RestoreAction::class, ['record' => $record->getKey()]); - } - - /** - * The user with no permissions cannot force delete a record. - */ - public function testUserCannotForceDeleteRecord(): void - { - $record = GroupModel::factory()->createOne(); - - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(ForceDeleteAction::class); - - Livewire::test(static::getIndexPage()) - ->assertActionHidden(ForceDeleteAction::class, ['record' => $record->getKey()]); - } -} + Livewire::test(getIndexPage(Group::class)) + ->assertActionHidden(ForceDeleteAction::class, ['record' => $record->getKey()]); +}); diff --git a/tests/Unit/Filament/Resources/Wiki/ImageTest.php b/tests/Unit/Filament/Resources/Wiki/ImageTest.php index 84273c646..7ff332f7d 100644 --- a/tests/Unit/Filament/Resources/Wiki/ImageTest.php +++ b/tests/Unit/Filament/Resources/Wiki/ImageTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Filament\Resources\Wiki; - use App\Enums\Auth\CrudPermission; use App\Enums\Auth\SpecialPermission; use App\Filament\Actions\Base\DeleteAction; @@ -14,156 +12,97 @@ use App\Filament\Resources\Wiki\Image; use App\Models\Auth\User; use App\Models\Wiki\Image as ImageModel; use Livewire\Livewire; -use Tests\Unit\Filament\BaseResourceTestCase; -class ImageTest extends BaseResourceTestCase -{ - /** - * Get the index page class of the resource. - */ - protected static function getIndexPage(): string - { - $pages = Image::getPages(); +use function Pest\Laravel\actingAs; +use function Pest\Laravel\get; - return $pages['index']->getPage(); - } +test('render index page', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(ImageModel::class) + ) + ->createOne(); - /** - * Get the edit page class of the resource. - */ - protected static function getEditPage(): string - { - $pages = Image::getPages(); + actingAs($user); - return $pages['edit']->getPage(); - } + $records = ImageModel::factory()->count(10)->create(); - /** - * Get the view page class of the resource. - */ - protected static function getViewPage(): string - { - $pages = Image::getPages(); + get(Image::getUrl('index')) + ->assertSuccessful(); - return $pages['view']->getPage(); - } + Livewire::test(getIndexPage(Image::class)) + ->assertCanSeeTableRecords($records); +}); - /** - * The index page of the resource shall be rendered. - */ - public function testRenderIndexPage(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(ImageModel::class) - ) - ->createOne(); +test('render view page', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(ImageModel::class) + ) + ->createOne(); - $this->actingAs($user); + actingAs($user); - $records = ImageModel::factory()->count(10)->create(); + $record = ImageModel::factory()->createOne(); - $this->get(Image::getUrl('index')) - ->assertSuccessful(); + get(Image::getUrl('view', ['record' => $record])) + ->assertSuccessful(); +}); - Livewire::test(static::getIndexPage()) - ->assertCanSeeTableRecords($records); - } +test('mount edit action', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::UPDATE->format(ImageModel::class) + ) + ->createOne(); - /** - * The view page of the resource shall be rendered. - */ - public function testRenderViewPage(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(ImageModel::class) - ) - ->createOne(); + actingAs($user); - $this->actingAs($user); + $record = ImageModel::factory()->createOne(); - $record = ImageModel::factory()->createOne(); + Livewire::test(getIndexPage(Image::class)) + ->mountAction(EditAction::class, ['record' => $record]) + ->assertActionMounted(EditAction::class); +}); - $this->get(Image::getUrl('view', ['record' => $record])) - ->assertSuccessful(); - } +test('user cannot edit record', function () { + $record = ImageModel::factory()->createOne(); - /** - * The create action of the resource shall be mounted. - */ - public function testMountEditAction(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::UPDATE->format(ImageModel::class) - ) - ->createOne(); + Livewire::test(getIndexPage(Image::class)) + ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); +}); - $this->actingAs($user); +test('user cannot delete record', function () { + $record = ImageModel::factory()->createOne(); - $record = ImageModel::factory()->createOne(); + Livewire::test(getViewPage(Image::class), ['record' => $record->getKey()]) + ->assertActionHidden(DeleteAction::class); - Livewire::test(static::getIndexPage()) - ->mountAction(EditAction::class, ['record' => $record]) - ->assertActionMounted(EditAction::class); - } + Livewire::test(getIndexPage(Image::class)) + ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); +}); - /** - * The user with no permissions cannot edit a record. - */ - public function testUserCannotEditRecord(): void - { - $record = ImageModel::factory()->createOne(); +test('user cannot restore record', function () { + $record = ImageModel::factory()->createOne(); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); - } + $record->delete(); - /** - * The user with no permissions cannot delete a record. - */ - public function testUserCannotDeleteRecord(): void - { - $record = ImageModel::factory()->createOne(); + Livewire::test(getViewPage(Image::class), ['record' => $record->getKey()]) + ->assertActionHidden(RestoreAction::class); - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(DeleteAction::class); + Livewire::test(getIndexPage(Image::class)) + ->assertActionHidden(RestoreAction::class, ['record' => $record->getKey()]); +}); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); - } +test('user cannot force delete record', function () { + $record = ImageModel::factory()->createOne(); - /** - * The user with no permissions cannot restore a record. - */ - public function testUserCannotRestoreRecord(): void - { - $record = ImageModel::factory()->createOne(); + Livewire::test(getViewPage(Image::class), ['record' => $record->getKey()]) + ->assertActionHidden(ForceDeleteAction::class); - $record->delete(); - - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(RestoreAction::class); - - Livewire::test(static::getIndexPage()) - ->assertActionHidden(RestoreAction::class, ['record' => $record->getKey()]); - } - - /** - * The user with no permissions cannot force delete a record. - */ - public function testUserCannotForceDeleteRecord(): void - { - $record = ImageModel::factory()->createOne(); - - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(ForceDeleteAction::class); - - Livewire::test(static::getIndexPage()) - ->assertActionHidden(ForceDeleteAction::class, ['record' => $record->getKey()]); - } -} + Livewire::test(getIndexPage(Image::class)) + ->assertActionHidden(ForceDeleteAction::class, ['record' => $record->getKey()]); +}); diff --git a/tests/Unit/Filament/Resources/Wiki/SeriesTest.php b/tests/Unit/Filament/Resources/Wiki/SeriesTest.php index 124b8f79a..60c384db8 100644 --- a/tests/Unit/Filament/Resources/Wiki/SeriesTest.php +++ b/tests/Unit/Filament/Resources/Wiki/SeriesTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Filament\Resources\Wiki; - use App\Enums\Auth\CrudPermission; use App\Enums\Auth\SpecialPermission; use App\Filament\Actions\Base\CreateAction; @@ -15,174 +13,117 @@ use App\Filament\Resources\Wiki\Series; use App\Models\Auth\User; use App\Models\Wiki\Series as SeriesModel; use Livewire\Livewire; -use Tests\Unit\Filament\BaseResourceTestCase; -class SeriesTest extends BaseResourceTestCase -{ - /** - * Get the index page class of the resource. - */ - protected static function getIndexPage(): string - { - $pages = Series::getPages(); +use function Pest\Laravel\actingAs; +use function Pest\Laravel\get; - return $pages['index']->getPage(); - } +test('render index page', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(SeriesModel::class) + ) + ->createOne(); - /** - * Get the view page class of the resource. - */ - protected static function getViewPage(): string - { - $pages = Series::getPages(); + actingAs($user); - return $pages['view']->getPage(); - } + $records = SeriesModel::factory()->count(10)->create(); - /** - * The index page of the resource shall be rendered. - */ - public function testRenderIndexPage(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(SeriesModel::class) - ) - ->createOne(); + get(Series::getUrl('index')) + ->assertSuccessful(); - $this->actingAs($user); + Livewire::test(getIndexPage(Series::class)) + ->assertCanSeeTableRecords($records); +}); - $records = SeriesModel::factory()->count(10)->create(); +test('render view page', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(SeriesModel::class) + ) + ->createOne(); - $this->get(Series::getUrl('index')) - ->assertSuccessful(); + actingAs($user); - Livewire::test(static::getIndexPage()) - ->assertCanSeeTableRecords($records); - } + $record = SeriesModel::factory()->createOne(); - /** - * The view page of the resource shall be rendered. - */ - public function testRenderViewPage(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(SeriesModel::class) - ) - ->createOne(); + get(Series::getUrl('view', ['record' => $record])) + ->assertSuccessful(); +}); - $this->actingAs($user); +test('mount create action', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::CREATE->format(SeriesModel::class) + ) + ->createOne(); - $record = SeriesModel::factory()->createOne(); + actingAs($user); - $this->get(Series::getUrl('view', ['record' => $record])) - ->assertSuccessful(); - } + Livewire::test(getIndexPage(Series::class)) + ->mountAction(CreateAction::class) + ->assertActionMounted(CreateAction::class); +}); - /** - * The create action of the resource shall be mounted. - */ - public function testMountCreateAction(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::CREATE->format(SeriesModel::class) - ) - ->createOne(); +test('mount edit action', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::UPDATE->format(SeriesModel::class) + ) + ->createOne(); - $this->actingAs($user); + actingAs($user); - Livewire::test(static::getIndexPage()) - ->mountAction(CreateAction::class) - ->assertActionMounted(CreateAction::class); - } + $record = SeriesModel::factory()->createOne(); - /** - * The create action of the resource shall be mounted. - */ - public function testMountEditAction(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::UPDATE->format(SeriesModel::class) - ) - ->createOne(); + Livewire::test(getIndexPage(Series::class)) + ->mountAction(EditAction::class, ['record' => $record]) + ->assertActionMounted(EditAction::class); +}); - $this->actingAs($user); +test('user cannot create record', function () { + Livewire::test(getIndexPage(Series::class)) + ->assertActionHidden(CreateAction::class); +}); - $record = SeriesModel::factory()->createOne(); +test('user cannot edit record', function () { + $record = SeriesModel::factory()->createOne(); - Livewire::test(static::getIndexPage()) - ->mountAction(EditAction::class, ['record' => $record]) - ->assertActionMounted(EditAction::class); - } + Livewire::test(getIndexPage(Series::class)) + ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); +}); - /** - * The user with no permissions cannot create a record. - */ - public function testUserCannotCreateRecord(): void - { - Livewire::test(static::getIndexPage()) - ->assertActionHidden(CreateAction::class); - } +test('user cannot delete record', function () { + $record = SeriesModel::factory()->createOne(); - /** - * The user with no permissions cannot edit a record. - */ - public function testUserCannotEditRecord(): void - { - $record = SeriesModel::factory()->createOne(); + Livewire::test(getViewPage(Series::class), ['record' => $record->getKey()]) + ->assertActionHidden(DeleteAction::class); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); - } + Livewire::test(getIndexPage(Series::class)) + ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); +}); - /** - * The user with no permissions cannot delete a record. - */ - public function testUserCannotDeleteRecord(): void - { - $record = SeriesModel::factory()->createOne(); +test('user cannot restore record', function () { + $record = SeriesModel::factory()->createOne(); - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(DeleteAction::class); + $record->delete(); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); - } + Livewire::test(getViewPage(Series::class), ['record' => $record->getKey()]) + ->assertActionHidden(RestoreAction::class); - /** - * The user with no permissions cannot restore a record. - */ - public function testUserCannotRestoreRecord(): void - { - $record = SeriesModel::factory()->createOne(); + Livewire::test(getIndexPage(Series::class)) + ->assertActionHidden(RestoreAction::class, ['record' => $record->getKey()]); +}); - $record->delete(); +test('user cannot force delete record', function () { + $record = SeriesModel::factory()->createOne(); - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(RestoreAction::class); + Livewire::test(getViewPage(Series::class), ['record' => $record->getKey()]) + ->assertActionHidden(ForceDeleteAction::class); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(RestoreAction::class, ['record' => $record->getKey()]); - } - - /** - * The user with no permissions cannot force delete a record. - */ - public function testUserCannotForceDeleteRecord(): void - { - $record = SeriesModel::factory()->createOne(); - - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(ForceDeleteAction::class); - - Livewire::test(static::getIndexPage()) - ->assertActionHidden(ForceDeleteAction::class, ['record' => $record->getKey()]); - } -} + Livewire::test(getIndexPage(Series::class)) + ->assertActionHidden(ForceDeleteAction::class, ['record' => $record->getKey()]); +}); diff --git a/tests/Unit/Filament/Resources/Wiki/Song/MembershipTest.php b/tests/Unit/Filament/Resources/Wiki/Song/MembershipTest.php index 7c07bfa49..2f38d4aee 100644 --- a/tests/Unit/Filament/Resources/Wiki/Song/MembershipTest.php +++ b/tests/Unit/Filament/Resources/Wiki/Song/MembershipTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Filament\Resources\Wiki\Song; - use App\Enums\Auth\CrudPermission; use App\Enums\Auth\SpecialPermission; use App\Filament\Actions\Base\CreateAction; @@ -16,196 +14,139 @@ use App\Models\Auth\User; use App\Models\Wiki\Artist; use App\Models\Wiki\Song\Membership as MembershipModel; use Livewire\Livewire; -use Tests\Unit\Filament\BaseResourceTestCase; -class MembershipTest extends BaseResourceTestCase -{ - /** - * Get the index page class of the resource. - */ - protected static function getIndexPage(): string - { - $pages = Membership::getPages(); +use function Pest\Laravel\actingAs; +use function Pest\Laravel\get; - return $pages['index']->getPage(); - } +test('render index page', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(MembershipModel::class) + ) + ->createOne(); - /** - * Get the view page class of the resource. - */ - protected static function getViewPage(): string - { - $pages = Membership::getPages(); + actingAs($user); - return $pages['view']->getPage(); - } + $records = MembershipModel::factory() + ->count(10) + ->for(Artist::factory(), MembershipModel::RELATION_ARTIST) + ->for(Artist::factory(), MembershipModel::RELATION_MEMBER) + ->create(); - /** - * The index page of the resource shall be rendered. - */ - public function testRenderIndexPage(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(MembershipModel::class) - ) - ->createOne(); + get(Membership::getUrl('index')) + ->assertSuccessful(); - $this->actingAs($user); + Livewire::test(getIndexPage(Membership::class)) + ->assertCanSeeTableRecords($records); +}); - $records = MembershipModel::factory() - ->count(10) - ->for(Artist::factory(), MembershipModel::RELATION_ARTIST) - ->for(Artist::factory(), MembershipModel::RELATION_MEMBER) - ->create(); +test('render view page', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(MembershipModel::class) + ) + ->createOne(); - $this->get(Membership::getUrl('index')) - ->assertSuccessful(); + actingAs($user); - Livewire::test(static::getIndexPage()) - ->assertCanSeeTableRecords($records); - } + $record = MembershipModel::factory() + ->for(Artist::factory(), MembershipModel::RELATION_ARTIST) + ->for(Artist::factory(), MembershipModel::RELATION_MEMBER) + ->createOne(); - /** - * The view page of the resource shall be rendered. - */ - public function testRenderViewPage(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(MembershipModel::class) - ) - ->createOne(); + get(Membership::getUrl('view', ['record' => $record])) + ->assertSuccessful(); +}); - $this->actingAs($user); +test('mount create action', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::CREATE->format(MembershipModel::class) + ) + ->createOne(); - $record = MembershipModel::factory() - ->for(Artist::factory(), MembershipModel::RELATION_ARTIST) - ->for(Artist::factory(), MembershipModel::RELATION_MEMBER) - ->createOne(); + actingAs($user); - $this->get(Membership::getUrl('view', ['record' => $record])) - ->assertSuccessful(); - } + Livewire::test(getIndexPage(Membership::class)) + ->mountAction(CreateAction::class) + ->assertActionMounted(CreateAction::class); +}); - /** - * The create action of the resource shall be mounted. - */ - public function testMountCreateAction(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::CREATE->format(MembershipModel::class) - ) - ->createOne(); +test('mount edit action', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::UPDATE->format(MembershipModel::class) + ) + ->createOne(); - $this->actingAs($user); + actingAs($user); - Livewire::test(static::getIndexPage()) - ->mountAction(CreateAction::class) - ->assertActionMounted(CreateAction::class); - } + $record = MembershipModel::factory() + ->for(Artist::factory(), MembershipModel::RELATION_ARTIST) + ->for(Artist::factory(), MembershipModel::RELATION_MEMBER) + ->createOne(); - /** - * The create action of the resource shall be mounted. - */ - public function testMountEditAction(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::UPDATE->format(MembershipModel::class) - ) - ->createOne(); + Livewire::test(getIndexPage(Membership::class)) + ->mountAction(EditAction::class, ['record' => $record]) + ->assertActionMounted(EditAction::class); +}); - $this->actingAs($user); +test('user cannot create record', function () { + Livewire::test(getIndexPage(Membership::class)) + ->assertActionHidden(CreateAction::class); +}); - $record = MembershipModel::factory() - ->for(Artist::factory(), MembershipModel::RELATION_ARTIST) - ->for(Artist::factory(), MembershipModel::RELATION_MEMBER) - ->createOne(); +test('user cannot edit record', function () { + $record = MembershipModel::factory() + ->for(Artist::factory(), MembershipModel::RELATION_ARTIST) + ->for(Artist::factory(), MembershipModel::RELATION_MEMBER) + ->createOne(); - Livewire::test(static::getIndexPage()) - ->mountAction(EditAction::class, ['record' => $record]) - ->assertActionMounted(EditAction::class); - } + Livewire::test(getIndexPage(Membership::class)) + ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); +}); - /** - * The user with no permissions cannot create a record. - */ - public function testUserCannotCreateRecord(): void - { - Livewire::test(static::getIndexPage()) - ->assertActionHidden(CreateAction::class); - } +test('user cannot delete record', function () { + $record = MembershipModel::factory() + ->for(Artist::factory(), MembershipModel::RELATION_ARTIST) + ->for(Artist::factory(), MembershipModel::RELATION_MEMBER) + ->createOne(); - /** - * The user with no permissions cannot edit a record. - */ - public function testUserCannotEditRecord(): void - { - $record = MembershipModel::factory() - ->for(Artist::factory(), MembershipModel::RELATION_ARTIST) - ->for(Artist::factory(), MembershipModel::RELATION_MEMBER) - ->createOne(); + Livewire::test(getViewPage(Membership::class), ['record' => $record->getKey()]) + ->assertActionHidden(DeleteAction::class); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); - } + Livewire::test(getIndexPage(Membership::class)) + ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); +}); - /** - * The user with no permissions cannot delete a record. - */ - public function testUserCannotDeleteRecord(): void - { - $record = MembershipModel::factory() - ->for(Artist::factory(), MembershipModel::RELATION_ARTIST) - ->for(Artist::factory(), MembershipModel::RELATION_MEMBER) - ->createOne(); +test('user cannot restore record', function () { + $record = MembershipModel::factory() + ->for(Artist::factory(), MembershipModel::RELATION_ARTIST) + ->for(Artist::factory(), MembershipModel::RELATION_MEMBER) + ->createOne(); - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(DeleteAction::class); + $record->delete(); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); - } + Livewire::test(getViewPage(Membership::class), ['record' => $record->getKey()]) + ->assertActionHidden(RestoreAction::class); - /** - * The user with no permissions cannot restore a record. - */ - public function testUserCannotRestoreRecord(): void - { - $record = MembershipModel::factory() - ->for(Artist::factory(), MembershipModel::RELATION_ARTIST) - ->for(Artist::factory(), MembershipModel::RELATION_MEMBER) - ->createOne(); + Livewire::test(getIndexPage(Membership::class)) + ->assertActionHidden(RestoreAction::class, ['record' => $record->getKey()]); +}); - $record->delete(); +test('user cannot force delete record', function () { + $record = MembershipModel::factory() + ->for(Artist::factory(), MembershipModel::RELATION_ARTIST) + ->for(Artist::factory(), MembershipModel::RELATION_MEMBER) + ->createOne(); - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(RestoreAction::class); + Livewire::test(getViewPage(Membership::class), ['record' => $record->getKey()]) + ->assertActionHidden(ForceDeleteAction::class); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(RestoreAction::class, ['record' => $record->getKey()]); - } - - /** - * The user with no permissions cannot force delete a record. - */ - public function testUserCannotForceDeleteRecord(): void - { - $record = MembershipModel::factory() - ->for(Artist::factory(), MembershipModel::RELATION_ARTIST) - ->for(Artist::factory(), MembershipModel::RELATION_MEMBER) - ->createOne(); - - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(ForceDeleteAction::class); - - Livewire::test(static::getIndexPage()) - ->assertActionHidden(ForceDeleteAction::class, ['record' => $record->getKey()]); - } -} + Livewire::test(getIndexPage(Membership::class)) + ->assertActionHidden(ForceDeleteAction::class, ['record' => $record->getKey()]); +}); diff --git a/tests/Unit/Filament/Resources/Wiki/Song/PerformanceTest.php b/tests/Unit/Filament/Resources/Wiki/Song/PerformanceTest.php index f044bf49e..02845ffe8 100644 --- a/tests/Unit/Filament/Resources/Wiki/Song/PerformanceTest.php +++ b/tests/Unit/Filament/Resources/Wiki/Song/PerformanceTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Filament\Resources\Wiki\Song; - use App\Enums\Auth\CrudPermission; use App\Enums\Auth\SpecialPermission; use App\Filament\Actions\Base\DeleteAction; @@ -16,195 +14,138 @@ use App\Models\Wiki\Artist; use App\Models\Wiki\Song; use App\Models\Wiki\Song\Performance as PerformanceModel; use Livewire\Livewire; -use Tests\Unit\Filament\BaseResourceTestCase; -class PerformanceTest extends BaseResourceTestCase -{ - /** - * Get the index page class of the resource. - */ - protected static function getIndexPage(): string - { - $pages = Performance::getPages(); +use function Pest\Laravel\actingAs; +use function Pest\Laravel\get; - return $pages['index']->getPage(); - } +test('render index page', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(PerformanceModel::class) + ) + ->createOne(); - /** - * Get the view page class of the resource. - */ - protected static function getViewPage(): string - { - $pages = Performance::getPages(); + actingAs($user); - return $pages['view']->getPage(); - } + $records = PerformanceModel::factory() + ->for(Song::factory()) + ->artist(Artist::factory()->createOne()) + ->create(); - /** - * The index page of the resource shall be rendered. - */ - public function testRenderIndexPage(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(PerformanceModel::class) - ) - ->createOne(); + get(Performance::getUrl('index')) + ->assertSuccessful(); - $this->actingAs($user); + Livewire::test(getIndexPage(Performance::class)) + ->assertCanSeeTableRecords(collect([$records])); +}); - $records = PerformanceModel::factory() - ->for(Song::factory()) - ->artist(Artist::factory()->createOne()) - ->create(); +test('render view page', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(PerformanceModel::class) + ) + ->createOne(); - $this->get(Performance::getUrl('index')) - ->assertSuccessful(); + actingAs($user); - Livewire::test(static::getIndexPage()) - ->assertCanSeeTableRecords(collect([$records])); - } + $record = PerformanceModel::factory() + ->for(Song::factory()) + ->artist(Artist::factory()->createOne()) + ->createOne(); - /** - * The view page of the resource shall be rendered. - */ - public function testRenderViewPage(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(PerformanceModel::class) - ) - ->createOne(); + get(Performance::getUrl('view', ['record' => $record])) + ->assertSuccessful(); +}); - $this->actingAs($user); +test('mount create action', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::CREATE->format(PerformanceModel::class) + ) + ->createOne(); - $record = PerformanceModel::factory() - ->for(Song::factory()) - ->artist(Artist::factory()->createOne()) - ->createOne(); + actingAs($user); - $this->get(Performance::getUrl('view', ['record' => $record])) - ->assertSuccessful(); - } + Livewire::test(getIndexPage(Performance::class)) + ->mountAction('new performance') + ->assertActionMounted('new performance'); +}); - /** - * The create action of the resource shall be mounted. - */ - public function testMountCreateAction(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::CREATE->format(PerformanceModel::class) - ) - ->createOne(); +test('mount edit action', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::UPDATE->format(PerformanceModel::class) + ) + ->createOne(); - $this->actingAs($user); + actingAs($user); - Livewire::test(static::getIndexPage()) - ->mountAction('new performance') - ->assertActionMounted('new performance'); - } + $record = PerformanceModel::factory() + ->for(Song::factory()) + ->artist(Artist::factory()->createOne()) + ->createOne(); - /** - * The create action of the resource shall be mounted. - */ - public function testMountEditAction(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::UPDATE->format(PerformanceModel::class) - ) - ->createOne(); + Livewire::test(getIndexPage(Performance::class)) + ->mountAction(EditAction::class, ['record' => $record]) + ->assertActionMounted(EditAction::class); +}); - $this->actingAs($user); +test('user cannot create record', function () { + Livewire::test(getIndexPage(Performance::class)) + ->assertActionHidden('new performance'); +}); - $record = PerformanceModel::factory() - ->for(Song::factory()) - ->artist(Artist::factory()->createOne()) - ->createOne(); +test('user cannot edit record', function () { + $record = PerformanceModel::factory() + ->for(Song::factory()) + ->artist(Artist::factory()->createOne()) + ->createOne(); - Livewire::test(static::getIndexPage()) - ->mountAction(EditAction::class, ['record' => $record]) - ->assertActionMounted(EditAction::class); - } + Livewire::test(getIndexPage(Performance::class)) + ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); +}); - /** - * The user with no permissions cannot create a record. - */ - public function testUserCannotCreateRecord(): void - { - Livewire::test(static::getIndexPage()) - ->assertActionHidden('new performance'); - } +test('user cannot delete record', function () { + $record = PerformanceModel::factory() + ->for(Song::factory()) + ->artist(Artist::factory()->createOne()) + ->createOne(); - /** - * The user with no permissions cannot edit a record. - */ - public function testUserCannotEditRecord(): void - { - $record = PerformanceModel::factory() - ->for(Song::factory()) - ->artist(Artist::factory()->createOne()) - ->createOne(); + Livewire::test(getViewPage(Performance::class), ['record' => $record->getKey()]) + ->assertActionHidden(DeleteAction::class); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); - } + Livewire::test(getIndexPage(Performance::class)) + ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); +}); - /** - * The user with no permissions cannot delete a record. - */ - public function testUserCannotDeleteRecord(): void - { - $record = PerformanceModel::factory() - ->for(Song::factory()) - ->artist(Artist::factory()->createOne()) - ->createOne(); +test('user cannot restore record', function () { + $record = PerformanceModel::factory() + ->for(Song::factory()) + ->artist(Artist::factory()->createOne()) + ->createOne(); - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(DeleteAction::class); + $record->delete(); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); - } + Livewire::test(getViewPage(Performance::class), ['record' => $record->getKey()]) + ->assertActionHidden(RestoreAction::class); - /** - * The user with no permissions cannot restore a record. - */ - public function testUserCannotRestoreRecord(): void - { - $record = PerformanceModel::factory() - ->for(Song::factory()) - ->artist(Artist::factory()->createOne()) - ->createOne(); + Livewire::test(getIndexPage(Performance::class)) + ->assertActionHidden(RestoreAction::class, ['record' => $record->getKey()]); +}); - $record->delete(); +test('user cannot force delete record', function () { + $record = PerformanceModel::factory() + ->for(Song::factory()) + ->artist(Artist::factory()->createOne()) + ->createOne(); - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(RestoreAction::class); + Livewire::test(getViewPage(Performance::class), ['record' => $record->getKey()]) + ->assertActionHidden(ForceDeleteAction::class); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(RestoreAction::class, ['record' => $record->getKey()]); - } - - /** - * The user with no permissions cannot force delete a record. - */ - public function testUserCannotForceDeleteRecord(): void - { - $record = PerformanceModel::factory() - ->for(Song::factory()) - ->artist(Artist::factory()->createOne()) - ->createOne(); - - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(ForceDeleteAction::class); - - Livewire::test(static::getIndexPage()) - ->assertActionHidden(ForceDeleteAction::class, ['record' => $record->getKey()]); - } -} + Livewire::test(getIndexPage(Performance::class)) + ->assertActionHidden(ForceDeleteAction::class, ['record' => $record->getKey()]); +}); diff --git a/tests/Unit/Filament/Resources/Wiki/SongTest.php b/tests/Unit/Filament/Resources/Wiki/SongTest.php index c85ed5a98..c94b585de 100644 --- a/tests/Unit/Filament/Resources/Wiki/SongTest.php +++ b/tests/Unit/Filament/Resources/Wiki/SongTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Filament\Resources\Wiki; - use App\Enums\Auth\CrudPermission; use App\Enums\Auth\SpecialPermission; use App\Filament\Actions\Base\CreateAction; @@ -15,174 +13,117 @@ use App\Filament\Resources\Wiki\Song; use App\Models\Auth\User; use App\Models\Wiki\Song as SongModel; use Livewire\Livewire; -use Tests\Unit\Filament\BaseResourceTestCase; -class SongTest extends BaseResourceTestCase -{ - /** - * Get the index page class of the resource. - */ - protected static function getIndexPage(): string - { - $pages = Song::getPages(); +use function Pest\Laravel\actingAs; +use function Pest\Laravel\get; - return $pages['index']->getPage(); - } +test('render index page', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(SongModel::class) + ) + ->createOne(); - /** - * Get the view page class of the resource. - */ - protected static function getViewPage(): string - { - $pages = Song::getPages(); + actingAs($user); - return $pages['view']->getPage(); - } + $records = SongModel::factory()->count(10)->create(); - /** - * The index page of the resource shall be rendered. - */ - public function testRenderIndexPage(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(SongModel::class) - ) - ->createOne(); + get(Song::getUrl('index')) + ->assertSuccessful(); - $this->actingAs($user); + Livewire::test(getIndexPage(Song::class)) + ->assertCanSeeTableRecords($records); +}); - $records = SongModel::factory()->count(10)->create(); +test('render view page', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(SongModel::class) + ) + ->createOne(); - $this->get(Song::getUrl('index')) - ->assertSuccessful(); + actingAs($user); - Livewire::test(static::getIndexPage()) - ->assertCanSeeTableRecords($records); - } + $record = SongModel::factory()->createOne(); - /** - * The view page of the resource shall be rendered. - */ - public function testRenderViewPage(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(SongModel::class) - ) - ->createOne(); + get(Song::getUrl('view', ['record' => $record])) + ->assertSuccessful(); +}); - $this->actingAs($user); +test('mount create action', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::CREATE->format(SongModel::class) + ) + ->createOne(); - $record = SongModel::factory()->createOne(); + actingAs($user); - $this->get(Song::getUrl('view', ['record' => $record])) - ->assertSuccessful(); - } + Livewire::test(getIndexPage(Song::class)) + ->mountAction(CreateAction::class) + ->assertActionMounted(CreateAction::class); +}); - /** - * The create action of the resource shall be mounted. - */ - public function testMountCreateAction(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::CREATE->format(SongModel::class) - ) - ->createOne(); +test('mount edit action', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::UPDATE->format(SongModel::class) + ) + ->createOne(); - $this->actingAs($user); + actingAs($user); - Livewire::test(static::getIndexPage()) - ->mountAction(CreateAction::class) - ->assertActionMounted(CreateAction::class); - } + $record = SongModel::factory()->createOne(); - /** - * The create action of the resource shall be mounted. - */ - public function testMountEditAction(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::UPDATE->format(SongModel::class) - ) - ->createOne(); + Livewire::test(getIndexPage(Song::class)) + ->mountAction(EditAction::class, ['record' => $record]) + ->assertActionMounted(EditAction::class); +}); - $this->actingAs($user); +test('user cannot create record', function () { + Livewire::test(getIndexPage(Song::class)) + ->assertActionHidden(CreateAction::class); +}); - $record = SongModel::factory()->createOne(); +test('user cannot edit record', function () { + $record = SongModel::factory()->createOne(); - Livewire::test(static::getIndexPage()) - ->mountAction(EditAction::class, ['record' => $record]) - ->assertActionMounted(EditAction::class); - } + Livewire::test(getIndexPage(Song::class)) + ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); +}); - /** - * The user with no permissions cannot create a record. - */ - public function testUserCannotCreateRecord(): void - { - Livewire::test(static::getIndexPage()) - ->assertActionHidden(CreateAction::class); - } +test('user cannot delete record', function () { + $record = SongModel::factory()->createOne(); - /** - * The user with no permissions cannot edit a record. - */ - public function testUserCannotEditRecord(): void - { - $record = SongModel::factory()->createOne(); + Livewire::test(getViewPage(Song::class), ['record' => $record->getKey()]) + ->assertActionHidden(DeleteAction::class); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); - } + Livewire::test(getIndexPage(Song::class)) + ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); +}); - /** - * The user with no permissions cannot delete a record. - */ - public function testUserCannotDeleteRecord(): void - { - $record = SongModel::factory()->createOne(); +test('user cannot restore record', function () { + $record = SongModel::factory()->createOne(); - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(DeleteAction::class); + $record->delete(); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); - } + Livewire::test(getViewPage(Song::class), ['record' => $record->getKey()]) + ->assertActionHidden(RestoreAction::class); - /** - * The user with no permissions cannot restore a record. - */ - public function testUserCannotRestoreRecord(): void - { - $record = SongModel::factory()->createOne(); + Livewire::test(getIndexPage(Song::class)) + ->assertActionHidden(RestoreAction::class, ['record' => $record->getKey()]); +}); - $record->delete(); +test('user cannot force delete record', function () { + $record = SongModel::factory()->createOne(); - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(RestoreAction::class); + Livewire::test(getViewPage(Song::class), ['record' => $record->getKey()]) + ->assertActionHidden(ForceDeleteAction::class); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(RestoreAction::class, ['record' => $record->getKey()]); - } - - /** - * The user with no permissions cannot force delete a record. - */ - public function testUserCannotForceDeleteRecord(): void - { - $record = SongModel::factory()->createOne(); - - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(ForceDeleteAction::class); - - Livewire::test(static::getIndexPage()) - ->assertActionHidden(ForceDeleteAction::class, ['record' => $record->getKey()]); - } -} + Livewire::test(getIndexPage(Song::class)) + ->assertActionHidden(ForceDeleteAction::class, ['record' => $record->getKey()]); +}); diff --git a/tests/Unit/Filament/Resources/Wiki/StudioTest.php b/tests/Unit/Filament/Resources/Wiki/StudioTest.php index d5b62d2bd..a9125d20f 100644 --- a/tests/Unit/Filament/Resources/Wiki/StudioTest.php +++ b/tests/Unit/Filament/Resources/Wiki/StudioTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Filament\Resources\Wiki; - use App\Enums\Auth\CrudPermission; use App\Enums\Auth\SpecialPermission; use App\Filament\Actions\Base\CreateAction; @@ -15,174 +13,117 @@ use App\Filament\Resources\Wiki\Studio; use App\Models\Auth\User; use App\Models\Wiki\Studio as StudioModel; use Livewire\Livewire; -use Tests\Unit\Filament\BaseResourceTestCase; -class StudioTest extends BaseResourceTestCase -{ - /** - * Get the index page class of the resource. - */ - protected static function getIndexPage(): string - { - $pages = Studio::getPages(); +use function Pest\Laravel\actingAs; +use function Pest\Laravel\get; - return $pages['index']->getPage(); - } +test('render index page', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(StudioModel::class) + ) + ->createOne(); - /** - * Get the view page class of the resource. - */ - protected static function getViewPage(): string - { - $pages = Studio::getPages(); + actingAs($user); - return $pages['view']->getPage(); - } + $records = StudioModel::factory()->count(10)->create(); - /** - * The index page of the resource shall be rendered. - */ - public function testRenderIndexPage(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(StudioModel::class) - ) - ->createOne(); + get(Studio::getUrl('index')) + ->assertSuccessful(); - $this->actingAs($user); + Livewire::test(getIndexPage(Studio::class)) + ->assertCanSeeTableRecords($records); +}); - $records = StudioModel::factory()->count(10)->create(); +test('render view page', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(StudioModel::class) + ) + ->createOne(); - $this->get(Studio::getUrl('index')) - ->assertSuccessful(); + actingAs($user); - Livewire::test(static::getIndexPage()) - ->assertCanSeeTableRecords($records); - } + $record = StudioModel::factory()->createOne(); - /** - * The view page of the resource shall be rendered. - */ - public function testRenderViewPage(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(StudioModel::class) - ) - ->createOne(); + get(Studio::getUrl('view', ['record' => $record])) + ->assertSuccessful(); +}); - $this->actingAs($user); +test('mount create action', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::CREATE->format(StudioModel::class) + ) + ->createOne(); - $record = StudioModel::factory()->createOne(); + actingAs($user); - $this->get(Studio::getUrl('view', ['record' => $record])) - ->assertSuccessful(); - } + Livewire::test(getIndexPage(Studio::class)) + ->mountAction(CreateAction::class) + ->assertActionMounted(CreateAction::class); +}); - /** - * The create action of the resource shall be mounted. - */ - public function testMountCreateAction(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::CREATE->format(StudioModel::class) - ) - ->createOne(); +test('mount edit action', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::UPDATE->format(StudioModel::class) + ) + ->createOne(); - $this->actingAs($user); + actingAs($user); - Livewire::test(static::getIndexPage()) - ->mountAction(CreateAction::class) - ->assertActionMounted(CreateAction::class); - } + $record = StudioModel::factory()->createOne(); - /** - * The create action of the resource shall be mounted. - */ - public function testMountEditAction(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::UPDATE->format(StudioModel::class) - ) - ->createOne(); + Livewire::test(getIndexPage(Studio::class)) + ->mountAction(EditAction::class, ['record' => $record]) + ->assertActionMounted(EditAction::class); +}); - $this->actingAs($user); +test('user cannot create record', function () { + Livewire::test(getIndexPage(Studio::class)) + ->assertActionHidden(CreateAction::class); +}); - $record = StudioModel::factory()->createOne(); +test('user cannot edit record', function () { + $record = StudioModel::factory()->createOne(); - Livewire::test(static::getIndexPage()) - ->mountAction(EditAction::class, ['record' => $record]) - ->assertActionMounted(EditAction::class); - } + Livewire::test(getIndexPage(Studio::class)) + ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); +}); - /** - * The user with no permissions cannot create a record. - */ - public function testUserCannotCreateRecord(): void - { - Livewire::test(static::getIndexPage()) - ->assertActionHidden(CreateAction::class); - } +test('user cannot delete record', function () { + $record = StudioModel::factory()->createOne(); - /** - * The user with no permissions cannot edit a record. - */ - public function testUserCannotEditRecord(): void - { - $record = StudioModel::factory()->createOne(); + Livewire::test(getViewPage(Studio::class), ['record' => $record->getKey()]) + ->assertActionHidden(DeleteAction::class); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); - } + Livewire::test(getIndexPage(Studio::class)) + ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); +}); - /** - * The user with no permissions cannot delete a record. - */ - public function testUserCannotDeleteRecord(): void - { - $record = StudioModel::factory()->createOne(); +test('user cannot restore record', function () { + $record = StudioModel::factory()->createOne(); - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(DeleteAction::class); + $record->delete(); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); - } + Livewire::test(getViewPage(Studio::class), ['record' => $record->getKey()]) + ->assertActionHidden(RestoreAction::class); - /** - * The user with no permissions cannot restore a record. - */ - public function testUserCannotRestoreRecord(): void - { - $record = StudioModel::factory()->createOne(); + Livewire::test(getIndexPage(Studio::class)) + ->assertActionHidden(RestoreAction::class, ['record' => $record->getKey()]); +}); - $record->delete(); +test('user cannot force delete record', function () { + $record = StudioModel::factory()->createOne(); - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(RestoreAction::class); + Livewire::test(getViewPage(Studio::class), ['record' => $record->getKey()]) + ->assertActionHidden(ForceDeleteAction::class); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(RestoreAction::class, ['record' => $record->getKey()]); - } - - /** - * The user with no permissions cannot force delete a record. - */ - public function testUserCannotForceDeleteRecord(): void - { - $record = StudioModel::factory()->createOne(); - - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(ForceDeleteAction::class); - - Livewire::test(static::getIndexPage()) - ->assertActionHidden(ForceDeleteAction::class, ['record' => $record->getKey()]); - } -} + Livewire::test(getIndexPage(Studio::class)) + ->assertActionHidden(ForceDeleteAction::class, ['record' => $record->getKey()]); +}); diff --git a/tests/Unit/Filament/Resources/Wiki/Video/ScriptTest.php b/tests/Unit/Filament/Resources/Wiki/Video/ScriptTest.php index 751c4a677..b15ff7e3c 100644 --- a/tests/Unit/Filament/Resources/Wiki/Video/ScriptTest.php +++ b/tests/Unit/Filament/Resources/Wiki/Video/ScriptTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Filament\Resources\Wiki\Video; - use App\Enums\Auth\CrudPermission; use App\Enums\Auth\SpecialPermission; use App\Filament\Actions\Base\DeleteAction; @@ -14,146 +12,97 @@ use App\Filament\Resources\Wiki\Video\Script; use App\Models\Auth\User; use App\Models\Wiki\Video\VideoScript as VideoScriptModel; use Livewire\Livewire; -use Tests\Unit\Filament\BaseResourceTestCase; -class ScriptTest extends BaseResourceTestCase -{ - /** - * Get the index page class of the resource. - */ - protected static function getIndexPage(): string - { - $pages = Script::getPages(); +use function Pest\Laravel\actingAs; +use function Pest\Laravel\get; - return $pages['index']->getPage(); - } +test('render index page', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(VideoScriptModel::class) + ) + ->createOne(); - /** - * Get the view page class of the resource. - */ - protected static function getViewPage(): string - { - $pages = Script::getPages(); + actingAs($user); - return $pages['view']->getPage(); - } + $records = VideoScriptModel::factory()->count(10)->create(); - /** - * The index page of the resource shall be rendered. - */ - public function testRenderIndexPage(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(VideoScriptModel::class) - ) - ->createOne(); + get(Script::getUrl('index')) + ->assertSuccessful(); - $this->actingAs($user); + Livewire::test(getIndexPage(Script::class)) + ->assertCanSeeTableRecords($records); +}); - $records = VideoScriptModel::factory()->count(10)->create(); +test('render view page', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(VideoScriptModel::class) + ) + ->createOne(); - $this->get(Script::getUrl('index')) - ->assertSuccessful(); + actingAs($user); - Livewire::test(static::getIndexPage()) - ->assertCanSeeTableRecords($records); - } + $record = VideoScriptModel::factory()->createOne(); - /** - * The view page of the resource shall be rendered. - */ - public function testRenderViewPage(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(VideoScriptModel::class) - ) - ->createOne(); + get(Script::getUrl('view', ['record' => $record])) + ->assertSuccessful(); +}); - $this->actingAs($user); +test('mount edit action', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::UPDATE->format(VideoScriptModel::class) + ) + ->createOne(); - $record = VideoScriptModel::factory()->createOne(); + actingAs($user); - $this->get(Script::getUrl('view', ['record' => $record])) - ->assertSuccessful(); - } + $record = VideoScriptModel::factory()->createOne(); - /** - * The create action of the resource shall be mounted. - */ - public function testMountEditAction(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::UPDATE->format(VideoScriptModel::class) - ) - ->createOne(); + Livewire::test(getIndexPage(Script::class)) + ->mountAction(EditAction::class, ['record' => $record]) + ->assertActionMounted(EditAction::class); +}); - $this->actingAs($user); +test('user cannot edit record', function () { + $record = VideoScriptModel::factory()->createOne(); - $record = VideoScriptModel::factory()->createOne(); + Livewire::test(getIndexPage(Script::class)) + ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); +}); - Livewire::test(static::getIndexPage()) - ->mountAction(EditAction::class, ['record' => $record]) - ->assertActionMounted(EditAction::class); - } +test('user cannot delete record', function () { + $record = VideoScriptModel::factory()->createOne(); - /** - * The user with no permissions cannot edit a record. - */ - public function testUserCannotEditRecord(): void - { - $record = VideoScriptModel::factory()->createOne(); + Livewire::test(getViewPage(Script::class), ['record' => $record->getKey()]) + ->assertActionHidden(DeleteAction::class); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); - } + Livewire::test(getIndexPage(Script::class)) + ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); +}); - /** - * The user with no permissions cannot delete a record. - */ - public function testUserCannotDeleteRecord(): void - { - $record = VideoScriptModel::factory()->createOne(); +test('user cannot restore record', function () { + $record = VideoScriptModel::factory()->createOne(); - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(DeleteAction::class); + $record->delete(); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); - } + Livewire::test(getViewPage(Script::class), ['record' => $record->getKey()]) + ->assertActionHidden(RestoreAction::class); - /** - * The user with no permissions cannot restore a record. - */ - public function testUserCannotRestoreRecord(): void - { - $record = VideoScriptModel::factory()->createOne(); + Livewire::test(getIndexPage(Script::class)) + ->assertActionHidden(RestoreAction::class, ['record' => $record->getKey()]); +}); - $record->delete(); +test('user cannot force delete record', function () { + $record = VideoScriptModel::factory()->createOne(); - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(RestoreAction::class); + Livewire::test(getViewPage(Script::class), ['record' => $record->getKey()]) + ->assertActionHidden(ForceDeleteAction::class); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(RestoreAction::class, ['record' => $record->getKey()]); - } - - /** - * The user with no permissions cannot force delete a record. - */ - public function testUserCannotForceDeleteRecord(): void - { - $record = VideoScriptModel::factory()->createOne(); - - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(ForceDeleteAction::class); - - Livewire::test(static::getIndexPage()) - ->assertActionHidden(ForceDeleteAction::class, ['record' => $record->getKey()]); - } -} + Livewire::test(getIndexPage(Script::class)) + ->assertActionHidden(ForceDeleteAction::class, ['record' => $record->getKey()]); +}); diff --git a/tests/Unit/Filament/Resources/Wiki/VideoTest.php b/tests/Unit/Filament/Resources/Wiki/VideoTest.php index cfbf6a2b9..464f3ae48 100644 --- a/tests/Unit/Filament/Resources/Wiki/VideoTest.php +++ b/tests/Unit/Filament/Resources/Wiki/VideoTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Filament\Resources\Wiki; - use App\Enums\Auth\CrudPermission; use App\Enums\Auth\SpecialPermission; use App\Filament\Actions\Base\DeleteAction; @@ -14,156 +12,97 @@ use App\Filament\Resources\Wiki\Video; use App\Models\Auth\User; use App\Models\Wiki\Video as VideoModel; use Livewire\Livewire; -use Tests\Unit\Filament\BaseResourceTestCase; -class VideoTest extends BaseResourceTestCase -{ - /** - * Get the index page class of the resource. - */ - protected static function getIndexPage(): string - { - $pages = Video::getPages(); +use function Pest\Laravel\actingAs; +use function Pest\Laravel\get; - return $pages['index']->getPage(); - } +test('render index page', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(VideoModel::class) + ) + ->createOne(); - /** - * Get the edit page class of the resource. - */ - protected static function getEditPage(): string - { - $pages = Video::getPages(); + actingAs($user); - return $pages['edit']->getPage(); - } + $records = VideoModel::factory()->count(10)->create(); - /** - * Get the view page class of the resource. - */ - protected static function getViewPage(): string - { - $pages = Video::getPages(); + get(Video::getUrl('index')) + ->assertSuccessful(); - return $pages['view']->getPage(); - } + Livewire::test(getIndexPage(Video::class)) + ->assertCanSeeTableRecords($records); +}); - /** - * The index page of the resource shall be rendered. - */ - public function testRenderIndexPage(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(VideoModel::class) - ) - ->createOne(); +test('render view page', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::VIEW->format(VideoModel::class) + ) + ->createOne(); - $this->actingAs($user); + actingAs($user); - $records = VideoModel::factory()->count(10)->create(); + $record = VideoModel::factory()->createOne(); - $this->get(Video::getUrl('index')) - ->assertSuccessful(); + get(Video::getUrl('view', ['record' => $record])) + ->assertSuccessful(); +}); - Livewire::test(static::getIndexPage()) - ->assertCanSeeTableRecords($records); - } +test('mount edit action', function () { + $user = User::factory() + ->withPermissions( + SpecialPermission::VIEW_FILAMENT->value, + CrudPermission::UPDATE->format(VideoModel::class) + ) + ->createOne(); - /** - * The view page of the resource shall be rendered. - */ - public function testRenderViewPage(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::VIEW->format(VideoModel::class) - ) - ->createOne(); + actingAs($user); - $this->actingAs($user); + $record = VideoModel::factory()->createOne(); - $record = VideoModel::factory()->createOne(); + Livewire::test(getIndexPage(Video::class)) + ->mountAction(EditAction::class, ['record' => $record]) + ->assertActionMounted(EditAction::class); +}); - $this->get(Video::getUrl('view', ['record' => $record])) - ->assertSuccessful(); - } +test('user cannot edit record', function () { + $record = VideoModel::factory()->createOne(); - /** - * The create action of the resource shall be mounted. - */ - public function testMountEditAction(): void - { - $user = User::factory() - ->withPermissions( - SpecialPermission::VIEW_FILAMENT->value, - CrudPermission::UPDATE->format(VideoModel::class) - ) - ->createOne(); + Livewire::test(getIndexPage(Video::class)) + ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); +}); - $this->actingAs($user); +test('user cannot delete record', function () { + $record = VideoModel::factory()->createOne(); - $record = VideoModel::factory()->createOne(); + Livewire::test(getViewPage(Video::class), ['record' => $record->getKey()]) + ->assertActionHidden(DeleteAction::class); - Livewire::test(static::getIndexPage()) - ->mountAction(EditAction::class, ['record' => $record]) - ->assertActionMounted(EditAction::class); - } + Livewire::test(getIndexPage(Video::class)) + ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); +}); - /** - * The user with no permissions cannot edit a record. - */ - public function testUserCannotEditRecord(): void - { - $record = VideoModel::factory()->createOne(); +test('user cannot restore record', function () { + $record = VideoModel::factory()->createOne(); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(EditAction::class, ['record' => $record->getKey()]); - } + $record->delete(); - /** - * The user with no permissions cannot delete a record. - */ - public function testUserCannotDeleteRecord(): void - { - $record = VideoModel::factory()->createOne(); + Livewire::test(getViewPage(Video::class), ['record' => $record->getKey()]) + ->assertActionHidden(RestoreAction::class); - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(DeleteAction::class); + Livewire::test(getIndexPage(Video::class)) + ->assertActionHidden(RestoreAction::class, ['record' => $record->getKey()]); +}); - Livewire::test(static::getIndexPage()) - ->assertActionHidden(DeleteAction::class, ['record' => $record->getKey()]); - } +test('user cannot force delete record', function () { + $record = VideoModel::factory()->createOne(); - /** - * The user with no permissions cannot restore a record. - */ - public function testUserCannotRestoreRecord(): void - { - $record = VideoModel::factory()->createOne(); + Livewire::test(getViewPage(Video::class), ['record' => $record->getKey()]) + ->assertActionHidden(ForceDeleteAction::class); - $record->delete(); - - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(RestoreAction::class); - - Livewire::test(static::getIndexPage()) - ->assertActionHidden(RestoreAction::class, ['record' => $record->getKey()]); - } - - /** - * The user with no permissions cannot force delete a record. - */ - public function testUserCannotForceDeleteRecord(): void - { - $record = VideoModel::factory()->createOne(); - - Livewire::test(static::getViewPage(), ['record' => $record->getKey()]) - ->assertActionHidden(ForceDeleteAction::class); - - Livewire::test(static::getIndexPage()) - ->assertActionHidden(ForceDeleteAction::class, ['record' => $record->getKey()]); - } -} + Livewire::test(getIndexPage(Video::class)) + ->assertActionHidden(ForceDeleteAction::class, ['record' => $record->getKey()]); +}); diff --git a/tests/Unit/Http/Api/Criteria/Field/CriteriaTest.php b/tests/Unit/Http/Api/Criteria/Field/CriteriaTest.php index 88eda05b5..534f78cc6 100644 --- a/tests/Unit/Http/Api/Criteria/Field/CriteriaTest.php +++ b/tests/Unit/Http/Api/Criteria/Field/CriteriaTest.php @@ -2,38 +2,23 @@ declare(strict_types=1); -namespace Tests\Unit\Http\Api\Criteria\Field; - use App\Http\Api\Criteria\Field\Criteria; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Str; -use Tests\TestCase; -class CriteriaTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The field criteria shall return true if the field is allowed. - */ - public function testIsAllowedField(): void - { - $fields = collect($this->faker->words($this->faker->randomDigitNotNull())); +test('is allowed field', function () { + $fields = collect(fake()->words(fake()->randomDigitNotNull())); - $criteria = new Criteria($this->faker->word(), $fields); + $criteria = new Criteria(fake()->word(), $fields); - static::assertTrue($criteria->isAllowedField($fields->random())); - } + $this->assertTrue($criteria->isAllowedField($fields->random())); +}); - /** - * The field criteria shall return false if the field is not allowed. - */ - public function testIsNotAllowed(): void - { - $fields = collect($this->faker->words($this->faker->randomDigitNotNull())); +test('is not allowed', function () { + $fields = collect(fake()->words(fake()->randomDigitNotNull())); - $criteria = new Criteria($this->faker->word(), $fields); + $criteria = new Criteria(fake()->word(), $fields); - static::assertFalse($criteria->isAllowedField(Str::random())); - } -} + $this->assertFalse($criteria->isAllowedField(Str::random())); +}); diff --git a/tests/Unit/Http/Api/Criteria/Filter/CriteriaTest.php b/tests/Unit/Http/Api/Criteria/Filter/CriteriaTest.php index c46a06387..db5ae6980 100644 --- a/tests/Unit/Http/Api/Criteria/Filter/CriteriaTest.php +++ b/tests/Unit/Http/Api/Criteria/Filter/CriteriaTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Http\Api\Criteria\Filter; - use App\Enums\Http\Api\Filter\BinaryLogicalOperator; use App\Enums\Http\Api\Filter\ComparisonOperator; use App\Http\Api\Criteria\Filter\Expression; @@ -11,306 +9,289 @@ use App\Http\Api\Criteria\Filter\Predicate; use App\Http\Api\Filter\Filter; use App\Http\Api\Scope\GlobalScope; use App\Http\Api\Scope\TypeScope; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Str; -use Tests\TestCase; -class CriteriaTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * If the criteria and filter keys do not match, the filter should not be applied. - */ - public function testShouldNotFilterIfKeyMismatch(): void +use Tests\Unit\Http\Api\Criteria\Filter\FakeCriteria; + +uses(Illuminate\Foundation\Testing\WithFaker::class); + +test('should not filter if key mismatch', function () { + $expression = new Expression(fake()->word()); + $comparisonOperator = Arr::random(ComparisonOperator::cases()); + $predicate = new Predicate(fake()->word(), $comparisonOperator, $expression); + $scope = new GlobalScope(); + $logicalOperator = Arr::random(BinaryLogicalOperator::cases()); + + $criteria = new FakeCriteria($predicate, $logicalOperator, $scope); + + $filter = new class(fake()->word()) extends Filter { - $expression = new Expression($this->faker->word()); - $comparisonOperator = Arr::random(ComparisonOperator::cases()); - $predicate = new Predicate($this->faker->word(), $comparisonOperator, $expression); - $scope = new GlobalScope(); - $logicalOperator = Arr::random(BinaryLogicalOperator::cases()); - - $criteria = new FakeCriteria($predicate, $logicalOperator, $scope); - - $filter = new class($this->faker->word()) extends Filter + /** + * Convert filter values to integers. + * + * @param array $filterValues + * @return array + */ + public function convertFilterValues(array $filterValues): array { - /** - * Convert filter values to integers. - * - * @param array $filterValues - * @return array - */ - protected function convertFilterValues(array $filterValues): array - { - return $filterValues; - } + return $filterValues; + } - /** - * Get only filter values that are integers. - * - * @param array $filterValues - * @return array - */ - protected function getValidFilterValues(array $filterValues): array - { - return $filterValues; - } + /** + * Get only filter values that are integers. + * + * @param array $filterValues + * @return array + */ + public function getValidFilterValues(array $filterValues): array + { + return $filterValues; + } - /** - * Determine if all valid filter values have been specified. - * By default, this is false as we assume an unrestricted amount of valid values. - * - * @param array $filterValues - */ - public function isAllFilterValues(array $filterValues): bool - { - return false; - } + /** + * Determine if all valid filter values have been specified. + * By default, this is false as we assume an unrestricted amount of valid values. + * + * @param array $filterValues + */ + public function isAllFilterValues(array $filterValues): bool + { + return false; + } - /** - * Get the validation rules for the filter. - * - * @return array - */ - public function getRules(): array - { - return []; - } + /** + * Get the validation rules for the filter. + * + * @return array + */ + public function getRules(): array + { + return []; + } - /** - * Get the allowed comparison operators for the filter. - * - * @return ComparisonOperator[] - */ - public function getAllowedComparisonOperators(): array - { - return []; - } - }; + /** + * Get the allowed comparison operators for the filter. + * + * @return ComparisonOperator[] + */ + public function getAllowedComparisonOperators(): array + { + return []; + } + }; - static::assertFalse($criteria->shouldFilter($filter, $criteria->getScope())); - } + $this->assertFalse($criteria->shouldFilter($filter, $criteria->getScope())); +}); - /** - * If the criteria and filter keys match, the filter should be applied. - */ - public function testShouldFilterIfKeyMatch(): void +test('should filter if key match', function () { + $key = fake()->word(); + + $expression = new Expression(fake()->word()); + $comparisonOperator = Arr::random(ComparisonOperator::cases()); + $predicate = new Predicate($key, $comparisonOperator, $expression); + $scope = new GlobalScope(); + $logicalOperator = Arr::random(BinaryLogicalOperator::cases()); + + $criteria = new FakeCriteria($predicate, $logicalOperator, $scope); + + $filter = new class($key) extends Filter { - $key = $this->faker->word(); - - $expression = new Expression($this->faker->word()); - $comparisonOperator = Arr::random(ComparisonOperator::cases()); - $predicate = new Predicate($key, $comparisonOperator, $expression); - $scope = new GlobalScope(); - $logicalOperator = Arr::random(BinaryLogicalOperator::cases()); - - $criteria = new FakeCriteria($predicate, $logicalOperator, $scope); - - $filter = new class($key) extends Filter + /** + * Convert filter values to integers. + * + * @param array $filterValues + * @return array + */ + public function convertFilterValues(array $filterValues): array { - /** - * Convert filter values to integers. - * - * @param array $filterValues - * @return array - */ - protected function convertFilterValues(array $filterValues): array - { - return $filterValues; - } + return $filterValues; + } - /** - * Get only filter values that are integers. - * - * @param array $filterValues - * @return array - */ - protected function getValidFilterValues(array $filterValues): array - { - return $filterValues; - } + /** + * Get only filter values that are integers. + * + * @param array $filterValues + * @return array + */ + public function getValidFilterValues(array $filterValues): array + { + return $filterValues; + } - /** - * Determine if all valid filter values have been specified. - * By default, this is false as we assume an unrestricted amount of valid values. - * - * @param array $filterValues - */ - public function isAllFilterValues(array $filterValues): bool - { - return false; - } + /** + * Determine if all valid filter values have been specified. + * By default, this is false as we assume an unrestricted amount of valid values. + * + * @param array $filterValues + */ + public function isAllFilterValues(array $filterValues): bool + { + return false; + } - /** - * Get the validation rules for the filter. - * - * @return array - */ - public function getRules(): array - { - return []; - } + /** + * Get the validation rules for the filter. + * + * @return array + */ + public function getRules(): array + { + return []; + } - /** - * Get the allowed comparison operators for the filter. - * - * @return ComparisonOperator[] - */ - public function getAllowedComparisonOperators(): array - { - return []; - } - }; + /** + * Get the allowed comparison operators for the filter. + * + * @return ComparisonOperator[] + */ + public function getAllowedComparisonOperators(): array + { + return []; + } + }; - static::assertTrue($criteria->shouldFilter($filter, $criteria->getScope())); - } + $this->assertTrue($criteria->shouldFilter($filter, $criteria->getScope())); +}); - /** - * If the criteria and filter keys match, the filter should be applied. - */ - public function testShouldNotFilterIfNotWithinScope(): void +test('should not filter if not within scope', function () { + $key = fake()->word(); + + $expression = new Expression(fake()->word()); + $comparisonOperator = Arr::random(ComparisonOperator::cases()); + $predicate = new Predicate($key, $comparisonOperator, $expression); + $scope = new TypeScope(fake()->word()); + $logicalOperator = Arr::random(BinaryLogicalOperator::cases()); + + $criteria = new FakeCriteria($predicate, $logicalOperator, $scope); + + $filter = new class($key) extends Filter { - $key = $this->faker->word(); - - $expression = new Expression($this->faker->word()); - $comparisonOperator = Arr::random(ComparisonOperator::cases()); - $predicate = new Predicate($key, $comparisonOperator, $expression); - $scope = new TypeScope($this->faker->word()); - $logicalOperator = Arr::random(BinaryLogicalOperator::cases()); - - $criteria = new FakeCriteria($predicate, $logicalOperator, $scope); - - $filter = new class($key) extends Filter + /** + * Convert filter values to integers. + * + * @param array $filterValues + * @return array + */ + public function convertFilterValues(array $filterValues): array { - /** - * Convert filter values to integers. - * - * @param array $filterValues - * @return array - */ - protected function convertFilterValues(array $filterValues): array - { - return $filterValues; - } + return $filterValues; + } - /** - * Get only filter values that are integers. - * - * @param array $filterValues - * @return array - */ - protected function getValidFilterValues(array $filterValues): array - { - return $filterValues; - } + /** + * Get only filter values that are integers. + * + * @param array $filterValues + * @return array + */ + public function getValidFilterValues(array $filterValues): array + { + return $filterValues; + } - /** - * Determine if all valid filter values have been specified. - * By default, this is false as we assume an unrestricted amount of valid values. - * - * @param array $filterValues - */ - public function isAllFilterValues(array $filterValues): bool - { - return false; - } + /** + * Determine if all valid filter values have been specified. + * By default, this is false as we assume an unrestricted amount of valid values. + * + * @param array $filterValues + */ + public function isAllFilterValues(array $filterValues): bool + { + return false; + } - /** - * Get the validation rules for the filter. - * - * @return array - */ - public function getRules(): array - { - return []; - } + /** + * Get the validation rules for the filter. + * + * @return array + */ + public function getRules(): array + { + return []; + } - /** - * Get the allowed comparison operators for the filter. - * - * @return ComparisonOperator[] - */ - public function getAllowedComparisonOperators(): array - { - return []; - } - }; + /** + * Get the allowed comparison operators for the filter. + * + * @return ComparisonOperator[] + */ + public function getAllowedComparisonOperators(): array + { + return []; + } + }; - static::assertFalse($criteria->shouldFilter($filter, new GlobalScope())); - } + $this->assertFalse($criteria->shouldFilter($filter, new GlobalScope())); +}); - /** - * If the criteria and filter keys match, the filter should be applied. - */ - public function testShouldFilterIfWithinScope(): void +test('should filter if within scope', function () { + $key = fake()->word(); + + $expression = new Expression(fake()->word()); + $comparisonOperator = Arr::random(ComparisonOperator::cases()); + $predicate = new Predicate($key, $comparisonOperator, $expression); + $scope = new TypeScope(Str::of(Str::random())->lower()->singular()->__toString()); + $logicalOperator = Arr::random(BinaryLogicalOperator::cases()); + + $criteria = new FakeCriteria($predicate, $logicalOperator, $scope); + + $filter = new class($key) extends Filter { - $key = $this->faker->word(); - - $expression = new Expression($this->faker->word()); - $comparisonOperator = Arr::random(ComparisonOperator::cases()); - $predicate = new Predicate($key, $comparisonOperator, $expression); - $scope = new TypeScope(Str::of(Str::random())->lower()->singular()->__toString()); - $logicalOperator = Arr::random(BinaryLogicalOperator::cases()); - - $criteria = new FakeCriteria($predicate, $logicalOperator, $scope); - - $filter = new class($key) extends Filter + /** + * Convert filter values to integers. + * + * @param array $filterValues + * @return array + */ + public function convertFilterValues(array $filterValues): array { - /** - * Convert filter values to integers. - * - * @param array $filterValues - * @return array - */ - protected function convertFilterValues(array $filterValues): array - { - return $filterValues; - } + return $filterValues; + } - /** - * Get only filter values that are integers. - * - * @param array $filterValues - * @return array - */ - protected function getValidFilterValues(array $filterValues): array - { - return $filterValues; - } + /** + * Get only filter values that are integers. + * + * @param array $filterValues + * @return array + */ + public function getValidFilterValues(array $filterValues): array + { + return $filterValues; + } - /** - * Determine if all valid filter values have been specified. - * By default, this is false as we assume an unrestricted amount of valid values. - * - * @param array $filterValues - */ - public function isAllFilterValues(array $filterValues): bool - { - return false; - } + /** + * Determine if all valid filter values have been specified. + * By default, this is false as we assume an unrestricted amount of valid values. + * + * @param array $filterValues + */ + public function isAllFilterValues(array $filterValues): bool + { + return false; + } - /** - * Get the validation rules for the filter. - * - * @return array - */ - public function getRules(): array - { - return []; - } + /** + * Get the validation rules for the filter. + * + * @return array + */ + public function getRules(): array + { + return []; + } - /** - * Get the allowed comparison operators for the filter. - * - * @return ComparisonOperator[] - */ - public function getAllowedComparisonOperators(): array - { - return []; - } - }; + /** + * Get the allowed comparison operators for the filter. + * + * @return ComparisonOperator[] + */ + public function getAllowedComparisonOperators(): array + { + return []; + } + }; - static::assertTrue($criteria->shouldFilter($filter, $scope)); - } -} + $this->assertTrue($criteria->shouldFilter($filter, $scope)); +}); diff --git a/tests/Unit/Http/Api/Criteria/Filter/HasCriteriaTest.php b/tests/Unit/Http/Api/Criteria/Filter/HasCriteriaTest.php index 61013e9fd..91413767a 100644 --- a/tests/Unit/Http/Api/Criteria/Filter/HasCriteriaTest.php +++ b/tests/Unit/Http/Api/Criteria/Filter/HasCriteriaTest.php @@ -2,101 +2,66 @@ declare(strict_types=1); -namespace Tests\Unit\Http\Api\Criteria\Filter; - use App\Enums\Http\Api\Filter\BinaryLogicalOperator; use App\Enums\Http\Api\Filter\ComparisonOperator; use App\Http\Api\Criteria\Filter\Criteria; use App\Http\Api\Criteria\Filter\HasCriteria; use App\Http\Api\Scope\GlobalScope; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Str; -use Tests\TestCase; -class HasCriteriaTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Has Criteria shall parse the field. - */ - public function testField(): void - { - $criteria = HasCriteria::make(new GlobalScope(), HasCriteria::PARAM_VALUE, $this->faker->word()); +test('field', function () { + $criteria = HasCriteria::make(new GlobalScope(), HasCriteria::PARAM_VALUE, fake()->word()); - static::assertEquals(HasCriteria::PARAM_VALUE, $criteria->getField()); - } + $this->assertEquals(HasCriteria::PARAM_VALUE, $criteria->getField()); +}); - /** - * By default, the Has Criteria shall use the GTE comparison operator. - */ - public function testDefaultComparisonOperator(): void - { - $criteria = HasCriteria::make(new GlobalScope(), HasCriteria::PARAM_VALUE, $this->faker->word()); +test('default comparison operator', function () { + $criteria = HasCriteria::make(new GlobalScope(), HasCriteria::PARAM_VALUE, fake()->word()); - static::assertEquals(ComparisonOperator::GTE, $criteria->getComparisonOperator()); - } + $this->assertEquals(ComparisonOperator::GTE, $criteria->getComparisonOperator()); +}); - /** - * The Has Criteria shall parse the comparison operator. - */ - public function testComparisonOperator(): void - { - $operator = Arr::random(ComparisonOperator::cases()); +test('comparison operator', function () { + $operator = Arr::random(ComparisonOperator::cases()); - $filterParam = Str::of(HasCriteria::PARAM_VALUE)->append(Criteria::PARAM_SEPARATOR)->append($operator->name)->__toString(); + $filterParam = Str::of(HasCriteria::PARAM_VALUE)->append(Criteria::PARAM_SEPARATOR)->append($operator->name)->__toString(); - $criteria = HasCriteria::make(new GlobalScope(), $filterParam, $this->faker->word()); + $criteria = HasCriteria::make(new GlobalScope(), $filterParam, fake()->word()); - static::assertEquals($operator, $criteria->getComparisonOperator()); - } + $this->assertEquals($operator, $criteria->getComparisonOperator()); +}); - /** - * By default, the Has Criteria shall have a count of 1. - */ - public function testDefaultCount(): void - { - $criteria = HasCriteria::make(new GlobalScope(), HasCriteria::PARAM_VALUE, $this->faker->word()); +test('default count', function () { + $criteria = HasCriteria::make(new GlobalScope(), HasCriteria::PARAM_VALUE, fake()->word()); - static::assertEquals(1, $criteria->getCount()); - } + $this->assertEquals(1, $criteria->getCount()); +}); - /** - * The Has Criteria shall parse count. - */ - public function testCount(): void - { - $count = $this->faker->randomDigitNotNull(); +test('count', function () { + $count = fake()->randomDigitNotNull(); - $filterParam = Str::of(HasCriteria::PARAM_VALUE)->append(Criteria::PARAM_SEPARATOR)->append(strval($count))->__toString(); + $filterParam = Str::of(HasCriteria::PARAM_VALUE)->append(Criteria::PARAM_SEPARATOR)->append(strval($count))->__toString(); - $criteria = HasCriteria::make(new GlobalScope(), $filterParam, $this->faker->word()); + $criteria = HasCriteria::make(new GlobalScope(), $filterParam, fake()->word()); - static::assertEquals($count, $criteria->getCount()); - } + $this->assertEquals($count, $criteria->getCount()); +}); - /** - * By default, the Has Criteria shall use the AND logical operator. - */ - public function testDefaultLogicalOperator(): void - { - $criteria = HasCriteria::make(new GlobalScope(), $this->faker->word(), $this->faker->word()); +test('default logical operator', function () { + $criteria = HasCriteria::make(new GlobalScope(), fake()->word(), fake()->word()); - static::assertEquals(BinaryLogicalOperator::AND, $criteria->getLogicalOperator()); - } + $this->assertEquals(BinaryLogicalOperator::AND, $criteria->getLogicalOperator()); +}); - /** - * The Has Criteria shall parse the logical operator. - */ - public function testLogicalOperator(): void - { - $operator = Arr::random(BinaryLogicalOperator::cases()); +test('logical operator', function () { + $operator = Arr::random(BinaryLogicalOperator::cases()); - $filterParam = Str::of(HasCriteria::PARAM_VALUE)->append(Criteria::PARAM_SEPARATOR)->append($operator->name)->__toString(); + $filterParam = Str::of(HasCriteria::PARAM_VALUE)->append(Criteria::PARAM_SEPARATOR)->append($operator->name)->__toString(); - $criteria = HasCriteria::make(new GlobalScope(), $filterParam, $this->faker->word()); + $criteria = HasCriteria::make(new GlobalScope(), $filterParam, fake()->word()); - static::assertEquals($operator, $criteria->getLogicalOperator()); - } -} + $this->assertEquals($operator, $criteria->getLogicalOperator()); +}); diff --git a/tests/Unit/Http/Api/Criteria/Filter/TrashedCriteriaTest.php b/tests/Unit/Http/Api/Criteria/Filter/TrashedCriteriaTest.php index ba830b7ec..e9fbe7a06 100644 --- a/tests/Unit/Http/Api/Criteria/Filter/TrashedCriteriaTest.php +++ b/tests/Unit/Http/Api/Criteria/Filter/TrashedCriteriaTest.php @@ -2,24 +2,13 @@ declare(strict_types=1); -namespace Tests\Unit\Http\Api\Criteria\Filter; - use App\Http\Api\Criteria\Filter\TrashedCriteria; use App\Http\Api\Scope\GlobalScope; -use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; -class TrashedCriteriaTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Trashed Criteria shall parse the field. - */ - public function testField(): void - { - $criteria = TrashedCriteria::make(new GlobalScope(), TrashedCriteria::PARAM_VALUE, $this->faker->word()); +test('field', function () { + $criteria = TrashedCriteria::make(new GlobalScope(), TrashedCriteria::PARAM_VALUE, fake()->word()); - static::assertEquals(TrashedCriteria::PARAM_VALUE, $criteria->getField()); - } -} + $this->assertEquals(TrashedCriteria::PARAM_VALUE, $criteria->getField()); +}); diff --git a/tests/Unit/Http/Api/Criteria/Filter/WhereCriteriaTest.php b/tests/Unit/Http/Api/Criteria/Filter/WhereCriteriaTest.php index a6bc2a9e2..09c6536e8 100644 --- a/tests/Unit/Http/Api/Criteria/Filter/WhereCriteriaTest.php +++ b/tests/Unit/Http/Api/Criteria/Filter/WhereCriteriaTest.php @@ -2,79 +2,52 @@ declare(strict_types=1); -namespace Tests\Unit\Http\Api\Criteria\Filter; - use App\Enums\Http\Api\Filter\BinaryLogicalOperator; use App\Enums\Http\Api\Filter\ComparisonOperator; use App\Http\Api\Criteria\Filter\Criteria; use App\Http\Api\Criteria\Filter\WhereCriteria; use App\Http\Api\Scope\GlobalScope; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Str; -use Tests\TestCase; -class WhereCriteriaTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Where Criteria shall parse the field. - */ - public function testField(): void - { - $field = $this->faker->word(); +test('field', function () { + $field = fake()->word(); - $criteria = WhereCriteria::make(new GlobalScope(), $field, $this->faker->word()); + $criteria = WhereCriteria::make(new GlobalScope(), $field, fake()->word()); - static::assertEquals($field, $criteria->getField()); - } + $this->assertEquals($field, $criteria->getField()); +}); - /** - * By default, the Where Criteria shall use the EQ comparison operator. - */ - public function testDefaultComparisonOperator(): void - { - $criteria = WhereCriteria::make(new GlobalScope(), $this->faker->word(), $this->faker->word()); +test('default comparison operator', function () { + $criteria = WhereCriteria::make(new GlobalScope(), fake()->word(), fake()->word()); - static::assertEquals(ComparisonOperator::EQ, $criteria->getComparisonOperator()); - } + $this->assertEquals(ComparisonOperator::EQ, $criteria->getComparisonOperator()); +}); - /** - * The Where Criteria shall parse the comparison operator. - */ - public function testComparisonOperator(): void - { - $operator = Arr::random(ComparisonOperator::cases()); +test('comparison operator', function () { + $operator = Arr::random(ComparisonOperator::cases()); - $filterParam = Str::of($this->faker->word())->append(Criteria::PARAM_SEPARATOR)->append($operator->name)->__toString(); + $filterParam = Str::of(fake()->word())->append(Criteria::PARAM_SEPARATOR)->append($operator->name)->__toString(); - $criteria = WhereCriteria::make(new GlobalScope(), $filterParam, $this->faker->word()); + $criteria = WhereCriteria::make(new GlobalScope(), $filterParam, fake()->word()); - static::assertEquals($operator, $criteria->getComparisonOperator()); - } + $this->assertEquals($operator, $criteria->getComparisonOperator()); +}); - /** - * By default, the Where Criteria shall use the AND logical operator. - */ - public function testDefaultLogicalOperator(): void - { - $criteria = WhereCriteria::make(new GlobalScope(), $this->faker->word(), $this->faker->word()); +test('default logical operator', function () { + $criteria = WhereCriteria::make(new GlobalScope(), fake()->word(), fake()->word()); - static::assertEquals(BinaryLogicalOperator::AND, $criteria->getLogicalOperator()); - } + $this->assertEquals(BinaryLogicalOperator::AND, $criteria->getLogicalOperator()); +}); - /** - * The Where Criteria shall parse the logical operator. - */ - public function testLogicalOperator(): void - { - $operator = Arr::random(BinaryLogicalOperator::cases()); +test('logical operator', function () { + $operator = Arr::random(BinaryLogicalOperator::cases()); - $filterParam = Str::of($this->faker->word())->append(Criteria::PARAM_SEPARATOR)->append($operator->name)->__toString(); + $filterParam = Str::of(fake()->word())->append(Criteria::PARAM_SEPARATOR)->append($operator->name)->__toString(); - $criteria = WhereCriteria::make(new GlobalScope(), $filterParam, $this->faker->word()); + $criteria = WhereCriteria::make(new GlobalScope(), $filterParam, fake()->word()); - static::assertEquals($operator, $criteria->getLogicalOperator()); - } -} + $this->assertEquals($operator, $criteria->getLogicalOperator()); +}); diff --git a/tests/Unit/Http/Api/Criteria/Filter/WhereInCriteriaTest.php b/tests/Unit/Http/Api/Criteria/Filter/WhereInCriteriaTest.php index 70f288ac8..321648d97 100644 --- a/tests/Unit/Http/Api/Criteria/Filter/WhereInCriteriaTest.php +++ b/tests/Unit/Http/Api/Criteria/Filter/WhereInCriteriaTest.php @@ -2,102 +2,71 @@ declare(strict_types=1); -namespace Tests\Unit\Http\Api\Criteria\Filter; - use App\Enums\Http\Api\Filter\BinaryLogicalOperator; use App\Enums\Http\Api\Filter\ComparisonOperator; use App\Enums\Http\Api\Filter\UnaryLogicalOperator; use App\Http\Api\Criteria\Filter\Criteria; use App\Http\Api\Criteria\Filter\WhereInCriteria; use App\Http\Api\Scope\GlobalScope; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Str; -use Tests\TestCase; -class WhereInCriteriaTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Where In Criteria shall parse the field. - */ - public function testField(): void - { - $field = $this->faker->word(); +test('field', function () { + $field = fake()->word(); - $criteria = WhereInCriteria::make(new GlobalScope(), $field, $this->faker->word()); + $criteria = WhereInCriteria::make(new GlobalScope(), $field, fake()->word()); - static::assertEquals($field, $criteria->getField()); - } + $this->assertEquals($field, $criteria->getField()); +}); - /** - * The Where In Criteria shall not parse the comparison operator. - */ - public function testComparisonOperator(): void - { - $operator = Arr::random(ComparisonOperator::cases()); +test('comparison operator', function () { + $operator = Arr::random(ComparisonOperator::cases()); - $filterParam = Str::of($this->faker->word()) - ->append('.') - ->append($this->faker->word()) - ->append('.') - ->append($operator->name) - ->__toString(); + $filterParam = Str::of(fake()->word()) + ->append('.') + ->append(fake()->word()) + ->append('.') + ->append($operator->name) + ->__toString(); - $criteria = WhereInCriteria::make(new GlobalScope(), $filterParam, $this->faker->word()); + $criteria = WhereInCriteria::make(new GlobalScope(), $filterParam, fake()->word()); - static::assertNull($criteria->getComparisonOperator()); - } + $this->assertNull($criteria->getComparisonOperator()); +}); - /** - * By default, the Where In Criteria shall use the AND logical operator. - */ - public function testDefaultLogicalOperator(): void - { - $criteria = WhereInCriteria::make(new GlobalScope(), $this->faker->word(), $this->faker->word()); +test('default logical operator', function () { + $criteria = WhereInCriteria::make(new GlobalScope(), fake()->word(), fake()->word()); - static::assertEquals(BinaryLogicalOperator::AND, $criteria->getLogicalOperator()); - } + $this->assertEquals(BinaryLogicalOperator::AND, $criteria->getLogicalOperator()); +}); - /** - * The Where In Criteria shall parse the logical operator. - */ - public function testLogicalOperator(): void - { - $operator = Arr::random(BinaryLogicalOperator::cases()); +test('logical operator', function () { + $operator = Arr::random(BinaryLogicalOperator::cases()); - $filterParam = Str::of($this->faker->word())->append(Criteria::PARAM_SEPARATOR)->append($operator->name)->__toString(); + $filterParam = Str::of(fake()->word())->append(Criteria::PARAM_SEPARATOR)->append($operator->name)->__toString(); - $criteria = WhereInCriteria::make(new GlobalScope(), $filterParam, $this->faker->word()); + $criteria = WhereInCriteria::make(new GlobalScope(), $filterParam, fake()->word()); - static::assertEquals($operator, $criteria->getLogicalOperator()); - } + $this->assertEquals($operator, $criteria->getLogicalOperator()); +}); - /** - * By default, the Where In Criteria shall not use the NOT operator. - */ - public function testDefaultUnaryOperator(): void - { - $criteria = WhereInCriteria::make(new GlobalScope(), $this->faker->word(), $this->faker->word()); +test('default unary operator', function () { + $criteria = WhereInCriteria::make(new GlobalScope(), fake()->word(), fake()->word()); - static::assertFalse($criteria->not()); - } + $this->assertFalse($criteria->not()); +}); - /** - * The Where In Criteria shall parse the NOT operator. - */ - public function testUnaryOperator(): void - { - $filterParam = Str::of($this->faker->word()) - ->append(Criteria::PARAM_SEPARATOR) - ->append($this->faker->word()) - ->append(Criteria::PARAM_SEPARATOR) - ->append(UnaryLogicalOperator::NOT->value) - ->__toString(); +test('unary operator', function () { + $filterParam = Str::of(fake()->word()) + ->append(Criteria::PARAM_SEPARATOR) + ->append(fake()->word()) + ->append(Criteria::PARAM_SEPARATOR) + ->append(UnaryLogicalOperator::NOT->value) + ->__toString(); - $criteria = WhereInCriteria::make(new GlobalScope(), $filterParam, $this->faker->word()); + $criteria = WhereInCriteria::make(new GlobalScope(), $filterParam, fake()->word()); - static::assertTrue($criteria->not()); - } -} + $this->assertTrue($criteria->not()); +}); diff --git a/tests/Unit/Http/Api/Criteria/Paging/CriteriaTest.php b/tests/Unit/Http/Api/Criteria/Paging/CriteriaTest.php index 35cecaac7..d44ccd7a2 100644 --- a/tests/Unit/Http/Api/Criteria/Paging/CriteriaTest.php +++ b/tests/Unit/Http/Api/Criteria/Paging/CriteriaTest.php @@ -2,119 +2,102 @@ declare(strict_types=1); -namespace Tests\Unit\Http\Api\Criteria\Paging; - use App\Enums\Http\Api\Paging\PaginationStrategy; use App\Http\Api\Criteria\Paging\Criteria; use Illuminate\Contracts\Pagination\Paginator; use Illuminate\Database\Eloquent\Builder; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; -use Tests\TestCase; -class CriteriaTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the Paging Criteria shall return the provided size. - */ - public function testDefaultSize(): void +uses(Illuminate\Foundation\Testing\WithFaker::class); + +test('default size', function () { + $resultSize = fake()->numberBetween(1, Criteria::MAX_RESULTS); + + $criteria = new class($resultSize) extends Criteria { - $resultSize = $this->faker->numberBetween(1, Criteria::MAX_RESULTS); - - $criteria = new class($resultSize) extends Criteria + /** + * Get the intended pagination strategy. + * + * @return PaginationStrategy + */ + public function getStrategy(): PaginationStrategy { - /** - * Get the intended pagination strategy. - * - * @return PaginationStrategy - */ - public function getStrategy(): PaginationStrategy - { - return Arr::random(PaginationStrategy::cases()); - } + return Arr::random(PaginationStrategy::cases()); + } - /** - * Paginate the query. - * - * @param Builder $builder - * @return Paginator - */ - public function paginate(Builder $builder): Paginator - { - return $builder->paginate(); - } - }; + /** + * Paginate the query. + * + * @param Builder $builder + * @return Paginator + */ + public function paginate(Builder $builder): Paginator + { + return $builder->paginate(); + } + }; - static::assertEquals($resultSize, $criteria->getResultSize()); - } + $this->assertEquals($resultSize, $criteria->getResultSize()); +}); - /** - * If the size is greater than the default, the paging Criteria shall return the default. - */ - public function testUpperBoundSize(): void +test('upper bound size', function () { + $resultSize = Criteria::MAX_RESULTS + fake()->randomDigitNotNull(); + + $criteria = new class($resultSize) extends Criteria { - $resultSize = Criteria::MAX_RESULTS + $this->faker->randomDigitNotNull(); - - $criteria = new class($resultSize) extends Criteria + /** + * Get the intended pagination strategy. + * + * @return PaginationStrategy + */ + public function getStrategy(): PaginationStrategy { - /** - * Get the intended pagination strategy. - * - * @return PaginationStrategy - */ - public function getStrategy(): PaginationStrategy - { - return Arr::random(PaginationStrategy::cases()); - } + return Arr::random(PaginationStrategy::cases()); + } - /** - * Paginate the query. - * - * @param Builder $builder - * @return Paginator - */ - public function paginate(Builder $builder): Paginator - { - return $builder->paginate(); - } - }; + /** + * Paginate the query. + * + * @param Builder $builder + * @return Paginator + */ + public function paginate(Builder $builder): Paginator + { + return $builder->paginate(); + } + }; - static::assertEquals(Criteria::DEFAULT_SIZE, $criteria->getResultSize()); - } + $this->assertEquals(Criteria::DEFAULT_SIZE, $criteria->getResultSize()); +}); - /** - * If the size is lte to zero, the paging Criteria shall return the default size. - */ - public function testLowerBoundSize(): void +test('lower bound size', function () { + $resultSize = fake()->randomDigit() * -1; + + $criteria = new class($resultSize) extends Criteria { - $resultSize = $this->faker->randomDigit() * -1; - - $criteria = new class($resultSize) extends Criteria + /** + * Get the intended pagination strategy. + * + * @return PaginationStrategy + */ + public function getStrategy(): PaginationStrategy { - /** - * Get the intended pagination strategy. - * - * @return PaginationStrategy - */ - public function getStrategy(): PaginationStrategy - { - return Arr::random(PaginationStrategy::cases()); - } + return Arr::random(PaginationStrategy::cases()); + } - /** - * Paginate the query. - * - * @param Builder $builder - * @return Paginator - */ - public function paginate(Builder $builder): Paginator - { - return $builder->paginate(); - } - }; + /** + * Paginate the query. + * + * @param Builder $builder + * @return Paginator + */ + public function paginate(Builder $builder): Paginator + { + return $builder->paginate(); + } + }; - static::assertEquals(Criteria::DEFAULT_SIZE, $criteria->getResultSize()); - } -} + $this->assertEquals(Criteria::DEFAULT_SIZE, $criteria->getResultSize()); +}); diff --git a/tests/Unit/Http/Api/Criteria/Sort/CriteriaTest.php b/tests/Unit/Http/Api/Criteria/Sort/CriteriaTest.php index fc7c073d0..092d76c80 100644 --- a/tests/Unit/Http/Api/Criteria/Sort/CriteriaTest.php +++ b/tests/Unit/Http/Api/Criteria/Sort/CriteriaTest.php @@ -2,124 +2,101 @@ declare(strict_types=1); -namespace Tests\Unit\Http\Api\Criteria\Sort; - use App\Http\Api\Criteria\Sort\Criteria; use App\Http\Api\Scope\GlobalScope; use App\Http\Api\Scope\TypeScope; use App\Http\Api\Sort\Sort; use Illuminate\Database\Eloquent\Builder; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Str; -use Tests\TestCase; -class CriteriaTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * If the criteria and sort keys do not match, the sort should not be applied. - */ - public function testShouldNotSortIfKeyMismatch(): void +test('should not sort if key mismatch', function () { + $criteria = new class(new GlobalScope(), fake()->word()) extends Criteria { - $criteria = new class(new GlobalScope(), $this->faker->word()) extends Criteria + /** + * Apply criteria to builder. + * + * @param Builder $builder + * @return Builder + */ + public function sort(Builder $builder, Sort $sort): Builder { - /** - * Apply criteria to builder. - * - * @param Builder $builder - * @return Builder - */ - public function sort(Builder $builder, Sort $sort): Builder - { - return $builder; - } - }; + return $builder; + } + }; - $sort = new Sort($this->faker->word()); + $sort = new Sort(fake()->word()); - static::assertFalse($criteria->shouldSort($sort, $criteria->getScope())); - } + $this->assertFalse($criteria->shouldSort($sort, $criteria->getScope())); +}); - /** - * If the criteria and sort keys match, the sort should be applied. - */ - public function testShouldSortIfKeyMatch(): void +test('should sort if key match', function () { + $key = fake()->word(); + + $criteria = new class(new GlobalScope(), $key) extends Criteria { - $key = $this->faker->word(); - - $criteria = new class(new GlobalScope(), $key) extends Criteria + /** + * Apply criteria to builder. + * + * @param Builder $builder + * @return Builder + */ + public function sort(Builder $builder, Sort $sort): Builder { - /** - * Apply criteria to builder. - * - * @param Builder $builder - * @return Builder - */ - public function sort(Builder $builder, Sort $sort): Builder - { - return $builder; - } - }; + return $builder; + } + }; - $sort = new Sort($key); + $sort = new Sort($key); - static::assertTrue($criteria->shouldSort($sort, $criteria->getScope())); - } + $this->assertTrue($criteria->shouldSort($sort, $criteria->getScope())); +}); - /** - * If the criteria and sort keys match, the sort should be applied. - */ - public function testShouldNotSortIfNotWithinScope(): void +test('should not sort if not within scope', function () { + $key = fake()->word(); + + $scope = new TypeScope(fake()->word()); + + $criteria = new class($scope, $key) extends Criteria { - $key = $this->faker->word(); - - $scope = new TypeScope($this->faker->word()); - - $criteria = new class($scope, $key) extends Criteria + /** + * Apply criteria to builder. + * + * @param Builder $builder + * @return Builder + */ + public function sort(Builder $builder, Sort $sort): Builder { - /** - * Apply criteria to builder. - * - * @param Builder $builder - * @return Builder - */ - public function sort(Builder $builder, Sort $sort): Builder - { - return $builder; - } - }; + return $builder; + } + }; - $sort = new Sort($key); + $sort = new Sort($key); - static::assertFalse($criteria->shouldSort($sort, new GlobalScope())); - } + $this->assertFalse($criteria->shouldSort($sort, new GlobalScope())); +}); - /** - * If the criteria and sort keys match, the sort should be applied. - */ - public function testShouldSortIfWithinScope(): void +test('should sort if within scope', function () { + $key = fake()->word(); + + $scope = new TypeScope(Str::of(Str::random())->lower()->singular()->__toString()); + + $criteria = new class($scope, $key) extends Criteria { - $key = $this->faker->word(); - - $scope = new TypeScope(Str::of(Str::random())->lower()->singular()->__toString()); - - $criteria = new class($scope, $key) extends Criteria + /** + * Apply criteria to builder. + * + * @param Builder $builder + * @return Builder + */ + public function sort(Builder $builder, Sort $sort): Builder { - /** - * Apply criteria to builder. - * - * @param Builder $builder - * @return Builder - */ - public function sort(Builder $builder, Sort $sort): Builder - { - return $builder; - } - }; + return $builder; + } + }; - $sort = new Sort($key); + $sort = new Sort($key); - static::assertTrue($criteria->shouldSort($sort, $scope)); - } -} + $this->assertTrue($criteria->shouldSort($sort, $scope)); +}); diff --git a/tests/Unit/Http/Api/Filter/BooleanFilterTest.php b/tests/Unit/Http/Api/Filter/BooleanFilterTest.php index 7f0a16156..286aad222 100644 --- a/tests/Unit/Http/Api/Filter/BooleanFilterTest.php +++ b/tests/Unit/Http/Api/Filter/BooleanFilterTest.php @@ -2,59 +2,40 @@ declare(strict_types=1); -namespace Tests\Unit\Http\Api\Filter; - use App\Http\Api\Filter\BooleanFilter; use App\Http\Api\Scope\GlobalScope; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Str; -use Tests\TestCase; use Tests\Unit\Http\Api\Criteria\Filter\FakeCriteria; -class BooleanFilterTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * If values that are not mappable to booleans are specified for the key, don't apply the filter. - */ - public function testShouldNotApplyIfNoBooleans(): void - { - $filterField = $this->faker->word(); +test('should not apply if no booleans', function () { + $filterField = fake()->word(); - $criteria = FakeCriteria::make(new GlobalScope(), $filterField, Str::random()); + $criteria = FakeCriteria::make(new GlobalScope(), $filterField, Str::random()); - $filter = new BooleanFilter($filterField); + $filter = new BooleanFilter($filterField); - static::assertFalse($criteria->shouldFilter($filter, $criteria->getScope())); - } + $this->assertFalse($criteria->shouldFilter($filter, $criteria->getScope())); +}); - /** - * If both boolean values are specified for the key, don't apply the filter. - */ - public function testShouldNotApplyIfAllBooleans(): void - { - $filterField = $this->faker->word(); +test('should not apply if all booleans', function () { + $filterField = fake()->word(); - $criteria = FakeCriteria::make(new GlobalScope(), $filterField, 'true,false'); + $criteria = FakeCriteria::make(new GlobalScope(), $filterField, 'true,false'); - $filter = new BooleanFilter($filterField); + $filter = new BooleanFilter($filterField); - static::assertFalse($criteria->shouldFilter($filter, $criteria->getScope())); - } + $this->assertFalse($criteria->shouldFilter($filter, $criteria->getScope())); +}); - /** - * The boolean filter shall convert validated boolean options to boolean values. - */ - public function testConvertsValidatedBoolean(): void - { - $booleanValue = $this->faker->boolean(); +test('converts validated boolean', function () { + $booleanValue = fake()->boolean(); - $filter = new BooleanFilter($this->faker->word()); + $filter = new BooleanFilter(fake()->word()); - $filterValues = $filter->getFilterValues(Arr::wrap($booleanValue ? 'true' : 'false')); + $filterValues = $filter->getFilterValues(Arr::wrap($booleanValue ? 'true' : 'false')); - static::assertEquals($booleanValue, $filterValues[0]); - } -} + $this->assertEquals($booleanValue, $filterValues[0]); +}); diff --git a/tests/Unit/Http/Api/Filter/DateFilterTest.php b/tests/Unit/Http/Api/Filter/DateFilterTest.php index bdebbba93..c91df16a7 100644 --- a/tests/Unit/Http/Api/Filter/DateFilterTest.php +++ b/tests/Unit/Http/Api/Filter/DateFilterTest.php @@ -2,87 +2,62 @@ declare(strict_types=1); -namespace Tests\Unit\Http\Api\Filter; - use App\Enums\Http\Api\Filter\AllowedDateFormat; use App\Http\Api\Filter\DateFilter; use App\Http\Api\Scope\GlobalScope; -use DateTime; -use DateTimeInterface; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Date; -use Tests\TestCase; use Tests\Unit\Http\Api\Criteria\Filter\FakeCriteria; -class DateFilterTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * If values that are not mappable to dates are specified for the key, don't apply the filter. - */ - public function testShouldNotApplyIfNoDates(): void - { - $filterField = $this->faker->word(); +test('should not apply if no dates', function () { + $filterField = fake()->word(); - $criteria = FakeCriteria::make(new GlobalScope(), $filterField, $this->faker->words($this->faker->randomDigitNotNull())); + $criteria = FakeCriteria::make(new GlobalScope(), $filterField, fake()->words(fake()->randomDigitNotNull())); - $filter = new DateFilter($filterField); + $filter = new DateFilter($filterField); - static::assertFalse($criteria->shouldFilter($filter, $criteria->getScope())); - } + $this->assertFalse($criteria->shouldFilter($filter, $criteria->getScope())); +}); - /** - * If values do not use allowed date formats, don't apply the filter. - */ - public function testShouldNotApplyIfWrongFormat(): void - { - $filterField = $this->faker->word(); +test('should not apply if wrong format', function () { + $filterField = fake()->word(); - $criteria = FakeCriteria::make(new GlobalScope(), $filterField, Date::now()->format(DateTimeInterface::RFC1036)); + $criteria = FakeCriteria::make(new GlobalScope(), $filterField, Date::now()->format(DateTimeInterface::RFC1036)); - $filter = new DateFilter($filterField); + $filter = new DateFilter($filterField); - static::assertFalse($criteria->shouldFilter($filter, $criteria->getScope())); - } + $this->assertFalse($criteria->shouldFilter($filter, $criteria->getScope())); +}); - /** - * If values do use allowed date formats, apply the filter. - */ - public function testShouldApplyIfAcceptedFormat(): void - { - $filterField = $this->faker->word(); +test('should apply if accepted format', function () { + $filterField = fake()->word(); - $dateFormat = Arr::random(AllowedDateFormat::cases()); + $dateFormat = Arr::random(AllowedDateFormat::cases()); - $criteria = FakeCriteria::make(new GlobalScope(), $filterField, Date::now()->format($dateFormat->value)); + $criteria = FakeCriteria::make(new GlobalScope(), $filterField, Date::now()->format($dateFormat->value)); - $filter = new DateFilter($filterField); + $filter = new DateFilter($filterField); - static::assertTrue($criteria->shouldFilter($filter, $criteria->getScope())); - } + $this->assertTrue($criteria->shouldFilter($filter, $criteria->getScope())); +}); - /** - * The date filter shall convert validated boolean options to boolean values. - */ - public function testConvertsDatesToCanonicalFormat(): void - { - $filterField = $this->faker->word(); +test('converts dates to canonical format', function () { + $filterField = fake()->word(); - $dateFormat = Arr::random(AllowedDateFormat::cases()); + $dateFormat = Arr::random(AllowedDateFormat::cases()); - $dateFilter = Date::now()->format($dateFormat->value); + $dateFilter = Date::now()->format($dateFormat->value); - $criteria = FakeCriteria::make(new GlobalScope(), $filterField, $dateFilter); + $criteria = FakeCriteria::make(new GlobalScope(), $filterField, $dateFilter); - $filter = new DateFilter($filterField); + $filter = new DateFilter($filterField); - $filterValues = $filter->getFilterValues($criteria->getFilterValues()); + $filterValues = $filter->getFilterValues($criteria->getFilterValues()); - static::assertEquals( - DateTime::createFromFormat('!'.$dateFormat->value, $dateFilter)->format(AllowedDateFormat::YMDHISU->value), - $filterValues[0] - ); - } -} + $this->assertEquals( + DateTime::createFromFormat('!'.$dateFormat->value, $dateFilter)->format(AllowedDateFormat::YMDHISU->value), + $filterValues[0] + ); +}); diff --git a/tests/Unit/Http/Api/Filter/EnumFilterTest.php b/tests/Unit/Http/Api/Filter/EnumFilterTest.php index cd46d98e1..98e45ccea 100644 --- a/tests/Unit/Http/Api/Filter/EnumFilterTest.php +++ b/tests/Unit/Http/Api/Filter/EnumFilterTest.php @@ -2,67 +2,48 @@ declare(strict_types=1); -namespace Tests\Unit\Http\Api\Filter; - use App\Http\Api\Filter\EnumFilter; use App\Http\Api\Scope\GlobalScope; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; -use Tests\TestCase; use Tests\Unit\Enums\LocalizedEnum; use Tests\Unit\Http\Api\Criteria\Filter\FakeCriteria; -class EnumFilterTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * If values that are not mappable to enum instances are specified for the key, don't apply the filter. - */ - public function testShouldNotApplyIfNoEnums(): void - { - $filterField = $this->faker->word(); +test('should not apply if no enums', function () { + $filterField = fake()->word(); - $criteria = FakeCriteria::make(new GlobalScope(), $filterField, $this->faker->words($this->faker->randomDigitNotNull())); + $criteria = FakeCriteria::make(new GlobalScope(), $filterField, fake()->words(fake()->randomDigitNotNull())); - $filter = new EnumFilter($filterField, LocalizedEnum::class); + $filter = new EnumFilter($filterField, LocalizedEnum::class); - static::assertFalse($criteria->shouldFilter($filter, $criteria->getScope())); - } + $this->assertFalse($criteria->shouldFilter($filter, $criteria->getScope())); +}); - /** - * If all enum values are specified for the key, don't apply the filter. - */ - public function testShouldNotApplyIfAllEnums(): void - { - $filterField = $this->faker->word(); +test('should not apply if all enums', function () { + $filterField = fake()->word(); - $criteria = FakeCriteria::make( - new GlobalScope(), - $filterField, - array_column(LocalizedEnum::cases(), 'value') - ); + $criteria = FakeCriteria::make( + new GlobalScope(), + $filterField, + array_column(LocalizedEnum::cases(), 'value') + ); - $filter = new EnumFilter($filterField, LocalizedEnum::class); + $filter = new EnumFilter($filterField, LocalizedEnum::class); - static::assertFalse($criteria->shouldFilter($filter, $criteria->getScope())); - } + $this->assertFalse($criteria->shouldFilter($filter, $criteria->getScope())); +}); - /** - * The enum filter shall convert enum keys to enum values. - */ - public function testEnumKeyConvertedToValue(): void - { - $filterField = $this->faker->word(); +test('enum key converted to value', function () { + $filterField = fake()->word(); - $enum = Arr::random(LocalizedEnum::cases()); + $enum = Arr::random(LocalizedEnum::cases()); - $criteria = FakeCriteria::make(new GlobalScope(), $filterField, $enum->localize()); + $criteria = FakeCriteria::make(new GlobalScope(), $filterField, $enum->localize()); - $filter = new EnumFilter($filterField, LocalizedEnum::class); + $filter = new EnumFilter($filterField, LocalizedEnum::class); - $filterValues = $filter->getFilterValues($criteria->getFilterValues()); + $filterValues = $filter->getFilterValues($criteria->getFilterValues()); - static::assertEquals($enum->value, $filterValues[0]); - } -} + $this->assertEquals($enum->value, $filterValues[0]); +}); diff --git a/tests/Unit/Http/Api/Filter/FilterTest.php b/tests/Unit/Http/Api/Filter/FilterTest.php index 495cac58d..74395b761 100644 --- a/tests/Unit/Http/Api/Filter/FilterTest.php +++ b/tests/Unit/Http/Api/Filter/FilterTest.php @@ -2,78 +2,69 @@ declare(strict_types=1); -namespace Tests\Unit\Http\Api\Filter; - use App\Enums\Http\Api\Filter\ComparisonOperator; use App\Http\Api\Filter\Filter; -use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; -class FilterTest extends TestCase -{ - use WithFaker; +use function Pest\Laravel\get; - /** - * By default, the filter column shall be derived from the filter key. - */ - public function testDefaultColumn(): void +uses(Illuminate\Foundation\Testing\WithFaker::class); + +test('default column', function () { + $filter = new class(fake()->word()) extends Filter { - $filter = new class($this->faker->word()) extends Filter + /** + * Convert filter values to integers. + * + * @param array $filterValues + * @return array + */ + public function convertFilterValues(array $filterValues): array { - /** - * Convert filter values to integers. - * - * @param array $filterValues - * @return array - */ - protected function convertFilterValues(array $filterValues): array - { - return $filterValues; - } + return $filterValues; + } - /** - * Get only filter values that are integers. - * - * @param array $filterValues - * @return array - */ - protected function getValidFilterValues(array $filterValues): array - { - return $filterValues; - } + /** + * Get only filter values that are integers. + * + * @param array $filterValues + * @return array + */ + public function getValidFilterValues(array $filterValues): array + { + return $filterValues; + } - /** - * Determine if all valid filter values have been specified. - * By default, this is false as we assume an unrestricted amount of valid values. - * - * @param array $filterValues - */ - public function isAllFilterValues(array $filterValues): bool - { - return false; - } + /** + * Determine if all valid filter values have been specified. + * By default, this is false as we assume an unrestricted amount of valid values. + * + * @param array $filterValues + */ + public function isAllFilterValues(array $filterValues): bool + { + return false; + } - /** - * Get the validation rules for the filter. - * - * @return array - */ - public function getRules(): array - { - return []; - } + /** + * Get the validation rules for the filter. + * + * @return array + */ + public function getRules(): array + { + return []; + } - /** - * Get the allowed comparison operators for the filter. - * - * @return ComparisonOperator[] - */ - public function getAllowedComparisonOperators(): array - { - return []; - } - }; + /** + * Get the allowed comparison operators for the filter. + * + * @return ComparisonOperator[] + */ + public function getAllowedComparisonOperators(): array + { + return []; + } + }; - static::assertEquals($filter->getKey(), $filter->getColumn()); - } -} + $this->assertEquals($filter->getKey(), $filter->getColumn()); +}); diff --git a/tests/Unit/Http/Api/Filter/FloatFilterTest.php b/tests/Unit/Http/Api/Filter/FloatFilterTest.php index 156b68b2a..777bce8cc 100644 --- a/tests/Unit/Http/Api/Filter/FloatFilterTest.php +++ b/tests/Unit/Http/Api/Filter/FloatFilterTest.php @@ -2,47 +2,32 @@ declare(strict_types=1); -namespace Tests\Unit\Http\Api\Filter; - use App\Http\Api\Filter\FloatFilter; use App\Http\Api\Scope\GlobalScope; -use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; use Tests\Unit\Http\Api\Criteria\Filter\FakeCriteria; -class FloatFilterTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * If values that are not mappable to floats are specified for the key, don't apply the filter. - */ - public function testShouldNotApplyIfNoFloats(): void - { - $filterField = $this->faker->word(); +test('should not apply if no floats', function () { + $filterField = fake()->word(); - $criteria = FakeCriteria::make(new GlobalScope(), $filterField, $this->faker->words($this->faker->randomDigitNotNull())); + $criteria = FakeCriteria::make(new GlobalScope(), $filterField, fake()->words(fake()->randomDigitNotNull())); - $filter = new FloatFilter($filterField); + $filter = new FloatFilter($filterField); - static::assertFalse($criteria->shouldFilter($filter, $criteria->getScope())); - } + $this->assertFalse($criteria->shouldFilter($filter, $criteria->getScope())); +}); - /** - * The float filter shall convert validated float inputs to float values. - */ - public function testConvertsValidatedFloats(): void - { - $filterField = $this->faker->word(); +test('converts validated floats', function () { + $filterField = fake()->word(); - $floatValue = $this->faker->randomFloat(); + $floatValue = fake()->randomFloat(); - $criteria = FakeCriteria::make(new GlobalScope(), $filterField, $floatValue); + $criteria = FakeCriteria::make(new GlobalScope(), $filterField, $floatValue); - $filter = new FloatFilter($filterField); + $filter = new FloatFilter($filterField); - $filterValues = $filter->getFilterValues($criteria->getFilterValues()); + $filterValues = $filter->getFilterValues($criteria->getFilterValues()); - static::assertEqualsWithDelta($floatValue, $filterValues[0], 0.0001); - } -} + $this->assertEqualsWithDelta($floatValue, $filterValues[0], 0.0001); +}); diff --git a/tests/Unit/Http/Api/Filter/HasFilterTest.php b/tests/Unit/Http/Api/Filter/HasFilterTest.php index 13e169555..e38f646b9 100644 --- a/tests/Unit/Http/Api/Filter/HasFilterTest.php +++ b/tests/Unit/Http/Api/Filter/HasFilterTest.php @@ -2,124 +2,112 @@ declare(strict_types=1); -namespace Tests\Unit\Http\Api\Filter; - use App\Http\Api\Criteria\Filter\HasCriteria; use App\Http\Api\Field\Field; use App\Http\Api\Filter\HasFilter; use App\Http\Api\Include\AllowedInclude; use App\Http\Api\Schema\Schema; use App\Http\Api\Scope\GlobalScope; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Collection; use Illuminate\Support\Str; -use Tests\TestCase; + +use function Pest\Laravel\get; + use Tests\Unit\Http\Api\Criteria\Filter\FakeCriteria; -class HasFilterTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * If values that are not allowed paths are specified for the key, don't apply the filter. - */ - public function testShouldNotApplyIfNoAllowedPaths(): void +test('should not apply if no allowed paths', function () { + $criteria = FakeCriteria::make(new GlobalScope(), HasCriteria::PARAM_VALUE, Str::random()); + + $schema = new class() extends Schema { - $criteria = FakeCriteria::make(new GlobalScope(), HasCriteria::PARAM_VALUE, Str::random()); - - $schema = new class() extends Schema + /** + * Get the type of the resource. + */ + public function type(): string { - /** - * Get the type of the resource. - */ - public function type(): string - { - return Str::random(); - } + return Str::random(); + } - /** - * Get the allowed includes. - * - * @return AllowedInclude[] - */ - public function allowedIncludes(): array - { - return []; - } + /** + * Get the allowed includes. + * + * @return AllowedInclude[] + */ + public function allowedIncludes(): array + { + return []; + } - /** - * Get the direct fields of the resource. - * - * @return Field[] - * - * @noinspection PhpMissingParentCallCommonInspection - */ - public function fields(): array - { - return []; - } - }; + /** + * Get the direct fields of the resource. + * + * @return Field[] + * + * @noinspection PhpMissingParentCallCommonInspection + */ + public function fields(): array + { + return []; + } + }; - $allowedIncludes = Collection::times( - $this->faker->randomDigitNotNull(), - fn () => new AllowedInclude($schema, $this->faker->word()) - ); + $allowedIncludes = Collection::times( + fake()->randomDigitNotNull(), + fn () => new AllowedInclude($schema, fake()->word()) + ); - $filter = new HasFilter($allowedIncludes->all()); + $filter = new HasFilter($allowedIncludes->all()); - static::assertFalse($criteria->shouldFilter($filter, $criteria->getScope())); - } + $this->assertFalse($criteria->shouldFilter($filter, $criteria->getScope())); +}); - /** - * If values that are allowed paths are specified for the key, apply the filter. - */ - public function testShouldApplyIfAllowedPaths(): void +test('should apply if allowed paths', function () { + $schema = new class() extends Schema { - $schema = new class() extends Schema + /** + * Get the type of the resource. + */ + public function type(): string { - /** - * Get the type of the resource. - */ - public function type(): string - { - return Str::random(); - } + return Str::random(); + } - /** - * Get the allowed includes. - * - * @return AllowedInclude[] - */ - public function allowedIncludes(): array - { - return []; - } + /** + * Get the allowed includes. + * + * @return AllowedInclude[] + */ + public function allowedIncludes(): array + { + return []; + } - /** - * Get the direct fields of the resource. - * - * @return Field[] - * - * @noinspection PhpMissingParentCallCommonInspection - */ - public function fields(): array - { - return []; - } - }; + /** + * Get the direct fields of the resource. + * + * @return Field[] + * + * @noinspection PhpMissingParentCallCommonInspection + */ + public function fields(): array + { + return []; + } + }; - $allowedIncludes = Collection::times( - $this->faker->randomDigitNotNull(), - fn () => new AllowedInclude($schema, $this->faker->word()) - ); + $allowedIncludes = Collection::times( + fake()->randomDigitNotNull(), + fn () => new AllowedInclude($schema, fake()->word()) + ); - /** @var AllowedInclude $selectedInclude */ - $selectedInclude = $allowedIncludes->random(); + /** @var AllowedInclude $selectedInclude */ + $selectedInclude = $allowedIncludes->random(); - $criteria = FakeCriteria::make(new GlobalScope(), HasCriteria::PARAM_VALUE, $selectedInclude->path()); + $criteria = FakeCriteria::make(new GlobalScope(), HasCriteria::PARAM_VALUE, $selectedInclude->path()); - $filter = new HasFilter($allowedIncludes->all()); + $filter = new HasFilter($allowedIncludes->all()); - static::assertTrue($criteria->shouldFilter($filter, $criteria->getScope())); - } -} + $this->assertTrue($criteria->shouldFilter($filter, $criteria->getScope())); +}); diff --git a/tests/Unit/Http/Api/Filter/IntFilterTest.php b/tests/Unit/Http/Api/Filter/IntFilterTest.php index ef792288b..26e9c1eb5 100644 --- a/tests/Unit/Http/Api/Filter/IntFilterTest.php +++ b/tests/Unit/Http/Api/Filter/IntFilterTest.php @@ -2,47 +2,32 @@ declare(strict_types=1); -namespace Tests\Unit\Http\Api\Filter; - use App\Http\Api\Filter\IntFilter; use App\Http\Api\Scope\GlobalScope; -use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; use Tests\Unit\Http\Api\Criteria\Filter\FakeCriteria; -class IntFilterTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * If values that are not mappable to integers are specified for the key, don't apply the filter. - */ - public function testShouldNotApplyIfNoIntegers(): void - { - $filterField = $this->faker->word(); +test('should not apply if no integers', function () { + $filterField = fake()->word(); - $criteria = FakeCriteria::make(new GlobalScope(), $filterField, $this->faker->words($this->faker->randomDigitNotNull())); + $criteria = FakeCriteria::make(new GlobalScope(), $filterField, fake()->words(fake()->randomDigitNotNull())); - $filter = new IntFilter($filterField); + $filter = new IntFilter($filterField); - static::assertFalse($criteria->shouldFilter($filter, $criteria->getScope())); - } + $this->assertFalse($criteria->shouldFilter($filter, $criteria->getScope())); +}); - /** - * The int filter shall convert validated integer inputs to integer values. - */ - public function testConvertsValidatedIntegers(): void - { - $filterField = $this->faker->word(); +test('converts validated integers', function () { + $filterField = fake()->word(); - $intValue = $this->faker->year(); + $intValue = fake()->year(); - $criteria = FakeCriteria::make(new GlobalScope(), $filterField, $intValue); + $criteria = FakeCriteria::make(new GlobalScope(), $filterField, $intValue); - $filter = new IntFilter($filterField); + $filter = new IntFilter($filterField); - $filterValues = $filter->getFilterValues($criteria->getFilterValues()); + $filterValues = $filter->getFilterValues($criteria->getFilterValues()); - static::assertEquals(intval($intValue), $filterValues[0]); - } -} + $this->assertEquals(intval($intValue), $filterValues[0]); +}); diff --git a/tests/Unit/Http/Api/Parser/FieldParserTest.php b/tests/Unit/Http/Api/Parser/FieldParserTest.php index c8f13257c..85af5f44e 100644 --- a/tests/Unit/Http/Api/Parser/FieldParserTest.php +++ b/tests/Unit/Http/Api/Parser/FieldParserTest.php @@ -2,80 +2,57 @@ declare(strict_types=1); -namespace Tests\Unit\Http\Api\Parser; - use App\Http\Api\Criteria\Field\Criteria; use App\Http\Api\Parser\FieldParser; -use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; -class FieldParserTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * By default, the Field Parser shall return no criteria. - */ - public function testNoCriteriaByDefault(): void - { - $parameters = []; +test('no criteria by default', function () { + $parameters = []; - static::assertEmpty(FieldParser::parse($parameters)); - } + $this->assertEmpty(FieldParser::parse($parameters)); +}); - /** - * The Field Parser shall parse criteria defined in the field param. - */ - public function testParseCriteria(): void - { - $fields = collect($this->faker()->words($this->faker->randomDigitNotNull())); +test('parse criteria', function () { + $fields = collect(fake()->words(fake()->randomDigitNotNull())); - $parameters = [ - FieldParser::param() => [ - $this->faker->word() => $fields->join(','), - ], - ]; + $parameters = [ + FieldParser::param() => [ + fake()->word() => $fields->join(','), + ], + ]; - $criteria = FieldParser::parse($parameters)[0]; + $criteria = FieldParser::parse($parameters)[0]; - static::assertInstanceOf(Criteria::class, $criteria); - } + $this->assertInstanceOf(Criteria::class, $criteria); +}); - /** - * The Field Parser shall parse criteria type. - */ - public function testParseType(): void - { - $type = $this->faker->word(); +test('parse type', function () { + $type = fake()->word(); - $fields = collect($this->faker()->words($this->faker->randomDigitNotNull())); + $fields = collect(fake()->words(fake()->randomDigitNotNull())); - $parameters = [ - FieldParser::param() => [ - $type => $fields->join(','), - ], - ]; + $parameters = [ + FieldParser::param() => [ + $type => $fields->join(','), + ], + ]; - $criteria = FieldParser::parse($parameters)[0]; + $criteria = FieldParser::parse($parameters)[0]; - static::assertEquals($type, $criteria->getType()); - } + $this->assertEquals($type, $criteria->getType()); +}); - /** - * The Field Parser shall parse criteria fields. - */ - public function testParseFields(): void - { - $fields = $this->faker()->words($this->faker->randomDigitNotNull()); +test('parse fields', function () { + $fields = fake()->words(fake()->randomDigitNotNull()); - $parameters = [ - FieldParser::param() => [ - $this->faker->word() => collect($fields)->join(','), - ], - ]; + $parameters = [ + FieldParser::param() => [ + fake()->word() => collect($fields)->join(','), + ], + ]; - $criteria = FieldParser::parse($parameters)[0]; + $criteria = FieldParser::parse($parameters)[0]; - static::assertEquals($fields, $criteria->getFields()->all()); - } -} + $this->assertEquals($fields, $criteria->getFields()->all()); +}); diff --git a/tests/Unit/Http/Api/Parser/FilterParserTest.php b/tests/Unit/Http/Api/Parser/FilterParserTest.php index 58349eea9..8ca2ccee1 100644 --- a/tests/Unit/Http/Api/Parser/FilterParserTest.php +++ b/tests/Unit/Http/Api/Parser/FilterParserTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Http\Api\Parser; - use App\Http\Api\Criteria\Filter\HasCriteria; use App\Http\Api\Criteria\Filter\TrashedCriteria; use App\Http\Api\Criteria\Filter\WhereCriteria; @@ -11,125 +9,92 @@ use App\Http\Api\Criteria\Filter\WhereInCriteria; use App\Http\Api\Parser\FilterParser; use App\Http\Api\Scope\GlobalScope; use App\Http\Api\Scope\TypeScope; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Str; -use Tests\TestCase; -class FilterParserTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * By default, the Filter Parser shall return no criteria. - */ - public function testNoCriteriaByDefault(): void - { - $parameters = []; +test('no criteria by default', function () { + $parameters = []; - static::assertEmpty(FilterParser::parse($parameters)); - } + $this->assertEmpty(FilterParser::parse($parameters)); +}); - /** - * The Filter Parser shall parse Trashed Criteria. - */ - public function testParseTrashedCriteria(): void - { - $parameters = [ - FilterParser::param() => [ - TrashedCriteria::PARAM_VALUE => $this->faker->word(), +test('parse trashed criteria', function () { + $parameters = [ + FilterParser::param() => [ + TrashedCriteria::PARAM_VALUE => fake()->word(), + ], + ]; + + $criteria = FilterParser::parse($parameters)[0]; + + $this->assertInstanceOf(TrashedCriteria::class, $criteria); +}); + +test('parse where in criteria', function () { + $fields = collect(fake()->words()); + + $parameters = [ + FilterParser::param() => [ + fake()->word() => $fields->join(','), + ], + ]; + + $criteria = FilterParser::parse($parameters)[0]; + + $this->assertInstanceOf(WhereInCriteria::class, $criteria); +}); + +test('parse has criteria', function () { + $parameters = [ + FilterParser::param() => [ + HasCriteria::PARAM_VALUE => fake()->word(), + ], + ]; + + $criteria = FilterParser::parse($parameters)[0]; + + $this->assertInstanceOf(HasCriteria::class, $criteria); +}); + +test('parse where criteria', function () { + $parameters = [ + FilterParser::param() => [ + fake()->word() => fake()->word(), + ], + ]; + + $criteria = FilterParser::parse($parameters)[0]; + + $this->assertInstanceOf(WhereCriteria::class, $criteria); +}); + +test('parse global scope', function () { + $parameters = [ + FilterParser::param() => [ + fake()->word() => fake()->word(), + ], + ]; + + $criteria = FilterParser::parse($parameters)[0]; + + $this->assertInstanceOf(GlobalScope::class, $criteria->getScope()); +}); + +test('parse type scope', function () { + $type = Str::singular(fake()->word()); + + $parameters = [ + FilterParser::param() => [ + $type => [ + fake()->word() => fake()->word(), ], - ]; + ], + ]; - $criteria = FilterParser::parse($parameters)[0]; + $criteria = FilterParser::parse($parameters)[0]; - static::assertInstanceOf(TrashedCriteria::class, $criteria); - } + $scope = $criteria->getScope(); - /** - * The Filter Parser shall parse Where In criteria. - */ - public function testParseWhereInCriteria(): void - { - $fields = collect($this->faker()->words()); - - $parameters = [ - FilterParser::param() => [ - $this->faker->word() => $fields->join(','), - ], - ]; - - $criteria = FilterParser::parse($parameters)[0]; - - static::assertInstanceOf(WhereInCriteria::class, $criteria); - } - - /** - * The Filter Parser shall parse Has Criteria. - */ - public function testParseHasCriteria(): void - { - $parameters = [ - FilterParser::param() => [ - HasCriteria::PARAM_VALUE => $this->faker->word(), - ], - ]; - - $criteria = FilterParser::parse($parameters)[0]; - - static::assertInstanceOf(HasCriteria::class, $criteria); - } - - /** - * The Filter Parser shall parse Where criteria. - */ - public function testParseWhereCriteria(): void - { - $parameters = [ - FilterParser::param() => [ - $this->faker->word() => $this->faker->word(), - ], - ]; - - $criteria = FilterParser::parse($parameters)[0]; - - static::assertInstanceOf(WhereCriteria::class, $criteria); - } - - /** - * The Filter Parser shall parse a global scope if scope is not provided. - */ - public function testParseGlobalScope(): void - { - $parameters = [ - FilterParser::param() => [ - $this->faker->word() => $this->faker->word(), - ], - ]; - - $criteria = FilterParser::parse($parameters)[0]; - - static::assertInstanceOf(GlobalScope::class, $criteria->getScope()); - } - - /** - * The Filter Parser shall parse a scope if provided. - */ - public function testParseTypeScope(): void - { - $type = Str::singular($this->faker->word()); - - $parameters = [ - FilterParser::param() => [ - $type => [ - $this->faker->word() => $this->faker->word(), - ], - ], - ]; - - $criteria = FilterParser::parse($parameters)[0]; - - $scope = $criteria->getScope(); - - static::assertTrue($scope instanceof TypeScope && $scope->getType() === $type); - } -} + $this->assertTrue($scope instanceof TypeScope && $scope->getType() === $type); +}); diff --git a/tests/Unit/Http/Api/Parser/IncludeParserTest.php b/tests/Unit/Http/Api/Parser/IncludeParserTest.php index 6b6880ed4..1a0802233 100644 --- a/tests/Unit/Http/Api/Parser/IncludeParserTest.php +++ b/tests/Unit/Http/Api/Parser/IncludeParserTest.php @@ -2,116 +2,85 @@ declare(strict_types=1); -namespace Tests\Unit\Http\Api\Parser; - use App\Http\Api\Criteria\Include\Criteria; use App\Http\Api\Criteria\Include\ResourceCriteria; use App\Http\Api\Parser\IncludeParser; -use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; -class IncludeParserTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * By default, the Field Parser shall return no criteria. - */ - public function testNoCriteriaByDefault(): void - { - $parameters = []; +test('no criteria by default', function () { + $parameters = []; - static::assertEmpty(IncludeParser::parse($parameters)); - } + $this->assertEmpty(IncludeParser::parse($parameters)); +}); - /** - * The Include Parser shall parse Include Criteria. - */ - public function testParseCriteria(): void - { - $fields = collect($this->faker()->words($this->faker->randomDigitNotNull())); +test('parse criteria', function () { + $fields = collect(fake()->words(fake()->randomDigitNotNull())); - $parameters = [ - IncludeParser::param() => $fields->join(','), - ]; + $parameters = [ + IncludeParser::param() => $fields->join(','), + ]; - $criteria = IncludeParser::parse($parameters)[0]; + $criteria = IncludeParser::parse($parameters)[0]; - static::assertInstanceOf(Criteria::class, $criteria); - } + $this->assertInstanceOf(Criteria::class, $criteria); +}); - /** - * The Include Parser shall parse Include Criteria paths. - */ - public function testParseCriteriaPaths(): void - { - $fields = $this->faker()->words($this->faker->randomDigitNotNull()); +test('parse criteria paths', function () { + $fields = fake()->words(fake()->randomDigitNotNull()); - $parameters = [ - IncludeParser::param() => collect($fields)->join(','), - ]; + $parameters = [ + IncludeParser::param() => collect($fields)->join(','), + ]; - $criteria = IncludeParser::parse($parameters)[0]; + $criteria = IncludeParser::parse($parameters)[0]; - static::assertEquals($fields, $criteria->getPaths()->all()); - } + $this->assertEquals($fields, $criteria->getPaths()->all()); +}); - /** - * The Include Parser shall parse Resource Criteria. - */ - public function testParseResourceCriteria(): void - { - $fields = collect($this->faker()->words($this->faker->randomDigitNotNull())); +test('parse resource criteria', function () { + $fields = collect(fake()->words(fake()->randomDigitNotNull())); - $parameters = [ - IncludeParser::param() => [ - $this->faker->word() => $fields->join(','), - ], - ]; + $parameters = [ + IncludeParser::param() => [ + fake()->word() => $fields->join(','), + ], + ]; - $criteria = IncludeParser::parse($parameters)[0]; + $criteria = IncludeParser::parse($parameters)[0]; - static::assertInstanceOf(ResourceCriteria::class, $criteria); - } + $this->assertInstanceOf(ResourceCriteria::class, $criteria); +}); - /** - * The Include Parser shall parse Resource Criteria type. - */ - public function testParseResourceCriteriaType(): void - { - $type = $this->faker->word(); +test('parse resource criteria type', function () { + $type = fake()->word(); - $fields = collect($this->faker()->words($this->faker->randomDigitNotNull())); + $fields = collect(fake()->words(fake()->randomDigitNotNull())); - $parameters = [ - IncludeParser::param() => [ - $type => $fields->join(','), - ], - ]; + $parameters = [ + IncludeParser::param() => [ + $type => $fields->join(','), + ], + ]; - $criteria = IncludeParser::parse($parameters)[0]; + $criteria = IncludeParser::parse($parameters)[0]; - static::assertTrue( - $criteria instanceof ResourceCriteria - && $criteria->getType() === $type - ); - } + $this->assertTrue( + $criteria instanceof ResourceCriteria + && $criteria->getType() === $type + ); +}); - /** - * The Include Parser shall parse Include Resource Criteria paths. - */ - public function testParseResourceCriteriaPaths(): void - { - $fields = $this->faker()->words($this->faker->randomDigitNotNull()); +test('parse resource criteria paths', function () { + $fields = fake()->words(fake()->randomDigitNotNull()); - $parameters = [ - IncludeParser::param() => [ - $this->faker->word() => collect($fields)->join(','), - ], - ]; + $parameters = [ + IncludeParser::param() => [ + fake()->word() => collect($fields)->join(','), + ], + ]; - $criteria = IncludeParser::parse($parameters)[0]; + $criteria = IncludeParser::parse($parameters)[0]; - static::assertEquals($fields, $criteria->getPaths()->all()); - } -} + $this->assertEquals($fields, $criteria->getPaths()->all()); +}); diff --git a/tests/Unit/Http/Api/Parser/PagingParserTest.php b/tests/Unit/Http/Api/Parser/PagingParserTest.php index 95acadf58..044712fcd 100644 --- a/tests/Unit/Http/Api/Parser/PagingParserTest.php +++ b/tests/Unit/Http/Api/Parser/PagingParserTest.php @@ -2,137 +2,106 @@ declare(strict_types=1); -namespace Tests\Unit\Http\Api\Parser; - use App\Enums\Http\Api\Paging\PaginationStrategy; use App\Http\Api\Criteria\Paging\Criteria; use App\Http\Api\Criteria\Paging\LimitCriteria; use App\Http\Api\Criteria\Paging\OffsetCriteria; use App\Http\Api\Parser\PagingParser; -use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; -class PagingParserTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * By default, the Paging Parser shall return Limit Criteria. - */ - public function testParseLimitCriteriaByDefault(): void - { - $parameters = []; +test('parse limit criteria by default', function () { + $parameters = []; - $criteria = collect(PagingParser::parse($parameters))->first(function (Criteria $criteria) { - return $criteria->getStrategy() === PaginationStrategy::LIMIT; - }); + $criteria = collect(PagingParser::parse($parameters))->first(function (Criteria $criteria) { + return $criteria->getStrategy() === PaginationStrategy::LIMIT; + }); - static::assertInstanceOf(LimitCriteria::class, $criteria); - } + $this->assertInstanceOf(LimitCriteria::class, $criteria); +}); - /** - * If the provided limit is invalid, the Limit Parser shall use the default. - */ - public function testParseInvalidLimitCriteria(): void - { - $limit = $this->faker->word(); +test('parse invalid limit criteria', function () { + $limit = fake()->word(); - $parameters = [ - PagingParser::param() => [ - LimitCriteria::PARAM => $limit, - ], - ]; + $parameters = [ + PagingParser::param() => [ + LimitCriteria::PARAM => $limit, + ], + ]; - $criteria = collect(PagingParser::parse($parameters))->first(function (Criteria $criteria) { - return $criteria->getStrategy() === PaginationStrategy::LIMIT; - }); + $criteria = collect(PagingParser::parse($parameters))->first(function (Criteria $criteria) { + return $criteria->getStrategy() === PaginationStrategy::LIMIT; + }); - static::assertTrue( - $criteria instanceof LimitCriteria - && $criteria->getResultSize() === Criteria::DEFAULT_SIZE - ); - } + $this->assertTrue( + $criteria instanceof LimitCriteria + && $criteria->getResultSize() === Criteria::DEFAULT_SIZE + ); +}); - /** - * The Paging Parser shall parse valid limits. - */ - public function testParseValidLimitCriteria(): void - { - $limit = $this->faker->numberBetween(1, Criteria::DEFAULT_SIZE); +test('parse valid limit criteria', function () { + $limit = fake()->numberBetween(1, Criteria::DEFAULT_SIZE); - $parameters = [ - PagingParser::param() => [ - LimitCriteria::PARAM => $limit, - ], - ]; + $parameters = [ + PagingParser::param() => [ + LimitCriteria::PARAM => $limit, + ], + ]; - $criteria = collect(PagingParser::parse($parameters))->first(function (Criteria $criteria) { - return $criteria->getStrategy() === PaginationStrategy::LIMIT; - }); + $criteria = collect(PagingParser::parse($parameters))->first(function (Criteria $criteria) { + return $criteria->getStrategy() === PaginationStrategy::LIMIT; + }); - static::assertTrue( - $criteria instanceof LimitCriteria - && $criteria->getResultSize() === $limit - ); - } + $this->assertTrue( + $criteria instanceof LimitCriteria + && $criteria->getResultSize() === $limit + ); +}); - /** - * By default, the Paging Parser shall return Offset Criteria. - */ - public function testParseOffsetCriteriaByDefault(): void - { - $parameters = []; +test('parse offset criteria by default', function () { + $parameters = []; - $criteria = collect(PagingParser::parse($parameters))->first(function (Criteria $criteria) { - return $criteria->getStrategy() === PaginationStrategy::OFFSET; - }); + $criteria = collect(PagingParser::parse($parameters))->first(function (Criteria $criteria) { + return $criteria->getStrategy() === PaginationStrategy::OFFSET; + }); - static::assertInstanceOf(OffsetCriteria::class, $criteria); - } + $this->assertInstanceOf(OffsetCriteria::class, $criteria); +}); - /** - * If the provided size is invalid, the Limit Parser shall use the default. - */ - public function testParseInvalidOffsetCriteria(): void - { - $size = $this->faker->word(); +test('parse invalid offset criteria', function () { + $size = fake()->word(); - $parameters = [ - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => $size, - ], - ]; + $parameters = [ + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => $size, + ], + ]; - $criteria = collect(PagingParser::parse($parameters))->first(function (Criteria $criteria) { - return $criteria->getStrategy() === PaginationStrategy::OFFSET; - }); + $criteria = collect(PagingParser::parse($parameters))->first(function (Criteria $criteria) { + return $criteria->getStrategy() === PaginationStrategy::OFFSET; + }); - static::assertTrue( - $criteria instanceof OffsetCriteria - && $criteria->getResultSize() === Criteria::DEFAULT_SIZE - ); - } + $this->assertTrue( + $criteria instanceof OffsetCriteria + && $criteria->getResultSize() === Criteria::DEFAULT_SIZE + ); +}); - /** - * The Paging Parser shall parse valid sizes. - */ - public function testParseValidOffsetCriteria(): void - { - $size = $this->faker->numberBetween(1, Criteria::MAX_RESULTS); +test('parse valid offset criteria', function () { + $size = fake()->numberBetween(1, Criteria::MAX_RESULTS); - $parameters = [ - PagingParser::param() => [ - OffsetCriteria::SIZE_PARAM => $size, - ], - ]; + $parameters = [ + PagingParser::param() => [ + OffsetCriteria::SIZE_PARAM => $size, + ], + ]; - $criteria = collect(PagingParser::parse($parameters))->first(function (Criteria $criteria) { - return $criteria->getStrategy() === PaginationStrategy::OFFSET; - }); + $criteria = collect(PagingParser::parse($parameters))->first(function (Criteria $criteria) { + return $criteria->getStrategy() === PaginationStrategy::OFFSET; + }); - static::assertTrue( - $criteria instanceof OffsetCriteria - && $criteria->getResultSize() === $size - ); - } -} + $this->assertTrue( + $criteria instanceof OffsetCriteria + && $criteria->getResultSize() === $size + ); +}); diff --git a/tests/Unit/Http/Api/Parser/SearchParserTest.php b/tests/Unit/Http/Api/Parser/SearchParserTest.php index f4dee44e9..3c059ed5d 100644 --- a/tests/Unit/Http/Api/Parser/SearchParserTest.php +++ b/tests/Unit/Http/Api/Parser/SearchParserTest.php @@ -2,54 +2,35 @@ declare(strict_types=1); -namespace Tests\Unit\Http\Api\Parser; - use App\Http\Api\Criteria\Search\Criteria; use App\Http\Api\Parser\SearchParser; -use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; -class SearchParserTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * By default, the Search Parser shall return no criteria. - */ - public function testNoCriteriaByDefault(): void - { - $parameters = []; +test('no criteria by default', function () { + $parameters = []; - static::assertEmpty(SearchParser::parse($parameters)); - } + $this->assertEmpty(SearchParser::parse($parameters)); +}); - /** - * The Search parser shall parse the search query. - */ - public function testParseSearchCriteria(): void - { - $parameters = [ - SearchParser::param() => $this->faker->word(), - ]; +test('parse search criteria', function () { + $parameters = [ + SearchParser::param() => fake()->word(), + ]; - $criteria = SearchParser::parse($parameters)[0]; + $criteria = SearchParser::parse($parameters)[0]; - static::assertInstanceOf(Criteria::class, $criteria); - } + $this->assertInstanceOf(Criteria::class, $criteria); +}); - /** - * The Search parser shall parse the search term. - */ - public function testParseSearchCriteriaTerm(): void - { - $term = $this->faker->word(); +test('parse search criteria term', function () { + $term = fake()->word(); - $parameters = [ - SearchParser::param() => $term, - ]; + $parameters = [ + SearchParser::param() => $term, + ]; - $criteria = SearchParser::parse($parameters)[0]; + $criteria = SearchParser::parse($parameters)[0]; - static::assertEquals($term, $criteria->getTerm()); - } -} + $this->assertEquals($term, $criteria->getTerm()); +}); diff --git a/tests/Unit/Http/Api/Parser/SortParserTest.php b/tests/Unit/Http/Api/Parser/SortParserTest.php index e541b0837..630e24c76 100644 --- a/tests/Unit/Http/Api/Parser/SortParserTest.php +++ b/tests/Unit/Http/Api/Parser/SortParserTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Http\Api\Parser; - use App\Enums\Http\Api\Sort\Direction; use App\Http\Api\Criteria\Sort\FieldCriteria; use App\Http\Api\Criteria\Sort\RandomCriteria; @@ -11,149 +9,108 @@ use App\Http\Api\Criteria\Sort\RelationCriteria; use App\Http\Api\Parser\SortParser; use App\Http\Api\Scope\GlobalScope; use App\Http\Api\Scope\TypeScope; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Str; -use Tests\TestCase; -class SortParserTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * By default, the Sort Parser shall return no criteria. - */ - public function testNoCriteriaByDefault(): void - { - $parameters = []; +test('no criteria by default', function () { + $parameters = []; - static::assertEmpty(SortParser::parse($parameters)); - } + $this->assertEmpty(SortParser::parse($parameters)); +}); - /** - * The Sort Parser shall parse Random Criteria. - */ - public function testParseRandomCriteria(): void - { - $parameters = [ - SortParser::param() => RandomCriteria::PARAM_VALUE, - ]; +test('parse random criteria', function () { + $parameters = [ + SortParser::param() => RandomCriteria::PARAM_VALUE, + ]; - $criteria = SortParser::parse($parameters)[0]; + $criteria = SortParser::parse($parameters)[0]; - static::assertInstanceOf(RandomCriteria::class, $criteria); - } + $this->assertInstanceOf(RandomCriteria::class, $criteria); +}); - /** - * The Sort Parser shall parse Relation Criteria. - */ - public function testParseRelationCriteria(): void - { - $parameters = [ - SortParser::param() => collect($this->faker->words())->join('.'), - ]; +test('parse relation criteria', function () { + $parameters = [ + SortParser::param() => collect(fake()->words())->join('.'), + ]; - $criteria = SortParser::parse($parameters)[0]; + $criteria = SortParser::parse($parameters)[0]; - static::assertInstanceOf(RelationCriteria::class, $criteria); - } + $this->assertInstanceOf(RelationCriteria::class, $criteria); +}); - /** - * The Sort Parser shall parse Field Criteria. - */ - public function testParseFieldCriteria(): void - { - $parameters = [ - SortParser::param() => $this->faker->word(), - ]; +test('parse field criteria', function () { + $parameters = [ + SortParser::param() => fake()->word(), + ]; - $criteria = SortParser::parse($parameters)[0]; + $criteria = SortParser::parse($parameters)[0]; - static::assertInstanceOf(FieldCriteria::class, $criteria); - } + $this->assertInstanceOf(FieldCriteria::class, $criteria); +}); - /** - * The Sort Parser shall parse the sort field. - */ - public function testParseCriteriaField(): void - { - $field = $this->faker->word(); +test('parse criteria field', function () { + $field = fake()->word(); - $parameters = [ - SortParser::param() => $field, - ]; + $parameters = [ + SortParser::param() => $field, + ]; - $criteria = SortParser::parse($parameters)[0]; + $criteria = SortParser::parse($parameters)[0]; - static::assertEquals($field, $criteria->getField()); - } + $this->assertEquals($field, $criteria->getField()); +}); - /** - * By default, the Sort Parser shall parse an ascending sort direction. - */ - public function testParseDefaultDirection(): void - { - $parameters = [ - SortParser::param() => $this->faker->word(), - ]; +test('parse default direction', function () { + $parameters = [ + SortParser::param() => fake()->word(), + ]; - $criteria = SortParser::parse($parameters)[0]; + $criteria = SortParser::parse($parameters)[0]; - static::assertTrue( - $criteria instanceof FieldCriteria - && $criteria->getDirection() === Direction::ASCENDING - ); - } + $this->assertTrue( + $criteria instanceof FieldCriteria + && $criteria->getDirection() === Direction::ASCENDING + ); +}); - /** - * The Sort Parser shall parse a descending direction on fields that prepend a '-'. - */ - public function testParseDescendingDirection(): void - { - $field = Str::of('-')->append($this->faker->word())->__toString(); +test('parse descending direction', function () { + $field = Str::of('-')->append(fake()->word())->__toString(); - $parameters = [ - SortParser::param() => $field, - ]; + $parameters = [ + SortParser::param() => $field, + ]; - $criteria = SortParser::parse($parameters)[0]; + $criteria = SortParser::parse($parameters)[0]; - static::assertTrue( - $criteria instanceof FieldCriteria - && $criteria->getDirection() === Direction::DESCENDING - ); - } + $this->assertTrue( + $criteria instanceof FieldCriteria + && $criteria->getDirection() === Direction::DESCENDING + ); +}); - /** - * The Sort Parser shall parse a global scope if scope is not provided. - */ - public function testParseGlobalScope(): void - { - $parameters = [ - SortParser::param() => $this->faker->word(), - ]; +test('parse global scope', function () { + $parameters = [ + SortParser::param() => fake()->word(), + ]; - $criteria = SortParser::parse($parameters)[0]; + $criteria = SortParser::parse($parameters)[0]; - static::assertInstanceOf(GlobalScope::class, $criteria->getScope()); - } + $this->assertInstanceOf(GlobalScope::class, $criteria->getScope()); +}); - /** - * The Sort Parser shall parse a scope if provided. - */ - public function testParseTypeScope(): void - { - $type = Str::singular($this->faker->word()); +test('parse type scope', function () { + $type = Str::singular(fake()->word()); - $parameters = [ - SortParser::param() => [ - $type => $this->faker->word(), - ], - ]; + $parameters = [ + SortParser::param() => [ + $type => fake()->word(), + ], + ]; - $criteria = SortParser::parse($parameters)[0]; + $criteria = SortParser::parse($parameters)[0]; - $scope = $criteria->getScope(); + $scope = $criteria->getScope(); - static::assertTrue($scope instanceof TypeScope && $scope->getType() === $type); - } -} + $this->assertTrue($scope instanceof TypeScope && $scope->getType() === $type); +}); diff --git a/tests/Unit/Http/Api/Query/QueryTest.php b/tests/Unit/Http/Api/Query/QueryTest.php index 72bcb3edb..d6ae0de8f 100644 --- a/tests/Unit/Http/Api/Query/QueryTest.php +++ b/tests/Unit/Http/Api/Query/QueryTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Http\Api\Query; - use App\Enums\Http\Api\Paging\PaginationStrategy; use App\Http\Api\Criteria\Field\Criteria as FieldCriteria; use App\Http\Api\Criteria\Include\Criteria as IncludeCriteria; @@ -16,171 +14,123 @@ use App\Http\Api\Parser\FilterParser; use App\Http\Api\Parser\IncludeParser; use App\Http\Api\Parser\SearchParser; use App\Http\Api\Parser\SortParser; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Collection; use Illuminate\Support\Str; -use Tests\TestCase; +use Tests\Unit\Http\Api\Query\FakeQuery; -class QueryTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Query shall retrieve field criteria by type. - */ - public function testGetFieldCriteria(): void - { - $type = $this->faker->word(); +test('get field criteria', function () { + $type = fake()->word(); - $parameters = [ - FieldParser::param() => [ - $type => $this->faker->word(), - ], - ]; + $parameters = [ + FieldParser::param() => [ + $type => fake()->word(), + ], + ]; - $query = new FakeQuery($parameters); + $query = new FakeQuery($parameters); - static::assertInstanceOf(FieldCriteria::class, $query->getFieldCriteria($type)); - } + $this->assertInstanceOf(FieldCriteria::class, $query->getFieldCriteria($type)); +}); - /** - * The Query shall retrieve include criteria by type. - */ - public function testGetIncludeCriteria(): void - { - $parameters = [ - IncludeParser::param() => $this->faker->word(), - ]; +test('get include criteria', function () { + $parameters = [ + IncludeParser::param() => fake()->word(), + ]; - $query = new FakeQuery($parameters); + $query = new FakeQuery($parameters); - static::assertInstanceOf(IncludeCriteria::class, $query->getIncludeCriteria($this->faker->word())); - } + $this->assertInstanceOf(IncludeCriteria::class, $query->getIncludeCriteria(fake()->word())); +}); - /** - * The Query shall retrieve include resource criteria by type. - */ - public function testGetIncludeResourceCriteria(): void - { - $type = $this->faker->word(); +test('get include resource criteria', function () { + $type = fake()->word(); - $parameters = [ - IncludeParser::param() => [ - $type => $this->faker->word(), - ], - ]; + $parameters = [ + IncludeParser::param() => [ + $type => fake()->word(), + ], + ]; - $query = new FakeQuery($parameters); + $query = new FakeQuery($parameters); - static::assertInstanceOf(ResourceCriteria::class, $query->getIncludeCriteria($type)); - } + $this->assertInstanceOf(ResourceCriteria::class, $query->getIncludeCriteria($type)); +}); - /** - * The query shall retrieve all sort criteria. - */ - public function testGetSortCriteria(): void - { - $fields = collect($this->faker()->words($this->faker->randomDigitNotNull())); +test('get sort criteria', function () { + $fields = collect(fake()->words(fake()->randomDigitNotNull())); - $parameters = [ - SortParser::param() => $fields->join(','), - ]; + $parameters = [ + SortParser::param() => $fields->join(','), + ]; - $query = new FakeQuery($parameters); + $query = new FakeQuery($parameters); - static::assertCount($fields->count(), $query->getSortCriteria()); - } + $this->assertCount($fields->count(), $query->getSortCriteria()); +}); - /** - * The query shall retrieve all filter criteria. - */ - public function testGetFilterCriteria(): void - { - $filterCount = $this->faker->randomDigitNotNull(); +test('get filter criteria', function () { + $filterCount = fake()->randomDigitNotNull(); - $parameters = Collection::times($filterCount, fn () => FilterParser::param().'.'.Str::random()) - ->combine(Collection::times($filterCount, fn () => Str::random())) - ->undot() - ->all(); + $parameters = Collection::times($filterCount, fn () => FilterParser::param().'.'.Str::random()) + ->combine(Collection::times($filterCount, fn () => Str::random())) + ->undot() + ->all(); - $query = new FakeQuery($parameters); + $query = new FakeQuery($parameters); - static::assertCount($filterCount, $query->getFilterCriteria()); - } + $this->assertCount($filterCount, $query->getFilterCriteria()); +}); - /** - * By default, the query shall not have a search term. - */ - public function testDoesNotHaveSearch(): void - { - $parameters = []; +test('does not have search', function () { + $parameters = []; - $query = new FakeQuery($parameters); + $query = new FakeQuery($parameters); - static::assertFalse($query->hasSearchCriteria()); - } + $this->assertFalse($query->hasSearchCriteria()); +}); - /** - * The query shall have a search if a term is provided. - */ - public function testHasSearch(): void - { - $parameters = [ - SearchParser::param() => $this->faker->word(), - ]; +test('has search', function () { + $parameters = [ + SearchParser::param() => fake()->word(), + ]; - $query = new FakeQuery($parameters); + $query = new FakeQuery($parameters); - static::assertTrue($query->hasSearchCriteria()); - } + $this->assertTrue($query->hasSearchCriteria()); +}); - /** - * By default, the query shall return null search criteria. - */ - public function testNullSearch(): void - { - $parameters = []; +test('null search', function () { + $parameters = []; - $query = new FakeQuery($parameters); + $query = new FakeQuery($parameters); - static::assertNull($query->getSearchCriteria()); - } + $this->assertNull($query->getSearchCriteria()); +}); - /** - * The query shall return search criteria if a term is provided. - */ - public function testGetSearch(): void - { - $parameters = [ - SearchParser::param() => $this->faker->word(), - ]; +test('get search', function () { + $parameters = [ + SearchParser::param() => fake()->word(), + ]; - $query = new FakeQuery($parameters); + $query = new FakeQuery($parameters); - static::assertInstanceOf(SearchCriteria::class, $query->getSearchCriteria()); - } + $this->assertInstanceOf(SearchCriteria::class, $query->getSearchCriteria()); +}); - /** - * The query shall return limit criteria. - */ - public function testGetLimitCriteria(): void - { - $parameters = []; +test('get limit criteria', function () { + $parameters = []; - $query = new FakeQuery($parameters); + $query = new FakeQuery($parameters); - static::assertInstanceOf(LimitCriteria::class, $query->getPagingCriteria(PaginationStrategy::LIMIT)); - } + $this->assertInstanceOf(LimitCriteria::class, $query->getPagingCriteria(PaginationStrategy::LIMIT)); +}); - /** - * The query shall return limit criteria. - */ - public function testGetOffsetCriteria(): void - { - $parameters = []; +test('get offset criteria', function () { + $parameters = []; - $query = new FakeQuery($parameters); + $query = new FakeQuery($parameters); - static::assertInstanceOf(OffsetCriteria::class, $query->getPagingCriteria(PaginationStrategy::OFFSET)); - } -} + $this->assertInstanceOf(OffsetCriteria::class, $query->getPagingCriteria(PaginationStrategy::OFFSET)); +}); diff --git a/tests/Unit/Http/Api/Scope/GlobalScopeTest.php b/tests/Unit/Http/Api/Scope/GlobalScopeTest.php index 042cd8d25..6cfbbd89b 100644 --- a/tests/Unit/Http/Api/Scope/GlobalScopeTest.php +++ b/tests/Unit/Http/Api/Scope/GlobalScopeTest.php @@ -2,51 +2,32 @@ declare(strict_types=1); -namespace Tests\Unit\Http\Api\Scope; - use App\Http\Api\Scope\GlobalScope; use App\Http\Api\Scope\RelationScope; use App\Http\Api\Scope\TypeScope; -use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; -class GlobalScopeTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * A global scope shall be within the scope of a global scope. - */ - public function testGlobalScopeIsWithinScope(): void - { - $scope = new GlobalScope(); +test('global scope is within scope', function () { + $scope = new GlobalScope(); - $otherScope = new GlobalScope(); + $otherScope = new GlobalScope(); - static::assertTrue($scope->isWithinScope($otherScope)); - } + $this->assertTrue($scope->isWithinScope($otherScope)); +}); - /** - * A type scope shall be within the scope of a global scope. - */ - public function testTypeScopeIsWithinScope(): void - { - $scope = new GlobalScope(); +test('type scope is within scope', function () { + $scope = new GlobalScope(); - $otherScope = new TypeScope($this->faker->word()); + $otherScope = new TypeScope(fake()->word()); - static::assertTrue($scope->isWithinScope($otherScope)); - } + $this->assertTrue($scope->isWithinScope($otherScope)); +}); - /** - * A relation scope shall be within the scope of a global scope. - */ - public function testRelationScopeIsWithinScope(): void - { - $scope = new GlobalScope(); +test('relation scope is within scope', function () { + $scope = new GlobalScope(); - $otherScope = new RelationScope($this->faker->word()); + $otherScope = new RelationScope(fake()->word()); - static::assertTrue($scope->isWithinScope($otherScope)); - } -} + $this->assertTrue($scope->isWithinScope($otherScope)); +}); diff --git a/tests/Unit/Http/Api/Scope/RelationScopeTest.php b/tests/Unit/Http/Api/Scope/RelationScopeTest.php index ca617a5f0..1c0dcf07c 100644 --- a/tests/Unit/Http/Api/Scope/RelationScopeTest.php +++ b/tests/Unit/Http/Api/Scope/RelationScopeTest.php @@ -2,65 +2,42 @@ declare(strict_types=1); -namespace Tests\Unit\Http\Api\Scope; - use App\Http\Api\Scope\GlobalScope; use App\Http\Api\Scope\RelationScope; use App\Http\Api\Scope\TypeScope; -use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; -class RelationScopeTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * A global scope shall not be within the scope of a relation scope. - */ - public function testGlobalScopeIsNotWithinScope(): void - { - $scope = new RelationScope($this->faker->word()); +test('global scope is not within scope', function () { + $scope = new RelationScope(fake()->word()); - $otherScope = new GlobalScope(); + $otherScope = new GlobalScope(); - static::assertFalse($scope->isWithinScope($otherScope)); - } + $this->assertFalse($scope->isWithinScope($otherScope)); +}); - /** - * A type scope shall not be within the scope of a relation scope. - */ - public function testTypeScopeIsNotWithinScope(): void - { - $scope = new RelationScope($this->faker->word()); +test('type scope is not within scope', function () { + $scope = new RelationScope(fake()->word()); - $otherScope = new TypeScope($this->faker->word()); + $otherScope = new TypeScope(fake()->word()); - static::assertFalse($scope->isWithinScope($otherScope)); - } + $this->assertFalse($scope->isWithinScope($otherScope)); +}); - /** - * A relation scope of an unequal value shall not be within the scope of a relation scope. - */ - public function testUnequalRelationIsNotWithinScope(): void - { - $scope = new RelationScope($this->faker->word()); +test('unequal relation is not within scope', function () { + $scope = new RelationScope(fake()->word()); - $otherScope = new RelationScope($this->faker->word()); + $otherScope = new RelationScope(fake()->word()); - static::assertFalse($scope->isWithinScope($otherScope)); - } + $this->assertFalse($scope->isWithinScope($otherScope)); +}); - /** - * A relation scope of an equal value shall be within the scope of a relation scope. - */ - public function testRelationIsWithinScope(): void - { - $relation = $this->faker->word(); +test('relation is within scope', function () { + $relation = fake()->word(); - $scope = new RelationScope($relation); + $scope = new RelationScope($relation); - $otherScope = new RelationScope($relation); + $otherScope = new RelationScope($relation); - static::assertTrue($scope->isWithinScope($otherScope)); - } -} + $this->assertTrue($scope->isWithinScope($otherScope)); +}); diff --git a/tests/Unit/Http/Api/Scope/ScopeParserTest.php b/tests/Unit/Http/Api/Scope/ScopeParserTest.php index 09c3f71ff..33e3da6de 100644 --- a/tests/Unit/Http/Api/Scope/ScopeParserTest.php +++ b/tests/Unit/Http/Api/Scope/ScopeParserTest.php @@ -2,42 +2,23 @@ declare(strict_types=1); -namespace Tests\Unit\Http\Api\Scope; - use App\Http\Api\Scope\GlobalScope; use App\Http\Api\Scope\RelationScope; use App\Http\Api\Scope\ScopeParser; use App\Http\Api\Scope\TypeScope; -use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; -class ScopeParserTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Scope Parser shall parse global scopes. - */ - public function testParseGlobalScope(): void - { - static::assertInstanceOf(GlobalScope::class, ScopeParser::parse('')); - } +test('parse global scope', function () { + $this->assertInstanceOf(GlobalScope::class, ScopeParser::parse('')); +}); - /** - * The Scope Parser shall parse type scopes. - */ - public function testParseTypeScope(): void - { - static::assertInstanceOf(TypeScope::class, ScopeParser::parse($this->faker->word())); - } +test('parse type scope', function () { + $this->assertInstanceOf(TypeScope::class, ScopeParser::parse(fake()->word())); +}); - /** - * The Scope Parser shall parse relation scopes. - */ - public function testParseRelationScope(): void - { - $relation = collect($this->faker->words())->join('.'); +test('parse relation scope', function () { + $relation = collect(fake()->words())->join('.'); - static::assertInstanceOf(RelationScope::class, ScopeParser::parse($relation)); - } -} + $this->assertInstanceOf(RelationScope::class, ScopeParser::parse($relation)); +}); diff --git a/tests/Unit/Http/Api/Scope/TypeScopeTest.php b/tests/Unit/Http/Api/Scope/TypeScopeTest.php index 2b5b1cf85..f5d330cee 100644 --- a/tests/Unit/Http/Api/Scope/TypeScopeTest.php +++ b/tests/Unit/Http/Api/Scope/TypeScopeTest.php @@ -2,79 +2,52 @@ declare(strict_types=1); -namespace Tests\Unit\Http\Api\Scope; - use App\Http\Api\Scope\GlobalScope; use App\Http\Api\Scope\RelationScope; use App\Http\Api\Scope\TypeScope; -use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; -class TypeScopeTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * A global scope shall not be within the scope of a type scope. - */ - public function testGlobalScopeIsNotWithinScope(): void - { - $scope = new TypeScope($this->faker->word()); +test('global scope is not within scope', function () { + $scope = new TypeScope(fake()->word()); - $otherScope = new GlobalScope(); + $otherScope = new GlobalScope(); - static::assertFalse($scope->isWithinScope($otherScope)); - } + $this->assertFalse($scope->isWithinScope($otherScope)); +}); - /** - * A type scope of unequal value shall not be within the scope of a type scope. - */ - public function testTypeScopeIsNotWithinScope(): void - { - $scope = new TypeScope($this->faker->word()); +test('type scope is not within scope', function () { + $scope = new TypeScope(fake()->word()); - $otherScope = new TypeScope($this->faker->word()); + $otherScope = new TypeScope(fake()->word()); - static::assertFalse($scope->isWithinScope($otherScope)); - } + $this->assertFalse($scope->isWithinScope($otherScope)); +}); - /** - * A type scope of equal value shall be within the scope of a type scope. - */ - public function testTypeScopeIsWithinScope(): void - { - $type = $this->faker->word(); +test('type scope is within scope', function () { + $type = fake()->word(); - $scope = new TypeScope($type); + $scope = new TypeScope($type); - $otherScope = new TypeScope($type); + $otherScope = new TypeScope($type); - static::assertTrue($scope->isWithinScope($otherScope)); - } + $this->assertTrue($scope->isWithinScope($otherScope)); +}); - /** - * A relation scope of unequal type shall not be within the scope of a type scope. - */ - public function testRelationScopeIsNotWithinScope(): void - { - $scope = new TypeScope($this->faker->word()); +test('relation scope is not within scope', function () { + $scope = new TypeScope(fake()->word()); - $otherScope = new RelationScope($this->faker->word()); + $otherScope = new RelationScope(fake()->word()); - static::assertFalse($scope->isWithinScope($otherScope)); - } + $this->assertFalse($scope->isWithinScope($otherScope)); +}); - /** - * A relation scope of equal value shall be within the scope of a type scope. - */ - public function testRelationScopeIsWithinScope(): void - { - $type = $this->faker->word(); +test('relation scope is within scope', function () { + $type = fake()->word(); - $scope = new TypeScope($type); + $scope = new TypeScope($type); - $otherScope = new RelationScope($type); + $otherScope = new RelationScope($type); - static::assertTrue($scope->isWithinScope($otherScope)); - } -} + $this->assertTrue($scope->isWithinScope($otherScope)); +}); diff --git a/tests/Unit/Http/Api/Sort/RandomSortTest.php b/tests/Unit/Http/Api/Sort/RandomSortTest.php index abac2e860..7f792bd32 100644 --- a/tests/Unit/Http/Api/Sort/RandomSortTest.php +++ b/tests/Unit/Http/Api/Sort/RandomSortTest.php @@ -2,28 +2,17 @@ declare(strict_types=1); -namespace Tests\Unit\Http\Api\Sort; - use App\Enums\Http\Api\Sort\Direction; use App\Http\Api\Criteria\Sort\RandomCriteria; use App\Http\Api\Sort\RandomSort; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; -use Tests\TestCase; -class RandomSortTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Random Sort shall be formatted as "{key}" for the any Direction. - */ - public function testFormat(): void - { - $sort = new RandomSort(); +test('format', function () { + $sort = new RandomSort(); - $direction = Arr::random(Direction::cases()); + $direction = Arr::random(Direction::cases()); - static::assertEquals(RandomCriteria::PARAM_VALUE, $sort->format($direction)); - } -} + $this->assertEquals(RandomCriteria::PARAM_VALUE, $sort->format($direction)); +}); diff --git a/tests/Unit/Http/Api/Sort/SortTest.php b/tests/Unit/Http/Api/Sort/SortTest.php index a248591eb..5b8940617 100644 --- a/tests/Unit/Http/Api/Sort/SortTest.php +++ b/tests/Unit/Http/Api/Sort/SortTest.php @@ -2,48 +2,29 @@ declare(strict_types=1); -namespace Tests\Unit\Http\Api\Sort; - use App\Enums\Http\Api\Sort\Direction; use App\Http\Api\Sort\Sort; -use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; -class SortTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * By default, the sort column shall be derived from the sort key. - */ - public function testDefaultColumn(): void - { - $sort = new Sort($this->faker->word()); +test('default column', function () { + $sort = new Sort(fake()->word()); - static::assertEquals($sort->getKey(), $sort->getColumn()); - } + $this->assertEquals($sort->getKey(), $sort->getColumn()); +}); - /** - * The Sort shall be formatted as "{key}" for the Ascending Direction. - */ - public function testFormatAsc(): void - { - $sortField = $this->faker->word(); +test('format asc', function () { + $sortField = fake()->word(); - $sort = new Sort($sortField); + $sort = new Sort($sortField); - static::assertEquals($sortField, $sort->format(Direction::ASCENDING)); - } + $this->assertEquals($sortField, $sort->format(Direction::ASCENDING)); +}); - /** - * The Sort shall be formatted as "-{key}" for the Descending Direction. - */ - public function testFormatDesc(): void - { - $sortField = $this->faker->word(); +test('format desc', function () { + $sortField = fake()->word(); - $sort = new Sort($sortField); + $sort = new Sort($sortField); - static::assertEquals("-$sortField", $sort->format(Direction::DESCENDING)); - } -} + $this->assertEquals("-$sortField", $sort->format(Direction::DESCENDING)); +}); diff --git a/tests/Unit/Models/Admin/AnnouncementTest.php b/tests/Unit/Models/Admin/AnnouncementTest.php index 7ac4c508c..1175571db 100644 --- a/tests/Unit/Models/Admin/AnnouncementTest.php +++ b/tests/Unit/Models/Admin/AnnouncementTest.php @@ -2,30 +2,16 @@ declare(strict_types=1); -namespace Tests\Unit\Models\Admin; - use App\Models\Admin\Announcement; -use Tests\TestCase; -class AnnouncementTest extends TestCase -{ - /** - * Announcements shall be nameable. - */ - public function testNameable(): void - { - $announcement = Announcement::factory()->createOne(); +test('nameable', function () { + $announcement = Announcement::factory()->createOne(); - static::assertIsString($announcement->getName()); - } + $this->assertIsString($announcement->getName()); +}); - /** - * Announcements shall have subtitle. - */ - public function testHasSubtitle(): void - { - $announcement = Announcement::factory()->createOne(); +test('has subtitle', function () { + $announcement = Announcement::factory()->createOne(); - static::assertIsString($announcement->getSubtitle()); - } -} + $this->assertIsString($announcement->getSubtitle()); +}); diff --git a/tests/Unit/Models/Admin/DumpTest.php b/tests/Unit/Models/Admin/DumpTest.php index 2cfd8d51a..6c7732d67 100644 --- a/tests/Unit/Models/Admin/DumpTest.php +++ b/tests/Unit/Models/Admin/DumpTest.php @@ -2,30 +2,16 @@ declare(strict_types=1); -namespace Tests\Unit\Models\Admin; - use App\Models\Admin\Dump; -use Tests\TestCase; -class DumpTest extends TestCase -{ - /** - * Dumps shall be nameable. - */ - public function testNameable(): void - { - $dump = Dump::factory()->createOne(); +test('nameable', function () { + $dump = Dump::factory()->createOne(); - static::assertIsString($dump->getName()); - } + $this->assertIsString($dump->getName()); +}); - /** - * Dumps shall have subtitle. - */ - public function testHasSubtitle(): void - { - $dump = Dump::factory()->createOne(); +test('has subtitle', function () { + $dump = Dump::factory()->createOne(); - static::assertIsString($dump->getSubtitle()); - } -} + $this->assertIsString($dump->getSubtitle()); +}); diff --git a/tests/Unit/Models/Admin/FeatureTest.php b/tests/Unit/Models/Admin/FeatureTest.php index 64b1327eb..19ed1f0be 100644 --- a/tests/Unit/Models/Admin/FeatureTest.php +++ b/tests/Unit/Models/Admin/FeatureTest.php @@ -2,55 +2,32 @@ declare(strict_types=1); -namespace Tests\Unit\Models\Admin; - use App\Models\Admin\Feature; -use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; -class FeatureTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * Features shall be nameable. - */ - public function testNameable(): void - { - $feature = Feature::factory()->createOne(); +test('nameable', function () { + $feature = Feature::factory()->createOne(); - static::assertIsString($feature->getName()); - } + $this->assertIsString($feature->getName()); +}); - /** - * Features shall have subtitle. - */ - public function testHasSubtitle(): void - { - $feature = Feature::factory()->createOne(); +test('has subtitle', function () { + $feature = Feature::factory()->createOne(); - static::assertIsString($feature->getSubtitle()); - } + $this->assertIsString($feature->getSubtitle()); +}); - /** - * Feature shall indicate if the scope is null. - */ - public function testNullableScope(): void - { - $feature = Feature::factory()->createOne(); +test('nullable scope', function () { + $feature = Feature::factory()->createOne(); - static::assertTrue($feature->isNullScope()); - } + $this->assertTrue($feature->isNullScope()); +}); - /** - * Feature shall indicate if the scope is not null. - */ - public function testNonNullScope(): void - { - $feature = Feature::factory()->createOne([ - Feature::ATTRIBUTE_SCOPE => $this->faker->word(), - ]); +test('non null scope', function () { + $feature = Feature::factory()->createOne([ + Feature::ATTRIBUTE_SCOPE => fake()->word(), + ]); - static::assertFalse($feature->isNullScope()); - } -} + $this->assertFalse($feature->isNullScope()); +}); diff --git a/tests/Unit/Models/Admin/FeaturedThemeTest.php b/tests/Unit/Models/Admin/FeaturedThemeTest.php index adbbd4d84..4fb79efc4 100644 --- a/tests/Unit/Models/Admin/FeaturedThemeTest.php +++ b/tests/Unit/Models/Admin/FeaturedThemeTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Models\Admin; - use App\Models\Admin\FeaturedTheme; use App\Models\Auth\User; use App\Models\Wiki\Anime; @@ -12,88 +10,56 @@ use App\Models\Wiki\Anime\Theme\AnimeThemeEntry; use App\Models\Wiki\Video; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Support\Carbon; -use Tests\TestCase; -class FeaturedThemeTest extends TestCase -{ - /** - * Featured Themes shall be nameable. - */ - public function testNameable(): void - { - $featuredTheme = FeaturedTheme::factory()->createOne(); +test('nameable', function () { + $featuredTheme = FeaturedTheme::factory()->createOne(); - static::assertIsString($featuredTheme->getName()); - } + $this->assertIsString($featuredTheme->getName()); +}); - /** - * Featured Themes shall have subtitle. - */ - public function testHasSubtitle(): void - { - $featuredTheme = FeaturedTheme::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->createOne(); +test('has subtitle', function () { + $featuredTheme = FeaturedTheme::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->createOne(); - static::assertIsString($featuredTheme->getSubtitle()); - } + $this->assertIsString($featuredTheme->getSubtitle()); +}); - /** - * Featured Themes shall cast the end_at attribute to datetime. - */ - public function testCastsEndAt(): void - { - $featuredTheme = FeaturedTheme::factory()->createOne(); +test('casts end at', function () { + $featuredTheme = FeaturedTheme::factory()->createOne(); - static::assertInstanceOf(Carbon::class, $featuredTheme->end_at); - } + $this->assertInstanceOf(Carbon::class, $featuredTheme->end_at); +}); - /** - * Featured Themes shall cast the start_at attribute to datetime. - */ - public function testCastsStartAt(): void - { - $featuredTheme = FeaturedTheme::factory()->createOne(); +test('casts start at', function () { + $featuredTheme = FeaturedTheme::factory()->createOne(); - static::assertInstanceOf(Carbon::class, $featuredTheme->start_at); - } + $this->assertInstanceOf(Carbon::class, $featuredTheme->start_at); +}); - /** - * Featured themes shall belong to a User. - */ - public function testUser(): void - { - $featuredTheme = FeaturedTheme::factory() - ->for(User::factory()) - ->createOne(); +test('user', function () { + $featuredTheme = FeaturedTheme::factory() + ->for(User::factory()) + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $featuredTheme->user()); - static::assertInstanceOf(User::class, $featuredTheme->user()->first()); - } + $this->assertInstanceOf(BelongsTo::class, $featuredTheme->user()); + $this->assertInstanceOf(User::class, $featuredTheme->user()->first()); +}); - /** - * Featured themes shall belong to a Video. - */ - public function testVideo(): void - { - $featuredTheme = FeaturedTheme::factory() - ->for(Video::factory()) - ->createOne(); +test('video', function () { + $featuredTheme = FeaturedTheme::factory() + ->for(Video::factory()) + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $featuredTheme->video()); - static::assertInstanceOf(Video::class, $featuredTheme->video()->first()); - } + $this->assertInstanceOf(BelongsTo::class, $featuredTheme->video()); + $this->assertInstanceOf(Video::class, $featuredTheme->video()->first()); +}); - /** - * Featured themes shall belong to an Entry. - */ - public function testEntry(): void - { - $featuredTheme = FeaturedTheme::factory() - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->createOne(); +test('entry', function () { + $featuredTheme = FeaturedTheme::factory() + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $featuredTheme->animethemeentry()); - static::assertInstanceOf(AnimeThemeEntry::class, $featuredTheme->animethemeentry()->first()); - } -} + $this->assertInstanceOf(BelongsTo::class, $featuredTheme->animethemeentry()); + $this->assertInstanceOf(AnimeThemeEntry::class, $featuredTheme->animethemeentry()->first()); +}); diff --git a/tests/Unit/Models/Auth/UserTest.php b/tests/Unit/Models/Auth/UserTest.php index 4a2fa7e3d..a148d97b5 100644 --- a/tests/Unit/Models/Auth/UserTest.php +++ b/tests/Unit/Models/Auth/UserTest.php @@ -2,81 +2,54 @@ declare(strict_types=1); -namespace Tests\Unit\Models\Auth; - use App\Models\Auth\User; use App\Models\List\Playlist; use Illuminate\Auth\Notifications\VerifyEmail; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\MorphMany; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Facades\Notification; use Laravel\Sanctum\PersonalAccessToken; -use Tests\TestCase; -class UserTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * Users shall have a one-to-many polymorphic relationship to PersonalAccessToken. - */ - public function testTokens(): void - { - $user = User::factory()->createOne(); +test('tokens', function () { + $user = User::factory()->createOne(); - $user->createToken($this->faker->word()); + $user->createToken(fake()->word()); - static::assertInstanceOf(MorphMany::class, $user->tokens()); - static::assertEquals(1, $user->tokens()->count()); - static::assertInstanceOf(PersonalAccessToken::class, $user->tokens()->first()); - } + $this->assertInstanceOf(MorphMany::class, $user->tokens()); + $this->assertEquals(1, $user->tokens()->count()); + $this->assertInstanceOf(PersonalAccessToken::class, $user->tokens()->first()); +}); - /** - * Users shall verify email. - */ - public function testVerificationEmailNotification(): void - { - $user = User::factory()->createOne(); +test('verification email notification', function () { + $user = User::factory()->createOne(); - $user->sendEmailVerificationNotification(); + $user->sendEmailVerificationNotification(); - Notification::assertSentTo($user, VerifyEmail::class); - } + Notification::assertSentTo($user, VerifyEmail::class); +}); - /** - * Users shall be nameable. - */ - public function testNameable(): void - { - $user = User::factory()->createOne(); +test('nameable', function () { + $user = User::factory()->createOne(); - static::assertIsString($user->getName()); - } + $this->assertIsString($user->getName()); +}); - /** - * Users shall have subtitle. - */ - public function testHasSubtitle(): void - { - $user = User::factory()->createOne(); +test('has subtitle', function () { + $user = User::factory()->createOne(); - static::assertIsString($user->getSubtitle()); - } + $this->assertIsString($user->getSubtitle()); +}); - /** - * User shall have a one-to-many relationship with the type Playlist. - */ - public function testPlaylists(): void - { - $playlistCount = $this->faker->randomDigitNotNull(); +test('playlists', function () { + $playlistCount = fake()->randomDigitNotNull(); - $user = User::factory() - ->has(Playlist::factory()->count($playlistCount)) - ->createOne(); + $user = User::factory() + ->has(Playlist::factory()->count($playlistCount)) + ->createOne(); - static::assertInstanceOf(HasMany::class, $user->playlists()); - static::assertEquals($playlistCount, $user->playlists()->count()); - static::assertInstanceOf(Playlist::class, $user->playlists()->first()); - } -} + $this->assertInstanceOf(HasMany::class, $user->playlists()); + $this->assertEquals($playlistCount, $user->playlists()->count()); + $this->assertInstanceOf(Playlist::class, $user->playlists()->first()); +}); diff --git a/tests/Unit/Models/Discord/DiscordThreadTest.php b/tests/Unit/Models/Discord/DiscordThreadTest.php index 2307f4087..28ea794f8 100644 --- a/tests/Unit/Models/Discord/DiscordThreadTest.php +++ b/tests/Unit/Models/Discord/DiscordThreadTest.php @@ -2,52 +2,33 @@ declare(strict_types=1); -namespace Tests\Unit\Models\Discord; - use App\Models\Discord\DiscordThread; use App\Models\Wiki\Anime; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; -class DiscordThreadTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * Thread shall be nameable. - */ - public function testNameable(): void - { - $thread = DiscordThread::factory() - ->for(Anime::factory()) - ->createOne(); +test('nameable', function () { + $thread = DiscordThread::factory() + ->for(Anime::factory()) + ->createOne(); - static::assertIsString($thread->getName()); - } + $this->assertIsString($thread->getName()); +}); - /** - * Thread shall have subtitle. - */ - public function testHasSubtitle(): void - { - $thread = DiscordThread::factory() - ->for(Anime::factory()) - ->createOne(); +test('has subtitle', function () { + $thread = DiscordThread::factory() + ->for(Anime::factory()) + ->createOne(); - static::assertIsString($thread->getSubtitle()); - } + $this->assertIsString($thread->getSubtitle()); +}); - /** - * Discord Thread shall belong to an Anime. - */ - public function testAnime(): void - { - $thread = DiscordThread::factory() - ->for(Anime::factory()) - ->createOne(); +test('anime', function () { + $thread = DiscordThread::factory() + ->for(Anime::factory()) + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $thread->anime()); - static::assertInstanceOf(Anime::class, $thread->anime()->first()); - } -} + $this->assertInstanceOf(BelongsTo::class, $thread->anime()); + $this->assertInstanceOf(Anime::class, $thread->anime()->first()); +}); diff --git a/tests/Unit/Models/Document/PageTest.php b/tests/Unit/Models/Document/PageTest.php index 9e4d89e6c..96fd77efa 100644 --- a/tests/Unit/Models/Document/PageTest.php +++ b/tests/Unit/Models/Document/PageTest.php @@ -2,30 +2,16 @@ declare(strict_types=1); -namespace Tests\Unit\Models\Document; - use App\Models\Document\Page; -use Tests\TestCase; -class PageTest extends TestCase -{ - /** - * Pages shall be nameable. - */ - public function testNameable(): void - { - $page = Page::factory()->createOne(); +test('nameable', function () { + $page = Page::factory()->createOne(); - static::assertIsString($page->getName()); - } + $this->assertIsString($page->getName()); +}); - /** - * Pages shall have subtitle. - */ - public function testHasSubtitle(): void - { - $page = Page::factory()->createOne(); +test('has subtitle', function () { + $page = Page::factory()->createOne(); - static::assertIsString($page->getSubtitle()); - } -} + $this->assertIsString($page->getSubtitle()); +}); diff --git a/tests/Unit/Models/List/External/ExternalEntryTest.php b/tests/Unit/Models/List/External/ExternalEntryTest.php index 1f8493b7e..497d56577 100644 --- a/tests/Unit/Models/List/External/ExternalEntryTest.php +++ b/tests/Unit/Models/List/External/ExternalEntryTest.php @@ -2,94 +2,64 @@ declare(strict_types=1); -namespace Tests\Unit\Models\List\External; - use App\Enums\Models\List\ExternalEntryWatchStatus; use App\Models\List\External\ExternalEntry; use App\Models\List\ExternalProfile; use App\Models\Wiki\Anime; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Tests\TestCase; -class ExternalEntryTest extends TestCase -{ - /** - * The watch status attribute of an entry shall be cast to a ExternalEntryWatchStatus enum instance. - */ - public function testCastsWatchStatusToEnum(): void - { - $entry = ExternalEntry::factory() - ->for(ExternalProfile::factory()) - ->createOne(); +test('casts watch status to enum', function () { + $entry = ExternalEntry::factory() + ->for(ExternalProfile::factory()) + ->createOne(); - $status = $entry->watch_status; + $status = $entry->watch_status; - static::assertInstanceOf(ExternalEntryWatchStatus::class, $status); - } + $this->assertInstanceOf(ExternalEntryWatchStatus::class, $status); +}); - /** - * The is favorite attribute of an entry shall be cast to a bool. - */ - public function testCastsIsFavoriteToBool(): void - { - $entry = ExternalEntry::factory() - ->for(ExternalProfile::factory()) - ->createOne(); +test('casts is favorite to bool', function () { + $entry = ExternalEntry::factory() + ->for(ExternalProfile::factory()) + ->createOne(); - $is_favorite = $entry->is_favorite; + $is_favorite = $entry->is_favorite; - static::assertIsBool($is_favorite); - } + $this->assertIsBool($is_favorite); +}); - /** - * External entries shall be nameable. - */ - public function testNameable(): void - { - $entry = ExternalEntry::factory() - ->for(ExternalProfile::factory()) - ->createOne(); +test('nameable', function () { + $entry = ExternalEntry::factory() + ->for(ExternalProfile::factory()) + ->createOne(); - static::assertIsString($entry->getName()); - } + $this->assertIsString($entry->getName()); +}); - /** - * External entries shall have subtitle. - */ - public function testHasSubtitle(): void - { - $entry = ExternalEntry::factory() - ->for(ExternalProfile::factory()) - ->for(Anime::factory()) - ->createOne(); +test('has subtitle', function () { + $entry = ExternalEntry::factory() + ->for(ExternalProfile::factory()) + ->for(Anime::factory()) + ->createOne(); - static::assertIsString($entry->getSubtitle()); - } + $this->assertIsString($entry->getSubtitle()); +}); - /** - * External Entries shall belong to an External Profile. - */ - public function testProfile(): void - { - $entry = ExternalEntry::factory() - ->for(ExternalProfile::factory()) - ->createOne(); +test('profile', function () { + $entry = ExternalEntry::factory() + ->for(ExternalProfile::factory()) + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $entry->externalprofile()); - static::assertInstanceOf(ExternalProfile::class, $entry->externalprofile()->first()); - } + $this->assertInstanceOf(BelongsTo::class, $entry->externalprofile()); + $this->assertInstanceOf(ExternalProfile::class, $entry->externalprofile()->first()); +}); - /** - * External Entries shall belong to an Anime. - */ - public function testAnime(): void - { - $entry = ExternalEntry::factory() - ->for(ExternalProfile::factory()) - ->for(Anime::factory()) - ->createOne(); +test('anime', function () { + $entry = ExternalEntry::factory() + ->for(ExternalProfile::factory()) + ->for(Anime::factory()) + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $entry->anime()); - static::assertInstanceOf(Anime::class, $entry->anime()->first()); - } -} + $this->assertInstanceOf(BelongsTo::class, $entry->anime()); + $this->assertInstanceOf(Anime::class, $entry->anime()->first()); +}); diff --git a/tests/Unit/Models/List/External/ExternalTokenTest.php b/tests/Unit/Models/List/External/ExternalTokenTest.php index e681d0e16..8986720a3 100644 --- a/tests/Unit/Models/List/External/ExternalTokenTest.php +++ b/tests/Unit/Models/List/External/ExternalTokenTest.php @@ -2,63 +2,41 @@ declare(strict_types=1); -namespace Tests\Unit\Models\List\External; - use App\Models\Auth\User; use App\Models\List\External\ExternalToken; use App\Models\List\ExternalProfile; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Tests\TestCase; use Znck\Eloquent\Relations\BelongsToThrough; -class ExternalTokenTest extends TestCase -{ - /** - * External Tokens shall be nameable. - */ - public function testNameable(): void - { - $token = ExternalToken::factory() - ->createOne(); +test('nameable', function () { + $token = ExternalToken::factory() + ->createOne(); - static::assertIsString($token->getName()); - } + $this->assertIsString($token->getName()); +}); - /** - * External Tokens shall have subtitle. - */ - public function testHasSubtitle(): void - { - $token = ExternalToken::factory() - ->for(ExternalProfile::factory()) - ->createOne(); +test('has subtitle', function () { + $token = ExternalToken::factory() + ->for(ExternalProfile::factory()) + ->createOne(); - static::assertIsString($token->getSubtitle()); - } + $this->assertIsString($token->getSubtitle()); +}); - /** - * External Tokens shall belong to an External Profile. - */ - public function testProfile(): void - { - $token = ExternalToken::factory() - ->for(ExternalProfile::factory()) - ->createOne(); +test('profile', function () { + $token = ExternalToken::factory() + ->for(ExternalProfile::factory()) + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $token->externalprofile()); - static::assertInstanceOf(ExternalProfile::class, $token->externalprofile()->first()); - } + $this->assertInstanceOf(BelongsTo::class, $token->externalprofile()); + $this->assertInstanceOf(ExternalProfile::class, $token->externalprofile()->first()); +}); - /** - * External Tokens shall belong to a User through an External Profile. - */ - public function testUser(): void - { - $token = ExternalToken::factory() - ->for(ExternalProfile::factory()->for(User::factory())) - ->createOne(); +test('user', function () { + $token = ExternalToken::factory() + ->for(ExternalProfile::factory()->for(User::factory())) + ->createOne(); - static::assertInstanceOf(BelongsToThrough::class, $token->user()); - static::assertInstanceOf(User::class, $token->user()->first()); - } -} + $this->assertInstanceOf(BelongsToThrough::class, $token->user()); + $this->assertInstanceOf(User::class, $token->user()->first()); +}); diff --git a/tests/Unit/Models/List/ExternalProfileTest.php b/tests/Unit/Models/List/ExternalProfileTest.php index a7bbafa03..883aa7e1b 100644 --- a/tests/Unit/Models/List/ExternalProfileTest.php +++ b/tests/Unit/Models/List/ExternalProfileTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Models\List; - use App\Enums\Models\List\ExternalProfileSite; use App\Enums\Models\List\ExternalProfileVisibility; use App\Models\Auth\User; @@ -13,153 +11,108 @@ use App\Models\List\ExternalProfile; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasOne; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; -use Tests\TestCase; -class ExternalProfileTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The site attribute of a profile shall be cast to a ExternalProfileSite enum instance. - */ - public function testCastsSiteToEnum(): void - { - $profile = ExternalProfile::factory()->createOne(); +test('casts site to enum', function () { + $profile = ExternalProfile::factory()->createOne(); - $site = $profile->site; + $site = $profile->site; - static::assertInstanceOf(ExternalProfileSite::class, $site); - } + $this->assertInstanceOf(ExternalProfileSite::class, $site); +}); - /** - * The visibility attribute of a profile shall be cast to a ExternalProfileVisibility enum instance. - */ - public function testCastsVisibilityToEnum(): void - { - $profile = ExternalProfile::factory()->createOne(); +test('casts visibility to enum', function () { + $profile = ExternalProfile::factory()->createOne(); - $visibility = $profile->visibility; + $visibility = $profile->visibility; - static::assertInstanceOf(ExternalProfileVisibility::class, $visibility); - } + $this->assertInstanceOf(ExternalProfileVisibility::class, $visibility); +}); - /** - * Profile shall be nameable. - */ - public function testNameable(): void - { - $profile = ExternalProfile::factory()->createOne(); +test('nameable', function () { + $profile = ExternalProfile::factory()->createOne(); - static::assertIsString($profile->getName()); - } + $this->assertIsString($profile->getName()); +}); - /** - * Profile shall have subtitle. - */ - public function testHasSubtitle(): void - { - $profile = ExternalProfile::factory() - ->for(User::factory()) - ->createOne(); +test('has subtitle', function () { + $profile = ExternalProfile::factory() + ->for(User::factory()) + ->createOne(); - static::assertIsString($profile->getSubtitle()); - } + $this->assertIsString($profile->getSubtitle()); +}); - /** - * Public profiles shall be searchable. - */ - public function testSearchableIfPublic(): void - { - $profile = ExternalProfile::factory() - ->createOne([ - ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value, - ]); +test('searchable if public', function () { + $profile = ExternalProfile::factory() + ->createOne([ + ExternalProfile::ATTRIBUTE_VISIBILITY => ExternalProfileVisibility::PUBLIC->value, + ]); - static::assertTrue($profile->shouldBeSearchable()); - } + $this->assertTrue($profile->shouldBeSearchable()); +}); - /** - * Profiles shall not be searchable if not public. - */ - public function testNotSearchableIfNotPublic(): void - { - $visibility = null; +test('not searchable if not public', function () { + $visibility = null; - while ($visibility == null) { - $candidate = Arr::random(ExternalProfileVisibility::cases()); - if ($candidate !== ExternalProfileVisibility::PUBLIC) { - $visibility = $candidate; - } + while ($visibility == null) { + $candidate = Arr::random(ExternalProfileVisibility::cases()); + if ($candidate !== ExternalProfileVisibility::PUBLIC) { + $visibility = $candidate; } - - $profile = ExternalProfile::factory() - ->createOne([ - ExternalProfile::ATTRIBUTE_VISIBILITY => $visibility->value, - ]); - - static::assertFalse($profile->shouldBeSearchable()); } - /** - * Profile with a user shall be claimed. - */ - public function testClaimed(): void - { - $claimedProfile = ExternalProfile::factory() - ->for(User::factory()) - ->createOne(); + $profile = ExternalProfile::factory() + ->createOne([ + ExternalProfile::ATTRIBUTE_VISIBILITY => $visibility->value, + ]); - $unclaimedProfile = ExternalProfile::factory() - ->createOne(); + $this->assertFalse($profile->shouldBeSearchable()); +}); - static::assertTrue($claimedProfile->isClaimed()); - static::assertFalse($unclaimedProfile->isClaimed()); - } +test('claimed', function () { + $claimedProfile = ExternalProfile::factory() + ->for(User::factory()) + ->createOne(); - /** - * Profiles shall belong to a user. - */ - public function testUser(): void - { - $profile = ExternalProfile::factory() - ->for(User::factory()) - ->createOne(); + $unclaimedProfile = ExternalProfile::factory() + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $profile->user()); - static::assertInstanceOf(User::class, $profile->user()->first()); - } + $this->assertTrue($claimedProfile->isClaimed()); + $this->assertFalse($unclaimedProfile->isClaimed()); +}); - /** - * Profiles shall have a one-to-one relationship with the type external token. - */ - public function testExternalToken(): void - { - $profile = ExternalProfile::factory() - ->has(ExternalToken::factory(), ExternalProfile::RELATION_EXTERNAL_TOKEN) - ->createOne(); +test('user', function () { + $profile = ExternalProfile::factory() + ->for(User::factory()) + ->createOne(); - static::assertInstanceOf(HasOne::class, $profile->externaltoken()); - static::assertInstanceOf(ExternalToken::class, $profile->externaltoken()->first()); - } + $this->assertInstanceOf(BelongsTo::class, $profile->user()); + $this->assertInstanceOf(User::class, $profile->user()->first()); +}); - /** - * Profiles shall have a one-to-many relationship with the type ExternalEntry. - */ - public function testExternalEntries(): void - { - $entryCount = $this->faker->randomDigitNotNull(); +test('external token', function () { + $profile = ExternalProfile::factory() + ->has(ExternalToken::factory(), ExternalProfile::RELATION_EXTERNAL_TOKEN) + ->createOne(); - $profile = ExternalProfile::factory()->createOne(); + $this->assertInstanceOf(HasOne::class, $profile->externaltoken()); + $this->assertInstanceOf(ExternalToken::class, $profile->externaltoken()->first()); +}); - ExternalEntry::factory() - ->for($profile) - ->count($entryCount) - ->create(); +test('external entries', function () { + $entryCount = fake()->randomDigitNotNull(); - static::assertInstanceOf(HasMany::class, $profile->externalentries()); - static::assertEquals($entryCount, $profile->externalentries()->count()); - static::assertInstanceOf(ExternalEntry::class, $profile->externalentries()->first()); - } -} + $profile = ExternalProfile::factory()->createOne(); + + ExternalEntry::factory() + ->for($profile) + ->count($entryCount) + ->create(); + + $this->assertInstanceOf(HasMany::class, $profile->externalentries()); + $this->assertEquals($entryCount, $profile->externalentries()->count()); + $this->assertInstanceOf(ExternalEntry::class, $profile->externalentries()->first()); +}); diff --git a/tests/Unit/Models/List/Playlist/TrackTest.php b/tests/Unit/Models/List/Playlist/TrackTest.php index 4a038b004..6e15b480c 100644 --- a/tests/Unit/Models/List/Playlist/TrackTest.php +++ b/tests/Unit/Models/List/Playlist/TrackTest.php @@ -2,122 +2,88 @@ declare(strict_types=1); -namespace Tests\Unit\Models\List\Playlist; - use App\Models\Auth\User; use App\Models\List\Playlist; use App\Models\List\Playlist\PlaylistTrack; use App\Models\Wiki\Video; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Tests\TestCase; -class TrackTest extends TestCase -{ - /** - * Playlist Tracks shall be nameable. - */ - public function testNameable(): void - { - $track = PlaylistTrack::factory() - ->for(Playlist::factory()) - ->createOne(); +test('nameable', function () { + $track = PlaylistTrack::factory() + ->for(Playlist::factory()) + ->createOne(); - static::assertIsString($track->getName()); - } + $this->assertIsString($track->getName()); +}); - /** - * Playlist Tracks shall have subtitle. - */ - public function testHasSubtitle(): void - { - $track = PlaylistTrack::factory() - ->for(Playlist::factory()->for(User::factory())) - ->createOne(); +test('has subtitle', function () { + $track = PlaylistTrack::factory() + ->for(Playlist::factory()->for(User::factory())) + ->createOne(); - static::assertIsString($track->getSubtitle()); - } + $this->assertIsString($track->getSubtitle()); +}); - /** - * Playlists shall include playlist and track ids for hashids encoding. - */ - public function testHashids(): void - { - $playlist = Playlist::factory()->createOne(); +test('hashids', function () { + $playlist = Playlist::factory()->createOne(); - $track = PlaylistTrack::factory() - ->for($playlist) - ->createOne(); + $track = PlaylistTrack::factory() + ->for($playlist) + ->createOne(); - static::assertEmpty(array_diff([$playlist->playlist_id, $track->track_id], $track->hashids())); - static::assertEmpty(array_diff($track->hashids(), [$playlist->playlist_id, $track->track_id])); - } + $this->assertEmpty(array_diff([$playlist->playlist_id, $track->track_id], $track->hashids())); + $this->assertEmpty(array_diff($track->hashids(), [$playlist->playlist_id, $track->track_id])); +}); - /** - * Playlist Tracks shall belong to a Playlist. - */ - public function testPlaylist(): void - { - $track = PlaylistTrack::factory() - ->for(Playlist::factory()) - ->createOne(); +test('playlist', function () { + $track = PlaylistTrack::factory() + ->for(Playlist::factory()) + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $track->playlist()); - static::assertInstanceOf(Playlist::class, $track->playlist()->first()); - } + $this->assertInstanceOf(BelongsTo::class, $track->playlist()); + $this->assertInstanceOf(Playlist::class, $track->playlist()->first()); +}); - /** - * Playlist Tracks shall link to a previous Track. - */ - public function testPrevious(): void - { - $playlist = Playlist::factory()->createOne(); +test('previous', function () { + $playlist = Playlist::factory()->createOne(); - $track = PlaylistTrack::factory() - ->for($playlist) - ->createOne(); + $track = PlaylistTrack::factory() + ->for($playlist) + ->createOne(); - $previous = PlaylistTrack::factory() - ->for($playlist) - ->createOne(); + $previous = PlaylistTrack::factory() + ->for($playlist) + ->createOne(); - $track->previous()->associate($previous)->save(); + $track->previous()->associate($previous)->save(); - static::assertInstanceOf(BelongsTo::class, $track->previous()); - static::assertInstanceOf(PlaylistTrack::class, $track->previous()->first()); - } + $this->assertInstanceOf(BelongsTo::class, $track->previous()); + $this->assertInstanceOf(PlaylistTrack::class, $track->previous()->first()); +}); - /** - * Playlist Tracks shall link to a next Track. - */ - public function testNext(): void - { - $playlist = Playlist::factory()->createOne(); +test('next', function () { + $playlist = Playlist::factory()->createOne(); - $track = PlaylistTrack::factory() - ->for($playlist) - ->createOne(); + $track = PlaylistTrack::factory() + ->for($playlist) + ->createOne(); - $next = PlaylistTrack::factory() - ->for($playlist) - ->createOne(); + $next = PlaylistTrack::factory() + ->for($playlist) + ->createOne(); - $track->next()->associate($next)->save(); + $track->next()->associate($next)->save(); - static::assertInstanceOf(BelongsTo::class, $track->next()); - static::assertInstanceOf(PlaylistTrack::class, $track->next()->first()); - } + $this->assertInstanceOf(BelongsTo::class, $track->next()); + $this->assertInstanceOf(PlaylistTrack::class, $track->next()->first()); +}); - /** - * Playlist Tracks shall belong to a Video. - */ - public function testVideo(): void - { - $track = PlaylistTrack::factory() - ->for(Playlist::factory()) - ->for(Video::factory()) - ->createOne(); +test('video', function () { + $track = PlaylistTrack::factory() + ->for(Playlist::factory()) + ->for(Video::factory()) + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $track->video()); - static::assertInstanceOf(Video::class, $track->video()->first()); - } -} + $this->assertInstanceOf(BelongsTo::class, $track->video()); + $this->assertInstanceOf(Video::class, $track->video()->first()); +}); diff --git a/tests/Unit/Models/List/PlaylistTest.php b/tests/Unit/Models/List/PlaylistTest.php index 1e23437ea..fb97c7909 100644 --- a/tests/Unit/Models/List/PlaylistTest.php +++ b/tests/Unit/Models/List/PlaylistTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Models\List; - use App\Enums\Models\List\PlaylistVisibility; use App\Models\Auth\User; use App\Models\List\Playlist; @@ -13,190 +11,137 @@ use App\Pivots\List\PlaylistImage; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\HasMany; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; -use Tests\TestCase; -class PlaylistTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The visibility attribute of a playlist shall be cast to a PlaylistVisibility enum instance. - */ - public function testCastsSeasonToEnum(): void - { - $playlist = Playlist::factory()->createOne(); +test('casts season to enum', function () { + $playlist = Playlist::factory()->createOne(); - $visibility = $playlist->visibility; + $visibility = $playlist->visibility; - static::assertInstanceOf(PlaylistVisibility::class, $visibility); - } + $this->assertInstanceOf(PlaylistVisibility::class, $visibility); +}); - /** - * Playlist shall be nameable. - */ - public function testNameable(): void - { - $playlist = Playlist::factory()->createOne(); +test('nameable', function () { + $playlist = Playlist::factory()->createOne(); - static::assertIsString($playlist->getName()); - } + $this->assertIsString($playlist->getName()); +}); - /** - * Playlist shall have subtitle. - */ - public function testHasSubtitle(): void - { - $playlist = Playlist::factory() - ->for(User::factory()) - ->createOne(); +test('has subtitle', function () { + $playlist = Playlist::factory() + ->for(User::factory()) + ->createOne(); - static::assertIsString($playlist->getSubtitle()); - } + $this->assertIsString($playlist->getSubtitle()); +}); - /** - * Public playlists shall be searchable. - */ - public function testSearchableIfPublic(): void - { - $playlist = Playlist::factory() - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, - ]); +test('searchable if public', function () { + $playlist = Playlist::factory() + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC->value, + ]); - static::assertTrue($playlist->shouldBeSearchable()); - } + $this->assertTrue($playlist->shouldBeSearchable()); +}); - /** - * Playlists shall not be searchable if not public. - */ - public function testNotSearchableIfNotPublic(): void - { - $visibility = null; +test('not searchable if not public', function () { + $visibility = null; - while ($visibility == null) { - $candidate = Arr::random(PlaylistVisibility::cases()); - if ($candidate !== PlaylistVisibility::PUBLIC) { - $visibility = $candidate; - } + while ($visibility == null) { + $candidate = Arr::random(PlaylistVisibility::cases()); + if ($candidate !== PlaylistVisibility::PUBLIC) { + $visibility = $candidate; } - - $playlist = Playlist::factory() - ->createOne([ - Playlist::ATTRIBUTE_VISIBILITY => $visibility->value, - ]); - - static::assertFalse($playlist->shouldBeSearchable()); } - /** - * Playlists shall filter null user_id values from hashids. - */ - public function testHashidsNullableUser(): void - { - $playlist = Playlist::factory()->createOne(); + $playlist = Playlist::factory() + ->createOne([ + Playlist::ATTRIBUTE_VISIBILITY => $visibility->value, + ]); - static::assertEmpty(array_diff([$playlist->playlist_id], $playlist->hashids())); - static::assertEmpty(array_diff($playlist->hashids(), [$playlist->playlist_id])); - } + $this->assertFalse($playlist->shouldBeSearchable()); +}); - /** - * Playlists shall include nonnull user_id values from hashids. - */ - public function testHashidsNonNullUser(): void - { - $user = User::factory()->createOne(); +test('hashids nullable user', function () { + $playlist = Playlist::factory()->createOne(); - $playlist = Playlist::factory() - ->for($user) - ->createOne(); + $this->assertEmpty(array_diff([$playlist->playlist_id], $playlist->hashids())); + $this->assertEmpty(array_diff($playlist->hashids(), [$playlist->playlist_id])); +}); - static::assertEmpty(array_diff([$user->id, $playlist->playlist_id], $playlist->hashids())); - static::assertEmpty(array_diff($playlist->hashids(), [$user->id, $playlist->playlist_id])); - } +test('hashids non null user', function () { + $user = User::factory()->createOne(); - /** - * Playlists shall belong to a User. - */ - public function testUser(): void - { - $playlist = Playlist::factory() - ->for(User::factory()) - ->createOne(); + $playlist = Playlist::factory() + ->for($user) + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $playlist->user()); - static::assertInstanceOf(User::class, $playlist->user()->first()); - } + $this->assertEmpty(array_diff([$user->id, $playlist->playlist_id], $playlist->hashids())); + $this->assertEmpty(array_diff($playlist->hashids(), [$user->id, $playlist->playlist_id])); +}); - /** - * Playlists shall link to the first Track. - */ - public function testFirst(): void - { - $playlist = Playlist::factory() - ->createOne(); +test('user', function () { + $playlist = Playlist::factory() + ->for(User::factory()) + ->createOne(); - $first = PlaylistTrack::factory() - ->for($playlist) - ->createOne(); + $this->assertInstanceOf(BelongsTo::class, $playlist->user()); + $this->assertInstanceOf(User::class, $playlist->user()->first()); +}); - $playlist->first()->associate($first)->save(); +test('first', function () { + $playlist = Playlist::factory() + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $playlist->first()); - static::assertInstanceOf(PlaylistTrack::class, $playlist->first()->first()); - } + $first = PlaylistTrack::factory() + ->for($playlist) + ->createOne(); - /** - * Playlists shall link to the last Track. - */ - public function testLast(): void - { - $playlist = Playlist::factory()->createOne(); + $playlist->first()->associate($first)->save(); - $last = PlaylistTrack::factory() - ->for($playlist) - ->createOne(); + $this->assertInstanceOf(BelongsTo::class, $playlist->first()); + $this->assertInstanceOf(PlaylistTrack::class, $playlist->first()->first()); +}); - $playlist->last()->associate($last)->save(); +test('last', function () { + $playlist = Playlist::factory()->createOne(); - static::assertInstanceOf(BelongsTo::class, $playlist->last()); - static::assertInstanceOf(PlaylistTrack::class, $playlist->last()->first()); - } + $last = PlaylistTrack::factory() + ->for($playlist) + ->createOne(); - /** - * Playlists shall have a many-to-many relationship with the type Image. - */ - public function testImages(): void - { - $imageCount = $this->faker->randomDigitNotNull(); + $playlist->last()->associate($last)->save(); - $playlist = Playlist::factory() - ->has(Image::factory()->count($imageCount)) - ->createOne(); + $this->assertInstanceOf(BelongsTo::class, $playlist->last()); + $this->assertInstanceOf(PlaylistTrack::class, $playlist->last()->first()); +}); - static::assertInstanceOf(BelongsToMany::class, $playlist->images()); - static::assertEquals($imageCount, $playlist->images()->count()); - static::assertInstanceOf(Image::class, $playlist->images()->first()); - static::assertEquals(PlaylistImage::class, $playlist->images()->getPivotClass()); - } +test('images', function () { + $imageCount = fake()->randomDigitNotNull(); - /** - * Playlists shall have a one-to-many relationship with the type PlaylistTrack. - */ - public function testTracks(): void - { - $trackCount = $this->faker->randomDigitNotNull(); + $playlist = Playlist::factory() + ->has(Image::factory()->count($imageCount)) + ->createOne(); - $playlist = Playlist::factory()->createOne(); + $this->assertInstanceOf(BelongsToMany::class, $playlist->images()); + $this->assertEquals($imageCount, $playlist->images()->count()); + $this->assertInstanceOf(Image::class, $playlist->images()->first()); + $this->assertEquals(PlaylistImage::class, $playlist->images()->getPivotClass()); +}); - PlaylistTrack::factory() - ->for($playlist) - ->count($trackCount) - ->create(); +test('tracks', function () { + $trackCount = fake()->randomDigitNotNull(); - static::assertInstanceOf(HasMany::class, $playlist->tracks()); - static::assertEquals($trackCount, $playlist->tracks()->count()); - static::assertInstanceOf(PlaylistTrack::class, $playlist->tracks()->first()); - } -} + $playlist = Playlist::factory()->createOne(); + + PlaylistTrack::factory() + ->for($playlist) + ->count($trackCount) + ->create(); + + $this->assertInstanceOf(HasMany::class, $playlist->tracks()); + $this->assertEquals($trackCount, $playlist->tracks()->count()); + $this->assertInstanceOf(PlaylistTrack::class, $playlist->tracks()->first()); +}); diff --git a/tests/Unit/Models/User/Report/ReportStepTest.php b/tests/Unit/Models/User/Report/ReportStepTest.php index 933c960e0..b095bd68c 100644 --- a/tests/Unit/Models/User/Report/ReportStepTest.php +++ b/tests/Unit/Models/User/Report/ReportStepTest.php @@ -2,106 +2,71 @@ declare(strict_types=1); -namespace Tests\Unit\Models\User\Report; - use App\Enums\Models\User\ApprovableStatus; use App\Enums\Models\User\ReportActionType; use App\Models\User\Report; use App\Models\User\Report\ReportStep; use App\Models\Wiki\Anime; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Carbon; -use Tests\TestCase; -class ReportStepTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * Steps shall be nameable. - */ - public function testNameable(): void - { - $step = ReportStep::factory() - ->for(Report::factory()) - ->createOne(); +test('nameable', function () { + $step = ReportStep::factory() + ->for(Report::factory()) + ->createOne(); - static::assertIsString($step->getName()); - } + $this->assertIsString($step->getName()); +}); - /** - * Steps shall have subtitle. - */ - public function testHasSubtitle(): void - { - $step = ReportStep::factory() - ->for(Report::factory()) - ->createOne(); +test('has subtitle', function () { + $step = ReportStep::factory() + ->for(Report::factory()) + ->createOne(); - static::assertIsString($step->getSubtitle()); - } + $this->assertIsString($step->getSubtitle()); +}); - /** - * The action attribute of a step shall be cast to an ReportActionType enum instance. - */ - public function testCastsActionToEnum(): void - { - $step = ReportStep::factory() - ->for(Report::factory()) - ->createOne(); +test('casts action to enum', function () { + $step = ReportStep::factory() + ->for(Report::factory()) + ->createOne(); - static::assertInstanceOf(ReportActionType::class, $step->action); - } + $this->assertInstanceOf(ReportActionType::class, $step->action); +}); - /** - * The action attribute of a step shall be cast to an array. - */ - public function testCastsFieldsToArray(): void - { - $anime = Anime::factory()->makeOne(); +test('casts fields to array', function () { + $anime = Anime::factory()->makeOne(); - $step = ReportStep::factory() - ->for(Report::factory()) - ->createOne([ReportStep::ATTRIBUTE_FIELDS => $anime->attributesToArray()]); + $step = ReportStep::factory() + ->for(Report::factory()) + ->createOne([ReportStep::ATTRIBUTE_FIELDS => $anime->attributesToArray()]); - static::assertIsArray($step->fields); - } + $this->assertIsArray($step->fields); +}); - /** - * Steps shall cast the finished_at attribute to datetime. - */ - public function testCastsFinishedAt(): void - { - $step = ReportStep::factory() - ->for(Report::factory()) - ->createOne([ReportStep::ATTRIBUTE_FINISHED_AT => now()]); +test('casts finished at', function () { + $step = ReportStep::factory() + ->for(Report::factory()) + ->createOne([ReportStep::ATTRIBUTE_FINISHED_AT => now()]); - static::assertInstanceOf(Carbon::class, $step->finished_at); - } + $this->assertInstanceOf(Carbon::class, $step->finished_at); +}); - /** - * The status attribute of a step shall be cast to an ApprovableStatus enum instance. - */ - public function testCastsStatusToEnum(): void - { - $step = ReportStep::factory() - ->for(Report::factory()) - ->createOne(); +test('casts status to enum', function () { + $step = ReportStep::factory() + ->for(Report::factory()) + ->createOne(); - static::assertInstanceOf(ApprovableStatus::class, $step->status); - } + $this->assertInstanceOf(ApprovableStatus::class, $step->status); +}); - /** - * A step shall have a report attached. - */ - public function testReport(): void - { - $step = ReportStep::factory() - ->for(Report::factory()) - ->createOne(); +test('report', function () { + $step = ReportStep::factory() + ->for(Report::factory()) + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $step->report()); - static::assertInstanceOf(Report::class, $step->report()->first()); - } -} + $this->assertInstanceOf(BelongsTo::class, $step->report()); + $this->assertInstanceOf(Report::class, $step->report()->first()); +}); diff --git a/tests/Unit/Models/User/ReportTest.php b/tests/Unit/Models/User/ReportTest.php index 9fed7dcfb..dc3150471 100644 --- a/tests/Unit/Models/User/ReportTest.php +++ b/tests/Unit/Models/User/ReportTest.php @@ -2,104 +2,69 @@ declare(strict_types=1); -namespace Tests\Unit\Models\User; - use App\Enums\Models\User\ApprovableStatus; use App\Models\Auth\User; use App\Models\User\Report; use App\Models\User\Report\ReportStep; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Carbon; -use Tests\TestCase; -class ReportTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * Reports shall be nameable. - */ - public function testNameable(): void - { - $report = Report::factory()->createOne(); +test('nameable', function () { + $report = Report::factory()->createOne(); - static::assertIsString($report->getName()); - } + $this->assertIsString($report->getName()); +}); - /** - * Reports shall have subtitle. - */ - public function testHasSubtitle(): void - { - $report = Report::factory()->createOne(); +test('has subtitle', function () { + $report = Report::factory()->createOne(); - static::assertIsString($report->getSubtitle()); - } + $this->assertIsString($report->getSubtitle()); +}); - /** - * Reports shall cast the finished_at attribute to datetime. - */ - public function testCastsFinishedAt(): void - { - $report = Report::factory()->createOne([Report::ATTRIBUTE_FINISHED_AT => now()]); +test('casts finished at', function () { + $report = Report::factory()->createOne([Report::ATTRIBUTE_FINISHED_AT => now()]); - static::assertInstanceOf(Carbon::class, $report->finished_at); - } + $this->assertInstanceOf(Carbon::class, $report->finished_at); +}); - /** - * The status attribute of a report shall be cast to an ApprovableStatus enum instance. - */ - public function testCastsStatusToEnum(): void - { - $report = Report::factory()->createOne(); +test('casts status to enum', function () { + $report = Report::factory()->createOne(); - static::assertInstanceOf(ApprovableStatus::class, $report->status); - } + $this->assertInstanceOf(ApprovableStatus::class, $report->status); +}); - /** - * Reports shall have a one-to-many relationship with the type ReportStep. - */ - public function testSteps(): void - { - $stepsCount = $this->faker->randomDigitNotNull(); +test('steps', function () { + $stepsCount = fake()->randomDigitNotNull(); - $report = Report::factory()->createOne(); + $report = Report::factory()->createOne(); - ReportStep::factory() - ->for($report) - ->count($stepsCount) - ->create(); + ReportStep::factory() + ->for($report) + ->count($stepsCount) + ->create(); - static::assertInstanceOf(HasMany::class, $report->steps()); - static::assertEquals($stepsCount, $report->steps()->count()); - static::assertInstanceOf(ReportStep::class, $report->steps()->first()); - } + $this->assertInstanceOf(HasMany::class, $report->steps()); + $this->assertEquals($stepsCount, $report->steps()->count()); + $this->assertInstanceOf(ReportStep::class, $report->steps()->first()); +}); - /** - * A report shall have a user attached. - */ - public function testUser(): void - { - $report = Report::factory() - ->for(User::factory(), Report::RELATION_USER) - ->createOne(); +test('user', function () { + $report = Report::factory() + ->for(User::factory(), Report::RELATION_USER) + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $report->user()); - static::assertInstanceOf(User::class, $report->user()->first()); - } + $this->assertInstanceOf(BelongsTo::class, $report->user()); + $this->assertInstanceOf(User::class, $report->user()->first()); +}); - /** - * A report shall have a moderator attached. - */ - public function testModerator(): void - { - $report = Report::factory() - ->for(User::factory(), Report::RELATION_MODERATOR) - ->createOne(); +test('moderator', function () { + $report = Report::factory() + ->for(User::factory(), Report::RELATION_MODERATOR) + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $report->moderator()); - static::assertInstanceOf(User::class, $report->moderator()->first()); - } -} + $this->assertInstanceOf(BelongsTo::class, $report->moderator()); + $this->assertInstanceOf(User::class, $report->moderator()->first()); +}); diff --git a/tests/Unit/Models/Wiki/Anime/AnimeSynonymTest.php b/tests/Unit/Models/Wiki/Anime/AnimeSynonymTest.php index 6135d75f1..7e56d5f06 100644 --- a/tests/Unit/Models/Wiki/Anime/AnimeSynonymTest.php +++ b/tests/Unit/Models/Wiki/Anime/AnimeSynonymTest.php @@ -2,91 +2,61 @@ declare(strict_types=1); -namespace Tests\Unit\Models\Wiki\Anime; - use App\Enums\Models\Wiki\AnimeSynonymType; use App\Models\Wiki\Anime; use App\Models\Wiki\Anime\AnimeSynonym; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; -class AnimeSynonymTest extends TestCase -{ - use WithFaker; +uses(WithFaker::class); - /** - * The type attribute of a synonym shall be cast to a AnimeSynonymType enum instance. - */ - public function testCastsTypeToEnum(): void - { - $theme = AnimeSynonym::factory() - ->for(Anime::factory()) - ->createOne(); +test('casts type to enum', function () { + $theme = AnimeSynonym::factory() + ->for(Anime::factory()) + ->createOne(); - $type = $theme->type; + $type = $theme->type; - static::assertInstanceOf(AnimeSynonymType::class, $type); - } + $this->assertInstanceOf(AnimeSynonymType::class, $type); +}); - /** - * Synonym shall be a searchable resource. - */ - public function testSearchableAs(): void - { - $synonym = AnimeSynonym::factory() - ->for(Anime::factory()) - ->createOne(); +test('searchable as', function () { + $synonym = AnimeSynonym::factory() + ->for(Anime::factory()) + ->createOne(); - static::assertIsString($synonym->searchableAs()); - } + $this->assertIsString($synonym->searchableAs()); +}); - /** - * Synonym shall be a searchable resource. - */ - public function testToSearchableArray(): void - { - $synonym = AnimeSynonym::factory() - ->for(Anime::factory()) - ->createOne(); +test('to searchable array', function () { + $synonym = AnimeSynonym::factory() + ->for(Anime::factory()) + ->createOne(); - static::assertIsArray($synonym->toSearchableArray()); - } + $this->assertIsArray($synonym->toSearchableArray()); +}); - /** - * Synonyms shall be nameable. - */ - public function testNameable(): void - { - $synonym = AnimeSynonym::factory() - ->for(Anime::factory()) - ->createOne(); +test('nameable', function () { + $synonym = AnimeSynonym::factory() + ->for(Anime::factory()) + ->createOne(); - static::assertIsString($synonym->getName()); - } + $this->assertIsString($synonym->getName()); +}); - /** - * Synonyms shall have subtitle. - */ - public function testHasSubtitle(): void - { - $synonym = AnimeSynonym::factory() - ->for(Anime::factory()) - ->createOne(); +test('has subtitle', function () { + $synonym = AnimeSynonym::factory() + ->for(Anime::factory()) + ->createOne(); - static::assertIsString($synonym->getSubtitle()); - } + $this->assertIsString($synonym->getSubtitle()); +}); - /** - * Synonyms shall belong to an Anime. - */ - public function testAnime(): void - { - $synonym = AnimeSynonym::factory() - ->for(Anime::factory()) - ->createOne(); +test('anime', function () { + $synonym = AnimeSynonym::factory() + ->for(Anime::factory()) + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $synonym->anime()); - static::assertInstanceOf(Anime::class, $synonym->anime()->first()); - } -} + $this->assertInstanceOf(BelongsTo::class, $synonym->anime()); + $this->assertInstanceOf(Anime::class, $synonym->anime()->first()); +}); diff --git a/tests/Unit/Models/Wiki/Anime/AnimeThemeTest.php b/tests/Unit/Models/Wiki/Anime/AnimeThemeTest.php index a4f02ad33..fec3703d2 100644 --- a/tests/Unit/Models/Wiki/Anime/AnimeThemeTest.php +++ b/tests/Unit/Models/Wiki/Anime/AnimeThemeTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Models\Wiki\Anime; - use App\Enums\Models\Wiki\ThemeType; use App\Models\Wiki\Anime; use App\Models\Wiki\Anime\AnimeTheme; @@ -13,141 +11,97 @@ use App\Models\Wiki\Song; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; -class AnimeThemeTest extends TestCase -{ - use WithFaker; +uses(WithFaker::class); - /** - * The type attribute of a theme shall be cast to a ThemeType enum instance. - */ - public function testCastsTypeToEnum(): void - { - $theme = AnimeTheme::factory() - ->for(Anime::factory()) - ->createOne(); +test('casts type to enum', function () { + $theme = AnimeTheme::factory() + ->for(Anime::factory()) + ->createOne(); - $type = $theme->type; + $type = $theme->type; - static::assertInstanceOf(ThemeType::class, $type); - } + $this->assertInstanceOf(ThemeType::class, $type); +}); - /** - * Theme shall be a searchable resource. - */ - public function testSearchableAs(): void - { - $theme = AnimeTheme::factory() - ->for(Anime::factory()) - ->createOne(); +test('searchable as', function () { + $theme = AnimeTheme::factory() + ->for(Anime::factory()) + ->createOne(); - static::assertIsString($theme->searchableAs()); - } + $this->assertIsString($theme->searchableAs()); +}); - /** - * Theme shall be a searchable resource. - */ - public function testToSearchableArray(): void - { - $theme = AnimeTheme::factory() - ->for(Anime::factory()) - ->createOne(); +test('to searchable array', function () { + $theme = AnimeTheme::factory() + ->for(Anime::factory()) + ->createOne(); - static::assertIsArray($theme->toSearchableArray()); - } + $this->assertIsArray($theme->toSearchableArray()); +}); - /** - * Themes shall be nameable. - */ - public function testNameable(): void - { - $theme = AnimeTheme::factory() - ->for(Anime::factory()) - ->createOne(); +test('nameable', function () { + $theme = AnimeTheme::factory() + ->for(Anime::factory()) + ->createOne(); - static::assertIsString($theme->getName()); - } + $this->assertIsString($theme->getName()); +}); - /** - * Themes shall have subtitle. - */ - public function testHasSubtitle(): void - { - $theme = AnimeTheme::factory() - ->for(Anime::factory()) - ->createOne(); +test('has subtitle', function () { + $theme = AnimeTheme::factory() + ->for(Anime::factory()) + ->createOne(); - static::assertIsString($theme->getSubtitle()); - } + $this->assertIsString($theme->getSubtitle()); +}); - /** - * Themes shall belong to an Anime. - */ - public function testAnime(): void - { - $theme = AnimeTheme::factory() - ->for(Anime::factory()) - ->createOne(); +test('anime', function () { + $theme = AnimeTheme::factory() + ->for(Anime::factory()) + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $theme->anime()); - static::assertInstanceOf(Anime::class, $theme->anime()->first()); - } + $this->assertInstanceOf(BelongsTo::class, $theme->anime()); + $this->assertInstanceOf(Anime::class, $theme->anime()->first()); +}); - /** - * Themes shall belong to a Group. - */ - public function testGroup(): void - { - $theme = AnimeTheme::factory() - ->for(Anime::factory()) - ->for(Group::factory()) - ->createOne(); +test('group', function () { + $theme = AnimeTheme::factory() + ->for(Anime::factory()) + ->for(Group::factory()) + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $theme->group()); - static::assertInstanceOf(Group::class, $theme->group()->first()); - } + $this->assertInstanceOf(BelongsTo::class, $theme->group()); + $this->assertInstanceOf(Group::class, $theme->group()->first()); +}); - /** - * Themes shall belong to a Song. - */ - public function testSong(): void - { - $theme = AnimeTheme::factory() - ->for(Anime::factory()) - ->for(Song::factory()) - ->createOne(); +test('song', function () { + $theme = AnimeTheme::factory() + ->for(Anime::factory()) + ->for(Song::factory()) + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $theme->song()); - static::assertInstanceOf(Song::class, $theme->song()->first()); - } + $this->assertInstanceOf(BelongsTo::class, $theme->song()); + $this->assertInstanceOf(Song::class, $theme->song()->first()); +}); - /** - * Theme shall have a one-to-many relationship with the type Entry. - */ - public function testEntries(): void - { - $entryCount = $this->faker->randomDigitNotNull(); +test('entries', function () { + $entryCount = fake()->randomDigitNotNull(); - $theme = AnimeTheme::factory() - ->for(Anime::factory()) - ->has(AnimeThemeEntry::factory()->count($entryCount)) - ->createOne(); + $theme = AnimeTheme::factory() + ->for(Anime::factory()) + ->has(AnimeThemeEntry::factory()->count($entryCount)) + ->createOne(); - static::assertInstanceOf(HasMany::class, $theme->animethemeentries()); - static::assertEquals($entryCount, $theme->animethemeentries()->count()); - static::assertInstanceOf(AnimeThemeEntry::class, $theme->animethemeentries()->first()); - } + $this->assertInstanceOf(HasMany::class, $theme->animethemeentries()); + $this->assertEquals($entryCount, $theme->animethemeentries()->count()); + $this->assertInstanceOf(AnimeThemeEntry::class, $theme->animethemeentries()->first()); +}); - /** - * Themes shall have a generated slug on creation. - */ - public function testThemeCreatesSlug(): void - { - $theme = AnimeTheme::factory() - ->for(Anime::factory()) - ->createOne(); +test('theme creates slug', function () { + $theme = AnimeTheme::factory() + ->for(Anime::factory()) + ->createOne(); - static::assertArrayHasKey('slug', $theme); - } -} + $this->assertArrayHasKey('slug', $theme); +}); diff --git a/tests/Unit/Models/Wiki/Anime/Theme/AnimeThemeEntryTest.php b/tests/Unit/Models/Wiki/Anime/Theme/AnimeThemeEntryTest.php index 447018f5f..0bf3c9af3 100644 --- a/tests/Unit/Models/Wiki/Anime/Theme/AnimeThemeEntryTest.php +++ b/tests/Unit/Models/Wiki/Anime/Theme/AnimeThemeEntryTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Models\Wiki\Anime\Theme; - use App\Models\Wiki\Anime; use App\Models\Wiki\Anime\AnimeTheme; use App\Models\Wiki\Anime\Theme\AnimeThemeEntry; @@ -12,102 +10,70 @@ use App\Pivots\Wiki\AnimeThemeEntryVideo; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; use Znck\Eloquent\Relations\BelongsToThrough; -class AnimeThemeEntryTest extends TestCase -{ - use WithFaker; +uses(WithFaker::class); - /** - * Entry shall be a searchable resource. - */ - public function testSearchableAs(): void - { - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); +test('searchable as', function () { + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - static::assertIsString($entry->searchableAs()); - } + $this->assertIsString($entry->searchableAs()); +}); - /** - * Entry shall be a searchable resource. - */ - public function testToSearchableArray(): void - { - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); +test('to searchable array', function () { + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - static::assertIsArray($entry->toSearchableArray()); - } + $this->assertIsArray($entry->toSearchableArray()); +}); - /** - * Entries shall be nameable. - */ - public function testNameable(): void - { - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); +test('nameable', function () { + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - static::assertIsString($entry->getName()); - } + $this->assertIsString($entry->getName()); +}); - /** - * Entries shall have subtitle. - */ - public function testHasSubtitle(): void - { - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); +test('has subtitle', function () { + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - static::assertIsString($entry->getSubtitle()); - } + $this->assertIsString($entry->getSubtitle()); +}); - /** - * Entries shall belong to a Theme. - */ - public function testTheme(): void - { - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); +test('theme', function () { + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $entry->animetheme()); - static::assertInstanceOf(AnimeTheme::class, $entry->animetheme()->first()); - } + $this->assertInstanceOf(BelongsTo::class, $entry->animetheme()); + $this->assertInstanceOf(AnimeTheme::class, $entry->animetheme()->first()); +}); - /** - * Entries shall have a many-to-many relationship with the type Video. - */ - public function testVideos(): void - { - $videoCount = $this->faker->randomDigitNotNull(); +test('videos', function () { + $videoCount = fake()->randomDigitNotNull(); - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->has(Video::factory()->count($videoCount)) - ->createOne(); + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->has(Video::factory()->count($videoCount)) + ->createOne(); - static::assertInstanceOf(BelongsToMany::class, $entry->videos()); - static::assertEquals($videoCount, $entry->videos()->count()); - static::assertInstanceOf(Video::class, $entry->videos()->first()); - static::assertEquals(AnimeThemeEntryVideo::class, $entry->videos()->getPivotClass()); - } + $this->assertInstanceOf(BelongsToMany::class, $entry->videos()); + $this->assertEquals($videoCount, $entry->videos()->count()); + $this->assertInstanceOf(Video::class, $entry->videos()->first()); + $this->assertEquals(AnimeThemeEntryVideo::class, $entry->videos()->getPivotClass()); +}); - /** - * Entries shall belong to an Anime through a Theme. - */ - public function testAnime(): void - { - $entry = AnimeThemeEntry::factory() - ->for(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); +test('anime', function () { + $entry = AnimeThemeEntry::factory() + ->for(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - static::assertInstanceOf(BelongsToThrough::class, $entry->anime()); - static::assertInstanceOf(Anime::class, $entry->anime()->first()); - } -} + $this->assertInstanceOf(BelongsToThrough::class, $entry->anime()); + $this->assertInstanceOf(Anime::class, $entry->anime()->first()); +}); diff --git a/tests/Unit/Models/Wiki/AnimeTest.php b/tests/Unit/Models/Wiki/AnimeTest.php index f8f9a2d7f..233aa70a3 100644 --- a/tests/Unit/Models/Wiki/AnimeTest.php +++ b/tests/Unit/Models/Wiki/AnimeTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Models\Wiki; - use App\Enums\Models\Wiki\AnimeMediaFormat; use App\Enums\Models\Wiki\AnimeSeason; use App\Models\Wiki\Anime; @@ -20,173 +18,121 @@ use App\Pivots\Wiki\AnimeStudio; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; -class AnimeTest extends TestCase -{ - use WithFaker; +uses(WithFaker::class); - /** - * The season attribute of an anime shall be cast to an AnimeSeason enum instance. - */ - public function testCastsSeasonToEnum(): void - { - $anime = Anime::factory()->createOne(); +test('casts season to enum', function () { + $anime = Anime::factory()->createOne(); - $season = $anime->season; + $season = $anime->season; - static::assertInstanceOf(AnimeSeason::class, $season); - } + $this->assertInstanceOf(AnimeSeason::class, $season); +}); - /** - * The media_format attribute of an anime shall be cast to an AnimeMediaFormat enum instance. - */ - public function testCastsMediaFormatToEnum(): void - { - $anime = Anime::factory()->createOne(); +test('casts media format to enum', function () { + $anime = Anime::factory()->createOne(); - $media_format = $anime->media_format; + $media_format = $anime->media_format; - static::assertInstanceOf(AnimeMediaFormat::class, $media_format); - } + $this->assertInstanceOf(AnimeMediaFormat::class, $media_format); +}); - /** - * Anime shall be a searchable resource. - */ - public function testSearchableAs(): void - { - $anime = Anime::factory()->createOne(); +test('searchable as', function () { + $anime = Anime::factory()->createOne(); - static::assertIsString($anime->searchableAs()); - } + $this->assertIsString($anime->searchableAs()); +}); - /** - * Anime shall be a searchable resource. - */ - public function testToSearchableArray(): void - { - $anime = Anime::factory()->createOne(); +test('to searchable array', function () { + $anime = Anime::factory()->createOne(); - static::assertIsArray($anime->toSearchableArray()); - } + $this->assertIsArray($anime->toSearchableArray()); +}); - /** - * Anime shall be nameable. - */ - public function testNameable(): void - { - $anime = Anime::factory()->createOne(); +test('nameable', function () { + $anime = Anime::factory()->createOne(); - static::assertIsString($anime->getName()); - } + $this->assertIsString($anime->getName()); +}); - /** - * Anime shall have subtitle. - */ - public function testHasSubtitle(): void - { - $anime = Anime::factory()->createOne(); +test('has subtitle', function () { + $anime = Anime::factory()->createOne(); - static::assertIsString($anime->getSubtitle()); - } + $this->assertIsString($anime->getSubtitle()); +}); - /** - * Anime shall have a one-to-many relationship with the type Synonym. - */ - public function testSynonyms(): void - { - $synonymCount = $this->faker->randomDigitNotNull(); +test('synonyms', function () { + $synonymCount = fake()->randomDigitNotNull(); - $anime = Anime::factory() - ->has(AnimeSynonym::factory()->count($synonymCount)) - ->createOne(); + $anime = Anime::factory() + ->has(AnimeSynonym::factory()->count($synonymCount)) + ->createOne(); - static::assertInstanceOf(HasMany::class, $anime->animesynonyms()); - static::assertEquals($synonymCount, $anime->animesynonyms()->count()); - static::assertInstanceOf(AnimeSynonym::class, $anime->animesynonyms()->first()); - } + $this->assertInstanceOf(HasMany::class, $anime->animesynonyms()); + $this->assertEquals($synonymCount, $anime->animesynonyms()->count()); + $this->assertInstanceOf(AnimeSynonym::class, $anime->animesynonyms()->first()); +}); - /** - * Anime shall have a many-to-many relationship with the type Series. - */ - public function testSeries(): void - { - $seriesCount = $this->faker->randomDigitNotNull(); +test('series', function () { + $seriesCount = fake()->randomDigitNotNull(); - $anime = Anime::factory() - ->has(Series::factory()->count($seriesCount)) - ->createOne(); + $anime = Anime::factory() + ->has(Series::factory()->count($seriesCount)) + ->createOne(); - static::assertInstanceOf(BelongsToMany::class, $anime->series()); - static::assertEquals($seriesCount, $anime->series()->count()); - static::assertInstanceOf(Series::class, $anime->series()->first()); - static::assertEquals(AnimeSeries::class, $anime->series()->getPivotClass()); - } + $this->assertInstanceOf(BelongsToMany::class, $anime->series()); + $this->assertEquals($seriesCount, $anime->series()->count()); + $this->assertInstanceOf(Series::class, $anime->series()->first()); + $this->assertEquals(AnimeSeries::class, $anime->series()->getPivotClass()); +}); - /** - * Anime shall have a one-to-many relationship with the type Theme. - */ - public function testThemes(): void - { - $themeCount = $this->faker->randomDigitNotNull(); +test('themes', function () { + $themeCount = fake()->randomDigitNotNull(); - $anime = Anime::factory() - ->has(AnimeTheme::factory()->count($themeCount)) - ->createOne(); + $anime = Anime::factory() + ->has(AnimeTheme::factory()->count($themeCount)) + ->createOne(); - static::assertInstanceOf(HasMany::class, $anime->animethemes()); - static::assertEquals($themeCount, $anime->animethemes()->count()); - static::assertInstanceOf(AnimeTheme::class, $anime->animethemes()->first()); - } + $this->assertInstanceOf(HasMany::class, $anime->animethemes()); + $this->assertEquals($themeCount, $anime->animethemes()->count()); + $this->assertInstanceOf(AnimeTheme::class, $anime->animethemes()->first()); +}); - /** - * Anime shall have a many-to-many relationship with the type ExternalResource. - */ - public function testExternalResources(): void - { - $resourceCount = $this->faker->randomDigitNotNull(); +test('external resources', function () { + $resourceCount = fake()->randomDigitNotNull(); - $anime = Anime::factory() - ->has(ExternalResource::factory()->count($resourceCount), 'resources') - ->createOne(); + $anime = Anime::factory() + ->has(ExternalResource::factory()->count($resourceCount), 'resources') + ->createOne(); - static::assertInstanceOf(BelongsToMany::class, $anime->resources()); - static::assertEquals($resourceCount, $anime->resources()->count()); - static::assertInstanceOf(ExternalResource::class, $anime->resources()->first()); - static::assertEquals(AnimeResource::class, $anime->resources()->getPivotClass()); - } + $this->assertInstanceOf(BelongsToMany::class, $anime->resources()); + $this->assertEquals($resourceCount, $anime->resources()->count()); + $this->assertInstanceOf(ExternalResource::class, $anime->resources()->first()); + $this->assertEquals(AnimeResource::class, $anime->resources()->getPivotClass()); +}); - /** - * Anime shall have a many-to-many relationship with the type Image. - */ - public function testImages(): void - { - $imageCount = $this->faker->randomDigitNotNull(); +test('images', function () { + $imageCount = fake()->randomDigitNotNull(); - $anime = Anime::factory() - ->has(Image::factory()->count($imageCount)) - ->createOne(); + $anime = Anime::factory() + ->has(Image::factory()->count($imageCount)) + ->createOne(); - static::assertInstanceOf(BelongsToMany::class, $anime->images()); - static::assertEquals($imageCount, $anime->images()->count()); - static::assertInstanceOf(Image::class, $anime->images()->first()); - static::assertEquals(AnimeImage::class, $anime->images()->getPivotClass()); - } + $this->assertInstanceOf(BelongsToMany::class, $anime->images()); + $this->assertEquals($imageCount, $anime->images()->count()); + $this->assertInstanceOf(Image::class, $anime->images()->first()); + $this->assertEquals(AnimeImage::class, $anime->images()->getPivotClass()); +}); - /** - * Anime shall have a many-to-many relationship with the type Studio. - */ - public function testStudios(): void - { - $studioCount = $this->faker->randomDigitNotNull(); +test('studios', function () { + $studioCount = fake()->randomDigitNotNull(); - $anime = Anime::factory() - ->has(Studio::factory()->count($studioCount)) - ->createOne(); + $anime = Anime::factory() + ->has(Studio::factory()->count($studioCount)) + ->createOne(); - static::assertInstanceOf(BelongsToMany::class, $anime->studios()); - static::assertEquals($studioCount, $anime->studios()->count()); - static::assertInstanceOf(Studio::class, $anime->studios()->first()); - static::assertEquals(AnimeStudio::class, $anime->studios()->getPivotClass()); - } -} + $this->assertInstanceOf(BelongsToMany::class, $anime->studios()); + $this->assertEquals($studioCount, $anime->studios()->count()); + $this->assertInstanceOf(Studio::class, $anime->studios()->first()); + $this->assertEquals(AnimeStudio::class, $anime->studios()->getPivotClass()); +}); diff --git a/tests/Unit/Models/Wiki/ArtistTest.php b/tests/Unit/Models/Wiki/ArtistTest.php index 8ec3c2bea..4d6891c6a 100644 --- a/tests/Unit/Models/Wiki/ArtistTest.php +++ b/tests/Unit/Models/Wiki/ArtistTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Models\Wiki; - use App\Models\Wiki\Artist; use App\Models\Wiki\ExternalResource; use App\Models\Wiki\Image; @@ -14,134 +12,94 @@ use App\Pivots\Wiki\ArtistResource; use App\Pivots\Wiki\ArtistSong; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; -class ArtistTest extends TestCase -{ - use WithFaker; +uses(WithFaker::class); - /** - * Artist shall be a searchable resource. - */ - public function testSearchableAs(): void - { - $artist = Artist::factory()->createOne(); +test('searchable as', function () { + $artist = Artist::factory()->createOne(); - static::assertIsString($artist->searchableAs()); - } + $this->assertIsString($artist->searchableAs()); +}); - /** - * Artist shall be a searchable resource. - */ - public function testToSearchableArray(): void - { - $artist = Artist::factory()->createOne(); +test('to searchable array', function () { + $artist = Artist::factory()->createOne(); - static::assertIsArray($artist->toSearchableArray()); - } + $this->assertIsArray($artist->toSearchableArray()); +}); - /** - * Artists shall be nameable. - */ - public function testNameable(): void - { - $artist = Artist::factory()->createOne(); +test('nameable', function () { + $artist = Artist::factory()->createOne(); - static::assertIsString($artist->getName()); - } + $this->assertIsString($artist->getName()); +}); - /** - * Artists shall have subtitle. - */ - public function testHasSubtitle(): void - { - $artist = Artist::factory()->createOne(); +test('has subtitle', function () { + $artist = Artist::factory()->createOne(); - static::assertIsString($artist->getSubtitle()); - } + $this->assertIsString($artist->getSubtitle()); +}); - /** - * Artist shall have a many-to-many relationship with the type Song. - */ - public function testSongs(): void - { - $songCount = $this->faker->randomDigitNotNull(); +test('songs', function () { + $songCount = fake()->randomDigitNotNull(); - $artist = Artist::factory() - ->has(Song::factory()->count($songCount)) - ->createOne(); + $artist = Artist::factory() + ->has(Song::factory()->count($songCount)) + ->createOne(); - static::assertInstanceOf(BelongsToMany::class, $artist->songs()); - static::assertEquals($songCount, $artist->songs()->count()); - static::assertInstanceOf(Song::class, $artist->songs()->first()); - static::assertEquals(ArtistSong::class, $artist->songs()->getPivotClass()); - } + $this->assertInstanceOf(BelongsToMany::class, $artist->songs()); + $this->assertEquals($songCount, $artist->songs()->count()); + $this->assertInstanceOf(Song::class, $artist->songs()->first()); + $this->assertEquals(ArtistSong::class, $artist->songs()->getPivotClass()); +}); - /** - * Artist shall have a many-to-many relationship with the type ExternalResource. - */ - public function testExternalResources(): void - { - $resourceCount = $this->faker->randomDigitNotNull(); +test('external resources', function () { + $resourceCount = fake()->randomDigitNotNull(); - $artist = Artist::factory() - ->has(ExternalResource::factory()->count($resourceCount), 'resources') - ->createOne(); + $artist = Artist::factory() + ->has(ExternalResource::factory()->count($resourceCount), 'resources') + ->createOne(); - static::assertInstanceOf(BelongsToMany::class, $artist->resources()); - static::assertEquals($resourceCount, $artist->resources()->count()); - static::assertInstanceOf(ExternalResource::class, $artist->resources()->first()); - static::assertEquals(ArtistResource::class, $artist->resources()->getPivotClass()); - } + $this->assertInstanceOf(BelongsToMany::class, $artist->resources()); + $this->assertEquals($resourceCount, $artist->resources()->count()); + $this->assertInstanceOf(ExternalResource::class, $artist->resources()->first()); + $this->assertEquals(ArtistResource::class, $artist->resources()->getPivotClass()); +}); - /** - * Artist shall have a many-to-many relationship to the type Artist as "members". - */ - public function testMembers(): void - { - $memberCount = $this->faker->randomDigitNotNull(); +test('members', function () { + $memberCount = fake()->randomDigitNotNull(); - $artist = Artist::factory() - ->has(Artist::factory()->count($memberCount), 'members') - ->createOne(); + $artist = Artist::factory() + ->has(Artist::factory()->count($memberCount), 'members') + ->createOne(); - static::assertInstanceOf(BelongsToMany::class, $artist->members()); - static::assertEquals($memberCount, $artist->members()->count()); - static::assertInstanceOf(Artist::class, $artist->members()->first()); - static::assertEquals(ArtistMember::class, $artist->members()->getPivotClass()); - } + $this->assertInstanceOf(BelongsToMany::class, $artist->members()); + $this->assertEquals($memberCount, $artist->members()->count()); + $this->assertInstanceOf(Artist::class, $artist->members()->first()); + $this->assertEquals(ArtistMember::class, $artist->members()->getPivotClass()); +}); - /** - * Artist shall have a many-to-many relationship to the type Artist as "groups". - */ - public function testGroups(): void - { - $groupCount = $this->faker->randomDigitNotNull(); +test('groups', function () { + $groupCount = fake()->randomDigitNotNull(); - $artist = Artist::factory() - ->has(Artist::factory()->count($groupCount), 'groups') - ->createOne(); + $artist = Artist::factory() + ->has(Artist::factory()->count($groupCount), 'groups') + ->createOne(); - static::assertInstanceOf(BelongsToMany::class, $artist->groups()); - static::assertEquals($groupCount, $artist->groups()->count()); - static::assertInstanceOf(Artist::class, $artist->groups()->first()); - static::assertEquals(ArtistMember::class, $artist->groups()->getPivotClass()); - } + $this->assertInstanceOf(BelongsToMany::class, $artist->groups()); + $this->assertEquals($groupCount, $artist->groups()->count()); + $this->assertInstanceOf(Artist::class, $artist->groups()->first()); + $this->assertEquals(ArtistMember::class, $artist->groups()->getPivotClass()); +}); - /** - * Artist shall have a many-to-many relationship with the type Image. - */ - public function testImages(): void - { - $imageCount = $this->faker->randomDigitNotNull(); +test('images', function () { + $imageCount = fake()->randomDigitNotNull(); - $artist = Artist::factory() - ->has(Image::factory()->count($imageCount)) - ->createOne(); + $artist = Artist::factory() + ->has(Image::factory()->count($imageCount)) + ->createOne(); - static::assertInstanceOf(BelongsToMany::class, $artist->images()); - static::assertEquals($imageCount, $artist->images()->count()); - static::assertInstanceOf(Image::class, $artist->images()->first()); - static::assertEquals(ArtistImage::class, $artist->images()->getPivotClass()); - } -} + $this->assertInstanceOf(BelongsToMany::class, $artist->images()); + $this->assertEquals($imageCount, $artist->images()->count()); + $this->assertInstanceOf(Image::class, $artist->images()->first()); + $this->assertEquals(ArtistImage::class, $artist->images()->getPivotClass()); +}); diff --git a/tests/Unit/Models/Wiki/AudioTest.php b/tests/Unit/Models/Wiki/AudioTest.php index d4c5e03bf..bcd6bd812 100644 --- a/tests/Unit/Models/Wiki/AudioTest.php +++ b/tests/Unit/Models/Wiki/AudioTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Models\Wiki; - use App\Constants\Config\AudioConstants; use App\Events\Wiki\Audio\AudioForceDeleting; use App\Models\Wiki\Audio; @@ -16,97 +14,69 @@ use Illuminate\Http\Testing\File; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Storage; -use Tests\TestCase; -class AudioTest extends TestCase -{ - use WithFaker; +uses(WithFaker::class); - /** - * Audios shall be nameable. - */ - public function testNameable(): void - { - $audio = Audio::factory()->createOne(); +test('nameable', function () { + $audio = Audio::factory()->createOne(); - static::assertIsString($audio->getName()); - } + $this->assertIsString($audio->getName()); +}); - /** - * Audios shall have subtitle. - */ - public function testHasSubtitle(): void - { - $audio = Audio::factory()->createOne(); +test('has subtitle', function () { + $audio = Audio::factory()->createOne(); - static::assertIsString($audio->getSubtitle()); - } + $this->assertIsString($audio->getSubtitle()); +}); - /** - * Audio shall have a one-to-many relationship with the type Video. - */ - public function testVideos(): void - { - $videoCount = $this->faker->randomDigitNotNull(); +test('videos', function () { + $videoCount = fake()->randomDigitNotNull(); - $audio = Audio::factory() - ->has(Video::factory()->count($videoCount)) - ->createOne(); + $audio = Audio::factory() + ->has(Video::factory()->count($videoCount)) + ->createOne(); - static::assertInstanceOf(HasMany::class, $audio->videos()); - static::assertEquals($videoCount, $audio->videos()->count()); - static::assertInstanceOf(Video::class, $audio->videos()->first()); - } + $this->assertInstanceOf(HasMany::class, $audio->videos()); + $this->assertEquals($videoCount, $audio->videos()->count()); + $this->assertInstanceOf(Video::class, $audio->videos()->first()); +}); - /** - * Audios shall have a one-to-many polymorphic relationship to View. - */ - public function testViews(): void - { - $audio = Audio::factory()->createOne(); +test('views', function () { + $audio = Audio::factory()->createOne(); - views($audio)->record(); + views($audio)->record(); - static::assertInstanceOf(MorphMany::class, $audio->views()); - static::assertEquals(1, $audio->views()->count()); - static::assertInstanceOf(View::class, $audio->views()->first()); - } + $this->assertInstanceOf(MorphMany::class, $audio->views()); + $this->assertEquals(1, $audio->views()->count()); + $this->assertInstanceOf(View::class, $audio->views()->first()); +}); - /** - * The audio shall not be deleted from storage when the Audio is deleted. - */ - public function testAudioStorageDeletion(): void - { - $fs = Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); - $file = File::fake()->create($this->faker->word().'.ogg', $this->faker->randomDigitNotNull()); - $fsFile = $fs->putFile('', $file); +test('audio storage deletion', function () { + $fs = Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); + $file = File::fake()->create(fake()->word().'.ogg', fake()->randomDigitNotNull()); + $fsFile = $fs->putFile('', $file); - $audio = Audio::factory()->createOne([ - Audio::ATTRIBUTE_PATH => $fsFile, - ]); + $audio = Audio::factory()->createOne([ + Audio::ATTRIBUTE_PATH => $fsFile, + ]); - $audio->delete(); + $audio->delete(); - static::assertTrue($fs->exists($audio->path)); - } + $this->assertTrue($fs->exists($audio->path)); +}); - /** - * The audio shall be deleted from storage when the Audio is force deleted. - */ - public function testAudioStorageForceDeletion(): void - { - Event::fakeExcept(AudioForceDeleting::class); +test('audio storage force deletion', function () { + Event::fakeExcept(AudioForceDeleting::class); - $fs = Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); - $file = File::fake()->create($this->faker->word().'.ogg', $this->faker->randomDigitNotNull()); - $fsFile = $fs->putFile('', $file); + $fs = Storage::fake(Config::get(AudioConstants::DEFAULT_DISK_QUALIFIED)); + $file = File::fake()->create(fake()->word().'.ogg', fake()->randomDigitNotNull()); + $fsFile = $fs->putFile('', $file); - $audio = Audio::factory()->createOne([ - Audio::ATTRIBUTE_PATH => $fsFile, - ]); + $audio = Audio::factory()->createOne([ + Audio::ATTRIBUTE_PATH => $fsFile, + ]); - $audio->forceDelete(); + $audio->forceDelete(); - static::assertFalse($fs->exists($audio->path)); - } -} + $this->assertFalse($fs->exists($audio->path)); +}); diff --git a/tests/Unit/Models/Wiki/ExternalResourceTest.php b/tests/Unit/Models/Wiki/ExternalResourceTest.php index 03065ccf0..3413e8960 100644 --- a/tests/Unit/Models/Wiki/ExternalResourceTest.php +++ b/tests/Unit/Models/Wiki/ExternalResourceTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Models\Wiki; - use App\Enums\Models\Wiki\ResourceSite; use App\Models\Wiki\Anime; use App\Models\Wiki\Artist; @@ -16,109 +14,77 @@ use App\Pivots\Wiki\SongResource; use App\Pivots\Wiki\StudioResource; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; -class ExternalResourceTest extends TestCase -{ - use WithFaker; +uses(WithFaker::class); - /** - * The site attribute of a resource shall be cast to a ResourceSite enum instance. - */ - public function testCastsSeasonToEnum(): void - { - $resource = ExternalResource::factory()->createOne(); +test('casts season to enum', function () { + $resource = ExternalResource::factory()->createOne(); - $site = $resource->site; + $site = $resource->site; - static::assertInstanceOf(ResourceSite::class, $site); - } + $this->assertInstanceOf(ResourceSite::class, $site); +}); - /** - * Resources shall be nameable. - */ - public function testNameable(): void - { - $resource = ExternalResource::factory()->createOne(); +test('nameable', function () { + $resource = ExternalResource::factory()->createOne(); - static::assertIsString($resource->getName()); - } + $this->assertIsString($resource->getName()); +}); - /** - * Resources shall have subtitle. - */ - public function testHasSubtitle(): void - { - $resource = ExternalResource::factory()->createOne(); +test('has subtitle', function () { + $resource = ExternalResource::factory()->createOne(); - static::assertIsString($resource->getSubtitle()); - } + $this->assertIsString($resource->getSubtitle()); +}); - /** - * Resource shall have a many-to-many relationship with the type Anime. - */ - public function testAnime(): void - { - $animeCount = $this->faker->randomDigitNotNull(); +test('anime', function () { + $animeCount = fake()->randomDigitNotNull(); - $resource = ExternalResource::factory() - ->has(Anime::factory()->count($animeCount)) - ->createOne(); + $resource = ExternalResource::factory() + ->has(Anime::factory()->count($animeCount)) + ->createOne(); - static::assertInstanceOf(BelongsToMany::class, $resource->anime()); - static::assertEquals($animeCount, $resource->anime()->count()); - static::assertInstanceOf(Anime::class, $resource->anime()->first()); - static::assertEquals(AnimeResource::class, $resource->anime()->getPivotClass()); - } + $this->assertInstanceOf(BelongsToMany::class, $resource->anime()); + $this->assertEquals($animeCount, $resource->anime()->count()); + $this->assertInstanceOf(Anime::class, $resource->anime()->first()); + $this->assertEquals(AnimeResource::class, $resource->anime()->getPivotClass()); +}); - /** - * Resource shall have a many-to-many relationship with the type Artist. - */ - public function testArtists(): void - { - $artistCount = $this->faker->randomDigitNotNull(); +test('artists', function () { + $artistCount = fake()->randomDigitNotNull(); - $resource = ExternalResource::factory() - ->has(Artist::factory()->count($artistCount)) - ->createOne(); + $resource = ExternalResource::factory() + ->has(Artist::factory()->count($artistCount)) + ->createOne(); - static::assertInstanceOf(BelongsToMany::class, $resource->artists()); - static::assertEquals($artistCount, $resource->artists()->count()); - static::assertInstanceOf(Artist::class, $resource->artists()->first()); - static::assertEquals(ArtistResource::class, $resource->artists()->getPivotClass()); - } + $this->assertInstanceOf(BelongsToMany::class, $resource->artists()); + $this->assertEquals($artistCount, $resource->artists()->count()); + $this->assertInstanceOf(Artist::class, $resource->artists()->first()); + $this->assertEquals(ArtistResource::class, $resource->artists()->getPivotClass()); +}); - /** - * Resource shall have a many-to-many relationship with the type Song. - */ - public function testSong(): void - { - $songCount = $this->faker->randomDigitNotNull(); +test('song', function () { + $songCount = fake()->randomDigitNotNull(); - $resource = ExternalResource::factory() - ->has(Song::factory()->count($songCount)) - ->createOne(); + $resource = ExternalResource::factory() + ->has(Song::factory()->count($songCount)) + ->createOne(); - static::assertInstanceOf(BelongsToMany::class, $resource->songs()); - static::assertEquals($songCount, $resource->songs()->count()); - static::assertInstanceOf(Song::class, $resource->songs()->first()); - static::assertEquals(SongResource::class, $resource->songs()->getPivotClass()); - } + $this->assertInstanceOf(BelongsToMany::class, $resource->songs()); + $this->assertEquals($songCount, $resource->songs()->count()); + $this->assertInstanceOf(Song::class, $resource->songs()->first()); + $this->assertEquals(SongResource::class, $resource->songs()->getPivotClass()); +}); - /** - * Resource shall have a many-to-many relationship with the type Studio. - */ - public function testStudio(): void - { - $studioCount = $this->faker->randomDigitNotNull(); +test('studio', function () { + $studioCount = fake()->randomDigitNotNull(); - $resource = ExternalResource::factory() - ->has(Studio::factory()->count($studioCount)) - ->createOne(); + $resource = ExternalResource::factory() + ->has(Studio::factory()->count($studioCount)) + ->createOne(); - static::assertInstanceOf(BelongsToMany::class, $resource->studios()); - static::assertEquals($studioCount, $resource->studios()->count()); - static::assertInstanceOf(Studio::class, $resource->studios()->first()); - static::assertEquals(StudioResource::class, $resource->studios()->getPivotClass()); - } -} + $this->assertInstanceOf(BelongsToMany::class, $resource->studios()); + $this->assertEquals($studioCount, $resource->studios()->count()); + $this->assertInstanceOf(Studio::class, $resource->studios()->first()); + $this->assertEquals(StudioResource::class, $resource->studios()->getPivotClass()); +}); diff --git a/tests/Unit/Models/Wiki/GroupTest.php b/tests/Unit/Models/Wiki/GroupTest.php index a505f9c82..7b1d552a8 100644 --- a/tests/Unit/Models/Wiki/GroupTest.php +++ b/tests/Unit/Models/Wiki/GroupTest.php @@ -2,52 +2,34 @@ declare(strict_types=1); -namespace Tests\Unit\Models\Wiki; - use App\Models\Wiki\Anime; use App\Models\Wiki\Anime\AnimeTheme; use App\Models\Wiki\Group; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; -class GroupTest extends TestCase -{ - use WithFaker; +uses(WithFaker::class); - /** - * Groups shall be nameable. - */ - public function testNameable(): void - { - $group = Group::factory()->createOne(); +test('nameable', function () { + $group = Group::factory()->createOne(); - static::assertIsString($group->getName()); - } + $this->assertIsString($group->getName()); +}); - /** - * Groups shall have subtitle. - */ - public function testHasSubtitle(): void - { - $group = Group::factory()->createOne(); +test('has subtitle', function () { + $group = Group::factory()->createOne(); - static::assertIsString($group->getSubtitle()); - } + $this->assertIsString($group->getSubtitle()); +}); - /** - * Group shall have a one-to-many relationship with the type Theme. - */ - public function testThemes(): void - { - $themeCount = $this->faker->randomDigitNotNull(); +test('themes', function () { + $themeCount = fake()->randomDigitNotNull(); - $group = Group::factory() - ->has(AnimeTheme::factory()->for(Anime::factory())->count($themeCount)) - ->createOne(); + $group = Group::factory() + ->has(AnimeTheme::factory()->for(Anime::factory())->count($themeCount)) + ->createOne(); - static::assertInstanceOf(HasMany::class, $group->animethemes()); - static::assertEquals($themeCount, $group->animethemes()->count()); - static::assertInstanceOf(AnimeTheme::class, $group->animethemes()->first()); - } -} + $this->assertInstanceOf(HasMany::class, $group->animethemes()); + $this->assertEquals($themeCount, $group->animethemes()->count()); + $this->assertInstanceOf(AnimeTheme::class, $group->animethemes()->first()); +}); diff --git a/tests/Unit/Models/Wiki/ImageTest.php b/tests/Unit/Models/Wiki/ImageTest.php index cac74bbb3..57596ed07 100644 --- a/tests/Unit/Models/Wiki/ImageTest.php +++ b/tests/Unit/Models/Wiki/ImageTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Models\Wiki; - use App\Enums\Models\Wiki\ImageFacet; use App\Events\Wiki\Image\ImageForceDeleting; use App\Models\List\Playlist; @@ -21,152 +19,112 @@ use Illuminate\Support\Arr; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Storage; -use Tests\TestCase; -class ImageTest extends TestCase -{ - use WithFaker; +uses(WithFaker::class); - /** - * The facet attribute of an image shall be cast to an ImageFacet enum instance. - */ - public function testCastsFacetToEnum(): void - { - $image = Image::factory()->createOne(); +test('casts facet to enum', function () { + $image = Image::factory()->createOne(); - $facet = $image->facet; + $facet = $image->facet; - static::assertInstanceOf(ImageFacet::class, $facet); - } + $this->assertInstanceOf(ImageFacet::class, $facet); +}); - /** - * Images shall be nameable. - */ - public function testNameable(): void - { - $image = Image::factory()->createOne(); +test('nameable', function () { + $image = Image::factory()->createOne(); - static::assertIsString($image->getName()); - } + $this->assertIsString($image->getName()); +}); - /** - * Images shall have subtitle. - */ - public function testHasSubtitle(): void - { - $image = Image::factory()->createOne(); +test('has subtitle', function () { + $image = Image::factory()->createOne(); - static::assertIsString($image->getSubtitle()); - } + $this->assertIsString($image->getSubtitle()); +}); - /** - * Image shall have a many-to-many relationship with the type Anime. - */ - public function testAnime(): void - { - $animeCount = $this->faker->randomDigitNotNull(); +test('anime', function () { + $animeCount = fake()->randomDigitNotNull(); - $image = Image::factory() - ->has(Anime::factory()->count($animeCount)) - ->createOne(); + $image = Image::factory() + ->has(Anime::factory()->count($animeCount)) + ->createOne(); - static::assertInstanceOf(BelongsToMany::class, $image->anime()); - static::assertEquals($animeCount, $image->anime()->count()); - static::assertInstanceOf(Anime::class, $image->anime()->first()); - static::assertEquals(AnimeImage::class, $image->anime()->getPivotClass()); - } + $this->assertInstanceOf(BelongsToMany::class, $image->anime()); + $this->assertEquals($animeCount, $image->anime()->count()); + $this->assertInstanceOf(Anime::class, $image->anime()->first()); + $this->assertEquals(AnimeImage::class, $image->anime()->getPivotClass()); +}); - /** - * Image shall have a many-to-many relationship with the type Artist. - */ - public function testArtists(): void - { - $artistCount = $this->faker->randomDigitNotNull(); +test('artists', function () { + $artistCount = fake()->randomDigitNotNull(); - $image = Image::factory() - ->has(Artist::factory()->count($artistCount)) - ->createOne(); + $image = Image::factory() + ->has(Artist::factory()->count($artistCount)) + ->createOne(); - static::assertInstanceOf(BelongsToMany::class, $image->artists()); - static::assertEquals($artistCount, $image->artists()->count()); - static::assertInstanceOf(Artist::class, $image->artists()->first()); - static::assertEquals(ArtistImage::class, $image->artists()->getPivotClass()); - } + $this->assertInstanceOf(BelongsToMany::class, $image->artists()); + $this->assertEquals($artistCount, $image->artists()->count()); + $this->assertInstanceOf(Artist::class, $image->artists()->first()); + $this->assertEquals(ArtistImage::class, $image->artists()->getPivotClass()); +}); - /** - * Image shall have a many-to-many relationship with the type Studio. - */ - public function testStudios(): void - { - $studioCount = $this->faker->randomDigitNotNull(); +test('studios', function () { + $studioCount = fake()->randomDigitNotNull(); - $image = Image::factory() - ->has(Studio::factory()->count($studioCount)) - ->createOne(); + $image = Image::factory() + ->has(Studio::factory()->count($studioCount)) + ->createOne(); - static::assertInstanceOf(BelongsToMany::class, $image->studios()); - static::assertEquals($studioCount, $image->studios()->count()); - static::assertInstanceOf(Studio::class, $image->studios()->first()); - static::assertEquals(StudioImage::class, $image->studios()->getPivotClass()); - } + $this->assertInstanceOf(BelongsToMany::class, $image->studios()); + $this->assertEquals($studioCount, $image->studios()->count()); + $this->assertInstanceOf(Studio::class, $image->studios()->first()); + $this->assertEquals(StudioImage::class, $image->studios()->getPivotClass()); +}); - /** - * Image shall have a many-to-many relationship with the type Playlist. - */ - public function testPlaylists(): void - { - $playlistCount = $this->faker->randomDigitNotNull(); +test('playlists', function () { + $playlistCount = fake()->randomDigitNotNull(); - $image = Image::factory() - ->has(Playlist::factory()->count($playlistCount)) - ->createOne(); + $image = Image::factory() + ->has(Playlist::factory()->count($playlistCount)) + ->createOne(); - static::assertInstanceOf(BelongsToMany::class, $image->playlists()); - static::assertEquals($playlistCount, $image->playlists()->count()); - static::assertInstanceOf(Playlist::class, $image->playlists()->first()); - } + $this->assertInstanceOf(BelongsToMany::class, $image->playlists()); + $this->assertEquals($playlistCount, $image->playlists()->count()); + $this->assertInstanceOf(Playlist::class, $image->playlists()->first()); +}); - /** - * The image shall not be deleted from storage when the Image is deleted. - */ - public function testImageStorageDeletion(): void - { - $fs = Storage::fake(Config::get('image.disk')); - $file = File::fake()->image($this->faker->word().'.jpg'); - $fsFile = $fs->putFile('', $file); +test('image storage deletion', function () { + $fs = Storage::fake(Config::get('image.disk')); + $file = File::fake()->image(fake()->word().'.jpg'); + $fsFile = $fs->putFile('', $file); - $facet = Arr::random(ImageFacet::cases()); + $facet = Arr::random(ImageFacet::cases()); - $image = Image::factory()->createOne([ - Image::ATTRIBUTE_FACET => $facet->value, - Image::ATTRIBUTE_PATH => $fsFile, - ]); + $image = Image::factory()->createOne([ + Image::ATTRIBUTE_FACET => $facet->value, + Image::ATTRIBUTE_PATH => $fsFile, + ]); - $image->delete(); + $image->delete(); - static::assertTrue($fs->exists($image->path)); - } + $this->assertTrue($fs->exists($image->path)); +}); - /** - * The image shall be deleted from storage when the Image is force deleted. - */ - public function testImageStorageForceDeletion(): void - { - Event::fakeExcept(ImageForceDeleting::class); +test('image storage force deletion', function () { + Event::fakeExcept(ImageForceDeleting::class); - $fs = Storage::fake(Config::get('image.disk')); - $file = File::fake()->image($this->faker->word().'.jpg'); - $fsFile = $fs->putFile('', $file); + $fs = Storage::fake(Config::get('image.disk')); + $file = File::fake()->image(fake()->word().'.jpg'); + $fsFile = $fs->putFile('', $file); - $facet = Arr::random(ImageFacet::cases()); + $facet = Arr::random(ImageFacet::cases()); - $image = Image::factory()->createOne([ - Image::ATTRIBUTE_FACET => $facet->value, - Image::ATTRIBUTE_PATH => $fsFile, - ]); + $image = Image::factory()->createOne([ + Image::ATTRIBUTE_FACET => $facet->value, + Image::ATTRIBUTE_PATH => $fsFile, + ]); - $image->forceDelete(); + $image->forceDelete(); - static::assertFalse($fs->exists($image->path)); - } -} + $this->assertFalse($fs->exists($image->path)); +}); diff --git a/tests/Unit/Models/Wiki/SeriesTest.php b/tests/Unit/Models/Wiki/SeriesTest.php index 22e328223..ad025494f 100644 --- a/tests/Unit/Models/Wiki/SeriesTest.php +++ b/tests/Unit/Models/Wiki/SeriesTest.php @@ -2,73 +2,47 @@ declare(strict_types=1); -namespace Tests\Unit\Models\Wiki; - use App\Models\Wiki\Anime; use App\Models\Wiki\Series; use App\Pivots\Wiki\AnimeSeries; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; -class SeriesTest extends TestCase -{ - use WithFaker; +uses(WithFaker::class); - /** - * Series shall be a searchable resource. - */ - public function testSearchableAs(): void - { - $series = Series::factory()->createOne(); +test('searchable as', function () { + $series = Series::factory()->createOne(); - static::assertIsString($series->searchableAs()); - } + $this->assertIsString($series->searchableAs()); +}); - /** - * Series shall be a searchable resource. - */ - public function testToSearchableArray(): void - { - $series = Series::factory()->createOne(); +test('to searchable array', function () { + $series = Series::factory()->createOne(); - static::assertIsArray($series->toSearchableArray()); - } + $this->assertIsArray($series->toSearchableArray()); +}); - /** - * Series shall be nameable. - */ - public function testNameable(): void - { - $series = Series::factory()->createOne(); +test('nameable', function () { + $series = Series::factory()->createOne(); - static::assertIsString($series->getName()); - } + $this->assertIsString($series->getName()); +}); - /** - * Series shall have subtitle. - */ - public function testHasSubtitle(): void - { - $series = Series::factory()->createOne(); +test('has subtitle', function () { + $series = Series::factory()->createOne(); - static::assertIsString($series->getSubtitle()); - } + $this->assertIsString($series->getSubtitle()); +}); - /** - * Series shall have a many-to-many relationship with the type Anime. - */ - public function testAnime(): void - { - $animeCount = $this->faker->randomDigitNotNull(); +test('anime', function () { + $animeCount = fake()->randomDigitNotNull(); - $series = Series::factory() - ->has(Anime::factory()->count($animeCount)) - ->createOne(); + $series = Series::factory() + ->has(Anime::factory()->count($animeCount)) + ->createOne(); - static::assertInstanceOf(BelongsToMany::class, $series->anime()); - static::assertEquals($animeCount, $series->anime()->count()); - static::assertInstanceOf(Anime::class, $series->anime()->first()); - static::assertEquals(AnimeSeries::class, $series->anime()->getPivotClass()); - } -} + $this->assertInstanceOf(BelongsToMany::class, $series->anime()); + $this->assertEquals($animeCount, $series->anime()->count()); + $this->assertInstanceOf(Anime::class, $series->anime()->first()); + $this->assertEquals(AnimeSeries::class, $series->anime()->getPivotClass()); +}); diff --git a/tests/Unit/Models/Wiki/SongTest.php b/tests/Unit/Models/Wiki/SongTest.php index 0f3b711a6..3aa67c96b 100644 --- a/tests/Unit/Models/Wiki/SongTest.php +++ b/tests/Unit/Models/Wiki/SongTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Models\Wiki; - use App\Models\Wiki\Anime; use App\Models\Wiki\Anime\AnimeTheme; use App\Models\Wiki\Artist; @@ -14,101 +12,69 @@ use App\Pivots\Wiki\SongResource; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; -class SongTest extends TestCase -{ - use WithFaker; +uses(WithFaker::class); - /** - * Song shall be a searchable resource. - */ - public function testSearchableAs(): void - { - $song = Song::factory()->createOne(); +test('searchable as', function () { + $song = Song::factory()->createOne(); - static::assertIsString($song->searchableAs()); - } + $this->assertIsString($song->searchableAs()); +}); - /** - * Song shall be a searchable resource. - */ - public function testToSearchableArray(): void - { - $song = Song::factory()->createOne(); +test('to searchable array', function () { + $song = Song::factory()->createOne(); - static::assertIsArray($song->toSearchableArray()); - } + $this->assertIsArray($song->toSearchableArray()); +}); - /** - * Songs shall be nameable. - */ - public function testNameable(): void - { - $song = Song::factory()->createOne(); +test('nameable', function () { + $song = Song::factory()->createOne(); - static::assertIsString($song->getName()); - } + $this->assertIsString($song->getName()); +}); - /** - * Songs shall have subtitle. - */ - public function testHasSubtitle(): void - { - $song = Song::factory() - ->has(AnimeTheme::factory()->for(Anime::factory())) - ->createOne(); +test('has subtitle', function () { + $song = Song::factory() + ->has(AnimeTheme::factory()->for(Anime::factory())) + ->createOne(); - static::assertIsString($song->getSubtitle()); - } + $this->assertIsString($song->getSubtitle()); +}); - /** - * Song shall have a one-to-many relationship with the type Theme. - */ - public function testThemes(): void - { - $themeCount = $this->faker->randomDigitNotNull(); +test('themes', function () { + $themeCount = fake()->randomDigitNotNull(); - $song = Song::factory() - ->has(AnimeTheme::factory()->for(Anime::factory())->count($themeCount)) - ->createOne(); + $song = Song::factory() + ->has(AnimeTheme::factory()->for(Anime::factory())->count($themeCount)) + ->createOne(); - static::assertInstanceOf(HasMany::class, $song->animethemes()); - static::assertEquals($themeCount, $song->animethemes()->count()); - static::assertInstanceOf(AnimeTheme::class, $song->animethemes()->first()); - } + $this->assertInstanceOf(HasMany::class, $song->animethemes()); + $this->assertEquals($themeCount, $song->animethemes()->count()); + $this->assertInstanceOf(AnimeTheme::class, $song->animethemes()->first()); +}); - /** - * Song shall have a many-to-many relationship with the type Artist. - */ - public function testArtists(): void - { - $artistCount = $this->faker->randomDigitNotNull(); +test('artists', function () { + $artistCount = fake()->randomDigitNotNull(); - $song = Song::factory() - ->has(Artist::factory()->count($artistCount)) - ->createOne(); + $song = Song::factory() + ->has(Artist::factory()->count($artistCount)) + ->createOne(); - static::assertInstanceOf(BelongsToMany::class, $song->artists()); - static::assertEquals($artistCount, $song->artists()->count()); - static::assertInstanceOf(Artist::class, $song->artists()->first()); - static::assertEquals(ArtistSong::class, $song->artists()->getPivotClass()); - } + $this->assertInstanceOf(BelongsToMany::class, $song->artists()); + $this->assertEquals($artistCount, $song->artists()->count()); + $this->assertInstanceOf(Artist::class, $song->artists()->first()); + $this->assertEquals(ArtistSong::class, $song->artists()->getPivotClass()); +}); - /** - * Song shall have a many-to-many relationship with the type ExternalResource. - */ - public function testExternalResources(): void - { - $resourceCount = $this->faker->randomDigitNotNull(); +test('external resources', function () { + $resourceCount = fake()->randomDigitNotNull(); - $song = Song::factory() - ->has(ExternalResource::factory()->count($resourceCount), 'resources') - ->createOne(); + $song = Song::factory() + ->has(ExternalResource::factory()->count($resourceCount), 'resources') + ->createOne(); - static::assertInstanceOf(BelongsToMany::class, $song->resources()); - static::assertEquals($resourceCount, $song->resources()->count()); - static::assertInstanceOf(ExternalResource::class, $song->resources()->first()); - static::assertEquals(SongResource::class, $song->resources()->getPivotClass()); - } -} + $this->assertInstanceOf(BelongsToMany::class, $song->resources()); + $this->assertEquals($resourceCount, $song->resources()->count()); + $this->assertInstanceOf(ExternalResource::class, $song->resources()->first()); + $this->assertEquals(SongResource::class, $song->resources()->getPivotClass()); +}); diff --git a/tests/Unit/Models/Wiki/StudioTest.php b/tests/Unit/Models/Wiki/StudioTest.php index 5ae82e94a..94ee0e389 100644 --- a/tests/Unit/Models/Wiki/StudioTest.php +++ b/tests/Unit/Models/Wiki/StudioTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Models\Wiki; - use App\Models\Wiki\Anime; use App\Models\Wiki\ExternalResource; use App\Models\Wiki\Image; @@ -13,100 +11,68 @@ use App\Pivots\Wiki\StudioImage; use App\Pivots\Wiki\StudioResource; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; -class StudioTest extends TestCase -{ - use WithFaker; +uses(WithFaker::class); - /** - * Studio shall be a searchable resource. - */ - public function testSearchableAs(): void - { - $studio = Studio::factory()->createOne(); +test('searchable as', function () { + $studio = Studio::factory()->createOne(); - static::assertIsString($studio->searchableAs()); - } + $this->assertIsString($studio->searchableAs()); +}); - /** - * Studio shall be a searchable resource. - */ - public function testToSearchableArray(): void - { - $studio = Studio::factory()->createOne(); +test('to searchable array', function () { + $studio = Studio::factory()->createOne(); - static::assertIsArray($studio->toSearchableArray()); - } + $this->assertIsArray($studio->toSearchableArray()); +}); - /** - * Studio shall be nameable. - */ - public function testNameable(): void - { - $studio = Studio::factory()->createOne(); +test('nameable', function () { + $studio = Studio::factory()->createOne(); - static::assertIsString($studio->getName()); - } + $this->assertIsString($studio->getName()); +}); - /** - * Studio shall have subtitle. - */ - public function testHasSubtitle(): void - { - $studio = Studio::factory()->createOne(); +test('has subtitle', function () { + $studio = Studio::factory()->createOne(); - static::assertIsString($studio->getSubtitle()); - } + $this->assertIsString($studio->getSubtitle()); +}); - /** - * Studio shall have a many-to-many relationship with the type Anime. - */ - public function testAnime(): void - { - $animeCount = $this->faker->randomDigitNotNull(); +test('anime', function () { + $animeCount = fake()->randomDigitNotNull(); - $studio = Studio::factory() - ->has(Anime::factory()->count($animeCount)) - ->createOne(); + $studio = Studio::factory() + ->has(Anime::factory()->count($animeCount)) + ->createOne(); - static::assertInstanceOf(BelongsToMany::class, $studio->anime()); - static::assertEquals($animeCount, $studio->anime()->count()); - static::assertInstanceOf(Anime::class, $studio->anime()->first()); - static::assertEquals(AnimeStudio::class, $studio->anime()->getPivotClass()); - } + $this->assertInstanceOf(BelongsToMany::class, $studio->anime()); + $this->assertEquals($animeCount, $studio->anime()->count()); + $this->assertInstanceOf(Anime::class, $studio->anime()->first()); + $this->assertEquals(AnimeStudio::class, $studio->anime()->getPivotClass()); +}); - /** - * Studio shall have a many-to-many relationship with the type ExternalResource. - */ - public function testExternalResources(): void - { - $resourceCount = $this->faker->randomDigitNotNull(); +test('external resources', function () { + $resourceCount = fake()->randomDigitNotNull(); - $studio = Studio::factory() - ->has(ExternalResource::factory()->count($resourceCount), 'resources') - ->createOne(); + $studio = Studio::factory() + ->has(ExternalResource::factory()->count($resourceCount), 'resources') + ->createOne(); - static::assertInstanceOf(BelongsToMany::class, $studio->resources()); - static::assertEquals($resourceCount, $studio->resources()->count()); - static::assertInstanceOf(ExternalResource::class, $studio->resources()->first()); - static::assertEquals(StudioResource::class, $studio->resources()->getPivotClass()); - } + $this->assertInstanceOf(BelongsToMany::class, $studio->resources()); + $this->assertEquals($resourceCount, $studio->resources()->count()); + $this->assertInstanceOf(ExternalResource::class, $studio->resources()->first()); + $this->assertEquals(StudioResource::class, $studio->resources()->getPivotClass()); +}); - /** - * Studio shall have a many-to-many relationship with the type Image. - */ - public function testImages(): void - { - $imageCount = $this->faker->randomDigitNotNull(); +test('images', function () { + $imageCount = fake()->randomDigitNotNull(); - $studio = Studio::factory() - ->has(Image::factory()->count($imageCount)) - ->createOne(); + $studio = Studio::factory() + ->has(Image::factory()->count($imageCount)) + ->createOne(); - static::assertInstanceOf(BelongsToMany::class, $studio->images()); - static::assertEquals($imageCount, $studio->images()->count()); - static::assertInstanceOf(Image::class, $studio->images()->first()); - static::assertEquals(StudioImage::class, $studio->images()->getPivotClass()); - } -} + $this->assertInstanceOf(BelongsToMany::class, $studio->images()); + $this->assertEquals($imageCount, $studio->images()->count()); + $this->assertInstanceOf(Image::class, $studio->images()->first()); + $this->assertEquals(StudioImage::class, $studio->images()->getPivotClass()); +}); diff --git a/tests/Unit/Models/Wiki/Video/ScriptTest.php b/tests/Unit/Models/Wiki/Video/ScriptTest.php index c51b632b3..db9fcebd5 100644 --- a/tests/Unit/Models/Wiki/Video/ScriptTest.php +++ b/tests/Unit/Models/Wiki/Video/ScriptTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Models\Wiki\Video; - use App\Constants\Config\VideoConstants; use App\Events\Wiki\Video\Script\VideoScriptForceDeleting; use App\Models\Wiki\Video; @@ -14,82 +12,58 @@ use Illuminate\Http\Testing\File; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Storage; -use Tests\TestCase; -class ScriptTest extends TestCase -{ - use WithFaker; +uses(WithFaker::class); - /** - * Scripts shall be nameable. - */ - public function testNameable(): void - { - $script = VideoScript::factory()->createOne(); +test('nameable', function () { + $script = VideoScript::factory()->createOne(); - static::assertIsString($script->getName()); - } + $this->assertIsString($script->getName()); +}); - /** - * Scripts shall have subtitle. - */ - public function testHasSubtitle(): void - { - $script = VideoScript::factory() - ->for(Video::factory()) - ->createOne(); +test('has subtitle', function () { + $script = VideoScript::factory() + ->for(Video::factory()) + ->createOne(); - static::assertIsString($script->getSubtitle()); - } + $this->assertIsString($script->getSubtitle()); +}); - /** - * Scripts shall belong to a Video. - */ - public function testVideo(): void - { - $script = VideoScript::factory() - ->for(Video::factory()) - ->createOne(); +test('video', function () { + $script = VideoScript::factory() + ->for(Video::factory()) + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $script->video()); - static::assertInstanceOf(Video::class, $script->video()->first()); - } + $this->assertInstanceOf(BelongsTo::class, $script->video()); + $this->assertInstanceOf(Video::class, $script->video()->first()); +}); - /** - * The script shall not be deleted from storage when the VideoScript is deleted. - */ - public function testScriptStorageDeletion(): void - { - $fs = Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); - $file = File::fake()->create($this->faker->word().'.ogg', $this->faker->randomDigitNotNull()); - $fsFile = $fs->putFile('', $file); +test('script storage deletion', function () { + $fs = Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); + $file = File::fake()->create(fake()->word().'.ogg', fake()->randomDigitNotNull()); + $fsFile = $fs->putFile('', $file); - $script = VideoScript::factory()->createOne([ - VideoScript::ATTRIBUTE_PATH => $fsFile, - ]); + $script = VideoScript::factory()->createOne([ + VideoScript::ATTRIBUTE_PATH => $fsFile, + ]); - $script->delete(); + $script->delete(); - static::assertTrue($fs->exists($script->path)); - } + $this->assertTrue($fs->exists($script->path)); +}); - /** - * The script shall be deleted from storage when the VideoScript is force deleted. - */ - public function testScriptStorageForceDeletion(): void - { - Event::fakeExcept(VideoScriptForceDeleting::class); +test('script storage force deletion', function () { + Event::fakeExcept(VideoScriptForceDeleting::class); - $fs = Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); - $file = File::fake()->create($this->faker->word().'.ogg', $this->faker->randomDigitNotNull()); - $fsFile = $fs->putFile('', $file); + $fs = Storage::fake(Config::get(VideoConstants::SCRIPT_DISK_QUALIFIED)); + $file = File::fake()->create(fake()->word().'.ogg', fake()->randomDigitNotNull()); + $fsFile = $fs->putFile('', $file); - $script = VideoScript::factory()->createOne([ - VideoScript::ATTRIBUTE_PATH => $fsFile, - ]); + $script = VideoScript::factory()->createOne([ + VideoScript::ATTRIBUTE_PATH => $fsFile, + ]); - $script->forceDelete(); + $script->forceDelete(); - static::assertFalse($fs->exists($script->path)); - } -} + $this->assertFalse($fs->exists($script->path)); +}); diff --git a/tests/Unit/Models/Wiki/VideoTest.php b/tests/Unit/Models/Wiki/VideoTest.php index 0b9af9713..9c0418541 100644 --- a/tests/Unit/Models/Wiki/VideoTest.php +++ b/tests/Unit/Models/Wiki/VideoTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Models\Wiki; - use App\Constants\Config\VideoConstants; use App\Enums\Models\List\PlaylistVisibility; use App\Enums\Models\Wiki\VideoOverlap; @@ -30,425 +28,313 @@ use Illuminate\Support\Arr; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Storage; -use PHPUnit\Framework\Attributes\DataProvider; -use Tests\TestCase; -class VideoTest extends TestCase -{ - use WithFaker; +uses(WithFaker::class); - /** - * The overlap attribute of a video shall be cast to a VideoOverlap enum instance. - */ - public function testCastsOverlapToEnum(): void - { - $video = Video::factory()->createOne(); +test('casts overlap to enum', function () { + $video = Video::factory()->createOne(); - $overlap = $video->overlap; + $overlap = $video->overlap; - static::assertInstanceOf(VideoOverlap::class, $overlap); - } + $this->assertInstanceOf(VideoOverlap::class, $overlap); +}); - /** - * The source attribute of a video shall be cast to a VideoSource enum instance. - */ - public function testCastsSourceToEnum(): void - { - $video = Video::factory()->createOne(); +test('casts source to enum', function () { + $video = Video::factory()->createOne(); - $source = $video->source; + $source = $video->source; - static::assertInstanceOf(VideoSource::class, $source); - } + $this->assertInstanceOf(VideoSource::class, $source); +}); - /** - * Video shall be a searchable resource. - */ - public function testSearchableAs(): void - { - $video = Video::factory()->createOne(); +test('searchable as', function () { + $video = Video::factory()->createOne(); - static::assertIsString($video->searchableAs()); - } + $this->assertIsString($video->searchableAs()); +}); - /** - * Video shall be a searchable resource. - */ - public function testToSearchableArray(): void - { - $video = Video::factory()->createOne(); +test('to searchable array', function () { + $video = Video::factory()->createOne(); - static::assertIsArray($video->toSearchableArray()); - } + $this->assertIsArray($video->toSearchableArray()); +}); - /** - * Videos shall be nameable. - */ - public function testNameable(): void - { - $video = Video::factory()->createOne(); +test('nameable', function () { + $video = Video::factory()->createOne(); - static::assertIsString($video->getName()); - } + $this->assertIsString($video->getName()); +}); - /** - * Videos shall have subtitle. - */ - public function testHasSubtitle(): void - { - $video = Video::factory()->createOne(); +test('has subtitle', function () { + $video = Video::factory()->createOne(); - static::assertIsString($video->getSubtitle()); - } + $this->assertIsString($video->getSubtitle()); +}); - /** - * Videos shall have a one-to-many polymorphic relationship to View. - */ - public function testViews(): void - { - $video = Video::factory()->createOne(); +test('views', function () { + $video = Video::factory()->createOne(); - views($video)->record(); + views($video)->record(); - static::assertInstanceOf(MorphMany::class, $video->views()); - static::assertEquals(1, $video->views()->count()); - static::assertInstanceOf(View::class, $video->views()->first()); - } + $this->assertInstanceOf(MorphMany::class, $video->views()); + $this->assertEquals(1, $video->views()->count()); + $this->assertInstanceOf(View::class, $video->views()->first()); +}); - /** - * Videos shall append a 'tags' attribute. - */ - public function testAppendsTags(): void - { - $video = Video::factory()->createOne(); +test('appends tags', function () { + $video = Video::factory()->createOne(); - static::assertArrayHasKey(Video::ATTRIBUTE_TAGS, $video); - } + $this->assertArrayHasKey(Video::ATTRIBUTE_TAGS, $video); +}); - /** - * The Tags attribute shall contain 'NC' if the NC attribute is true. - */ - public function testNcTag(): void - { - $video = Video::factory()->createOne([ - Video::ATTRIBUTE_NC => true, - ]); +test('nc tag', function () { + $video = Video::factory()->createOne([ + Video::ATTRIBUTE_NC => true, + ]); - static::assertContains('NC', $video->tags); - } + $this->assertContains('NC', $video->tags); +}); - /** - * The Tags attribute shall not contain 'NC' if the NC attribute is false. - */ - public function testNoNcTag(): void - { - $video = Video::factory()->createOne([ - Video::ATTRIBUTE_NC => false, - ]); +test('no nc tag', function () { + $video = Video::factory()->createOne([ + Video::ATTRIBUTE_NC => false, + ]); - static::assertNotContains('NC', $video->tags); - } + $this->assertNotContains('NC', $video->tags); +}); - /** - * The Tags attribute shall contain 'DVD' if the source is DVD. - */ - public function testDvdTag(): void - { - $source = VideoSource::DVD; +test('dvd tag', function () { + $source = VideoSource::DVD; - $video = Video::factory()->createOne([ - Video::ATTRIBUTE_SOURCE => $source->value, - ]); + $video = Video::factory()->createOne([ + Video::ATTRIBUTE_SOURCE => $source->value, + ]); - static::assertContains($source->localize(), $video->tags); - } + $this->assertContains($source->localize(), $video->tags); +}); - /** - * The Tags attribute shall contain 'BD' if the source is BD. - */ - public function testBdTag(): void - { - $source = VideoSource::BD; +test('bd tag', function () { + $source = VideoSource::BD; - $video = Video::factory()->createOne([ - Video::ATTRIBUTE_SOURCE => $source->value, - ]); + $video = Video::factory()->createOne([ + Video::ATTRIBUTE_SOURCE => $source->value, + ]); - static::assertContains($source->localize(), $video->tags); - } + $this->assertContains($source->localize(), $video->tags); +}); - /** - * The Tags attribute shall not contain the description of the source if not DVD or BD. - */ - public function testOtherSourceTag(): void - { - $source = null; - while ($source === null) { - $sourceCandidate = Arr::random(VideoSource::cases()); - if ($sourceCandidate !== VideoSource::BD && $sourceCandidate !== VideoSource::DVD) { - $source = $sourceCandidate; - } +test('other source tag', function () { + $source = null; + while ($source === null) { + $sourceCandidate = Arr::random(VideoSource::cases()); + if ($sourceCandidate !== VideoSource::BD && $sourceCandidate !== VideoSource::DVD) { + $source = $sourceCandidate; } - - $video = Video::factory()->createOne([ - Video::ATTRIBUTE_SOURCE => $source->value, - ]); - - static::assertNotContains($source->localize(), $video->tags); } - /** - * The Tags attribute shall contain resolution. - */ - public function testResolutionTag(): void - { - $video = Video::factory()->createOne(); + $video = Video::factory()->createOne([ + Video::ATTRIBUTE_SOURCE => $source->value, + ]); - static::assertContains(strval($video->resolution), $video->tags); - } + $this->assertNotContains($source->localize(), $video->tags); +}); - /** - * The Tags attribute shall exclude 720 resolution from tags. - */ - public function testNo720ResolutionTag(): void - { - $video = Video::factory()->createOne([ - Video::ATTRIBUTE_RESOLUTION => 720, - ]); +test('resolution tag', function () { + $video = Video::factory()->createOne(); - static::assertNotContains(strval($video->resolution), $video->tags); - } + $this->assertContains(strval($video->resolution), $video->tags); +}); - /** - * The Tags attribute shall contain 'Subbed' if the subbed attribute is true. - */ - public function testSubbedTag(): void - { - $video = Video::factory()->createOne([ - Video::ATTRIBUTE_SUBBED => true, - ]); +test('no720 resolution tag', function () { + $video = Video::factory()->createOne([ + Video::ATTRIBUTE_RESOLUTION => 720, + ]); - static::assertContains('Subbed', $video->tags); - static::assertNotContains('Lyrics', $video->tags); - } + $this->assertNotContains(strval($video->resolution), $video->tags); +}); - /** - * The Tags attribute shall contain 'Lyrics' if the lyrics attribute is true and subbed attribute is false. - */ - public function testLyricsTag(): void - { - $video = Video::factory()->createOne([ - Video::ATTRIBUTE_SUBBED => false, - Video::ATTRIBUTE_LYRICS => true, - ]); +test('subbed tag', function () { + $video = Video::factory()->createOne([ + Video::ATTRIBUTE_SUBBED => true, + ]); - static::assertNotContains('Subbed', $video->tags); - static::assertContains('Lyrics', $video->tags); - } + $this->assertContains('Subbed', $video->tags); + $this->assertNotContains('Lyrics', $video->tags); +}); - /** - * The video source shall be the primary criterion for scoring. - * - * @param array $a - * @param array $b - */ - #[DataProvider('priorityProvider')] - public function testSourcePriority(array $a, array $b): void - { - $first = Video::factory()->createOne($a); +test('lyrics tag', function () { + $video = Video::factory()->createOne([ + Video::ATTRIBUTE_SUBBED => false, + Video::ATTRIBUTE_LYRICS => true, + ]); - $second = Video::factory()->createOne($b); + $this->assertNotContains('Subbed', $video->tags); + $this->assertContains('Lyrics', $video->tags); +}); - static::assertGreaterThan($first->getSourcePriority(), $second->getSourcePriority()); - } +test('source priority', function (array $a, array $b) { + $first = Video::factory()->createOne($a); - /** - * Videos shall have a many-to-many relationship with the type Entry. - */ - public function testEntries(): void - { - $entryCount = $this->faker->randomDigitNotNull(); + $second = Video::factory()->createOne($b); - $video = Video::factory() - ->has(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))->count($entryCount)) - ->createOne(); + $this->assertGreaterThan($first->getSourcePriority(), $second->getSourcePriority()); +})->with('priorityProvider'); +test('entries', function () { + $entryCount = fake()->randomDigitNotNull(); - static::assertInstanceOf(BelongsToMany::class, $video->animethemeentries()); - static::assertEquals($entryCount, $video->animethemeentries()->count()); - static::assertInstanceOf(AnimeThemeEntry::class, $video->animethemeentries()->first()); - static::assertEquals(AnimeThemeEntryVideo::class, $video->animethemeentries()->getPivotClass()); - } + $video = Video::factory() + ->has(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))->count($entryCount)) + ->createOne(); - /** - * Video shall belong to an Audio. - */ - public function testAudio(): void - { - $video = Video::factory() - ->for(Audio::factory()) - ->createOne(); + $this->assertInstanceOf(BelongsToMany::class, $video->animethemeentries()); + $this->assertEquals($entryCount, $video->animethemeentries()->count()); + $this->assertInstanceOf(AnimeThemeEntry::class, $video->animethemeentries()->first()); + $this->assertEquals(AnimeThemeEntryVideo::class, $video->animethemeentries()->getPivotClass()); +}); - static::assertInstanceOf(BelongsTo::class, $video->audio()); - static::assertInstanceOf(Audio::class, $video->audio()->first()); - } +test('audio', function () { + $video = Video::factory() + ->for(Audio::factory()) + ->createOne(); - /** - * Video shall have a one-to-many relationship with the type PlaylistTrack, but only if the playlist is public. - */ - public function testTracksPublic(): void - { - $trackCount = $this->faker->randomDigitNotNull(); + $this->assertInstanceOf(BelongsTo::class, $video->audio()); + $this->assertInstanceOf(Audio::class, $video->audio()->first()); +}); - $playlist = Playlist::factory()->createOne([Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC]); - $video = Video::factory() - ->has(PlaylistTrack::factory()->for($playlist)->count($trackCount), Video::RELATION_TRACKS) - ->createOne(); +test('tracks public', function () { + $trackCount = fake()->randomDigitNotNull(); - static::assertInstanceOf(HasMany::class, $video->tracks()); - static::assertEquals($trackCount, $video->tracks()->count()); - static::assertInstanceOf(PlaylistTrack::class, $video->tracks()->first()); - } + $playlist = Playlist::factory()->createOne([Playlist::ATTRIBUTE_VISIBILITY => PlaylistVisibility::PUBLIC]); + $video = Video::factory() + ->has(PlaylistTrack::factory()->for($playlist)->count($trackCount), Video::RELATION_TRACKS) + ->createOne(); - /** - * Video shall have a one-to-many relationship with the type PlaylistTrack, but only if the playlist is public. - */ - public function testTracksNotPublic(): void - { - $trackCount = $this->faker->randomDigitNotNull(); + $this->assertInstanceOf(HasMany::class, $video->tracks()); + $this->assertEquals($trackCount, $video->tracks()->count()); + $this->assertInstanceOf(PlaylistTrack::class, $video->tracks()->first()); +}); - $visibility = Arr::random([PlaylistVisibility::PRIVATE, PlaylistVisibility::UNLISTED]); - $playlist = Playlist::factory()->createOne([Playlist::ATTRIBUTE_VISIBILITY => $visibility]); - $video = Video::factory() - ->has(PlaylistTrack::factory()->for($playlist)->count($trackCount), Video::RELATION_TRACKS) - ->createOne(); +test('tracks not public', function () { + $trackCount = fake()->randomDigitNotNull(); - static::assertInstanceOf(HasMany::class, $video->tracks()); - static::assertNotEquals($trackCount, $video->tracks()->count()); - } + $visibility = Arr::random([PlaylistVisibility::PRIVATE, PlaylistVisibility::UNLISTED]); + $playlist = Playlist::factory()->createOne([Playlist::ATTRIBUTE_VISIBILITY => $visibility]); + $video = Video::factory() + ->has(PlaylistTrack::factory()->for($playlist)->count($trackCount), Video::RELATION_TRACKS) + ->createOne(); - /** - * Video shall have a one-to-one relationship with the type Script. - */ - public function testScript(): void - { - $video = Video::factory() - ->has(VideoScript::factory(), Video::RELATION_SCRIPT) - ->createOne(); + $this->assertInstanceOf(HasMany::class, $video->tracks()); + $this->assertNotEquals($trackCount, $video->tracks()->count()); +}); - static::assertInstanceOf(HasOne::class, $video->videoscript()); - static::assertInstanceOf(VideoScript::class, $video->videoscript()->first()); - } +test('script', function () { + $video = Video::factory() + ->has(VideoScript::factory(), Video::RELATION_SCRIPT) + ->createOne(); - /** - * Provider for source priority testing. - * - * @return array - */ - public static function priorityProvider(): array - { - return [ + $this->assertInstanceOf(HasOne::class, $video->videoscript()); + $this->assertInstanceOf(VideoScript::class, $video->videoscript()->first()); +}); +/** + * Provider for source priority testing. + * + * @return array + */ +dataset('priorityProvider', function () { + return [ + [ [ - [ - Video::ATTRIBUTE_SOURCE => VideoSource::WEB->value, - ], - [ - Video::ATTRIBUTE_SOURCE => VideoSource::BD->value, - ], + Video::ATTRIBUTE_SOURCE => VideoSource::WEB->value, ], [ - [ - Video::ATTRIBUTE_SOURCE => VideoSource::BD->value, - Video::ATTRIBUTE_OVERLAP => VideoOverlap::OVER->value, - Video::ATTRIBUTE_LYRICS => false, - Video::ATTRIBUTE_SUBBED => false, - ], - [ - Video::ATTRIBUTE_SOURCE => VideoSource::BD->value, - Video::ATTRIBUTE_OVERLAP => VideoOverlap::NONE->value, - Video::ATTRIBUTE_LYRICS => false, - Video::ATTRIBUTE_SUBBED => false, - ], + Video::ATTRIBUTE_SOURCE => VideoSource::BD->value, + ], + ], + [ + [ + Video::ATTRIBUTE_SOURCE => VideoSource::BD->value, + Video::ATTRIBUTE_OVERLAP => VideoOverlap::OVER->value, + Video::ATTRIBUTE_LYRICS => false, + Video::ATTRIBUTE_SUBBED => false, ], [ - [ - Video::ATTRIBUTE_SOURCE => VideoSource::BD->value, - Video::ATTRIBUTE_OVERLAP => VideoOverlap::TRANS->value, - Video::ATTRIBUTE_LYRICS => false, - Video::ATTRIBUTE_SUBBED => false, - ], - [ - Video::ATTRIBUTE_SOURCE => VideoSource::BD->value, - Video::ATTRIBUTE_OVERLAP => VideoOverlap::NONE->value, - Video::ATTRIBUTE_LYRICS => false, - Video::ATTRIBUTE_SUBBED => false, - ], + Video::ATTRIBUTE_SOURCE => VideoSource::BD->value, + Video::ATTRIBUTE_OVERLAP => VideoOverlap::NONE->value, + Video::ATTRIBUTE_LYRICS => false, + Video::ATTRIBUTE_SUBBED => false, + ], + ], + [ + [ + Video::ATTRIBUTE_SOURCE => VideoSource::BD->value, + Video::ATTRIBUTE_OVERLAP => VideoOverlap::TRANS->value, + Video::ATTRIBUTE_LYRICS => false, + Video::ATTRIBUTE_SUBBED => false, ], [ - [ - Video::ATTRIBUTE_SOURCE => VideoSource::BD->value, - Video::ATTRIBUTE_OVERLAP => VideoOverlap::NONE->value, - Video::ATTRIBUTE_LYRICS => true, - Video::ATTRIBUTE_SUBBED => false, - ], - [ - Video::ATTRIBUTE_SOURCE => VideoSource::BD->value, - Video::ATTRIBUTE_OVERLAP => VideoOverlap::NONE->value, - Video::ATTRIBUTE_LYRICS => false, - Video::ATTRIBUTE_SUBBED => false, - ], + Video::ATTRIBUTE_SOURCE => VideoSource::BD->value, + Video::ATTRIBUTE_OVERLAP => VideoOverlap::NONE->value, + Video::ATTRIBUTE_LYRICS => false, + Video::ATTRIBUTE_SUBBED => false, + ], + ], + [ + [ + Video::ATTRIBUTE_SOURCE => VideoSource::BD->value, + Video::ATTRIBUTE_OVERLAP => VideoOverlap::NONE->value, + Video::ATTRIBUTE_LYRICS => true, + Video::ATTRIBUTE_SUBBED => false, ], [ - [ - Video::ATTRIBUTE_SOURCE => VideoSource::BD->value, - Video::ATTRIBUTE_OVERLAP => VideoOverlap::NONE->value, - Video::ATTRIBUTE_LYRICS => false, - Video::ATTRIBUTE_SUBBED => true, - ], - [ - Video::ATTRIBUTE_SOURCE => VideoSource::BD->value, - Video::ATTRIBUTE_OVERLAP => VideoOverlap::NONE, - Video::ATTRIBUTE_LYRICS => false, - Video::ATTRIBUTE_SUBBED => false, - ], + Video::ATTRIBUTE_SOURCE => VideoSource::BD->value, + Video::ATTRIBUTE_OVERLAP => VideoOverlap::NONE->value, + Video::ATTRIBUTE_LYRICS => false, + Video::ATTRIBUTE_SUBBED => false, ], - ]; - } + ], + [ + [ + Video::ATTRIBUTE_SOURCE => VideoSource::BD->value, + Video::ATTRIBUTE_OVERLAP => VideoOverlap::NONE->value, + Video::ATTRIBUTE_LYRICS => false, + Video::ATTRIBUTE_SUBBED => true, + ], + [ + Video::ATTRIBUTE_SOURCE => VideoSource::BD->value, + Video::ATTRIBUTE_OVERLAP => VideoOverlap::NONE, + Video::ATTRIBUTE_LYRICS => false, + Video::ATTRIBUTE_SUBBED => false, + ], + ], + ]; +}); - /** - * The video shall not be deleted from storage when the Video is deleted. - */ - public function testVideoStorageDeletion(): void - { - $fs = Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); - $file = File::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); - $fsFile = $fs->putFile('', $file); +test('video storage deletion', function () { + $fs = Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); + $file = File::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); + $fsFile = $fs->putFile('', $file); - $video = Video::factory()->createOne([ - Video::ATTRIBUTE_PATH => $fsFile, - ]); + $video = Video::factory()->createOne([ + Video::ATTRIBUTE_PATH => $fsFile, + ]); - $video->delete(); + $video->delete(); - static::assertTrue($fs->exists($video->path)); - } + $this->assertTrue($fs->exists($video->path)); +}); - /** - * The video shall be deleted from storage when the Video is force deleted. - */ - public function testVideoStorageForceDeletion(): void - { - Event::fakeExcept(VideoForceDeleting::class); +test('video storage force deletion', function () { + Event::fakeExcept(VideoForceDeleting::class); - $fs = Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); - $file = File::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); - $fsFile = $fs->putFile('', $file); + $fs = Storage::fake(Config::get(VideoConstants::DEFAULT_DISK_QUALIFIED)); + $file = File::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); + $fsFile = $fs->putFile('', $file); - $video = Video::factory()->createOne([ - Video::ATTRIBUTE_PATH => $fsFile, - ]); + $video = Video::factory()->createOne([ + Video::ATTRIBUTE_PATH => $fsFile, + ]); - $video->forceDelete(); + $video->forceDelete(); - static::assertFalse($fs->exists($video->path)); - } -} + $this->assertFalse($fs->exists($video->path)); +}); diff --git a/tests/Unit/Notifications/DiscordNotificationTest.php b/tests/Unit/Notifications/DiscordNotificationTest.php index c0a32cd96..6d088569e 100644 --- a/tests/Unit/Notifications/DiscordNotificationTest.php +++ b/tests/Unit/Notifications/DiscordNotificationTest.php @@ -2,37 +2,23 @@ declare(strict_types=1); -namespace Tests\Unit\Notifications; - use App\Notifications\DiscordNotification; use Illuminate\Notifications\AnonymousNotifiable; use NotificationChannels\Discord\DiscordChannel; use NotificationChannels\Discord\DiscordMessage; -use Tests\TestCase; -class DiscordNotificationTest extends TestCase -{ - /** - * A Discord Notification shall be delivered to a Discord Channel. - */ - public function testViaDiscordMessage(): void - { - $message = DiscordMessage::create(); +test('via discord message', function () { + $message = DiscordMessage::create(); - $notification = new DiscordNotification($message); + $notification = new DiscordNotification($message); - static::assertEquals([DiscordChannel::class], $notification->via(new AnonymousNotifiable())); - } + $this->assertEquals([DiscordChannel::class], $notification->via(new AnonymousNotifiable())); +}); - /** - * A Discord Notification shall deliver a Discord Message. - */ - public function testToDiscordMessage(): void - { - $message = DiscordMessage::create(); +test('to discord message', function () { + $message = DiscordMessage::create(); - $notification = new DiscordNotification($message); + $notification = new DiscordNotification($message); - static::assertInstanceOf(DiscordMessage::class, $notification->toDiscord(new AnonymousNotifiable())); - } -} + $this->assertInstanceOf(DiscordMessage::class, $notification->toDiscord(new AnonymousNotifiable())); +}); diff --git a/tests/Unit/Pivots/List/PlaylistImageTest.php b/tests/Unit/Pivots/List/PlaylistImageTest.php index d806b98cc..41dbb39eb 100644 --- a/tests/Unit/Pivots/List/PlaylistImageTest.php +++ b/tests/Unit/Pivots/List/PlaylistImageTest.php @@ -2,41 +2,27 @@ declare(strict_types=1); -namespace Tests\Unit\Pivots\List; - use App\Models\List\Playlist; use App\Models\Wiki\Image; use App\Pivots\List\PlaylistImage; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Tests\TestCase; -class PlaylistImageTest extends TestCase -{ - /** - * An PlaylistImage shall belong to a Playlist. - */ - public function testPlaylist(): void - { - $playlistImage = PlaylistImage::factory() - ->for(Playlist::factory()) - ->for(Image::factory()) - ->createOne(); +test('playlist', function () { + $playlistImage = PlaylistImage::factory() + ->for(Playlist::factory()) + ->for(Image::factory()) + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $playlistImage->playlist()); - static::assertInstanceOf(Playlist::class, $playlistImage->playlist()->first()); - } + $this->assertInstanceOf(BelongsTo::class, $playlistImage->playlist()); + $this->assertInstanceOf(Playlist::class, $playlistImage->playlist()->first()); +}); - /** - * An PlaylistImage shall belong to an Image. - */ - public function testImage(): void - { - $playlistImage = PlaylistImage::factory() - ->for(Playlist::factory()) - ->for(Image::factory()) - ->createOne(); +test('image', function () { + $playlistImage = PlaylistImage::factory() + ->for(Playlist::factory()) + ->for(Image::factory()) + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $playlistImage->image()); - static::assertInstanceOf(Image::class, $playlistImage->image()->first()); - } -} + $this->assertInstanceOf(BelongsTo::class, $playlistImage->image()); + $this->assertInstanceOf(Image::class, $playlistImage->image()->first()); +}); diff --git a/tests/Unit/Pivots/Wiki/AnimeImageTest.php b/tests/Unit/Pivots/Wiki/AnimeImageTest.php index ae8951519..3c7ac0938 100644 --- a/tests/Unit/Pivots/Wiki/AnimeImageTest.php +++ b/tests/Unit/Pivots/Wiki/AnimeImageTest.php @@ -2,41 +2,27 @@ declare(strict_types=1); -namespace Tests\Unit\Pivots\Wiki; - use App\Models\Wiki\Anime; use App\Models\Wiki\Image; use App\Pivots\Wiki\AnimeImage; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Tests\TestCase; -class AnimeImageTest extends TestCase -{ - /** - * An AnimeImage shall belong to an Anime. - */ - public function testAnime(): void - { - $animeImage = AnimeImage::factory() - ->for(Anime::factory()) - ->for(Image::factory()) - ->createOne(); +test('anime', function () { + $animeImage = AnimeImage::factory() + ->for(Anime::factory()) + ->for(Image::factory()) + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $animeImage->anime()); - static::assertInstanceOf(Anime::class, $animeImage->anime()->first()); - } + $this->assertInstanceOf(BelongsTo::class, $animeImage->anime()); + $this->assertInstanceOf(Anime::class, $animeImage->anime()->first()); +}); - /** - * An AnimeImage shall belong to an Image. - */ - public function testImage(): void - { - $animeImage = AnimeImage::factory() - ->for(Anime::factory()) - ->for(Image::factory()) - ->createOne(); +test('image', function () { + $animeImage = AnimeImage::factory() + ->for(Anime::factory()) + ->for(Image::factory()) + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $animeImage->image()); - static::assertInstanceOf(Image::class, $animeImage->image()->first()); - } -} + $this->assertInstanceOf(BelongsTo::class, $animeImage->image()); + $this->assertInstanceOf(Image::class, $animeImage->image()->first()); +}); diff --git a/tests/Unit/Pivots/Wiki/AnimeResourceTest.php b/tests/Unit/Pivots/Wiki/AnimeResourceTest.php index 177f4a7ae..b1c4583d1 100644 --- a/tests/Unit/Pivots/Wiki/AnimeResourceTest.php +++ b/tests/Unit/Pivots/Wiki/AnimeResourceTest.php @@ -2,41 +2,27 @@ declare(strict_types=1); -namespace Tests\Unit\Pivots\Wiki; - use App\Models\Wiki\Anime; use App\Models\Wiki\ExternalResource; use App\Pivots\Wiki\AnimeResource; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Tests\TestCase; -class AnimeResourceTest extends TestCase -{ - /** - * An AnimeResource shall belong to an Anime. - */ - public function testAnime(): void - { - $animeResource = AnimeResource::factory() - ->for(Anime::factory()) - ->for(ExternalResource::factory(), 'resource') - ->createOne(); +test('anime', function () { + $animeResource = AnimeResource::factory() + ->for(Anime::factory()) + ->for(ExternalResource::factory(), 'resource') + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $animeResource->anime()); - static::assertInstanceOf(Anime::class, $animeResource->anime()->first()); - } + $this->assertInstanceOf(BelongsTo::class, $animeResource->anime()); + $this->assertInstanceOf(Anime::class, $animeResource->anime()->first()); +}); - /** - * An AnimeResource shall belong to an ExternalResource. - */ - public function testResource(): void - { - $animeResource = AnimeResource::factory() - ->for(Anime::factory()) - ->for(ExternalResource::factory(), 'resource') - ->createOne(); +test('resource', function () { + $animeResource = AnimeResource::factory() + ->for(Anime::factory()) + ->for(ExternalResource::factory(), 'resource') + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $animeResource->resource()); - static::assertInstanceOf(ExternalResource::class, $animeResource->resource()->first()); - } -} + $this->assertInstanceOf(BelongsTo::class, $animeResource->resource()); + $this->assertInstanceOf(ExternalResource::class, $animeResource->resource()->first()); +}); diff --git a/tests/Unit/Pivots/Wiki/AnimeSeriesTest.php b/tests/Unit/Pivots/Wiki/AnimeSeriesTest.php index 72202486f..f1b406f61 100644 --- a/tests/Unit/Pivots/Wiki/AnimeSeriesTest.php +++ b/tests/Unit/Pivots/Wiki/AnimeSeriesTest.php @@ -2,41 +2,27 @@ declare(strict_types=1); -namespace Tests\Unit\Pivots\Wiki; - use App\Models\Wiki\Anime; use App\Models\Wiki\Series; use App\Pivots\Wiki\AnimeSeries; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Tests\TestCase; -class AnimeSeriesTest extends TestCase -{ - /** - * An AnimeSeries shall belong to an Anime. - */ - public function testAnime(): void - { - $animeSeries = AnimeSeries::factory() - ->for(Anime::factory()) - ->for(Series::factory()) - ->createOne(); +test('anime', function () { + $animeSeries = AnimeSeries::factory() + ->for(Anime::factory()) + ->for(Series::factory()) + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $animeSeries->anime()); - static::assertInstanceOf(Anime::class, $animeSeries->anime()->first()); - } + $this->assertInstanceOf(BelongsTo::class, $animeSeries->anime()); + $this->assertInstanceOf(Anime::class, $animeSeries->anime()->first()); +}); - /** - * An AnimeSeries shall belong to a Series. - */ - public function testSeries(): void - { - $animeSeries = AnimeSeries::factory() - ->for(Anime::factory()) - ->for(Series::factory()) - ->createOne(); +test('series', function () { + $animeSeries = AnimeSeries::factory() + ->for(Anime::factory()) + ->for(Series::factory()) + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $animeSeries->series()); - static::assertInstanceOf(Series::class, $animeSeries->series()->first()); - } -} + $this->assertInstanceOf(BelongsTo::class, $animeSeries->series()); + $this->assertInstanceOf(Series::class, $animeSeries->series()->first()); +}); diff --git a/tests/Unit/Pivots/Wiki/AnimeStudioTest.php b/tests/Unit/Pivots/Wiki/AnimeStudioTest.php index 15f29e7d1..2364ffb04 100644 --- a/tests/Unit/Pivots/Wiki/AnimeStudioTest.php +++ b/tests/Unit/Pivots/Wiki/AnimeStudioTest.php @@ -2,41 +2,27 @@ declare(strict_types=1); -namespace Tests\Unit\Pivots\Wiki; - use App\Models\Wiki\Anime; use App\Models\Wiki\Studio; use App\Pivots\Wiki\AnimeStudio; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Tests\TestCase; -class AnimeStudioTest extends TestCase -{ - /** - * An AnimeStudio shall belong to an Anime. - */ - public function testAnime(): void - { - $animeStudio = AnimeStudio::factory() - ->for(Anime::factory()) - ->for(Studio::factory()) - ->createOne(); +test('anime', function () { + $animeStudio = AnimeStudio::factory() + ->for(Anime::factory()) + ->for(Studio::factory()) + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $animeStudio->anime()); - static::assertInstanceOf(Anime::class, $animeStudio->anime()->first()); - } + $this->assertInstanceOf(BelongsTo::class, $animeStudio->anime()); + $this->assertInstanceOf(Anime::class, $animeStudio->anime()->first()); +}); - /** - * An AnimeStudio shall belong to a Studio. - */ - public function testStudio(): void - { - $animeStudio = AnimeStudio::factory() - ->for(Anime::factory()) - ->for(Studio::factory()) - ->createOne(); +test('studio', function () { + $animeStudio = AnimeStudio::factory() + ->for(Anime::factory()) + ->for(Studio::factory()) + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $animeStudio->studio()); - static::assertInstanceOf(Studio::class, $animeStudio->studio()->first()); - } -} + $this->assertInstanceOf(BelongsTo::class, $animeStudio->studio()); + $this->assertInstanceOf(Studio::class, $animeStudio->studio()->first()); +}); diff --git a/tests/Unit/Pivots/Wiki/AnimeThemeEntryVideoTest.php b/tests/Unit/Pivots/Wiki/AnimeThemeEntryVideoTest.php index 2cb115164..6c385cb40 100644 --- a/tests/Unit/Pivots/Wiki/AnimeThemeEntryVideoTest.php +++ b/tests/Unit/Pivots/Wiki/AnimeThemeEntryVideoTest.php @@ -2,43 +2,29 @@ declare(strict_types=1); -namespace Tests\Unit\Pivots\Wiki; - use App\Models\Wiki\Anime; use App\Models\Wiki\Anime\AnimeTheme; use App\Models\Wiki\Anime\Theme\AnimeThemeEntry; use App\Models\Wiki\Video; use App\Pivots\Wiki\AnimeThemeEntryVideo; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Tests\TestCase; -class AnimeThemeEntryVideoTest extends TestCase -{ - /** - * An AnimeThemeEntryVideo shall belong to a Video. - */ - public function testVideo(): void - { - $animeThemeEntryVideo = AnimeThemeEntryVideo::factory() - ->for(Video::factory()) - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->createOne(); +test('video', function () { + $animeThemeEntryVideo = AnimeThemeEntryVideo::factory() + ->for(Video::factory()) + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $animeThemeEntryVideo->video()); - static::assertInstanceOf(Video::class, $animeThemeEntryVideo->video()->first()); - } + $this->assertInstanceOf(BelongsTo::class, $animeThemeEntryVideo->video()); + $this->assertInstanceOf(Video::class, $animeThemeEntryVideo->video()->first()); +}); - /** - * An AnimeThemeEntryVideo shall belong to an Entry. - */ - public function testEntry(): void - { - $animeThemeEntryVideo = AnimeThemeEntryVideo::factory() - ->for(Video::factory()) - ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) - ->createOne(); +test('entry', function () { + $animeThemeEntryVideo = AnimeThemeEntryVideo::factory() + ->for(Video::factory()) + ->for(AnimeThemeEntry::factory()->for(AnimeTheme::factory()->for(Anime::factory()))) + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $animeThemeEntryVideo->animethemeentry()); - static::assertInstanceOf(AnimeThemeEntry::class, $animeThemeEntryVideo->animethemeentry()->first()); - } -} + $this->assertInstanceOf(BelongsTo::class, $animeThemeEntryVideo->animethemeentry()); + $this->assertInstanceOf(AnimeThemeEntry::class, $animeThemeEntryVideo->animethemeentry()->first()); +}); diff --git a/tests/Unit/Pivots/Wiki/ArtistImageTest.php b/tests/Unit/Pivots/Wiki/ArtistImageTest.php index d50810578..ba19223ab 100644 --- a/tests/Unit/Pivots/Wiki/ArtistImageTest.php +++ b/tests/Unit/Pivots/Wiki/ArtistImageTest.php @@ -2,41 +2,27 @@ declare(strict_types=1); -namespace Tests\Unit\Pivots\Wiki; - use App\Models\Wiki\Artist; use App\Models\Wiki\Image; use App\Pivots\Wiki\ArtistImage; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Tests\TestCase; -class ArtistImageTest extends TestCase -{ - /** - * An ArtistImage shall belong to an Artist. - */ - public function testArtist(): void - { - $artistImage = ArtistImage::factory() - ->for(Artist::factory()) - ->for(Image::factory()) - ->createOne(); +test('artist', function () { + $artistImage = ArtistImage::factory() + ->for(Artist::factory()) + ->for(Image::factory()) + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $artistImage->artist()); - static::assertInstanceOf(Artist::class, $artistImage->artist()->first()); - } + $this->assertInstanceOf(BelongsTo::class, $artistImage->artist()); + $this->assertInstanceOf(Artist::class, $artistImage->artist()->first()); +}); - /** - * An ArtistImage shall belong to an Image. - */ - public function testImage(): void - { - $artistImage = ArtistImage::factory() - ->for(Artist::factory()) - ->for(Image::factory()) - ->createOne(); +test('image', function () { + $artistImage = ArtistImage::factory() + ->for(Artist::factory()) + ->for(Image::factory()) + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $artistImage->image()); - static::assertInstanceOf(Image::class, $artistImage->image()->first()); - } -} + $this->assertInstanceOf(BelongsTo::class, $artistImage->image()); + $this->assertInstanceOf(Image::class, $artistImage->image()->first()); +}); diff --git a/tests/Unit/Pivots/Wiki/ArtistMemberTest.php b/tests/Unit/Pivots/Wiki/ArtistMemberTest.php index af5e83197..bad4bd74e 100644 --- a/tests/Unit/Pivots/Wiki/ArtistMemberTest.php +++ b/tests/Unit/Pivots/Wiki/ArtistMemberTest.php @@ -2,40 +2,26 @@ declare(strict_types=1); -namespace Tests\Unit\Pivots\Wiki; - use App\Models\Wiki\Artist; use App\Pivots\Wiki\ArtistMember; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Tests\TestCase; -class ArtistMemberTest extends TestCase -{ - /** - * An ArtistMember shall belong to an Artist. - */ - public function testArtist(): void - { - $artistMember = ArtistMember::factory() - ->for(Artist::factory(), 'artist') - ->for(Artist::factory(), 'member') - ->createOne(); +test('artist', function () { + $artistMember = ArtistMember::factory() + ->for(Artist::factory(), 'artist') + ->for(Artist::factory(), 'member') + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $artistMember->artist()); - static::assertInstanceOf(Artist::class, $artistMember->artist()->first()); - } + $this->assertInstanceOf(BelongsTo::class, $artistMember->artist()); + $this->assertInstanceOf(Artist::class, $artistMember->artist()->first()); +}); - /** - * An ArtistMember shall belong to a Member. - */ - public function testMember(): void - { - $artistMember = ArtistMember::factory() - ->for(Artist::factory(), 'artist') - ->for(Artist::factory(), 'member') - ->createOne(); +test('member', function () { + $artistMember = ArtistMember::factory() + ->for(Artist::factory(), 'artist') + ->for(Artist::factory(), 'member') + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $artistMember->member()); - static::assertInstanceOf(Artist::class, $artistMember->member()->first()); - } -} + $this->assertInstanceOf(BelongsTo::class, $artistMember->member()); + $this->assertInstanceOf(Artist::class, $artistMember->member()->first()); +}); diff --git a/tests/Unit/Pivots/Wiki/ArtistResourceTest.php b/tests/Unit/Pivots/Wiki/ArtistResourceTest.php index 82ff72d1f..c521c0701 100644 --- a/tests/Unit/Pivots/Wiki/ArtistResourceTest.php +++ b/tests/Unit/Pivots/Wiki/ArtistResourceTest.php @@ -2,41 +2,27 @@ declare(strict_types=1); -namespace Tests\Unit\Pivots\Wiki; - use App\Models\Wiki\Artist; use App\Models\Wiki\ExternalResource; use App\Pivots\Wiki\ArtistResource; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Tests\TestCase; -class ArtistResourceTest extends TestCase -{ - /** - * An ArtistResource shall belong to an Artist. - */ - public function testArtist(): void - { - $artistResource = ArtistResource::factory() - ->for(Artist::factory()) - ->for(ExternalResource::factory(), 'resource') - ->createOne(); +test('artist', function () { + $artistResource = ArtistResource::factory() + ->for(Artist::factory()) + ->for(ExternalResource::factory(), 'resource') + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $artistResource->artist()); - static::assertInstanceOf(Artist::class, $artistResource->artist()->first()); - } + $this->assertInstanceOf(BelongsTo::class, $artistResource->artist()); + $this->assertInstanceOf(Artist::class, $artistResource->artist()->first()); +}); - /** - * An ArtistResource shall belong to an ExternalResource. - */ - public function testResource(): void - { - $artistResource = ArtistResource::factory() - ->for(Artist::factory()) - ->for(ExternalResource::factory(), 'resource') - ->createOne(); +test('resource', function () { + $artistResource = ArtistResource::factory() + ->for(Artist::factory()) + ->for(ExternalResource::factory(), 'resource') + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $artistResource->resource()); - static::assertInstanceOf(ExternalResource::class, $artistResource->resource()->first()); - } -} + $this->assertInstanceOf(BelongsTo::class, $artistResource->resource()); + $this->assertInstanceOf(ExternalResource::class, $artistResource->resource()->first()); +}); diff --git a/tests/Unit/Pivots/Wiki/ArtistSongTest.php b/tests/Unit/Pivots/Wiki/ArtistSongTest.php index 868395734..80dc85f26 100644 --- a/tests/Unit/Pivots/Wiki/ArtistSongTest.php +++ b/tests/Unit/Pivots/Wiki/ArtistSongTest.php @@ -2,41 +2,27 @@ declare(strict_types=1); -namespace Tests\Unit\Pivots\Wiki; - use App\Models\Wiki\Artist; use App\Models\Wiki\Song; use App\Pivots\Wiki\ArtistSong; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Tests\TestCase; -class ArtistSongTest extends TestCase -{ - /** - * An ArtistSong shall belong to an Artist. - */ - public function testArtist(): void - { - $artistSong = ArtistSong::factory() - ->for(Artist::factory()) - ->for(Song::factory()) - ->createOne(); +test('artist', function () { + $artistSong = ArtistSong::factory() + ->for(Artist::factory()) + ->for(Song::factory()) + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $artistSong->artist()); - static::assertInstanceOf(Artist::class, $artistSong->artist()->first()); - } + $this->assertInstanceOf(BelongsTo::class, $artistSong->artist()); + $this->assertInstanceOf(Artist::class, $artistSong->artist()->first()); +}); - /** - * An ArtistSong shall belong to a Song. - */ - public function testSong(): void - { - $artistSong = ArtistSong::factory() - ->for(Artist::factory()) - ->for(Song::factory()) - ->createOne(); +test('song', function () { + $artistSong = ArtistSong::factory() + ->for(Artist::factory()) + ->for(Song::factory()) + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $artistSong->song()); - static::assertInstanceOf(Song::class, $artistSong->song()->first()); - } -} + $this->assertInstanceOf(BelongsTo::class, $artistSong->song()); + $this->assertInstanceOf(Song::class, $artistSong->song()->first()); +}); diff --git a/tests/Unit/Pivots/Wiki/SongResourceTest.php b/tests/Unit/Pivots/Wiki/SongResourceTest.php index cfb16e208..1458932b5 100644 --- a/tests/Unit/Pivots/Wiki/SongResourceTest.php +++ b/tests/Unit/Pivots/Wiki/SongResourceTest.php @@ -2,41 +2,27 @@ declare(strict_types=1); -namespace Tests\Unit\Pivots\Wiki; - use App\Models\Wiki\ExternalResource; use App\Models\Wiki\Song; use App\Pivots\Wiki\SongResource; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Tests\TestCase; -class SongResourceTest extends TestCase -{ - /** - * An SongResource shall belong to an Song. - */ - public function testSong(): void - { - $songResource = SongResource::factory() - ->for(Song::factory()) - ->for(ExternalResource::factory(), 'resource') - ->createOne(); +test('song', function () { + $songResource = SongResource::factory() + ->for(Song::factory()) + ->for(ExternalResource::factory(), 'resource') + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $songResource->song()); - static::assertInstanceOf(Song::class, $songResource->song()->first()); - } + $this->assertInstanceOf(BelongsTo::class, $songResource->song()); + $this->assertInstanceOf(Song::class, $songResource->song()->first()); +}); - /** - * An SongResource shall belong to an ExternalResource. - */ - public function testResource(): void - { - $songResource = SongResource::factory() - ->for(Song::factory()) - ->for(ExternalResource::factory(), 'resource') - ->createOne(); +test('resource', function () { + $songResource = SongResource::factory() + ->for(Song::factory()) + ->for(ExternalResource::factory(), 'resource') + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $songResource->resource()); - static::assertInstanceOf(ExternalResource::class, $songResource->resource()->first()); - } -} + $this->assertInstanceOf(BelongsTo::class, $songResource->resource()); + $this->assertInstanceOf(ExternalResource::class, $songResource->resource()->first()); +}); diff --git a/tests/Unit/Pivots/Wiki/StudioImageTest.php b/tests/Unit/Pivots/Wiki/StudioImageTest.php index a18073025..2bdbb2e65 100644 --- a/tests/Unit/Pivots/Wiki/StudioImageTest.php +++ b/tests/Unit/Pivots/Wiki/StudioImageTest.php @@ -2,41 +2,27 @@ declare(strict_types=1); -namespace Tests\Unit\Pivots\Wiki; - use App\Models\Wiki\Image; use App\Models\Wiki\Studio; use App\Pivots\Wiki\StudioImage; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Tests\TestCase; -class StudioImageTest extends TestCase -{ - /** - * An StudioImage shall belong to a Studio. - */ - public function testStudio(): void - { - $studioImage = StudioImage::factory() - ->for(Studio::factory()) - ->for(Image::factory()) - ->createOne(); +test('studio', function () { + $studioImage = StudioImage::factory() + ->for(Studio::factory()) + ->for(Image::factory()) + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $studioImage->studio()); - static::assertInstanceOf(Studio::class, $studioImage->studio()->first()); - } + $this->assertInstanceOf(BelongsTo::class, $studioImage->studio()); + $this->assertInstanceOf(Studio::class, $studioImage->studio()->first()); +}); - /** - * An StudioImage shall belong to an Image. - */ - public function testImage(): void - { - $studioImage = StudioImage::factory() - ->for(Studio::factory()) - ->for(Image::factory()) - ->createOne(); +test('image', function () { + $studioImage = StudioImage::factory() + ->for(Studio::factory()) + ->for(Image::factory()) + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $studioImage->image()); - static::assertInstanceOf(Image::class, $studioImage->image()->first()); - } -} + $this->assertInstanceOf(BelongsTo::class, $studioImage->image()); + $this->assertInstanceOf(Image::class, $studioImage->image()->first()); +}); diff --git a/tests/Unit/Pivots/Wiki/StudioResourceTest.php b/tests/Unit/Pivots/Wiki/StudioResourceTest.php index 4bbaf1df0..679d31193 100644 --- a/tests/Unit/Pivots/Wiki/StudioResourceTest.php +++ b/tests/Unit/Pivots/Wiki/StudioResourceTest.php @@ -2,41 +2,27 @@ declare(strict_types=1); -namespace Tests\Unit\Pivots\Wiki; - use App\Models\Wiki\ExternalResource; use App\Models\Wiki\Studio; use App\Pivots\Wiki\StudioResource; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Tests\TestCase; -class StudioResourceTest extends TestCase -{ - /** - * A StudioResource shall belong to a Studio. - */ - public function testStudio(): void - { - $studioResource = StudioResource::factory() - ->for(Studio::factory()) - ->for(ExternalResource::factory(), 'resource') - ->createOne(); +test('studio', function () { + $studioResource = StudioResource::factory() + ->for(Studio::factory()) + ->for(ExternalResource::factory(), 'resource') + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $studioResource->studio()); - static::assertInstanceOf(Studio::class, $studioResource->studio()->first()); - } + $this->assertInstanceOf(BelongsTo::class, $studioResource->studio()); + $this->assertInstanceOf(Studio::class, $studioResource->studio()->first()); +}); - /** - * A StudioResource shall belong to an ExternalResource. - */ - public function testResource(): void - { - $studioResource = StudioResource::factory() - ->for(Studio::factory()) - ->for(ExternalResource::factory(), 'resource') - ->createOne(); +test('resource', function () { + $studioResource = StudioResource::factory() + ->for(Studio::factory()) + ->for(ExternalResource::factory(), 'resource') + ->createOne(); - static::assertInstanceOf(BelongsTo::class, $studioResource->resource()); - static::assertInstanceOf(ExternalResource::class, $studioResource->resource()->first()); - } -} + $this->assertInstanceOf(BelongsTo::class, $studioResource->resource()); + $this->assertInstanceOf(ExternalResource::class, $studioResource->resource()->first()); +}); diff --git a/tests/Unit/Rules/Api/DelimitedTest.php b/tests/Unit/Rules/Api/DelimitedTest.php index ff5b6726c..dcdc06735 100644 --- a/tests/Unit/Rules/Api/DelimitedTest.php +++ b/tests/Unit/Rules/Api/DelimitedTest.php @@ -2,84 +2,61 @@ declare(strict_types=1); -namespace Tests\Unit\Rules\Api; - use App\Rules\Api\DelimitedRule; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Facades\Validator; -use Tests\TestCase; -class DelimitedTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Delimited Rule shall pass if all values pass the given rules. - */ - public function testPassesIfAllValuesPass(): void - { - $attribute = $this->faker->word(); +test('passes if all values pass', function () { + $attribute = fake()->word(); - $values = collect($this->faker->words()); + $values = collect(fake()->words()); - $validator = Validator::make( - [$attribute => $values->implode(',')], - [$attribute => new DelimitedRule(['required', 'string'])] - ); + $validator = Validator::make( + [$attribute => $values->implode(',')], + [$attribute => new DelimitedRule(['required', 'string'])] + ); - static::assertTrue($validator->passes()); - } + $this->assertTrue($validator->passes()); +}); - /** - * The Delimited Rule shall fail if there exist duplicate values. - */ - public function testFailsForDuplicateValues(): void - { - $attribute = $this->faker->word(); +test('fails for duplicate values', function () { + $attribute = fake()->word(); - $duplicate = $this->faker->word(); + $duplicate = fake()->word(); - $values = collect([$duplicate, $this->faker->word(), $duplicate]); + $values = collect([$duplicate, fake()->word(), $duplicate]); - $validator = Validator::make( - [$attribute => $values->implode(',')], - [$attribute => new DelimitedRule(['required', 'string'])] - ); + $validator = Validator::make( + [$attribute => $values->implode(',')], + [$attribute => new DelimitedRule(['required', 'string'])] + ); - static::assertFalse($validator->passes()); - } + $this->assertFalse($validator->passes()); +}); - /** - * The Delimited Rule shall fail if any value fails a rule. - */ - public function testFailsForInvalidValue(): void - { - $attribute = $this->faker->word(); +test('fails for invalid value', function () { + $attribute = fake()->word(); - $values = collect([$this->faker->randomDigitNotNull(), $this->faker->word(), $this->faker->randomDigitNotNull()]); + $values = collect([fake()->randomDigitNotNull(), fake()->word(), fake()->randomDigitNotNull()]); - $validator = Validator::make( - [$attribute => $values->implode(',')], - [$attribute => new DelimitedRule(['required', 'integer'])] - ); + $validator = Validator::make( + [$attribute => $values->implode(',')], + [$attribute => new DelimitedRule(['required', 'integer'])] + ); - static::assertFalse($validator->passes()); - } + $this->assertFalse($validator->passes()); +}); - /** - * The Delimited Rule shall validate empty values. - */ - public function testValidatesEmptyValues(): void - { - $attribute = $this->faker->word(); +test('validates empty values', function () { + $attribute = fake()->word(); - $values = collect(array_merge($this->faker->words(), [''])); + $values = collect(array_merge(fake()->words(), [''])); - $validator = Validator::make( - [$attribute => $values->implode(',')], - [$attribute => new DelimitedRule(['required', 'string'])] - ); + $validator = Validator::make( + [$attribute => $values->implode(',')], + [$attribute => new DelimitedRule(['required', 'string'])] + ); - static::assertFalse($validator->passes()); - } -} + $this->assertFalse($validator->passes()); +}); diff --git a/tests/Unit/Rules/Api/DistinctIgnoringDirectionTest.php b/tests/Unit/Rules/Api/DistinctIgnoringDirectionTest.php index 400637595..6c9ae1528 100644 --- a/tests/Unit/Rules/Api/DistinctIgnoringDirectionTest.php +++ b/tests/Unit/Rules/Api/DistinctIgnoringDirectionTest.php @@ -2,77 +2,58 @@ declare(strict_types=1); -namespace Tests\Unit\Rules\Api; - use App\Enums\Http\Api\Sort\Direction; use App\Http\Api\Sort\Sort; use App\Rules\Api\DistinctIgnoringDirectionRule; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Facades\Validator; -use Tests\TestCase; -class DistinctIgnoringDirectionTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Distinct Ignoring Direction Rule shall return false if there exist duplicate sort keys. - */ - public function testFailsIfDuplicateSort(): void - { - $key = $this->faker->word(); +test('fails if duplicate sort', function () { + $key = fake()->word(); - $sorts = collect()->pad($this->faker->numberBetween(2, 9), $key); + $sorts = collect()->pad(fake()->numberBetween(2, 9), $key); - $attribute = $this->faker->word(); + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $sorts->join(',')], - [$attribute => new DistinctIgnoringDirectionRule()] - ); + $validator = Validator::make( + [$attribute => $sorts->join(',')], + [$attribute => new DistinctIgnoringDirectionRule()] + ); - static::assertFalse($validator->passes()); + $this->assertFalse($validator->passes()); +}); + +test('fails if duplicate sort different direction', function () { + $key = fake()->word(); + + $sort = new Sort($key); + + $sorts = []; + + foreach (Direction::cases() as $direction) { + $sorts[] = $sort->format($direction); } - /** - * The Distinct Ignoring Direction Rule shall return false if there exists duplicate sort keys of differing directions. - */ - public function testFailsIfDuplicateSortDifferentDirection(): void - { - $key = $this->faker->word(); + $attribute = fake()->word(); - $sort = new Sort($key); + $validator = Validator::make( + [$attribute => implode(',', $sorts)], + [$attribute => new DistinctIgnoringDirectionRule()] + ); - $sorts = []; + $this->assertFalse($validator->passes()); +}); - foreach (Direction::cases() as $direction) { - $sorts[] = $sort->format($direction); - } +test('passes if no duplicates', function () { + $sorts = collect(fake()->words(fake()->randomDigitNotNull()))->unique(); - $attribute = $this->faker->word(); + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => implode(',', $sorts)], - [$attribute => new DistinctIgnoringDirectionRule()] - ); + $validator = Validator::make( + [$attribute => $sorts->join(',')], + [$attribute => new DistinctIgnoringDirectionRule()] + ); - static::assertFalse($validator->passes()); - } - - /** - * The Distinct Ignoring Direction Rule shall return true if there exist no duplicate sort keys. - */ - public function testPassesIfNoDuplicates(): void - { - $sorts = collect($this->faker->words($this->faker->randomDigitNotNull()))->unique(); - - $attribute = $this->faker->word(); - - $validator = Validator::make( - [$attribute => $sorts->join(',')], - [$attribute => new DistinctIgnoringDirectionRule()] - ); - - static::assertTrue($validator->passes()); - } -} + $this->assertTrue($validator->passes()); +}); diff --git a/tests/Unit/Rules/Api/EnumLocalizedNameTest.php b/tests/Unit/Rules/Api/EnumLocalizedNameTest.php index 6ed9accc0..942642f4f 100644 --- a/tests/Unit/Rules/Api/EnumLocalizedNameTest.php +++ b/tests/Unit/Rules/Api/EnumLocalizedNameTest.php @@ -2,66 +2,47 @@ declare(strict_types=1); -namespace Tests\Unit\Rules\Api; - use App\Rules\Api\EnumLocalizedNameRule; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Validator; use Illuminate\Support\Str; -use Tests\TestCase; use Tests\Unit\Enums\LocalizedEnum; -class EnumLocalizedNameTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Enum Description Rule shall return true if an enum description is provided. - */ - public function testPassesIfEnumDescription(): void - { - $enum = Arr::random(LocalizedEnum::cases()); +test('passes if enum description', function () { + $enum = Arr::random(LocalizedEnum::cases()); - $attribute = $this->faker->word(); + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $enum->localize()], - [$attribute => new EnumLocalizedNameRule(LocalizedEnum::class)] - ); + $validator = Validator::make( + [$attribute => $enum->localize()], + [$attribute => new EnumLocalizedNameRule(LocalizedEnum::class)] + ); - static::assertTrue($validator->passes()); - } + $this->assertTrue($validator->passes()); +}); - /** - * The Enum Description Rule shall return false if an enum value is provided. - */ - public function testFailsIfEnumValue(): void - { - $enum = Arr::random(LocalizedEnum::cases()); +test('fails if enum value', function () { + $enum = Arr::random(LocalizedEnum::cases()); - $attribute = $this->faker->word(); + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $enum->value], - [$attribute => new EnumLocalizedNameRule(LocalizedEnum::class)] - ); + $validator = Validator::make( + [$attribute => $enum->value], + [$attribute => new EnumLocalizedNameRule(LocalizedEnum::class)] + ); - static::assertFalse($validator->passes()); - } + $this->assertFalse($validator->passes()); +}); - /** - * The Enum Description Rule shall return false if an enum description is not provided. - */ - public function testFailsIfString(): void - { - $attribute = $this->faker->word(); +test('fails if string', function () { + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => Str::random()], - [$attribute => new EnumLocalizedNameRule(LocalizedEnum::class)] - ); + $validator = Validator::make( + [$attribute => Str::random()], + [$attribute => new EnumLocalizedNameRule(LocalizedEnum::class)] + ); - static::assertFalse($validator->passes()); - } -} + $this->assertFalse($validator->passes()); +}); diff --git a/tests/Unit/Rules/Api/IsValidBooleanTest.php b/tests/Unit/Rules/Api/IsValidBooleanTest.php index 19afbe4da..4807a5044 100644 --- a/tests/Unit/Rules/Api/IsValidBooleanTest.php +++ b/tests/Unit/Rules/Api/IsValidBooleanTest.php @@ -2,113 +2,79 @@ declare(strict_types=1); -namespace Tests\Unit\Rules\Api; - use App\Rules\Api\IsValidBoolean; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Facades\Validator; -use Tests\TestCase; -/** - * IsValidBooleanTest. - */ -class IsValidBooleanTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Is Valid Boolean Rule shall return true if a boolean is provided. - */ - public function testPassesIfBoolean(): void - { - $attribute = $this->faker->word(); +test('passes if boolean', function () { + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $this->faker->boolean()], - [$attribute => new IsValidBoolean()] - ); + $validator = Validator::make( + [$attribute => fake()->boolean()], + [$attribute => new IsValidBoolean()] + ); - static::assertTrue($validator->passes()); - } + $this->assertTrue($validator->passes()); +}); - /** - * The Is Valid Boolean Rule shall return true if "true" or "false" is provided. - */ - public function testPassesIfBooleanString(): void - { - $booleanString = $this->faker->boolean() ? 'true' : 'false'; +test('passes if boolean string', function () { + $booleanString = fake()->boolean() ? 'true' : 'false'; - $attribute = $this->faker->word(); + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $booleanString], - [$attribute => new IsValidBoolean()] - ); + $validator = Validator::make( + [$attribute => $booleanString], + [$attribute => new IsValidBoolean()] + ); - static::assertTrue($validator->passes()); - } + $this->assertTrue($validator->passes()); +}); - /** - * The Is Valid Boolean Rule shall return true if 1 or 0 is provided. - */ - public function testPassesIfBooleanInteger(): void - { - $booleanInteger = $this->faker->boolean() ? 1 : 0; +test('passes if boolean integer', function () { + $booleanInteger = fake()->boolean() ? 1 : 0; - $attribute = $this->faker->word(); + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $booleanInteger], - [$attribute => new IsValidBoolean()] - ); + $validator = Validator::make( + [$attribute => $booleanInteger], + [$attribute => new IsValidBoolean()] + ); - static::assertTrue($validator->passes()); - } + $this->assertTrue($validator->passes()); +}); - /** - * The Is Valid Boolean Rule shall return true if "on" or "off" is provided. - */ - public function testPassesIfBooleanCheckbox(): void - { - $booleanCheckbox = $this->faker->boolean() ? 'on' : 'off'; +test('passes if boolean checkbox', function () { + $booleanCheckbox = fake()->boolean() ? 'on' : 'off'; - $attribute = $this->faker->word(); + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $booleanCheckbox], - [$attribute => new IsValidBoolean()] - ); + $validator = Validator::make( + [$attribute => $booleanCheckbox], + [$attribute => new IsValidBoolean()] + ); - static::assertTrue($validator->passes()); - } + $this->assertTrue($validator->passes()); +}); - /** - * The Is Valid Boolean Rule shall return false a string is provided. - */ - public function testFailsIfString(): void - { - $attribute = $this->faker->word(); +test('fails if string', function () { + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $this->faker->word()], - [$attribute => new IsValidBoolean()] - ); + $validator = Validator::make( + [$attribute => fake()->word()], + [$attribute => new IsValidBoolean()] + ); - static::assertFalse($validator->passes()); - } + $this->assertFalse($validator->passes()); +}); - /** - * The Is Valid Boolean Rule shall return false a number is provided. - */ - public function testFailsIfNumber(): void - { - $attribute = $this->faker->word(); +test('fails if number', function () { + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $this->faker->numberBetween(2, 9)], - [$attribute => new IsValidBoolean()] - ); + $validator = Validator::make( + [$attribute => fake()->numberBetween(2, 9)], + [$attribute => new IsValidBoolean()] + ); - static::assertFalse($validator->passes()); - } -} + $this->assertFalse($validator->passes()); +}); diff --git a/tests/Unit/Rules/Api/RandomSoleTest.php b/tests/Unit/Rules/Api/RandomSoleTest.php index 4cb2c6569..476679d7e 100644 --- a/tests/Unit/Rules/Api/RandomSoleTest.php +++ b/tests/Unit/Rules/Api/RandomSoleTest.php @@ -2,66 +2,47 @@ declare(strict_types=1); -namespace Tests\Unit\Rules\Api; - use App\Http\Api\Criteria\Sort\RandomCriteria; use App\Rules\Api\RandomSoleRule; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Facades\Validator; -use Tests\TestCase; -class RandomSoleTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Random Sole Rule shall return false if the random key is provided and is not the sole sort. - */ - public function testFailsIfRandomIsNotSoleSort(): void - { - $sorts = $this->faker->words($this->faker->randomDigitNotNull()); +test('fails if random is not sole sort', function () { + $sorts = fake()->words(fake()->randomDigitNotNull()); - $sorts[] = RandomCriteria::PARAM_VALUE; + $sorts[] = RandomCriteria::PARAM_VALUE; - $attribute = $this->faker->word(); + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => implode(',', $sorts)], - [$attribute => new RandomSoleRule()] - ); + $validator = Validator::make( + [$attribute => implode(',', $sorts)], + [$attribute => new RandomSoleRule()] + ); - static::assertFalse($validator->passes()); - } + $this->assertFalse($validator->passes()); +}); - /** - * The Random Sole Rule shall return true if the random key is not provided. - */ - public function testPassesIfRandomIsNotIncluded(): void - { - $sorts = $this->faker->words($this->faker->randomDigitNotNull()); +test('passes if random is not included', function () { + $sorts = fake()->words(fake()->randomDigitNotNull()); - $attribute = $this->faker->word(); + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => implode(',', $sorts)], - [$attribute => new RandomSoleRule()] - ); + $validator = Validator::make( + [$attribute => implode(',', $sorts)], + [$attribute => new RandomSoleRule()] + ); - static::assertTrue($validator->passes()); - } + $this->assertTrue($validator->passes()); +}); - /** - * The Random Sole Rule shall return true if the random key is the only sort provided. - */ - public function testPassesIfRandomIsSoleSort(): void - { - $attribute = $this->faker->word(); +test('passes if random is sole sort', function () { + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => RandomCriteria::PARAM_VALUE], - [$attribute => new RandomSoleRule()] - ); + $validator = Validator::make( + [$attribute => RandomCriteria::PARAM_VALUE], + [$attribute => new RandomSoleRule()] + ); - static::assertTrue($validator->passes()); - } -} + $this->assertTrue($validator->passes()); +}); diff --git a/tests/Unit/Rules/ModerationTest.php b/tests/Unit/Rules/ModerationTest.php index 1fdb0e49e..488ae3560 100644 --- a/tests/Unit/Rules/ModerationTest.php +++ b/tests/Unit/Rules/ModerationTest.php @@ -2,113 +2,89 @@ declare(strict_types=1); -namespace Tests\Unit\Rules; - use App\Constants\Config\ValidationConstants; use App\Enums\Rules\ModerationService; use App\Rules\ModerationRule; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Validator; -use RuntimeException; -use Tests\TestCase; -class ModerationTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Moderation Rule shall fail if the moderation service is unknown. - */ - public function testFailsIfUnknownModerationService(): void - { - static::expectException(RuntimeException::class); +test('fails if unknown moderation service', function () { + $this->expectException(RuntimeException::class); - Config::set(ValidationConstants::MODERATION_SERVICE_QUALIFIED, $this->faker->word()); + Config::set(ValidationConstants::MODERATION_SERVICE_QUALIFIED, fake()->word()); - $attribute = $this->faker->word(); + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $this->faker->word()], - [$attribute => new ModerationRule()], - ); + $validator = Validator::make( + [$attribute => fake()->word()], + [$attribute => new ModerationRule()], + ); - $validator->passes(); - } + $validator->passes(); +}); - /** - * The Moderation Rule shall fail if the value is flagged by OpenAI. - */ - public function testFailsIfFlaggedByOpenAi(): void - { - Config::set(ValidationConstants::MODERATION_SERVICE_QUALIFIED, ModerationService::OPENAI->value); +test('fails if flagged by open ai', function () { + Config::set(ValidationConstants::MODERATION_SERVICE_QUALIFIED, ModerationService::OPENAI->value); - Http::fake([ - 'https://api.openai.com/v1/moderations' => Http::response([ - 'results' => [ - 0 => [ - 'flagged' => true, - ], + Http::fake([ + 'https://api.openai.com/v1/moderations' => Http::response([ + 'results' => [ + 0 => [ + 'flagged' => true, ], - ]), - ]); + ], + ]), + ]); - $attribute = $this->faker->word(); + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $this->faker->word()], - [$attribute => new ModerationRule()], - ); + $validator = Validator::make( + [$attribute => fake()->word()], + [$attribute => new ModerationRule()], + ); - static::assertFalse($validator->passes()); - } + $this->assertFalse($validator->passes()); +}); - /** - * The Moderation Rule shall fail if the value is flagged by OpenAI. - */ - public function testPassesIfNotFlaggedByOpenAi(): void - { - Config::set(ValidationConstants::MODERATION_SERVICE_QUALIFIED, ModerationService::OPENAI->value); +test('passes if not flagged by open ai', function () { + Config::set(ValidationConstants::MODERATION_SERVICE_QUALIFIED, ModerationService::OPENAI->value); - Http::fake([ - 'https://api.openai.com/v1/moderations' => Http::response([ - 'results' => [ - 0 => [ - 'flagged' => false, - ], + Http::fake([ + 'https://api.openai.com/v1/moderations' => Http::response([ + 'results' => [ + 0 => [ + 'flagged' => false, ], - ]), - ]); + ], + ]), + ]); - $attribute = $this->faker->word(); + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $this->faker->word()], - [$attribute => new ModerationRule()], - ); + $validator = Validator::make( + [$attribute => fake()->word()], + [$attribute => new ModerationRule()], + ); - static::assertTrue($validator->passes()); - } + $this->assertTrue($validator->passes()); +}); - /** - * The Moderation Rule shall fail if OpenAI returns some error. - */ - public function testPassesIfOpenAiFails(): void - { - Config::set(ValidationConstants::MODERATION_SERVICE_QUALIFIED, ModerationService::OPENAI->value); +test('passes if open ai fails', function () { + Config::set(ValidationConstants::MODERATION_SERVICE_QUALIFIED, ModerationService::OPENAI->value); - Http::fake([ - 'https://api.openai.com/v1/moderations' => Http::response(status: 404), - ]); + Http::fake([ + 'https://api.openai.com/v1/moderations' => Http::response(status: 404), + ]); - $attribute = $this->faker->word(); + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $this->faker->word()], - [$attribute => new ModerationRule()], - ); + $validator = Validator::make( + [$attribute => fake()->word()], + [$attribute => new ModerationRule()], + ); - static::assertTrue($validator->passes()); - } -} + $this->assertTrue($validator->passes()); +}); diff --git a/tests/Unit/Rules/Storage/StorageDirectoryExistsTest.php b/tests/Unit/Rules/Storage/StorageDirectoryExistsTest.php index 50a869013..9d66307ea 100644 --- a/tests/Unit/Rules/Storage/StorageDirectoryExistsTest.php +++ b/tests/Unit/Rules/Storage/StorageDirectoryExistsTest.php @@ -2,53 +2,38 @@ declare(strict_types=1); -namespace Tests\Unit\Rules\Storage; - use App\Rules\Storage\StorageDirectoryExistsRule; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Validator; -use Tests\TestCase; -class StorageDirectoryExistsTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Storage Directory Exists Rule shall return true if the directory exists in the filesystem. - */ - public function testPassesIfDirectoryExists(): void - { - $directory = $this->faker->word(); +test('passes if directory exists', function () { + $directory = fake()->word(); - $fs = Storage::fake($this->faker->word()); + $fs = Storage::fake(fake()->word()); - $fs->makeDirectory($directory); + $fs->makeDirectory($directory); - $attribute = $this->faker->word(); + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $directory], - [$attribute => new StorageDirectoryExistsRule($fs)] - ); + $validator = Validator::make( + [$attribute => $directory], + [$attribute => new StorageDirectoryExistsRule($fs)] + ); - static::assertTrue($validator->passes()); - } + $this->assertTrue($validator->passes()); +}); - /** - * The Storage Directory Exists Rule shall return false if the directory does not exist in the filesystem. - */ - public function testFailsIfDirectoryDoesNotExist(): void - { - $fs = Storage::fake($this->faker->word()); +test('fails if directory does not exist', function () { + $fs = Storage::fake(fake()->word()); - $attribute = $this->faker->word(); + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $this->faker->word()], - [$attribute => new StorageDirectoryExistsRule($fs)] - ); + $validator = Validator::make( + [$attribute => fake()->word()], + [$attribute => new StorageDirectoryExistsRule($fs)] + ); - static::assertFalse($validator->passes()); - } -} + $this->assertFalse($validator->passes()); +}); diff --git a/tests/Unit/Rules/Storage/StorageFileDirectoryExistsTest.php b/tests/Unit/Rules/Storage/StorageFileDirectoryExistsTest.php index f27cb033f..524cef2c0 100644 --- a/tests/Unit/Rules/Storage/StorageFileDirectoryExistsTest.php +++ b/tests/Unit/Rules/Storage/StorageFileDirectoryExistsTest.php @@ -2,56 +2,41 @@ declare(strict_types=1); -namespace Tests\Unit\Rules\Storage; - use App\Rules\Storage\StorageFileDirectoryExistsRule; use Illuminate\Filesystem\FilesystemAdapter; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Http\Testing\File; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Validator; -use Tests\TestCase; -class StorageFileDirectoryExistsTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Storage File Directory Exists Rule shall return true if the directory exists in the filesystem. - */ - public function testPassesIfDirectoryExists(): void - { - /** @var FilesystemAdapter $fs */ - $fs = Storage::fake($this->faker->word()); +test('passes if directory exists', function () { + /** @var FilesystemAdapter $fs */ + $fs = Storage::fake(fake()->word()); - $file = File::fake()->create($this->faker->word()); + $file = File::fake()->create(fake()->word()); - $path = $fs->putFile($this->faker->word(), $file); + $path = $fs->putFile(fake()->word(), $file); - $attribute = $this->faker->word(); + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $path], - [$attribute => new StorageFileDirectoryExistsRule($fs)] - ); + $validator = Validator::make( + [$attribute => $path], + [$attribute => new StorageFileDirectoryExistsRule($fs)] + ); - static::assertTrue($validator->passes()); - } + $this->assertTrue($validator->passes()); +}); - /** - * The Storage File Directory Exists Rule shall return false if the directory does not exist in the filesystem. - */ - public function testFailsIfDirectoryDoesNotExist(): void - { - $fs = Storage::fake($this->faker->word()); +test('fails if directory does not exist', function () { + $fs = Storage::fake(fake()->word()); - $attribute = $this->faker->word(); + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $this->faker->filePath()], - [$attribute => new StorageFileDirectoryExistsRule($fs)] - ); + $validator = Validator::make( + [$attribute => fake()->filePath()], + [$attribute => new StorageFileDirectoryExistsRule($fs)] + ); - static::assertFalse($validator->passes()); - } -} + $this->assertFalse($validator->passes()); +}); diff --git a/tests/Unit/Rules/Wiki/Resource/AnimeResourceLinkFormatTest.php b/tests/Unit/Rules/Wiki/Resource/AnimeResourceLinkFormatTest.php index 402b2d83f..ca7ca181e 100644 --- a/tests/Unit/Rules/Wiki/Resource/AnimeResourceLinkFormatTest.php +++ b/tests/Unit/Rules/Wiki/Resource/AnimeResourceLinkFormatTest.php @@ -2,127 +2,100 @@ declare(strict_types=1); -namespace Tests\Unit\Rules\Wiki\Resource; - use App\Enums\Models\Wiki\ResourceSite; use App\Models\Wiki\Anime; use App\Rules\Wiki\Resource\AnimeResourceLinkFormatRule; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Validator; use Illuminate\Support\Str; -use Tests\TestCase; -class AnimeResourceLinkFormatTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Anime Resource Link Format Rule shall fail for sites with no defined pattern. - */ - public function testFailsForNoPattern(): void - { - $attribute = $this->faker->word(); +test('fails for no pattern', function () { + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $this->faker->url()], - [$attribute => new AnimeResourceLinkFormatRule(ResourceSite::YOUTUBE_MUSIC)], - ); + $validator = Validator::make( + [$attribute => fake()->url()], + [$attribute => new AnimeResourceLinkFormatRule(ResourceSite::YOUTUBE_MUSIC)], + ); - static::assertFalse($validator->passes()); - } + $this->assertFalse($validator->passes()); +}); - /** - * The Anime Resource Link Format Rule shall pass for URLs that match the expected pattern. - */ - public function testPassesForPattern(): void - { - /** @var ResourceSite $site */ - $site = Arr::random(ResourceSite::getForModel(Anime::class)); +test('passes for pattern', function () { + /** @var ResourceSite $site */ + $site = Arr::random(ResourceSite::getForModel(Anime::class)); - $url = $site->formatResourceLink(Anime::class, $this->faker->randomDigitNotNull(), $this->faker->word(), 'null'); + $url = $site->formatResourceLink(Anime::class, fake()->randomDigitNotNull(), fake()->word(), 'null'); - $attribute = $this->faker->word(); + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $url], - [$attribute => new AnimeResourceLinkFormatRule($site)], - ); + $validator = Validator::make( + [$attribute => $url], + [$attribute => new AnimeResourceLinkFormatRule($site)], + ); - static::assertTrue($validator->passes()); - } + $this->assertTrue($validator->passes()); +}); - /** - * The Anime Resource Link Format Rule shall fail for trailing slashes in URLs with defined patterns. - */ - public function testFailsForTrailingSlash(): void - { - /** @var ResourceSite $site */ - $site = Arr::random(ResourceSite::getForModel(Anime::class)); +test('fails for trailing slash', function () { + /** @var ResourceSite $site */ + $site = Arr::random(ResourceSite::getForModel(Anime::class)); - $url = $site->formatResourceLink(Anime::class, $this->faker->randomDigitNotNull(), $this->faker->word()); + $url = $site->formatResourceLink(Anime::class, fake()->randomDigitNotNull(), fake()->word()); - $url = Str::of($url) - ->append('/') - ->__toString(); + $url = Str::of($url) + ->append('/') + ->__toString(); - $attribute = $this->faker->word(); + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $url], - [$attribute => new AnimeResourceLinkFormatRule($site)], - ); + $validator = Validator::make( + [$attribute => $url], + [$attribute => new AnimeResourceLinkFormatRule($site)], + ); - static::assertFalse($site->getPattern(Anime::class) && $validator->passes()); - } + $this->assertFalse($site->getPattern(Anime::class) && $validator->passes()); +}); - /** - * The Anime Resource Link Format Rule shall fail for trailing slugs in URLs with defined patterns. - */ - public function testFailsForTrailingSlug(): void - { - /** @var ResourceSite $site */ - $site = Arr::random(ResourceSite::getForModel(Anime::class)); +test('fails for trailing slug', function () { + /** @var ResourceSite $site */ + $site = Arr::random(ResourceSite::getForModel(Anime::class)); - $url = $site->formatResourceLink(Anime::class, $this->faker->randomDigitNotNull(), $this->faker->word()); + $url = $site->formatResourceLink(Anime::class, fake()->randomDigitNotNull(), fake()->word()); - $url = Str::of($url) - ->append('/') - ->append($this->faker->word()) - ->__toString(); + $url = Str::of($url) + ->append('/') + ->append(fake()->word()) + ->__toString(); - $attribute = $this->faker->word(); + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $url], - [$attribute => new AnimeResourceLinkFormatRule($site)], - ); + $validator = Validator::make( + [$attribute => $url], + [$attribute => new AnimeResourceLinkFormatRule($site)], + ); - static::assertFalse($site->getPattern(Anime::class) && $validator->passes()); - } + $this->assertFalse($site->getPattern(Anime::class) && $validator->passes()); +}); - /** - * The Anime Resource Link Format Rule shall fail for other resources not allowed. - */ - public function testFailsForOtherResources(): void - { - /** @var ResourceSite $site */ - $site = Arr::random( - array_filter( - ResourceSite::cases(), - fn ($value) => ! in_array($value, ResourceSite::getForModel(Anime::class)) - ) - ); +test('fails for other resources', function () { + /** @var ResourceSite $site */ + $site = Arr::random( + array_filter( + ResourceSite::cases(), + fn ($value) => ! in_array($value, ResourceSite::getForModel(Anime::class)) + ) + ); - $url = $site->formatResourceLink(Anime::class, $this->faker->randomDigitNotNull(), $this->faker->word()); + $url = $site->formatResourceLink(Anime::class, fake()->randomDigitNotNull(), fake()->word()); - $attribute = $this->faker->word(); + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $url], - [$attribute => new AnimeResourceLinkFormatRule($site)], - ); + $validator = Validator::make( + [$attribute => $url], + [$attribute => new AnimeResourceLinkFormatRule($site)], + ); - static::assertFalse($validator->passes()); - } -} + $this->assertFalse($validator->passes()); +}); diff --git a/tests/Unit/Rules/Wiki/Resource/ArtistResourceLinkFormatTest.php b/tests/Unit/Rules/Wiki/Resource/ArtistResourceLinkFormatTest.php index bc0f95718..0b4e862de 100644 --- a/tests/Unit/Rules/Wiki/Resource/ArtistResourceLinkFormatTest.php +++ b/tests/Unit/Rules/Wiki/Resource/ArtistResourceLinkFormatTest.php @@ -2,127 +2,100 @@ declare(strict_types=1); -namespace Tests\Unit\Rules\Wiki\Resource; - use App\Enums\Models\Wiki\ResourceSite; use App\Models\Wiki\Artist; use App\Rules\Wiki\Resource\ArtistResourceLinkFormatRule; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Validator; use Illuminate\Support\Str; -use Tests\TestCase; -class ArtistResourceLinkFormatTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Artist Resource Link Format Rule shall fail for sites with no defined pattern. - */ - public function testFailsForNoPattern(): void - { - $attribute = $this->faker->word(); +test('fails for no pattern', function () { + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $this->faker->url()], - [$attribute => new ArtistResourceLinkFormatRule(ResourceSite::DISNEY_PLUS)], - ); + $validator = Validator::make( + [$attribute => fake()->url()], + [$attribute => new ArtistResourceLinkFormatRule(ResourceSite::DISNEY_PLUS)], + ); - static::assertFalse($validator->passes()); - } + $this->assertFalse($validator->passes()); +}); - /** - * The Artist Resource Link Format Rule shall pass for URLs that match the expected pattern. - */ - public function testPassesForPattern(): void - { - /** @var ResourceSite $site */ - $site = Arr::random(ResourceSite::getForModel(Artist::class)); +test('passes for pattern', function () { + /** @var ResourceSite $site */ + $site = Arr::random(ResourceSite::getForModel(Artist::class)); - $url = $site->formatResourceLink(Artist::class, $this->faker->randomDigitNotNull(), $this->faker->word(), 'null'); + $url = $site->formatResourceLink(Artist::class, fake()->randomDigitNotNull(), fake()->word(), 'null'); - $attribute = $this->faker->word(); + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $url], - [$attribute => new ArtistResourceLinkFormatRule($site)], - ); + $validator = Validator::make( + [$attribute => $url], + [$attribute => new ArtistResourceLinkFormatRule($site)], + ); - static::assertTrue($validator->passes()); - } + $this->assertTrue($validator->passes()); +}); - /** - * The Artist Resource Link Format Rule shall fail for trailing slashes in URLs with defined patterns. - */ - public function testFailsForTrailingSlash(): void - { - /** @var ResourceSite $site */ - $site = Arr::random(ResourceSite::getForModel(Artist::class)); +test('fails for trailing slash', function () { + /** @var ResourceSite $site */ + $site = Arr::random(ResourceSite::getForModel(Artist::class)); - $url = $site->formatResourceLink(Artist::class, $this->faker->randomDigitNotNull(), $this->faker->word()); + $url = $site->formatResourceLink(Artist::class, fake()->randomDigitNotNull(), fake()->word()); - $url = Str::of($url) - ->append('/') - ->__toString(); + $url = Str::of($url) + ->append('/') + ->__toString(); - $attribute = $this->faker->word(); + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $url], - [$attribute => new ArtistResourceLinkFormatRule($site)], - ); + $validator = Validator::make( + [$attribute => $url], + [$attribute => new ArtistResourceLinkFormatRule($site)], + ); - static::assertFalse($site->getPattern(Artist::class) && $validator->passes()); - } + $this->assertFalse($site->getPattern(Artist::class) && $validator->passes()); +}); - /** - * The Artist Resource Link Format Rule shall fail for trailing slugs in URLs with defined patterns. - */ - public function testFailsForTrailingSlug(): void - { - /** @var ResourceSite $site */ - $site = Arr::random(ResourceSite::getForModel(Artist::class)); +test('fails for trailing slug', function () { + /** @var ResourceSite $site */ + $site = Arr::random(ResourceSite::getForModel(Artist::class)); - $url = $site->formatResourceLink(Artist::class, $this->faker->randomDigitNotNull(), $this->faker->word()); + $url = $site->formatResourceLink(Artist::class, fake()->randomDigitNotNull(), fake()->word()); - $url = Str::of($url) - ->append('/') - ->append($this->faker->word()) - ->__toString(); + $url = Str::of($url) + ->append('/') + ->append(fake()->word()) + ->__toString(); - $attribute = $this->faker->word(); + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $url], - [$attribute => new ArtistResourceLinkFormatRule($site)], - ); + $validator = Validator::make( + [$attribute => $url], + [$attribute => new ArtistResourceLinkFormatRule($site)], + ); - static::assertFalse($site->getPattern(Artist::class) && $validator->passes()); - } + $this->assertFalse($site->getPattern(Artist::class) && $validator->passes()); +}); - /** - * The Artist Resource Link Format Rule shall fail for other resources. - */ - public function testFailsForOtherResources(): void - { - /** @var ResourceSite $site */ - $site = Arr::random( - array_filter( - ResourceSite::cases(), - fn ($value) => ! in_array($value, ResourceSite::getForModel(Artist::class)) - ) - ); +test('fails for other resources', function () { + /** @var ResourceSite $site */ + $site = Arr::random( + array_filter( + ResourceSite::cases(), + fn ($value) => ! in_array($value, ResourceSite::getForModel(Artist::class)) + ) + ); - $url = $site->formatResourceLink(Artist::class, $this->faker->randomDigitNotNull(), $this->faker->word()); + $url = $site->formatResourceLink(Artist::class, fake()->randomDigitNotNull(), fake()->word()); - $attribute = $this->faker->word(); + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $url], - [$attribute => new ArtistResourceLinkFormatRule($site)], - ); + $validator = Validator::make( + [$attribute => $url], + [$attribute => new ArtistResourceLinkFormatRule($site)], + ); - static::assertFalse($validator->passes()); - } -} + $this->assertFalse($validator->passes()); +}); diff --git a/tests/Unit/Rules/Wiki/Resource/ResourceLinkFormatTest.php b/tests/Unit/Rules/Wiki/Resource/ResourceLinkFormatTest.php index 7c17fee1d..1768a1375 100644 --- a/tests/Unit/Rules/Wiki/Resource/ResourceLinkFormatTest.php +++ b/tests/Unit/Rules/Wiki/Resource/ResourceLinkFormatTest.php @@ -2,188 +2,153 @@ declare(strict_types=1); -namespace Tests\Unit\Rules\Wiki\Resource; - use App\Enums\Models\Wiki\ResourceSite; use App\Models\Wiki\Anime; use App\Models\Wiki\Artist; use App\Models\Wiki\Song; use App\Models\Wiki\Studio; use App\Rules\Wiki\Resource\ResourceLinkFormatRule; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Validator; use Illuminate\Support\Str; -use Tests\TestCase; -class ResourceLinkFormatTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Resource Link Format Rule shall pass if the site cannot be resolved. - */ - public function testPassesForNoSite(): void - { - $attribute = $this->faker->word(); +test('passes for no site', function () { + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $this->faker->url()], - [$attribute => new ResourceLinkFormatRule()], - ); + $validator = Validator::make( + [$attribute => fake()->url()], + [$attribute => new ResourceLinkFormatRule()], + ); - static::assertTrue($validator->passes()); - } + $this->assertTrue($validator->passes()); +}); - /** - * The Resource Link Format Rule shall pass for sites with no expected pattern. - */ - public function testPassesForNoPattern(): void - { - $attribute = $this->faker->word(); +test('passes for no pattern', function () { + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $this->faker->url()], - [$attribute => new ResourceLinkFormatRule(ResourceSite::OFFICIAL_SITE)], - ); + $validator = Validator::make( + [$attribute => fake()->url()], + [$attribute => new ResourceLinkFormatRule(ResourceSite::OFFICIAL_SITE)], + ); - static::assertTrue($validator->passes()); - } + $this->assertTrue($validator->passes()); +}); - /** - * The Resource Link Format Rule shall pass for anime resources. - */ - public function testPassesForAnimeResource(): void - { - /** @var ResourceSite $site */ - $site = Arr::random([ - ResourceSite::X, - ResourceSite::ANIDB, - ResourceSite::ANILIST, - ResourceSite::ANIME_PLANET, - ResourceSite::ANN, - ResourceSite::KITSU, - ResourceSite::MAL, - ResourceSite::YOUTUBE, - ]); +test('passes for anime resource', function () { + /** @var ResourceSite $site */ + $site = Arr::random([ + ResourceSite::X, + ResourceSite::ANIDB, + ResourceSite::ANILIST, + ResourceSite::ANIME_PLANET, + ResourceSite::ANN, + ResourceSite::KITSU, + ResourceSite::MAL, + ResourceSite::YOUTUBE, + ]); - $url = $site->formatResourceLink(Anime::class, $this->faker->randomDigitNotNull(), $this->faker->word()); + $url = $site->formatResourceLink(Anime::class, fake()->randomDigitNotNull(), fake()->word()); - $attribute = $this->faker->word(); + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $url], - [$attribute => new ResourceLinkFormatRule($site)], - ); + $validator = Validator::make( + [$attribute => $url], + [$attribute => new ResourceLinkFormatRule($site)], + ); - static::assertTrue($validator->passes()); - } + $this->assertTrue($validator->passes()); +}); - /** - * The Resource Link Format Rule shall pass for artist resources. - */ - public function testPassesForArtistResource(): void - { - /** @var ResourceSite $site */ - $site = Arr::random([ - ResourceSite::X, - ResourceSite::ANIDB, - ResourceSite::ANILIST, - ResourceSite::ANIME_PLANET, - ResourceSite::ANN, - ResourceSite::MAL, - ResourceSite::SPOTIFY, - ResourceSite::YOUTUBE, - ]); +test('passes for artist resource', function () { + /** @var ResourceSite $site */ + $site = Arr::random([ + ResourceSite::X, + ResourceSite::ANIDB, + ResourceSite::ANILIST, + ResourceSite::ANIME_PLANET, + ResourceSite::ANN, + ResourceSite::MAL, + ResourceSite::SPOTIFY, + ResourceSite::YOUTUBE, + ]); - $url = $site->formatResourceLink(Artist::class, $this->faker->randomDigitNotNull(), $this->faker->word()); + $url = $site->formatResourceLink(Artist::class, fake()->randomDigitNotNull(), fake()->word()); - $attribute = $this->faker->word(); + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $url], - [$attribute => new ResourceLinkFormatRule($site)], - ); + $validator = Validator::make( + [$attribute => $url], + [$attribute => new ResourceLinkFormatRule($site)], + ); - static::assertTrue($validator->passes()); - } + $this->assertTrue($validator->passes()); +}); - /** - * The Resource Link Format Rule shall pass for song resources. - */ - public function testPassesForSongResource(): void - { - /** @var ResourceSite $site */ - $site = Arr::random([ - ResourceSite::SPOTIFY, - ResourceSite::YOUTUBE_MUSIC, - ResourceSite::YOUTUBE, - ResourceSite::APPLE_MUSIC, - ResourceSite::AMAZON_MUSIC, - ]); +test('passes for song resource', function () { + /** @var ResourceSite $site */ + $site = Arr::random([ + ResourceSite::SPOTIFY, + ResourceSite::YOUTUBE_MUSIC, + ResourceSite::YOUTUBE, + ResourceSite::APPLE_MUSIC, + ResourceSite::AMAZON_MUSIC, + ]); - $url = $site->formatResourceLink(Song::class, $this->faker->randomDigitNotNull(), $this->faker->word()); + $url = $site->formatResourceLink(Song::class, fake()->randomDigitNotNull(), fake()->word()); - $attribute = $this->faker->word(); + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $url], - [$attribute => new ResourceLinkFormatRule($site)], - ); + $validator = Validator::make( + [$attribute => $url], + [$attribute => new ResourceLinkFormatRule($site)], + ); - static::assertTrue($validator->passes()); - } + $this->assertTrue($validator->passes()); +}); - /** - * The Resource Link Format Rule shall pass for studio resources. - */ - public function testPassesForStudioResource(): void - { - /** @var ResourceSite $site */ - $site = Arr::random([ - ResourceSite::X, - ResourceSite::ANIDB, - ResourceSite::ANILIST, - ResourceSite::ANIME_PLANET, - ResourceSite::ANN, - ResourceSite::MAL, - ]); +test('passes for studio resource', function () { + /** @var ResourceSite $site */ + $site = Arr::random([ + ResourceSite::X, + ResourceSite::ANIDB, + ResourceSite::ANILIST, + ResourceSite::ANIME_PLANET, + ResourceSite::ANN, + ResourceSite::MAL, + ]); - $url = $site->formatResourceLink(Studio::class, $this->faker->randomDigitNotNull(), $this->faker->word()); + $url = $site->formatResourceLink(Studio::class, fake()->randomDigitNotNull(), fake()->word()); - $attribute = $this->faker->word(); + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $url], - [$attribute => new ResourceLinkFormatRule($site)], - ); + $validator = Validator::make( + [$attribute => $url], + [$attribute => new ResourceLinkFormatRule($site)], + ); - static::assertTrue($validator->passes()); - } + $this->assertTrue($validator->passes()); +}); - /** - * The Resource Link Format Rule shall fail for trailing slashes in URLs with defined patterns. - */ - public function testFailsForTrailingSlash(): void - { - // Resource sites that can be attached for all models. - $site = Arr::random([ - ResourceSite::ANIDB, - ]); +test('fails for trailing slash', function () { + // Resource sites that can be attached for all models. + $site = Arr::random([ + ResourceSite::ANIDB, + ]); - $url = $site->formatResourceLink(Anime::class, $this->faker->randomDigitNotNull(), $this->faker->word()); + $url = $site->formatResourceLink(Anime::class, fake()->randomDigitNotNull(), fake()->word()); - $url = Str::of($url) - ->append('/') - ->__toString(); + $url = Str::of($url) + ->append('/') + ->__toString(); - $attribute = $this->faker->word(); + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $url], - [$attribute => new ResourceLinkFormatRule($site)], - ); + $validator = Validator::make( + [$attribute => $url], + [$attribute => new ResourceLinkFormatRule($site)], + ); - static::assertFalse($validator->passes()); - } -} + $this->assertFalse($validator->passes()); +}); diff --git a/tests/Unit/Rules/Wiki/Resource/ResourceSiteMatchesLinkTest.php b/tests/Unit/Rules/Wiki/Resource/ResourceSiteMatchesLinkTest.php index e9c513917..90954de44 100644 --- a/tests/Unit/Rules/Wiki/Resource/ResourceSiteMatchesLinkTest.php +++ b/tests/Unit/Rules/Wiki/Resource/ResourceSiteMatchesLinkTest.php @@ -2,85 +2,66 @@ declare(strict_types=1); -namespace Tests\Unit\Rules\Wiki\Resource; - use App\Enums\Models\Wiki\ResourceSite; use App\Rules\Wiki\Resource\ResourceSiteMatchesLinkRule; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Validator; -use Tests\TestCase; -class ResourceSiteMatchesLinkTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Resource Site Matches Link Rule shall return true if the site matches the link. - */ - public function testPassesIfSiteMatchesLink(): void - { - $site = null; +test('passes if site matches link', function () { + $site = null; - while ($site === null) { - $siteCandidate = Arr::random(ResourceSite::cases()); - if ($siteCandidate !== ResourceSite::OFFICIAL_SITE) { - $site = $siteCandidate; - } + while ($site === null) { + $siteCandidate = Arr::random(ResourceSite::cases()); + if ($siteCandidate !== ResourceSite::OFFICIAL_SITE) { + $site = $siteCandidate; } - - $url = null; - $domain = ResourceSite::getDomain($site->value); - if ($domain !== null) { - $url = 'https://'.$domain; - } - - $attribute = $this->faker->word(); - - $validator = Validator::make( - [$attribute => $site->value], - [$attribute => new ResourceSiteMatchesLinkRule($url)], - ); - - static::assertTrue($validator->passes()); } - /** - * The Resource Site Matches Link Rule shall return true if the site does not have a domain. - */ - public function testResourceSiteDomainRuleOfficialPasses(): void - { - $attribute = $this->faker->word(); - - $validator = Validator::make( - [$attribute => ResourceSite::OFFICIAL_SITE->value], - [$attribute => new ResourceSiteMatchesLinkRule($this->faker->url())], - ); - - static::assertTrue($validator->passes()); + $url = null; + $domain = ResourceSite::getDomain($site->value); + if ($domain !== null) { + $url = 'https://'.$domain; } - /** - * The Resource Site Matches Link Rule shall return false if the site does not match the link. - */ - public function testResourceSiteDomainRuleFails(): void - { - $site = null; + $attribute = fake()->word(); - while ($site === null) { - $siteCandidate = Arr::random(ResourceSite::cases()); - if ($siteCandidate !== ResourceSite::OFFICIAL_SITE) { - $site = $siteCandidate; - } + $validator = Validator::make( + [$attribute => $site->value], + [$attribute => new ResourceSiteMatchesLinkRule($url)], + ); + + $this->assertTrue($validator->passes()); +}); + +test('resource site domain rule official passes', function () { + $attribute = fake()->word(); + + $validator = Validator::make( + [$attribute => ResourceSite::OFFICIAL_SITE->value], + [$attribute => new ResourceSiteMatchesLinkRule(fake()->url())], + ); + + $this->assertTrue($validator->passes()); +}); + +test('resource site domain rule fails', function () { + $site = null; + + while ($site === null) { + $siteCandidate = Arr::random(ResourceSite::cases()); + if ($siteCandidate !== ResourceSite::OFFICIAL_SITE) { + $site = $siteCandidate; } - - $attribute = $this->faker->word(); - - $validator = Validator::make( - [$attribute => $site->value], - [$attribute => new ResourceSiteMatchesLinkRule($this->faker->url())], - ); - - static::assertFalse($validator->passes()); } -} + + $attribute = fake()->word(); + + $validator = Validator::make( + [$attribute => $site->value], + [$attribute => new ResourceSiteMatchesLinkRule(fake()->url())], + ); + + $this->assertFalse($validator->passes()); +}); diff --git a/tests/Unit/Rules/Wiki/Resource/SongResourceLinkFormatTest.php b/tests/Unit/Rules/Wiki/Resource/SongResourceLinkFormatTest.php index 42fc3eee2..3a4e85ae2 100644 --- a/tests/Unit/Rules/Wiki/Resource/SongResourceLinkFormatTest.php +++ b/tests/Unit/Rules/Wiki/Resource/SongResourceLinkFormatTest.php @@ -2,127 +2,100 @@ declare(strict_types=1); -namespace Tests\Unit\Rules\Wiki\Resource; - use App\Enums\Models\Wiki\ResourceSite; use App\Models\Wiki\Song; use App\Rules\Wiki\Resource\SongResourceLinkFormatRule; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Validator; use Illuminate\Support\Str; -use Tests\TestCase; -class SongResourceLinkFormatTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Song Resource Link Format Rule shall fail for sites with no defined pattern. - */ - public function testFailsForNoPattern(): void - { - $attribute = $this->faker->word(); +test('fails for no pattern', function () { + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $this->faker->url()], - [$attribute => new SongResourceLinkFormatRule(ResourceSite::HULU)], - ); + $validator = Validator::make( + [$attribute => fake()->url()], + [$attribute => new SongResourceLinkFormatRule(ResourceSite::HULU)], + ); - static::assertFalse($validator->passes()); - } + $this->assertFalse($validator->passes()); +}); - /** - * The Song Resource Link Format Rule shall pass for URLs that match the expected pattern. - */ - public function testPassesForPattern(): void - { - /** @var ResourceSite $site */ - $site = Arr::random(ResourceSite::getForModel(Song::class)); +test('passes for pattern', function () { + /** @var ResourceSite $site */ + $site = Arr::random(ResourceSite::getForModel(Song::class)); - $url = $site->formatResourceLink(Song::class, $this->faker->randomDigitNotNull(), $this->faker->word(), 'null'); + $url = $site->formatResourceLink(Song::class, fake()->randomDigitNotNull(), fake()->word(), 'null'); - $attribute = $this->faker->word(); + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $url], - [$attribute => new SongResourceLinkFormatRule($site)], - ); + $validator = Validator::make( + [$attribute => $url], + [$attribute => new SongResourceLinkFormatRule($site)], + ); - static::assertTrue($validator->passes()); - } + $this->assertTrue($validator->passes()); +}); - /** - * The Song Resource Link Format Rule shall fail for trailing slashes in URLs with defined patterns. - */ - public function testFailsForTrailingSlash(): void - { - /** @var ResourceSite $site */ - $site = Arr::random(ResourceSite::getForModel(Song::class)); +test('fails for trailing slash', function () { + /** @var ResourceSite $site */ + $site = Arr::random(ResourceSite::getForModel(Song::class)); - $url = $site->formatResourceLink(Song::class, $this->faker->randomDigitNotNull(), $this->faker->word()); + $url = $site->formatResourceLink(Song::class, fake()->randomDigitNotNull(), fake()->word()); - $url = Str::of($url) - ->append('/') - ->__toString(); + $url = Str::of($url) + ->append('/') + ->__toString(); - $attribute = $this->faker->word(); + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $url], - [$attribute => new SongResourceLinkFormatRule($site)], - ); + $validator = Validator::make( + [$attribute => $url], + [$attribute => new SongResourceLinkFormatRule($site)], + ); - static::assertFalse($site->getPattern(Song::class) && $validator->passes()); - } + $this->assertFalse($site->getPattern(Song::class) && $validator->passes()); +}); - /** - * The Song Resource Link Format Rule shall fail for trailing slugs in URLs with defined patterns. - */ - public function testFailsForTrailingSlug(): void - { - /** @var ResourceSite $site */ - $site = Arr::random(ResourceSite::getForModel(Song::class)); +test('fails for trailing slug', function () { + /** @var ResourceSite $site */ + $site = Arr::random(ResourceSite::getForModel(Song::class)); - $url = $site->formatResourceLink(Song::class, $this->faker->randomDigitNotNull(), $this->faker->word()); + $url = $site->formatResourceLink(Song::class, fake()->randomDigitNotNull(), fake()->word()); - $url = Str::of($url) - ->append('/') - ->append($this->faker->word()) - ->__toString(); + $url = Str::of($url) + ->append('/') + ->append(fake()->word()) + ->__toString(); - $attribute = $this->faker->word(); + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $url], - [$attribute => new SongResourceLinkFormatRule($site)], - ); + $validator = Validator::make( + [$attribute => $url], + [$attribute => new SongResourceLinkFormatRule($site)], + ); - static::assertFalse($site->getPattern(Song::class) && $validator->passes()); - } + $this->assertFalse($site->getPattern(Song::class) && $validator->passes()); +}); - /** - * The Song Resource Link Format Rule shall fail for other resources. - */ - public function testFailsForOtherResources(): void - { - /** @var ResourceSite $site */ - $site = Arr::random( - array_filter( - ResourceSite::cases(), - fn ($value) => ! in_array($value, ResourceSite::getForModel(Song::class)) - ) - ); +test('fails for other resources', function () { + /** @var ResourceSite $site */ + $site = Arr::random( + array_filter( + ResourceSite::cases(), + fn ($value) => ! in_array($value, ResourceSite::getForModel(Song::class)) + ) + ); - $url = $site->formatResourceLink(Song::class, $this->faker->randomDigitNotNull(), $this->faker->word()); + $url = $site->formatResourceLink(Song::class, fake()->randomDigitNotNull(), fake()->word()); - $attribute = $this->faker->word(); + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $url], - [$attribute => new SongResourceLinkFormatRule($site)], - ); + $validator = Validator::make( + [$attribute => $url], + [$attribute => new SongResourceLinkFormatRule($site)], + ); - static::assertFalse($validator->passes()); - } -} + $this->assertFalse($validator->passes()); +}); diff --git a/tests/Unit/Rules/Wiki/Resource/StudioResourceLinkFormatTest.php b/tests/Unit/Rules/Wiki/Resource/StudioResourceLinkFormatTest.php index 59e50b851..e35c1d9fe 100644 --- a/tests/Unit/Rules/Wiki/Resource/StudioResourceLinkFormatTest.php +++ b/tests/Unit/Rules/Wiki/Resource/StudioResourceLinkFormatTest.php @@ -2,127 +2,100 @@ declare(strict_types=1); -namespace Tests\Unit\Rules\Wiki\Resource; - use App\Enums\Models\Wiki\ResourceSite; use App\Models\Wiki\Studio; use App\Rules\Wiki\Resource\StudioResourceLinkFormatRule; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Validator; use Illuminate\Support\Str; -use Tests\TestCase; -class StudioResourceLinkFormatTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Studio Resource Link Format Rule shall fail for sites with no defined pattern. - */ - public function testFailsForNoPattern(): void - { - $attribute = $this->faker->word(); +test('fails for no pattern', function () { + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $this->faker->url()], - [$attribute => new StudioResourceLinkFormatRule(ResourceSite::SPOTIFY)], - ); + $validator = Validator::make( + [$attribute => fake()->url()], + [$attribute => new StudioResourceLinkFormatRule(ResourceSite::SPOTIFY)], + ); - static::assertFalse($validator->passes()); - } + $this->assertFalse($validator->passes()); +}); - /** - * The Studio Resource Link Format Rule shall pass for URLs that match the expected pattern. - */ - public function testPassesForPattern(): void - { - /** @var ResourceSite $site */ - $site = Arr::random(ResourceSite::getForModel(Studio::class)); +test('passes for pattern', function () { + /** @var ResourceSite $site */ + $site = Arr::random(ResourceSite::getForModel(Studio::class)); - $url = $site->formatResourceLink(Studio::class, $this->faker->randomDigitNotNull(), $this->faker->word(), 'null'); + $url = $site->formatResourceLink(Studio::class, fake()->randomDigitNotNull(), fake()->word(), 'null'); - $attribute = $this->faker->word(); + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $url], - [$attribute => new StudioResourceLinkFormatRule($site)], - ); + $validator = Validator::make( + [$attribute => $url], + [$attribute => new StudioResourceLinkFormatRule($site)], + ); - static::assertTrue($validator->passes()); - } + $this->assertTrue($validator->passes()); +}); - /** - * The Studio Resource Link Format Rule shall fail for trailing slashes in URLs with defined patterns. - */ - public function testFailsForTrailingSlash(): void - { - /** @var ResourceSite $site */ - $site = Arr::random(ResourceSite::getForModel(Studio::class)); +test('fails for trailing slash', function () { + /** @var ResourceSite $site */ + $site = Arr::random(ResourceSite::getForModel(Studio::class)); - $url = $site->formatResourceLink(Studio::class, $this->faker->randomDigitNotNull(), $this->faker->word()); + $url = $site->formatResourceLink(Studio::class, fake()->randomDigitNotNull(), fake()->word()); - $url = Str::of($url) - ->append('/') - ->__toString(); + $url = Str::of($url) + ->append('/') + ->__toString(); - $attribute = $this->faker->word(); + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $url], - [$attribute => new StudioResourceLinkFormatRule($site)], - ); + $validator = Validator::make( + [$attribute => $url], + [$attribute => new StudioResourceLinkFormatRule($site)], + ); - static::assertFalse($site->getPattern(Studio::class) && $validator->passes()); - } + $this->assertFalse($site->getPattern(Studio::class) && $validator->passes()); +}); - /** - * The Studio Resource Link Format Rule shall fail for trailing slugs in URLs with defined patterns. - */ - public function testFailsForTrailingSlug(): void - { - /** @var ResourceSite $site */ - $site = Arr::random(ResourceSite::getForModel(Studio::class)); +test('fails for trailing slug', function () { + /** @var ResourceSite $site */ + $site = Arr::random(ResourceSite::getForModel(Studio::class)); - $url = $site->formatResourceLink(Studio::class, $this->faker->randomDigitNotNull(), $this->faker->word()); + $url = $site->formatResourceLink(Studio::class, fake()->randomDigitNotNull(), fake()->word()); - $url = Str::of($url) - ->append('/') - ->append($this->faker->word()) - ->__toString(); + $url = Str::of($url) + ->append('/') + ->append(fake()->word()) + ->__toString(); - $attribute = $this->faker->word(); + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $url], - [$attribute => new StudioResourceLinkFormatRule($site)], - ); + $validator = Validator::make( + [$attribute => $url], + [$attribute => new StudioResourceLinkFormatRule($site)], + ); - static::assertFalse($site->getPattern(Studio::class) && $validator->passes()); - } + $this->assertFalse($site->getPattern(Studio::class) && $validator->passes()); +}); - /** - * The Studio Resource Link Format Rule shall fail for other resources. - */ - public function testFailsForOtherResources(): void - { - /** @var ResourceSite $site */ - $site = Arr::random( - array_filter( - ResourceSite::cases(), - fn ($value) => ! in_array($value, ResourceSite::getForModel(Studio::class)) - ) - ); +test('fails for other resources', function () { + /** @var ResourceSite $site */ + $site = Arr::random( + array_filter( + ResourceSite::cases(), + fn ($value) => ! in_array($value, ResourceSite::getForModel(Studio::class)) + ) + ); - $url = $site->formatResourceLink(Studio::class, $this->faker->randomDigitNotNull(), $this->faker->word()); + $url = $site->formatResourceLink(Studio::class, fake()->randomDigitNotNull(), fake()->word()); - $attribute = $this->faker->word(); + $attribute = fake()->word(); - $validator = Validator::make( - [$attribute => $url], - [$attribute => new StudioResourceLinkFormatRule($site)], - ); + $validator = Validator::make( + [$attribute => $url], + [$attribute => new StudioResourceLinkFormatRule($site)], + ); - static::assertFalse($validator->passes()); - } -} + $this->assertFalse($validator->passes()); +}); diff --git a/tests/Unit/Rules/Wiki/Submission/Audio/AudioChannelLayoutStreamTest.php b/tests/Unit/Rules/Wiki/Submission/Audio/AudioChannelLayoutStreamTest.php index 5ce73f96e..47330b6e0 100644 --- a/tests/Unit/Rules/Wiki/Submission/Audio/AudioChannelLayoutStreamTest.php +++ b/tests/Unit/Rules/Wiki/Submission/Audio/AudioChannelLayoutStreamTest.php @@ -2,97 +2,82 @@ declare(strict_types=1); -namespace Tests\Unit\Rules\Wiki\Submission\Audio; - use App\Actions\Storage\Wiki\UploadedFileAction; use App\Rules\Wiki\Submission\Audio\AudioChannelLayoutStreamRule; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\Process; use Illuminate\Support\Facades\Validator; -use Tests\TestCase; -class AudioChannelLayoutStreamTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Audio Channel Layout Rule Stream shall fail if the channel layout is not stereo. - */ - public function testFailsWhenLayoutIsNotStereo(): void - { - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); +test('fails when layout is not stereo', function () { + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->randomFloat(), - 'input_tp' => $this->faker->randomFloat(), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'streams' => [ - 0 => [ - 'codec_type' => 'audio', - 'channel_layout' => $this->faker->word(), - ], + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->randomFloat(), + 'input_tp' => fake()->randomFloat(), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'streams' => [ + 0 => [ + 'codec_type' => 'audio', + 'channel_layout' => fake()->word(), ], - ])), - ]); + ], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new AudioChannelLayoutStreamRule()], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new AudioChannelLayoutStreamRule()], + ); - static::assertFalse($validator->passes()); + $this->assertFalse($validator->passes()); - Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); - } + Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); +}); - /** - * The Audio Channel Layout Rule Stream shall pass if the channel layout is stereo. - */ - public function testPassesWhenLayoutIsStereo(): void - { - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); +test('passes when layout is stereo', function () { + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->randomFloat(), - 'input_tp' => $this->faker->randomFloat(), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'streams' => [ - 0 => [ - 'codec_type' => 'audio', - 'channel_layout' => 'stereo', - ], + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->randomFloat(), + 'input_tp' => fake()->randomFloat(), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'streams' => [ + 0 => [ + 'codec_type' => 'audio', + 'channel_layout' => 'stereo', ], - ])), - ]); + ], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new AudioChannelLayoutStreamRule()], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new AudioChannelLayoutStreamRule()], + ); - static::assertTrue($validator->passes()); + $this->assertTrue($validator->passes()); - Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); - } -} + Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); +}); diff --git a/tests/Unit/Rules/Wiki/Submission/Audio/AudioChannelsStreamTest.php b/tests/Unit/Rules/Wiki/Submission/Audio/AudioChannelsStreamTest.php index 5ae337b6e..570a9b8db 100644 --- a/tests/Unit/Rules/Wiki/Submission/Audio/AudioChannelsStreamTest.php +++ b/tests/Unit/Rules/Wiki/Submission/Audio/AudioChannelsStreamTest.php @@ -2,97 +2,82 @@ declare(strict_types=1); -namespace Tests\Unit\Rules\Wiki\Submission\Audio; - use App\Actions\Storage\Wiki\UploadedFileAction; use App\Rules\Wiki\Submission\Audio\AudioChannelsStreamRule; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\Process; use Illuminate\Support\Facades\Validator; -use Tests\TestCase; -class AudioChannelsStreamTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Audio Channels Stream Rule shall fail if the channel count is not 2. - */ - public function testFailsWhenChannelCountIsNotTwo(): void - { - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); +test('fails when channel count is not two', function () { + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->randomFloat(), - 'input_tp' => $this->faker->randomFloat(), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'streams' => [ - 0 => [ - 'codec_type' => 'audio', - 'channels' => $this->faker->randomDigitNot(2), - ], + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->randomFloat(), + 'input_tp' => fake()->randomFloat(), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'streams' => [ + 0 => [ + 'codec_type' => 'audio', + 'channels' => fake()->randomDigitNot(2), ], - ])), - ]); + ], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new AudioChannelsStreamRule()], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new AudioChannelsStreamRule()], + ); - static::assertFalse($validator->passes()); + $this->assertFalse($validator->passes()); - Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); - } + Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); +}); - /** - * The Audio Channels Stream Rule shall pass if the channel count is 2. - */ - public function testPassesWhenChannelCountIsTwo(): void - { - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); +test('passes when channel count is two', function () { + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->randomFloat(), - 'input_tp' => $this->faker->randomFloat(), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'streams' => [ - 0 => [ - 'codec_type' => 'audio', - 'channels' => 2, - ], + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->randomFloat(), + 'input_tp' => fake()->randomFloat(), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'streams' => [ + 0 => [ + 'codec_type' => 'audio', + 'channels' => 2, ], - ])), - ]); + ], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new AudioChannelsStreamRule()], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new AudioChannelsStreamRule()], + ); - static::assertTrue($validator->passes()); + $this->assertTrue($validator->passes()); - Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); - } -} + Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); +}); diff --git a/tests/Unit/Rules/Wiki/Submission/Audio/AudioCodecStreamTest.php b/tests/Unit/Rules/Wiki/Submission/Audio/AudioCodecStreamTest.php index c46fef671..c439699d8 100644 --- a/tests/Unit/Rules/Wiki/Submission/Audio/AudioCodecStreamTest.php +++ b/tests/Unit/Rules/Wiki/Submission/Audio/AudioCodecStreamTest.php @@ -2,97 +2,82 @@ declare(strict_types=1); -namespace Tests\Unit\Rules\Wiki\Submission\Audio; - use App\Actions\Storage\Wiki\UploadedFileAction; use App\Rules\Wiki\Submission\Audio\AudioCodecStreamRule; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\Process; use Illuminate\Support\Facades\Validator; -use Tests\TestCase; -class AudioCodecStreamTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Audio Codec Stream Rule shall fail if the audio connect is not opus. - */ - public function testFailsWhenCodecIsNotOpus(): void - { - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); +test('fails when codec is not opus', function () { + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->randomFloat(), - 'input_tp' => $this->faker->randomFloat(), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'streams' => [ - 0 => [ - 'codec_type' => 'audio', - 'codec_name' => $this->faker->randomDigitNot(2), - ], + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->randomFloat(), + 'input_tp' => fake()->randomFloat(), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'streams' => [ + 0 => [ + 'codec_type' => 'audio', + 'codec_name' => fake()->randomDigitNot(2), ], - ])), - ]); + ], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new AudioCodecStreamRule()], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new AudioCodecStreamRule()], + ); - static::assertFalse($validator->passes()); + $this->assertFalse($validator->passes()); - Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); - } + Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); +}); - /** - * The Audio Codec Stream Rule shall pass if the audio connect is opus. - */ - public function testPassesWhenCodecIsOpus(): void - { - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); +test('passes when codec is opus', function () { + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->randomFloat(), - 'input_tp' => $this->faker->randomFloat(), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'streams' => [ - 0 => [ - 'codec_type' => 'audio', - 'codec_name' => 'opus', - ], + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->randomFloat(), + 'input_tp' => fake()->randomFloat(), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'streams' => [ + 0 => [ + 'codec_type' => 'audio', + 'codec_name' => 'opus', ], - ])), - ]); + ], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new AudioCodecStreamRule()], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new AudioCodecStreamRule()], + ); - static::assertTrue($validator->passes()); + $this->assertTrue($validator->passes()); - Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); - } -} + Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); +}); diff --git a/tests/Unit/Rules/Wiki/Submission/Audio/AudioIndexStreamTest.php b/tests/Unit/Rules/Wiki/Submission/Audio/AudioIndexStreamTest.php index d6332240c..fbc4741a4 100644 --- a/tests/Unit/Rules/Wiki/Submission/Audio/AudioIndexStreamTest.php +++ b/tests/Unit/Rules/Wiki/Submission/Audio/AudioIndexStreamTest.php @@ -2,99 +2,84 @@ declare(strict_types=1); -namespace Tests\Unit\Rules\Wiki\Submission\Audio; - use App\Actions\Storage\Wiki\UploadedFileAction; use App\Rules\Wiki\Submission\Audio\AudioIndexStreamRule; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\Process; use Illuminate\Support\Facades\Validator; -use Tests\TestCase; -class AudioIndexStreamTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Audio Index Stream Rule shall fail if the stream index is not expected. - */ - public function testFailsWhenIndexIsNotExpected(): void - { - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); +test('fails when index is not expected', function () { + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->randomFloat(), - 'input_tp' => $this->faker->randomFloat(), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'streams' => [ - 0 => [ - 'codec_type' => 'audio', - 'index' => $this->faker->unique()->randomDigitNotNull(), - ], + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->randomFloat(), + 'input_tp' => fake()->randomFloat(), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'streams' => [ + 0 => [ + 'codec_type' => 'audio', + 'index' => fake()->unique()->randomDigitNotNull(), ], - ])), - ]); + ], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new AudioIndexStreamRule($this->faker->unique()->randomDigitNotNull())], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new AudioIndexStreamRule(fake()->unique()->randomDigitNotNull())], + ); - static::assertFalse($validator->passes()); + $this->assertFalse($validator->passes()); - Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); - } + Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); +}); - /** - * The Audio Index Stream Rule shall pass if the stream index is expected. - */ - public function testPassesWhenIndexIsExpected(): void - { - $index = $this->faker->randomDigitNotNull(); +test('passes when index is expected', function () { + $index = fake()->randomDigitNotNull(); - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->randomFloat(), - 'input_tp' => $this->faker->randomFloat(), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'streams' => [ - 0 => [ - 'codec_type' => 'audio', - 'index' => $index, - ], + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->randomFloat(), + 'input_tp' => fake()->randomFloat(), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'streams' => [ + 0 => [ + 'codec_type' => 'audio', + 'index' => $index, ], - ])), - ]); + ], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new AudioIndexStreamRule($index)], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new AudioIndexStreamRule($index)], + ); - static::assertTrue($validator->passes()); + $this->assertTrue($validator->passes()); - Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); - } -} + Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); +}); diff --git a/tests/Unit/Rules/Wiki/Submission/Audio/AudioLoudnessIntegratedTargetStreamTest.php b/tests/Unit/Rules/Wiki/Submission/Audio/AudioLoudnessIntegratedTargetStreamTest.php index 5a2ffb3d4..a306fc608 100644 --- a/tests/Unit/Rules/Wiki/Submission/Audio/AudioLoudnessIntegratedTargetStreamTest.php +++ b/tests/Unit/Rules/Wiki/Submission/Audio/AudioLoudnessIntegratedTargetStreamTest.php @@ -2,95 +2,80 @@ declare(strict_types=1); -namespace Tests\Unit\Rules\Wiki\Submission\Audio; - use App\Actions\Storage\Wiki\UploadedFileAction; use App\Rules\Wiki\Submission\Audio\AudioLoudnessIntegratedTargetStreamRule; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\Process; use Illuminate\Support\Facades\Validator; -use Tests\TestCase; -class AudioLoudnessIntegratedTargetStreamTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Audio Loudness Integrated Target Stream Rule shall fail if the integrated target is not within the accepted range. - */ - public function testFailsWhenIntegratedTargetIsNotExpected(): void - { - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); +test('fails when integrated target is not expected', function () { + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->randomFloat(), - 'input_tp' => $this->faker->randomFloat(), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'streams' => [ - 0 => [ - 'codec_type' => 'audio', - ], + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->randomFloat(), + 'input_tp' => fake()->randomFloat(), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'streams' => [ + 0 => [ + 'codec_type' => 'audio', ], - ])), - ]); + ], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new AudioLoudnessIntegratedTargetStreamRule()], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new AudioLoudnessIntegratedTargetStreamRule()], + ); - static::assertFalse($validator->passes()); + $this->assertFalse($validator->passes()); - Process::assertRan(UploadedFileAction::formatLoudnessCommand($file)); - } + Process::assertRan(UploadedFileAction::formatLoudnessCommand($file)); +}); - /** - * The Audio Loudness Integrated Target Stream Rule shall pass if the integrated target is within the accepted range. - */ - public function testPassesWhenIntegratedTargetIsNotExpected(): void - { - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); +test('passes when integrated target is not expected', function () { + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->numberBetween(-17, -14), - 'input_tp' => $this->faker->randomFloat(), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'streams' => [ - 0 => [ - 'codec_type' => 'audio', - ], + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->numberBetween(-17, -14), + 'input_tp' => fake()->randomFloat(), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'streams' => [ + 0 => [ + 'codec_type' => 'audio', ], - ])), - ]); + ], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new AudioLoudnessIntegratedTargetStreamRule()], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new AudioLoudnessIntegratedTargetStreamRule()], + ); - static::assertTrue($validator->passes()); + $this->assertTrue($validator->passes()); - Process::assertRan(UploadedFileAction::formatLoudnessCommand($file)); - } -} + Process::assertRan(UploadedFileAction::formatLoudnessCommand($file)); +}); diff --git a/tests/Unit/Rules/Wiki/Submission/Audio/AudioLoudnessTruePeakStreamTest.php b/tests/Unit/Rules/Wiki/Submission/Audio/AudioLoudnessTruePeakStreamTest.php index c7acd70f5..c5b5765ff 100644 --- a/tests/Unit/Rules/Wiki/Submission/Audio/AudioLoudnessTruePeakStreamTest.php +++ b/tests/Unit/Rules/Wiki/Submission/Audio/AudioLoudnessTruePeakStreamTest.php @@ -2,95 +2,80 @@ declare(strict_types=1); -namespace Tests\Unit\Rules\Wiki\Submission\Audio; - use App\Actions\Storage\Wiki\UploadedFileAction; use App\Rules\Wiki\Submission\Audio\AudioLoudnessTruePeakStreamRule; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\Process; use Illuminate\Support\Facades\Validator; -use Tests\TestCase; -class AudioLoudnessTruePeakStreamTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Audio Loudness True Peak Stream Rule shall fail if the true peak is greater than to 0. - */ - public function testFailsWhenTruePeakIsNotExpected(): void - { - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); +test('fails when true peak is not expected', function () { + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->randomFloat(), - 'input_tp' => $this->faker->randomFloat(min: 0.1), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'streams' => [ - 0 => [ - 'codec_type' => 'audio', - ], + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->randomFloat(), + 'input_tp' => fake()->randomFloat(min: 0.1), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'streams' => [ + 0 => [ + 'codec_type' => 'audio', ], - ])), - ]); + ], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new AudioLoudnessTruePeakStreamRule()], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new AudioLoudnessTruePeakStreamRule()], + ); - static::assertFalse($validator->passes()); + $this->assertFalse($validator->passes()); - Process::assertRan(UploadedFileAction::formatLoudnessCommand($file)); - } + Process::assertRan(UploadedFileAction::formatLoudnessCommand($file)); +}); - /** - * The Audio Loudness True Peak Stream Rule shall pass if the true peak is less than or equal to 0. - */ - public function testPassesWhenTruePeakIsExpected(): void - { - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); +test('passes when true peak is expected', function () { + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->numberBetween(), - 'input_tp' => $this->faker->randomFloat(min: -20, max: 0.1), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'streams' => [ - 0 => [ - 'codec_type' => 'audio', - ], + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->numberBetween(), + 'input_tp' => fake()->randomFloat(min: -20, max: 0.1), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'streams' => [ + 0 => [ + 'codec_type' => 'audio', ], - ])), - ]); + ], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new AudioLoudnessTruePeakStreamRule()], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new AudioLoudnessTruePeakStreamRule()], + ); - static::assertTrue($validator->passes()); + $this->assertTrue($validator->passes()); - Process::assertRan(UploadedFileAction::formatLoudnessCommand($file)); - } -} + Process::assertRan(UploadedFileAction::formatLoudnessCommand($file)); +}); diff --git a/tests/Unit/Rules/Wiki/Submission/Audio/AudioSampleRateStreamTest.php b/tests/Unit/Rules/Wiki/Submission/Audio/AudioSampleRateStreamTest.php index 1c0bf533a..4cd7a23e1 100644 --- a/tests/Unit/Rules/Wiki/Submission/Audio/AudioSampleRateStreamTest.php +++ b/tests/Unit/Rules/Wiki/Submission/Audio/AudioSampleRateStreamTest.php @@ -2,97 +2,82 @@ declare(strict_types=1); -namespace Tests\Unit\Rules\Wiki\Submission\Audio; - use App\Actions\Storage\Wiki\UploadedFileAction; use App\Rules\Wiki\Submission\Audio\AudioSampleRateStreamRule; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\Process; use Illuminate\Support\Facades\Validator; -use Tests\TestCase; -class AudioSampleRateStreamTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Audio Sample Rate Stream Rule shall fail if the sample rate is not 48k. - */ - public function testFailsWhenSampleRateIsNotExpected(): void - { - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); +test('fails when sample rate is not expected', function () { + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->randomFloat(), - 'input_tp' => $this->faker->randomFloat(), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'streams' => [ - 0 => [ - 'codec_type' => 'audio', - 'sample_rate' => $this->faker->randomDigitNotNull(), - ], + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->randomFloat(), + 'input_tp' => fake()->randomFloat(), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'streams' => [ + 0 => [ + 'codec_type' => 'audio', + 'sample_rate' => fake()->randomDigitNotNull(), ], - ])), - ]); + ], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new AudioSampleRateStreamRule()], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new AudioSampleRateStreamRule()], + ); - static::assertFalse($validator->passes()); + $this->assertFalse($validator->passes()); - Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); - } + Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); +}); - /** - * The Audio Sample Rate Stream Rule shall pass if the sample rate is 48k. - */ - public function testPassesWhenSampleRateIsExpected(): void - { - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); +test('passes when sample rate is expected', function () { + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->randomFloat(), - 'input_tp' => $this->faker->randomFloat(), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'streams' => [ - 0 => [ - 'codec_type' => 'audio', - 'sample_rate' => '48000', - ], + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->randomFloat(), + 'input_tp' => fake()->randomFloat(), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'streams' => [ + 0 => [ + 'codec_type' => 'audio', + 'sample_rate' => '48000', ], - ])), - ]); + ], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new AudioSampleRateStreamRule()], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new AudioSampleRateStreamRule()], + ); - static::assertTrue($validator->passes()); + $this->assertTrue($validator->passes()); - Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); - } -} + Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); +}); diff --git a/tests/Unit/Rules/Wiki/Submission/Format/AudioBitrateRestrictionFormatTest.php b/tests/Unit/Rules/Wiki/Submission/Format/AudioBitrateRestrictionFormatTest.php index 4bd6ad92f..d4a9a266b 100644 --- a/tests/Unit/Rules/Wiki/Submission/Format/AudioBitrateRestrictionFormatTest.php +++ b/tests/Unit/Rules/Wiki/Submission/Format/AudioBitrateRestrictionFormatTest.php @@ -2,97 +2,82 @@ declare(strict_types=1); -namespace Tests\Unit\Rules\Wiki\Submission\Format; - use App\Actions\Storage\Wiki\UploadedFileAction; use App\Constants\FeatureConstants; use App\Rules\Wiki\Submission\Format\AudioBitrateRestrictionFormatRule; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\Process; use Illuminate\Support\Facades\Validator; use Laravel\Pennant\Feature; -use Tests\TestCase; -class AudioBitrateRestrictionFormatTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Audio Bitrate Restriction Format Rule shall fail if the audio bitrate is outside the accepted boundaries. - */ - public function testFailsWhenBitrateIsNotExpected(): void - { - Feature::activate(FeatureConstants::AUDIO_BITRATE_RESTRICTION); +test('fails when bitrate is not expected', function () { + Feature::activate(FeatureConstants::AUDIO_BITRATE_RESTRICTION); - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->randomFloat(), - 'input_tp' => $this->faker->randomFloat(), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'format' => [ - 'bit_rate' => $this->faker->numberBetween(0, 127999), - ], - ])), - ]); + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->randomFloat(), + 'input_tp' => fake()->randomFloat(), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'format' => [ + 'bit_rate' => fake()->numberBetween(0, 127999), + ], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new AudioBitrateRestrictionFormatRule()], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new AudioBitrateRestrictionFormatRule()], + ); - static::assertFalse($validator->passes()); + $this->assertFalse($validator->passes()); - Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); - } + Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); +}); - /** - * The Audio Bitrate Restriction Format Rule shall fail if the audio bitrate is within the accepted boundaries. - */ - public function testPassesWhenBitrateIsExpected(): void - { - Feature::activate(FeatureConstants::AUDIO_BITRATE_RESTRICTION); +test('passes when bitrate is expected', function () { + Feature::activate(FeatureConstants::AUDIO_BITRATE_RESTRICTION); - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->randomFloat(), - 'input_tp' => $this->faker->randomFloat(), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'format' => [ - 'bit_rate' => $this->faker->numberBetween(128001, 359999), - ], - ])), - ]); + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->randomFloat(), + 'input_tp' => fake()->randomFloat(), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'format' => [ + 'bit_rate' => fake()->numberBetween(128001, 359999), + ], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new AudioBitrateRestrictionFormatRule()], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new AudioBitrateRestrictionFormatRule()], + ); - static::assertTrue($validator->passes()); + $this->assertTrue($validator->passes()); - Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); - } -} + Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); +}); diff --git a/tests/Unit/Rules/Wiki/Submission/Format/EncoderNameFormatTest.php b/tests/Unit/Rules/Wiki/Submission/Format/EncoderNameFormatTest.php index 05a7ae8c0..aff1cfffa 100644 --- a/tests/Unit/Rules/Wiki/Submission/Format/EncoderNameFormatTest.php +++ b/tests/Unit/Rules/Wiki/Submission/Format/EncoderNameFormatTest.php @@ -2,95 +2,80 @@ declare(strict_types=1); -namespace Tests\Unit\Rules\Wiki\Submission\Format; - use App\Actions\Storage\Wiki\UploadedFileAction; use App\Rules\Wiki\Submission\Format\EncoderNameFormatRule; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\Process; use Illuminate\Support\Facades\Validator; -use Tests\TestCase; -class EncoderNameFormatTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Encoder Name Format Rule shall fail if the encoder is not FFmpeg. - */ - public function testFailsWhenEncoderNameIsNotFFmpeg(): void - { - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); +test('fails when encoder name is not ffmpeg', function () { + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->randomFloat(), - 'input_tp' => $this->faker->randomFloat(), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'format' => [ - 'tags' => [ - 'ENCODER' => $this->faker->word(), - ], + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->randomFloat(), + 'input_tp' => fake()->randomFloat(), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'format' => [ + 'tags' => [ + 'ENCODER' => fake()->word(), ], - ])), - ]); + ], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new EncoderNameFormatRule()], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new EncoderNameFormatRule()], + ); - static::assertFalse($validator->passes()); + $this->assertFalse($validator->passes()); - Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); - } + Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); +}); - /** - * The Encoder Name Format Rule shall pass if the encoder is FFmpeg. - */ - public function testPassesWhenEncoderNameIsFFmpeg(): void - { - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); +test('passes when encoder name is ffmpeg', function () { + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->randomFloat(), - 'input_tp' => $this->faker->randomFloat(), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'format' => [ - 'tags' => [ - 'ENCODER' => "Lavf{$this->faker->numberBetween()}", - ], + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->randomFloat(), + 'input_tp' => fake()->randomFloat(), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'format' => [ + 'tags' => [ + 'ENCODER' => 'Lavf{fake()->numberBetween()}', ], - ])), - ]); + ], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new EncoderNameFormatRule()], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new EncoderNameFormatRule()], + ); - static::assertTrue($validator->passes()); + $this->assertTrue($validator->passes()); - Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); - } -} + Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); +}); diff --git a/tests/Unit/Rules/Wiki/Submission/Format/EncoderVersionFormatTest.php b/tests/Unit/Rules/Wiki/Submission/Format/EncoderVersionFormatTest.php index f78cb7206..752eb515c 100644 --- a/tests/Unit/Rules/Wiki/Submission/Format/EncoderVersionFormatTest.php +++ b/tests/Unit/Rules/Wiki/Submission/Format/EncoderVersionFormatTest.php @@ -2,101 +2,86 @@ declare(strict_types=1); -namespace Tests\Unit\Rules\Wiki\Submission\Format; - use App\Actions\Storage\Wiki\UploadedFileAction; use App\Constants\FeatureConstants; use App\Rules\Wiki\Submission\Format\EncoderVersionFormatRule; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\Process; use Illuminate\Support\Facades\Validator; use Laravel\Pennant\Feature; -use Tests\TestCase; -class EncoderVersionFormatTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Encoder Version Format Rule shall fail if the encoder version is older than the required version. - */ - public function testFailsWhenEncoderVersionIsOlderThanRequired(): void - { - Feature::activate(FeatureConstants::REQUIRED_ENCODER_VERSION, 'Lavf59.27.100'); +test('fails when encoder version is older than required', function () { + Feature::activate(FeatureConstants::REQUIRED_ENCODER_VERSION, 'Lavf59.27.100'); - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->randomFloat(), - 'input_tp' => $this->faker->randomFloat(), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'format' => [ - 'tags' => [ - 'ENCODER' => 'Lavf58.76.100', - ], + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->randomFloat(), + 'input_tp' => fake()->randomFloat(), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'format' => [ + 'tags' => [ + 'ENCODER' => 'Lavf58.76.100', ], - ])), - ]); + ], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new EncoderVersionFormatRule()], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new EncoderVersionFormatRule()], + ); - static::assertFalse($validator->passes()); + $this->assertFalse($validator->passes()); - Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); - } + Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); +}); - /** - * The Encoder Version Format Rule shall pass if the encoder version is up to date with the required version. - */ - public function testFailsWhenEncoderVersionIsUpToDate(): void - { - Feature::activate(FeatureConstants::REQUIRED_ENCODER_VERSION, 'Lavf59.27.100'); +test('fails when encoder version is up to date', function () { + Feature::activate(FeatureConstants::REQUIRED_ENCODER_VERSION, 'Lavf59.27.100'); - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->randomFloat(), - 'input_tp' => $this->faker->randomFloat(), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'format' => [ - 'tags' => [ - 'ENCODER' => 'Lavf59.27.100', - ], + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->randomFloat(), + 'input_tp' => fake()->randomFloat(), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'format' => [ + 'tags' => [ + 'ENCODER' => 'Lavf59.27.100', ], - ])), - ]); + ], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new EncoderVersionFormatRule()], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new EncoderVersionFormatRule()], + ); - static::assertTrue($validator->passes()); + $this->assertTrue($validator->passes()); - Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); - } -} + Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); +}); diff --git a/tests/Unit/Rules/Wiki/Submission/Format/ExtraneousChaptersFormatTest.php b/tests/Unit/Rules/Wiki/Submission/Format/ExtraneousChaptersFormatTest.php index 35f9047c2..a653940bc 100644 --- a/tests/Unit/Rules/Wiki/Submission/Format/ExtraneousChaptersFormatTest.php +++ b/tests/Unit/Rules/Wiki/Submission/Format/ExtraneousChaptersFormatTest.php @@ -2,89 +2,74 @@ declare(strict_types=1); -namespace Tests\Unit\Rules\Wiki\Submission\Format; - use App\Actions\Storage\Wiki\UploadedFileAction; use App\Rules\Wiki\Submission\Format\ExtraneousChaptersFormatRule; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\Process; use Illuminate\Support\Facades\Validator; -use Tests\TestCase; -class ExtraneousChaptersFormatTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Extraneous Chapters Format Rule shall fail if the chapter data is not empty. - */ - public function testFailsWhenChapterDataIsNotEmpty(): void - { - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); +test('fails when chapter data is not empty', function () { + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->randomFloat(), - 'input_tp' => $this->faker->randomFloat(), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'chapters' => [ - $this->faker->word() => $this->faker->word(), - ], - ])), - ]); + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->randomFloat(), + 'input_tp' => fake()->randomFloat(), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'chapters' => [ + fake()->word() => fake()->word(), + ], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new ExtraneousChaptersFormatRule()], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new ExtraneousChaptersFormatRule()], + ); - static::assertFalse($validator->passes()); + $this->assertFalse($validator->passes()); - Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); - } + Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); +}); - /** - * The Extraneous Chapters Format Rule shall pass if the chapter data is empty. - */ - public function testPassesWhenChapterDataIsEmpty(): void - { - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); +test('passes when chapter data is empty', function () { + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->randomFloat(), - 'input_tp' => $this->faker->randomFloat(), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'chapters' => [], - ])), - ]); + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->randomFloat(), + 'input_tp' => fake()->randomFloat(), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'chapters' => [], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new ExtraneousChaptersFormatRule()], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new ExtraneousChaptersFormatRule()], + ); - static::assertTrue($validator->passes()); + $this->assertTrue($validator->passes()); - Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); - } -} + Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); +}); diff --git a/tests/Unit/Rules/Wiki/Submission/Format/ExtraneousMetadataFormatTest.php b/tests/Unit/Rules/Wiki/Submission/Format/ExtraneousMetadataFormatTest.php index b8a35c12d..aced2a876 100644 --- a/tests/Unit/Rules/Wiki/Submission/Format/ExtraneousMetadataFormatTest.php +++ b/tests/Unit/Rules/Wiki/Submission/Format/ExtraneousMetadataFormatTest.php @@ -2,98 +2,83 @@ declare(strict_types=1); -namespace Tests\Unit\Rules\Wiki\Submission\Format; - use App\Actions\Storage\Wiki\UploadedFileAction; use App\Rules\Wiki\Submission\Format\ExtraneousMetadataFormatRule; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\Process; use Illuminate\Support\Facades\Validator; -use Tests\TestCase; -class ExtraneousMetadataFormatTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Extraneous Metadata Format Rule shall fail if the file has extraneous metadata. - */ - public function testFailsWhenExtraneousMetadataIsPresent(): void - { - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); +test('fails when extraneous metadata is present', function () { + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->randomFloat(), - 'input_tp' => $this->faker->randomFloat(), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'format' => [ - 'tags' => [ - 'ENCODER' => "Lavf{$this->faker->numberBetween()}", - 'DURATION' => '00:01:30.098000000', - $this->faker->word() => $this->faker->word(), - ], + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->randomFloat(), + 'input_tp' => fake()->randomFloat(), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'format' => [ + 'tags' => [ + 'ENCODER' => 'Lavf{fake()->numberBetween()}', + 'DURATION' => '00:01:30.098000000', + fake()->word() => fake()->word(), ], - ])), - ]); + ], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new ExtraneousMetadataFormatRule()], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new ExtraneousMetadataFormatRule()], + ); - static::assertFalse($validator->passes()); + $this->assertFalse($validator->passes()); - Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); - } + Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); +}); - /** - * The Extraneous Metadata Format Rule shall pass if the file does not have extraneous metadata. - */ - public function testPassesNoExtraneousMetadata(): void - { - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); +test('passes no extraneous metadata', function () { + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->randomFloat(), - 'input_tp' => $this->faker->randomFloat(), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'format' => [ - 'tags' => [ - 'ENCODER' => "Lavf{$this->faker->numberBetween()}", - 'DURATION' => '00:01:30.098000000', - ], + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->randomFloat(), + 'input_tp' => fake()->randomFloat(), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'format' => [ + 'tags' => [ + 'ENCODER' => 'Lavf{fake()->numberBetween()}', + 'DURATION' => '00:01:30.098000000', ], - ])), - ]); + ], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new ExtraneousMetadataFormatRule()], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new ExtraneousMetadataFormatRule()], + ); - static::assertTrue($validator->passes()); + $this->assertTrue($validator->passes()); - Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); - } -} + Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); +}); diff --git a/tests/Unit/Rules/Wiki/Submission/Format/FormatNameFormatTest.php b/tests/Unit/Rules/Wiki/Submission/Format/FormatNameFormatTest.php index dcd766b5d..748caa6b3 100644 --- a/tests/Unit/Rules/Wiki/Submission/Format/FormatNameFormatTest.php +++ b/tests/Unit/Rules/Wiki/Submission/Format/FormatNameFormatTest.php @@ -2,93 +2,78 @@ declare(strict_types=1); -namespace Tests\Unit\Rules\Wiki\Submission\Format; - use App\Actions\Storage\Wiki\UploadedFileAction; use App\Rules\Wiki\Submission\Format\FormatNameFormatRule; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\Process; use Illuminate\Support\Facades\Validator; -use Tests\TestCase; -class FormatNameFormatTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Format Name Format Rule shall fail if the format name is not expected. - */ - public function testFailsWhenFormatNameIsNotExpected(): void - { - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); +test('fails when format name is not expected', function () { + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->randomFloat(), - 'input_tp' => $this->faker->randomFloat(), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'format' => [ - 'format_name' => $this->faker->unique()->word(), - ], - ])), - ]); + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->randomFloat(), + 'input_tp' => fake()->randomFloat(), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'format' => [ + 'format_name' => fake()->unique()->word(), + ], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new FormatNameFormatRule($this->faker->unique()->word())], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new FormatNameFormatRule(fake()->unique()->word())], + ); - static::assertFalse($validator->passes()); + $this->assertFalse($validator->passes()); - Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); - } + Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); +}); - /** - * The Format Name Format Rule shall pass if the format name is expected. - */ - public function testPassesWhenFormatNameIsExpected(): void - { - $formatName = $this->faker->word(); +test('passes when format name is expected', function () { + $formatName = fake()->word(); - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->randomFloat(), - 'input_tp' => $this->faker->randomFloat(), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'format' => [ - 'format_name' => $formatName, - ], - ])), - ]); + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->randomFloat(), + 'input_tp' => fake()->randomFloat(), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'format' => [ + 'format_name' => $formatName, + ], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new FormatNameFormatRule($formatName)], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new FormatNameFormatRule($formatName)], + ); - static::assertTrue($validator->passes()); + $this->assertTrue($validator->passes()); - Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); - } -} + Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); +}); diff --git a/tests/Unit/Rules/Wiki/Submission/Format/TotalStreamsFormatTest.php b/tests/Unit/Rules/Wiki/Submission/Format/TotalStreamsFormatTest.php index 6316b8535..b6325e088 100644 --- a/tests/Unit/Rules/Wiki/Submission/Format/TotalStreamsFormatTest.php +++ b/tests/Unit/Rules/Wiki/Submission/Format/TotalStreamsFormatTest.php @@ -2,98 +2,83 @@ declare(strict_types=1); -namespace Tests\Unit\Rules\Wiki\Submission\Format; - use App\Actions\Storage\Wiki\UploadedFileAction; use App\Rules\Wiki\Submission\Format\TotalStreamsFormatRule; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\Process; use Illuminate\Support\Facades\Validator; -use Tests\TestCase; -class TotalStreamsFormatTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Total Streams Format Rule shall fail if the total stream count is not equal to the expected count. - */ - public function testFailsWhenCountIsNotExpected(): void - { - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); +test('fails when count is not expected', function () { + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->randomFloat(), - 'input_tp' => $this->faker->randomFloat(), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'streams' => [ - 0 => [ - 'index' => 0, - ], + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->randomFloat(), + 'input_tp' => fake()->randomFloat(), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'streams' => [ + 0 => [ + 'index' => 0, ], - ])), - ]); + ], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new TotalStreamsFormatRule(2)], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new TotalStreamsFormatRule(2)], + ); - static::assertFalse($validator->passes()); + $this->assertFalse($validator->passes()); - Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); - } + Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); +}); - /** - * The Total Streams Format Rule shall pass if the total stream count is equal to the expected count. - */ - public function testPassesWhenCountIsExpected(): void - { - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); +test('passes when count is expected', function () { + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->randomFloat(), - 'input_tp' => $this->faker->randomFloat(), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'streams' => [ - 0 => [ - 'index' => 0, - ], - 1 => [ - 'index' => 1, - ], + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->randomFloat(), + 'input_tp' => fake()->randomFloat(), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'streams' => [ + 0 => [ + 'index' => 0, ], - ])), - ]); + 1 => [ + 'index' => 1, + ], + ], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new TotalStreamsFormatRule(2)], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new TotalStreamsFormatRule(2)], + ); - static::assertTrue($validator->passes()); + $this->assertTrue($validator->passes()); - Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); - } -} + Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); +}); diff --git a/tests/Unit/Rules/Wiki/Submission/Format/VideoBitrateRestrictionFormatTest.php b/tests/Unit/Rules/Wiki/Submission/Format/VideoBitrateRestrictionFormatTest.php index 4febdaa20..0d38f0df9 100644 --- a/tests/Unit/Rules/Wiki/Submission/Format/VideoBitrateRestrictionFormatTest.php +++ b/tests/Unit/Rules/Wiki/Submission/Format/VideoBitrateRestrictionFormatTest.php @@ -2,115 +2,100 @@ declare(strict_types=1); -namespace Tests\Unit\Rules\Wiki\Submission\Format; - use App\Actions\Storage\Wiki\UploadedFileAction; use App\Constants\FeatureConstants; use App\Rules\Wiki\Submission\Format\VideoBitrateRestrictionFormatRule; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\Process; use Illuminate\Support\Facades\Validator; use Laravel\Pennant\Feature; -use Tests\TestCase; -class VideoBitrateRestrictionFormatTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Video Bitrate Restriction Format Rule shall fail if the video bitrate is outside the accepted boundaries. - */ - public function testFailsWhenBitrateIsNotExpected(): void - { - Feature::activate(FeatureConstants::VIDEO_BITRATE_RESTRICTION); +test('fails when bitrate is not expected', function () { + Feature::activate(FeatureConstants::VIDEO_BITRATE_RESTRICTION); - $height = $this->faker->numberBetween(360, 1080); - $bitrate = $height * 14200 + 475000; + $height = fake()->numberBetween(360, 1080); + $bitrate = $height * 14200 + 475000; - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->randomFloat(), - 'input_tp' => $this->faker->randomFloat(), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'format' => [ - 'bit_rate' => $bitrate, + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->randomFloat(), + 'input_tp' => fake()->randomFloat(), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'format' => [ + 'bit_rate' => $bitrate, + ], + 'streams' => [ + 0 => [ + 'codec_type' => 'video', + 'height' => $height, ], - 'streams' => [ - 0 => [ - 'codec_type' => 'video', - 'height' => $height, - ], + ], + ])), + ]); + + $validator = Validator::make( + ['file' => $file], + ['file' => new VideoBitrateRestrictionFormatRule()], + ); + + $this->assertFalse($validator->passes()); + + Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); +}); + +test('passes when bitrate is expected', function () { + Feature::activate(FeatureConstants::VIDEO_BITRATE_RESTRICTION); + + $height = fake()->numberBetween(360, 1080); + $bitrate = $height * 3550 + 475000; + + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); + + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->randomFloat(), + 'input_tp' => fake()->randomFloat(), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'format' => [ + 'bit_rate' => $bitrate, + ], + 'streams' => [ + 0 => [ + 'codec_type' => 'video', + 'height' => $height, ], - ])), - ]); + ], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new VideoBitrateRestrictionFormatRule()], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new VideoBitrateRestrictionFormatRule()], + ); - static::assertFalse($validator->passes()); + $this->assertTrue($validator->passes()); - Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); - } - - /** - * The Video Bitrate Restriction Format Rule shall fail if the video bitrate is within the accepted boundaries. - */ - public function testPassesWhenBitrateIsExpected(): void - { - Feature::activate(FeatureConstants::VIDEO_BITRATE_RESTRICTION); - - $height = $this->faker->numberBetween(360, 1080); - $bitrate = $height * 3550 + 475000; - - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); - - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->randomFloat(), - 'input_tp' => $this->faker->randomFloat(), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'format' => [ - 'bit_rate' => $bitrate, - ], - 'streams' => [ - 0 => [ - 'codec_type' => 'video', - 'height' => $height, - ], - ], - ])), - ]); - - $validator = Validator::make( - ['file' => $file], - ['file' => new VideoBitrateRestrictionFormatRule()], - ); - - static::assertTrue($validator->passes()); - - Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); - } -} + Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); +}); diff --git a/tests/Unit/Rules/Wiki/Submission/SubmissionTest.php b/tests/Unit/Rules/Wiki/Submission/SubmissionTest.php index e77319bfd..0ac9dc3aa 100644 --- a/tests/Unit/Rules/Wiki/Submission/SubmissionTest.php +++ b/tests/Unit/Rules/Wiki/Submission/SubmissionTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Rules\Wiki\Submission; - use App\Actions\Storage\Wiki\UploadedFileAction; use App\Constants\FeatureConstants; use App\Rules\Wiki\Submission\Audio\AudioChannelLayoutStreamRule; @@ -26,114 +24,105 @@ use App\Rules\Wiki\Submission\Video\VideoColorSpaceStreamRule; use App\Rules\Wiki\Submission\Video\VideoColorTransferStreamRule; use App\Rules\Wiki\Submission\Video\VideoIndexStreamRule; use App\Rules\Wiki\Submission\Video\VideoPixelFormatStreamRule; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Http\UploadedFile; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Process; use Illuminate\Support\Facades\Validator; use Laravel\Pennant\Feature; -use Tests\TestCase; -class SubmissionTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Submission Rules shall execute FFmpeg processes once. - */ - public function testRunsProcessesOnce(): void - { - Feature::activate(FeatureConstants::REQUIRED_ENCODER_VERSION, 'Lavf59.27.100'); - Feature::activate(FeatureConstants::AUDIO_BITRATE_RESTRICTION); - Feature::activate(FeatureConstants::VIDEO_BITRATE_RESTRICTION); - Feature::activate(FeatureConstants::VIDEO_CODEC_STREAM, 'vp9'); - Feature::activate(FeatureConstants::VIDEO_COLOR_PRIMARIES_STREAM, 'bt709,smpte170m,bt470bg'); - Feature::activate(FeatureConstants::VIDEO_COLOR_SPACE_STREAM, 'bt709,smpte170m,bt470bg'); - Feature::activate(FeatureConstants::VIDEO_COLOR_TRANSFER_STREAM, 'bt709,smpte170m,bt470bg'); - Feature::activate(FeatureConstants::VIDEO_PIXEL_FORMAT_STREAM, 'yuv420p'); +test('runs processes once', function () { + Feature::activate(FeatureConstants::REQUIRED_ENCODER_VERSION, 'Lavf59.27.100'); + Feature::activate(FeatureConstants::AUDIO_BITRATE_RESTRICTION); + Feature::activate(FeatureConstants::VIDEO_BITRATE_RESTRICTION); + Feature::activate(FeatureConstants::VIDEO_CODEC_STREAM, 'vp9'); + Feature::activate(FeatureConstants::VIDEO_COLOR_PRIMARIES_STREAM, 'bt709,smpte170m,bt470bg'); + Feature::activate(FeatureConstants::VIDEO_COLOR_SPACE_STREAM, 'bt709,smpte170m,bt470bg'); + Feature::activate(FeatureConstants::VIDEO_COLOR_TRANSFER_STREAM, 'bt709,smpte170m,bt470bg'); + Feature::activate(FeatureConstants::VIDEO_PIXEL_FORMAT_STREAM, 'yuv420p'); - $height = $this->faker->numberBetween(360, 1080); - $bitrate = $height * 3550 + 475000; + $height = fake()->numberBetween(360, 1080); + $bitrate = $height * 3550 + 475000; - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->numberBetween(-17, -14), - 'input_tp' => $this->faker->randomFloat(min: -20, max: 0.1), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'chapters' => [], - 'format' => [ - 'bit_rate' => $bitrate, - 'format_name' => 'matroska,webm', - 'tags' => [ - 'ENCODER' => 'Lavf59.27.100', - 'DURATION' => '00:01:30.098000000', - ], - ], - 'streams' => [ - 0 => [ - 'codec_name' => 'vp9', - 'codec_type' => 'video', - 'color_primaries' => Arr::random(['bt709', 'smpte170m', 'bt470bg']), - 'color_space' => Arr::random(['bt709', 'smpte170m', 'bt470bg']), - 'color_transfer' => Arr::random(['bt709', 'smpte170m', 'bt470bg']), - 'height' => $height, - 'index' => 0, - 'pix_fmt' => 'yuv420p', - ], - 1 => [ - 'channel_layout' => 'stereo', - 'channels' => 2, - 'codec_name' => 'opus', - 'codec_type' => 'audio', - 'index' => 1, - 'sample_rate' => '48000', - ], - ], - ])), - ]); - - $validator = Validator::make( - ['file' => $file], - [ - 'file' => [ - new TotalStreamsFormatRule(2), - new EncoderNameFormatRule(), - new EncoderVersionFormatRule(), - new FormatNameFormatRule('matroska,webm'), - new VideoBitrateRestrictionFormatRule(), - new ExtraneousMetadataFormatRule(), - new ExtraneousChaptersFormatRule(), - new AudioIndexStreamRule(1), - new AudioCodecStreamRule(), - new AudioSampleRateStreamRule(), - new AudioChannelsStreamRule(), - new AudioChannelLayoutStreamRule(), - new AudioLoudnessTruePeakStreamRule(), - new AudioLoudnessIntegratedTargetStreamRule(), - new VideoIndexStreamRule(), - new VideoCodecStreamRule(), - new VideoPixelFormatStreamRule(), - new VideoColorSpaceStreamRule(), - new VideoColorTransferStreamRule(), - new VideoColorPrimariesStreamRule(), + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->numberBetween(-17, -14), + 'input_tp' => fake()->randomFloat(min: -20, max: 0.1), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'chapters' => [], + 'format' => [ + 'bit_rate' => $bitrate, + 'format_name' => 'matroska,webm', + 'tags' => [ + 'ENCODER' => 'Lavf59.27.100', + 'DURATION' => '00:01:30.098000000', ], ], - ); + 'streams' => [ + 0 => [ + 'codec_name' => 'vp9', + 'codec_type' => 'video', + 'color_primaries' => Arr::random(['bt709', 'smpte170m', 'bt470bg']), + 'color_space' => Arr::random(['bt709', 'smpte170m', 'bt470bg']), + 'color_transfer' => Arr::random(['bt709', 'smpte170m', 'bt470bg']), + 'height' => $height, + 'index' => 0, + 'pix_fmt' => 'yuv420p', + ], + 1 => [ + 'channel_layout' => 'stereo', + 'channels' => 2, + 'codec_name' => 'opus', + 'codec_type' => 'audio', + 'index' => 1, + 'sample_rate' => '48000', + ], + ], + ])), + ]); - static::assertTrue($validator->passes()); + $validator = Validator::make( + ['file' => $file], + [ + 'file' => [ + new TotalStreamsFormatRule(2), + new EncoderNameFormatRule(), + new EncoderVersionFormatRule(), + new FormatNameFormatRule('matroska,webm'), + new VideoBitrateRestrictionFormatRule(), + new ExtraneousMetadataFormatRule(), + new ExtraneousChaptersFormatRule(), + new AudioIndexStreamRule(1), + new AudioCodecStreamRule(), + new AudioSampleRateStreamRule(), + new AudioChannelsStreamRule(), + new AudioChannelLayoutStreamRule(), + new AudioLoudnessTruePeakStreamRule(), + new AudioLoudnessIntegratedTargetStreamRule(), + new VideoIndexStreamRule(), + new VideoCodecStreamRule(), + new VideoPixelFormatStreamRule(), + new VideoColorSpaceStreamRule(), + new VideoColorTransferStreamRule(), + new VideoColorPrimariesStreamRule(), + ], + ], + ); - Process::assertRanTimes(UploadedFileAction::formatFfprobeCommand($file)); - Process::assertRanTimes(UploadedFileAction::formatLoudnessCommand($file)); - } -} + $this->assertTrue($validator->passes()); + + Process::assertRanTimes(UploadedFileAction::formatFfprobeCommand($file)); + Process::assertRanTimes(UploadedFileAction::formatLoudnessCommand($file)); +}); diff --git a/tests/Unit/Rules/Wiki/Submission/Video/VideoCodecStreamTest.php b/tests/Unit/Rules/Wiki/Submission/Video/VideoCodecStreamTest.php index 8fa9c8364..381aea71b 100644 --- a/tests/Unit/Rules/Wiki/Submission/Video/VideoCodecStreamTest.php +++ b/tests/Unit/Rules/Wiki/Submission/Video/VideoCodecStreamTest.php @@ -2,103 +2,88 @@ declare(strict_types=1); -namespace Tests\Unit\Rules\Wiki\Submission\Video; - use App\Actions\Storage\Wiki\UploadedFileAction; use App\Constants\FeatureConstants; use App\Rules\Wiki\Submission\Video\VideoCodecStreamRule; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\Process; use Illuminate\Support\Facades\Validator; use Laravel\Pennant\Feature; -use Tests\TestCase; -class VideoCodecStreamTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Video Codec Stream Rule shall fail if the video codec is not vp9. - */ - public function testFailsWhenCodecIsNotVp9(): void - { - Feature::activate(FeatureConstants::VIDEO_CODEC_STREAM, 'vp9'); +test('fails when codec is not vp9', function () { + Feature::activate(FeatureConstants::VIDEO_CODEC_STREAM, 'vp9'); - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->randomFloat(), - 'input_tp' => $this->faker->randomFloat(), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'streams' => [ - 0 => [ - 'codec_type' => 'video', - 'codec_name' => $this->faker->randomDigitNot(2), - ], + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->randomFloat(), + 'input_tp' => fake()->randomFloat(), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'streams' => [ + 0 => [ + 'codec_type' => 'video', + 'codec_name' => fake()->randomDigitNot(2), ], - ])), - ]); + ], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new VideoCodecStreamRule()], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new VideoCodecStreamRule()], + ); - static::assertFalse($validator->passes()); + $this->assertFalse($validator->passes()); - Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); - } + Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); +}); - /** - * The Video Codec Stream Rule shall pass if the video codec is vp9. - */ - public function testPassesWhenCodecIsVp9(): void - { - Feature::activate(FeatureConstants::VIDEO_CODEC_STREAM, 'vp9'); +test('passes when codec is vp9', function () { + Feature::activate(FeatureConstants::VIDEO_CODEC_STREAM, 'vp9'); - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->randomFloat(), - 'input_tp' => $this->faker->randomFloat(), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'streams' => [ - 0 => [ - 'codec_type' => 'video', - 'codec_name' => 'vp9', - ], + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->randomFloat(), + 'input_tp' => fake()->randomFloat(), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'streams' => [ + 0 => [ + 'codec_type' => 'video', + 'codec_name' => 'vp9', ], - ])), - ]); + ], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new VideoCodecStreamRule()], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new VideoCodecStreamRule()], + ); - static::assertTrue($validator->passes()); + $this->assertTrue($validator->passes()); - Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); - } -} + Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); +}); diff --git a/tests/Unit/Rules/Wiki/Submission/Video/VideoColorPrimariesStreamTest.php b/tests/Unit/Rules/Wiki/Submission/Video/VideoColorPrimariesStreamTest.php index 35a3eecac..b9561dae4 100644 --- a/tests/Unit/Rules/Wiki/Submission/Video/VideoColorPrimariesStreamTest.php +++ b/tests/Unit/Rules/Wiki/Submission/Video/VideoColorPrimariesStreamTest.php @@ -2,104 +2,89 @@ declare(strict_types=1); -namespace Tests\Unit\Rules\Wiki\Submission\Video; - use App\Actions\Storage\Wiki\UploadedFileAction; use App\Constants\FeatureConstants; use App\Rules\Wiki\Submission\Video\VideoColorPrimariesStreamRule; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Http\UploadedFile; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Process; use Illuminate\Support\Facades\Validator; use Laravel\Pennant\Feature; -use Tests\TestCase; -class VideoColorPrimariesStreamTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Video Color Primaries Stream Rule shall fail if the color primaries is not in the list of accepted values. - */ - public function testFailsWhenColorPrimariesIsNotAccepted(): void - { - Feature::activate(FeatureConstants::VIDEO_COLOR_PRIMARIES_STREAM, 'bt709,smpte170m,bt470bg'); +test('fails when color primaries is not accepted', function () { + Feature::activate(FeatureConstants::VIDEO_COLOR_PRIMARIES_STREAM, 'bt709,smpte170m,bt470bg'); - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->randomFloat(), - 'input_tp' => $this->faker->randomFloat(), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'streams' => [ - 0 => [ - 'codec_type' => 'video', - 'color_primaries' => $this->faker->word(), - ], + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->randomFloat(), + 'input_tp' => fake()->randomFloat(), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'streams' => [ + 0 => [ + 'codec_type' => 'video', + 'color_primaries' => fake()->word(), ], - ])), - ]); + ], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new VideoColorPrimariesStreamRule()], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new VideoColorPrimariesStreamRule()], + ); - static::assertFalse($validator->passes()); + $this->assertFalse($validator->passes()); - Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); - } + Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); +}); - /** - * The Video Color Primaries Stream Rule shall pass if the color primaries is in the list of accepted values. - */ - public function testPassesWhenColorPrimariesIsAccepted(): void - { - Feature::activate(FeatureConstants::VIDEO_COLOR_PRIMARIES_STREAM, 'bt709,smpte170m,bt470bg'); +test('passes when color primaries is accepted', function () { + Feature::activate(FeatureConstants::VIDEO_COLOR_PRIMARIES_STREAM, 'bt709,smpte170m,bt470bg'); - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->randomFloat(), - 'input_tp' => $this->faker->randomFloat(), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'streams' => [ - 0 => [ - 'codec_type' => 'video', - 'color_primaries' => Arr::random(['bt709', 'smpte170m', 'bt470bg']), - ], + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->randomFloat(), + 'input_tp' => fake()->randomFloat(), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'streams' => [ + 0 => [ + 'codec_type' => 'video', + 'color_primaries' => Arr::random(['bt709', 'smpte170m', 'bt470bg']), ], - ])), - ]); + ], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new VideoColorPrimariesStreamRule()], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new VideoColorPrimariesStreamRule()], + ); - static::assertTrue($validator->passes()); + $this->assertTrue($validator->passes()); - Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); - } -} + Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); +}); diff --git a/tests/Unit/Rules/Wiki/Submission/Video/VideoColorSpaceStreamTest.php b/tests/Unit/Rules/Wiki/Submission/Video/VideoColorSpaceStreamTest.php index f50514c45..1acb37629 100644 --- a/tests/Unit/Rules/Wiki/Submission/Video/VideoColorSpaceStreamTest.php +++ b/tests/Unit/Rules/Wiki/Submission/Video/VideoColorSpaceStreamTest.php @@ -2,104 +2,89 @@ declare(strict_types=1); -namespace Tests\Unit\Rules\Wiki\Submission\Video; - use App\Actions\Storage\Wiki\UploadedFileAction; use App\Constants\FeatureConstants; use App\Rules\Wiki\Submission\Video\VideoColorSpaceStreamRule; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Http\UploadedFile; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Process; use Illuminate\Support\Facades\Validator; use Laravel\Pennant\Feature; -use Tests\TestCase; -class VideoColorSpaceStreamTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Video Color Space Stream Rule shall fail if the color space is not in the list of accepted values. - */ - public function testFailsWhenColorSpaceIsNotAccepted(): void - { - Feature::activate(FeatureConstants::VIDEO_COLOR_SPACE_STREAM, 'bt709,smpte170m,bt470bg'); +test('fails when color space is not accepted', function () { + Feature::activate(FeatureConstants::VIDEO_COLOR_SPACE_STREAM, 'bt709,smpte170m,bt470bg'); - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->randomFloat(), - 'input_tp' => $this->faker->randomFloat(), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'streams' => [ - 0 => [ - 'codec_type' => 'video', - 'color_space' => $this->faker->word(), - ], + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->randomFloat(), + 'input_tp' => fake()->randomFloat(), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'streams' => [ + 0 => [ + 'codec_type' => 'video', + 'color_space' => fake()->word(), ], - ])), - ]); + ], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new VideoColorSpaceStreamRule()], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new VideoColorSpaceStreamRule()], + ); - static::assertFalse($validator->passes()); + $this->assertFalse($validator->passes()); - Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); - } + Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); +}); - /** - * The Video Color Space Stream Rule shall pass if the color space is in the list of accepted values. - */ - public function testPassesWhenColorSpaceIsAccepted(): void - { - Feature::activate(FeatureConstants::VIDEO_COLOR_SPACE_STREAM, 'bt709,smpte170m,bt470bg'); +test('passes when color space is accepted', function () { + Feature::activate(FeatureConstants::VIDEO_COLOR_SPACE_STREAM, 'bt709,smpte170m,bt470bg'); - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->randomFloat(), - 'input_tp' => $this->faker->randomFloat(), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'streams' => [ - 0 => [ - 'codec_type' => 'video', - 'color_space' => Arr::random(['bt709', 'smpte170m', 'bt470bg']), - ], + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->randomFloat(), + 'input_tp' => fake()->randomFloat(), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'streams' => [ + 0 => [ + 'codec_type' => 'video', + 'color_space' => Arr::random(['bt709', 'smpte170m', 'bt470bg']), ], - ])), - ]); + ], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new VideoColorSpaceStreamRule()], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new VideoColorSpaceStreamRule()], + ); - static::assertTrue($validator->passes()); + $this->assertTrue($validator->passes()); - Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); - } -} + Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); +}); diff --git a/tests/Unit/Rules/Wiki/Submission/Video/VideoColorTransferStreamTest.php b/tests/Unit/Rules/Wiki/Submission/Video/VideoColorTransferStreamTest.php index d6cc10a78..dc24d0ea0 100644 --- a/tests/Unit/Rules/Wiki/Submission/Video/VideoColorTransferStreamTest.php +++ b/tests/Unit/Rules/Wiki/Submission/Video/VideoColorTransferStreamTest.php @@ -2,104 +2,89 @@ declare(strict_types=1); -namespace Tests\Unit\Rules\Wiki\Submission\Video; - use App\Actions\Storage\Wiki\UploadedFileAction; use App\Constants\FeatureConstants; use App\Rules\Wiki\Submission\Video\VideoColorTransferStreamRule; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Http\UploadedFile; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Process; use Illuminate\Support\Facades\Validator; use Laravel\Pennant\Feature; -use Tests\TestCase; -class VideoColorTransferStreamTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Video Color Transfer Stream Rule shall fail if the color transfer is not in the list of accepted values. - */ - public function testFailsWhenColorTransferIsNotAccepted(): void - { - Feature::activate(FeatureConstants::VIDEO_COLOR_TRANSFER_STREAM, 'bt709,smpte170m,bt470bg'); +test('fails when color transfer is not accepted', function () { + Feature::activate(FeatureConstants::VIDEO_COLOR_TRANSFER_STREAM, 'bt709,smpte170m,bt470bg'); - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->randomFloat(), - 'input_tp' => $this->faker->randomFloat(), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'streams' => [ - 0 => [ - 'codec_type' => 'video', - 'color_transfer' => $this->faker->word(), - ], + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->randomFloat(), + 'input_tp' => fake()->randomFloat(), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'streams' => [ + 0 => [ + 'codec_type' => 'video', + 'color_transfer' => fake()->word(), ], - ])), - ]); + ], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new VideoColorTransferStreamRule()], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new VideoColorTransferStreamRule()], + ); - static::assertFalse($validator->passes()); + $this->assertFalse($validator->passes()); - Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); - } + Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); +}); - /** - * The Video Color Transfer Stream Rule shall pass if the color transfer is in the list of accepted values. - */ - public function testPassesWhenColorTransferIsAccepted(): void - { - Feature::activate(FeatureConstants::VIDEO_COLOR_TRANSFER_STREAM, 'bt709,smpte170m,bt470bg'); +test('passes when color transfer is accepted', function () { + Feature::activate(FeatureConstants::VIDEO_COLOR_TRANSFER_STREAM, 'bt709,smpte170m,bt470bg'); - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->randomFloat(), - 'input_tp' => $this->faker->randomFloat(), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'streams' => [ - 0 => [ - 'codec_type' => 'video', - 'color_transfer' => Arr::random(['bt709', 'smpte170m', 'bt470bg']), - ], + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->randomFloat(), + 'input_tp' => fake()->randomFloat(), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'streams' => [ + 0 => [ + 'codec_type' => 'video', + 'color_transfer' => Arr::random(['bt709', 'smpte170m', 'bt470bg']), ], - ])), - ]); + ], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new VideoColorTransferStreamRule()], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new VideoColorTransferStreamRule()], + ); - static::assertTrue($validator->passes()); + $this->assertTrue($validator->passes()); - Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); - } -} + Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); +}); diff --git a/tests/Unit/Rules/Wiki/Submission/Video/VideoIndexStreamTest.php b/tests/Unit/Rules/Wiki/Submission/Video/VideoIndexStreamTest.php index 19d0721c2..cf73b408b 100644 --- a/tests/Unit/Rules/Wiki/Submission/Video/VideoIndexStreamTest.php +++ b/tests/Unit/Rules/Wiki/Submission/Video/VideoIndexStreamTest.php @@ -2,97 +2,82 @@ declare(strict_types=1); -namespace Tests\Unit\Rules\Wiki\Submission\Video; - use App\Actions\Storage\Wiki\UploadedFileAction; use App\Rules\Wiki\Submission\Video\VideoIndexStreamRule; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\Process; use Illuminate\Support\Facades\Validator; -use Tests\TestCase; -class VideoIndexStreamTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Video Index Stream Rule shall fail if the stream index is not expected. - */ - public function testFailsWhenIndexIsNotExpected(): void - { - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); +test('fails when index is not expected', function () { + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->randomFloat(), - 'input_tp' => $this->faker->randomFloat(), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'streams' => [ - 0 => [ - 'codec_type' => 'video', - 'index' => $this->faker->randomDigitNotNull(), - ], + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->randomFloat(), + 'input_tp' => fake()->randomFloat(), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'streams' => [ + 0 => [ + 'codec_type' => 'video', + 'index' => fake()->randomDigitNotNull(), ], - ])), - ]); + ], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new VideoIndexStreamRule()], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new VideoIndexStreamRule()], + ); - static::assertFalse($validator->passes()); + $this->assertFalse($validator->passes()); - Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); - } + Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); +}); - /** - * The Video Index Stream Rule shall pass if the stream index is expected. - */ - public function testPassesWhenIndexIsExpected(): void - { - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); +test('passes when index is expected', function () { + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->randomFloat(), - 'input_tp' => $this->faker->randomFloat(), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'streams' => [ - 0 => [ - 'codec_type' => 'video', - 'index' => 0, - ], + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->randomFloat(), + 'input_tp' => fake()->randomFloat(), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'streams' => [ + 0 => [ + 'codec_type' => 'video', + 'index' => 0, ], - ])), - ]); + ], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new VideoIndexStreamRule()], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new VideoIndexStreamRule()], + ); - static::assertTrue($validator->passes()); + $this->assertTrue($validator->passes()); - Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); - } -} + Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); +}); diff --git a/tests/Unit/Rules/Wiki/Submission/Video/VideoPixelFormatStreamTest.php b/tests/Unit/Rules/Wiki/Submission/Video/VideoPixelFormatStreamTest.php index 3e7493fe5..ec60afd2b 100644 --- a/tests/Unit/Rules/Wiki/Submission/Video/VideoPixelFormatStreamTest.php +++ b/tests/Unit/Rules/Wiki/Submission/Video/VideoPixelFormatStreamTest.php @@ -2,103 +2,88 @@ declare(strict_types=1); -namespace Tests\Unit\Rules\Wiki\Submission\Video; - use App\Actions\Storage\Wiki\UploadedFileAction; use App\Constants\FeatureConstants; use App\Rules\Wiki\Submission\Video\VideoPixelFormatStreamRule; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\Process; use Illuminate\Support\Facades\Validator; use Laravel\Pennant\Feature; -use Tests\TestCase; -class VideoPixelFormatStreamTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Video Pixel Format Stream Rule shall fail if the pixel format is not yuv420p. - */ - public function testFailsWhenCodecIsNotYuv420p(): void - { - Feature::activate(FeatureConstants::VIDEO_PIXEL_FORMAT_STREAM, 'yuv420p'); +test('fails when codec is not yuv420p', function () { + Feature::activate(FeatureConstants::VIDEO_PIXEL_FORMAT_STREAM, 'yuv420p'); - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->randomFloat(), - 'input_tp' => $this->faker->randomFloat(), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'streams' => [ - 0 => [ - 'codec_type' => 'video', - 'pix_fmt' => $this->faker->randomDigitNot(2), - ], + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->randomFloat(), + 'input_tp' => fake()->randomFloat(), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'streams' => [ + 0 => [ + 'codec_type' => 'video', + 'pix_fmt' => fake()->randomDigitNot(2), ], - ])), - ]); + ], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new VideoPixelFormatStreamRule()], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new VideoPixelFormatStreamRule()], + ); - static::assertFalse($validator->passes()); + $this->assertFalse($validator->passes()); - Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); - } + Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); +}); - /** - * The Video Pixel Format Stream Rule shall pass if the pixel format is yuv420p. - */ - public function testPassesWhenCodecIsYuv420p(): void - { - Feature::activate(FeatureConstants::VIDEO_PIXEL_FORMAT_STREAM, 'yuv420p'); +test('passes when codec is yuv420p', function () { + Feature::activate(FeatureConstants::VIDEO_PIXEL_FORMAT_STREAM, 'yuv420p'); - $file = UploadedFile::fake()->create($this->faker->word().'.webm', $this->faker->randomDigitNotNull()); + $file = UploadedFile::fake()->create(fake()->word().'.webm', fake()->randomDigitNotNull()); - Process::fake([ - UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ - 'input_i' => $this->faker->randomFloat(), - 'input_tp' => $this->faker->randomFloat(), - 'input_lra' => $this->faker->randomFloat(), - 'input_thresh' => $this->faker->randomFloat(), - 'output_i' => $this->faker->randomFloat(), - 'output_tp' => $this->faker->randomFloat(), - 'output_lra' => $this->faker->randomFloat(), - 'output_thresh' => $this->faker->randomFloat(), - 'normalization_type' => 'dynamic', - 'target_offset' => $this->faker->randomFloat(), - ])), - UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ - 'streams' => [ - 0 => [ - 'codec_type' => 'video', - 'pix_fmt' => 'yuv420p', - ], + Process::fake([ + UploadedFileAction::formatLoudnessCommand($file) => Process::result(errorOutput: json_encode([ + 'input_i' => fake()->randomFloat(), + 'input_tp' => fake()->randomFloat(), + 'input_lra' => fake()->randomFloat(), + 'input_thresh' => fake()->randomFloat(), + 'output_i' => fake()->randomFloat(), + 'output_tp' => fake()->randomFloat(), + 'output_lra' => fake()->randomFloat(), + 'output_thresh' => fake()->randomFloat(), + 'normalization_type' => 'dynamic', + 'target_offset' => fake()->randomFloat(), + ])), + UploadedFileAction::formatFfprobeCommand($file) => Process::result(json_encode([ + 'streams' => [ + 0 => [ + 'codec_type' => 'video', + 'pix_fmt' => 'yuv420p', ], - ])), - ]); + ], + ])), + ]); - $validator = Validator::make( - ['file' => $file], - ['file' => new VideoPixelFormatStreamRule()], - ); + $validator = Validator::make( + ['file' => $file], + ['file' => new VideoPixelFormatStreamRule()], + ); - static::assertTrue($validator->passes()); + $this->assertTrue($validator->passes()); - Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); - } -} + Process::assertRan(UploadedFileAction::formatFfprobeCommand($file)); +}); diff --git a/tests/Unit/Scout/Elasticsearch/Api/Parser/FilterParserTest.php b/tests/Unit/Scout/Elasticsearch/Api/Parser/FilterParserTest.php index add773f51..4760797f9 100644 --- a/tests/Unit/Scout/Elasticsearch/Api/Parser/FilterParserTest.php +++ b/tests/Unit/Scout/Elasticsearch/Api/Parser/FilterParserTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Scout\Elasticsearch\Api\Parser; - use App\Enums\Http\Api\Filter\BinaryLogicalOperator; use App\Enums\Http\Api\Filter\ComparisonOperator; use App\Http\Api\Criteria\Filter\Expression; @@ -16,91 +14,70 @@ use App\Http\Api\Scope\GlobalScope; use App\Scout\Elasticsearch\Api\Criteria\Filter\WhereCriteria; use App\Scout\Elasticsearch\Api\Criteria\Filter\WhereInCriteria; use App\Scout\Elasticsearch\Api\Parser\FilterParser; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; -use Tests\TestCase; -class FilterParserTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Filter Parser shall parse Where Criteria. - */ - public function testWhereCriteria(): void - { - $expression = new Expression($this->faker->word()); +test('where criteria', function () { + $expression = new Expression(fake()->word()); - $comparisonOperator = Arr::random(ComparisonOperator::cases()); + $comparisonOperator = Arr::random(ComparisonOperator::cases()); - $predicate = new Predicate($this->faker->word(), $comparisonOperator, $expression); + $predicate = new Predicate(fake()->word(), $comparisonOperator, $expression); - $logicalOperator = Arr::random(BinaryLogicalOperator::cases()); + $logicalOperator = Arr::random(BinaryLogicalOperator::cases()); - $criteria = new BaseWhereCriteria($predicate, $logicalOperator, new GlobalScope()); + $criteria = new BaseWhereCriteria($predicate, $logicalOperator, new GlobalScope()); - static::assertInstanceOf(WhereCriteria::class, FilterParser::parse($criteria)); - } + $this->assertInstanceOf(WhereCriteria::class, FilterParser::parse($criteria)); +}); - /** - * The Filter Parser shall parse Where In Criteria. - */ - public function testWhereInCriteria(): void - { - $expression = new Expression($this->faker->word()); +test('where in criteria', function () { + $expression = new Expression(fake()->word()); - $comparisonOperator = Arr::random(ComparisonOperator::cases()); + $comparisonOperator = Arr::random(ComparisonOperator::cases()); - $predicate = new Predicate($this->faker->word(), $comparisonOperator, $expression); + $predicate = new Predicate(fake()->word(), $comparisonOperator, $expression); - $criteria = new BaseWhereInCriteria( - $predicate, - Arr::random(BinaryLogicalOperator::cases()), - $this->faker->boolean(), - new GlobalScope() - ); + $criteria = new BaseWhereInCriteria( + $predicate, + Arr::random(BinaryLogicalOperator::cases()), + fake()->boolean(), + new GlobalScope() + ); - static::assertInstanceOf(WhereInCriteria::class, FilterParser::parse($criteria)); - } + $this->assertInstanceOf(WhereInCriteria::class, FilterParser::parse($criteria)); +}); - /** - * The Filter Parser shall not parse Has Criteria. - */ - public function testHasCriteria(): void - { - $expression = new Expression($this->faker->word()); +test('has criteria', function () { + $expression = new Expression(fake()->word()); - $comparisonOperator = Arr::random(ComparisonOperator::cases()); + $comparisonOperator = Arr::random(ComparisonOperator::cases()); - $predicate = new Predicate($this->faker->word(), $comparisonOperator, $expression); + $predicate = new Predicate(fake()->word(), $comparisonOperator, $expression); - $criteria = new HasCriteria( - $predicate, - Arr::random(BinaryLogicalOperator::cases()), - new GlobalScope(), - $this->faker->randomDigitNotNull() - ); + $criteria = new HasCriteria( + $predicate, + Arr::random(BinaryLogicalOperator::cases()), + new GlobalScope(), + fake()->randomDigitNotNull() + ); - static::assertNull(FilterParser::parse($criteria)); - } + $this->assertNull(FilterParser::parse($criteria)); +}); - /** - * The Filter Parser shall not parse Trashed Criteria. - */ - public function testTrashedCriteria(): void - { - $expression = new Expression($this->faker->word()); +test('trashed criteria', function () { + $expression = new Expression(fake()->word()); - $comparisonOperator = Arr::random(ComparisonOperator::cases()); + $comparisonOperator = Arr::random(ComparisonOperator::cases()); - $predicate = new Predicate($this->faker->word(), $comparisonOperator, $expression); + $predicate = new Predicate(fake()->word(), $comparisonOperator, $expression); - $criteria = new TrashedCriteria( - $predicate, - Arr::random(BinaryLogicalOperator::cases()), - new GlobalScope() - ); + $criteria = new TrashedCriteria( + $predicate, + Arr::random(BinaryLogicalOperator::cases()), + new GlobalScope() + ); - static::assertNull(FilterParser::parse($criteria)); - } -} + $this->assertNull(FilterParser::parse($criteria)); +}); diff --git a/tests/Unit/Scout/Elasticsearch/Api/Parser/PagingParserTest.php b/tests/Unit/Scout/Elasticsearch/Api/Parser/PagingParserTest.php index 0694adfa7..fabdb3368 100644 --- a/tests/Unit/Scout/Elasticsearch/Api/Parser/PagingParserTest.php +++ b/tests/Unit/Scout/Elasticsearch/Api/Parser/PagingParserTest.php @@ -2,37 +2,22 @@ declare(strict_types=1); -namespace Tests\Unit\Scout\Elasticsearch\Api\Parser; - use App\Http\Api\Criteria\Paging\LimitCriteria as BaseLimitCriteria; use App\Http\Api\Criteria\Paging\OffsetCriteria as BaseOffsetCriteria; use App\Scout\Elasticsearch\Api\Criteria\Paging\LimitCriteria; use App\Scout\Elasticsearch\Api\Criteria\Paging\OffsetCriteria; use App\Scout\Elasticsearch\Api\Parser\PagingParser; -use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; -class PagingParserTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Paging Parser shall parse Limit Criteria. - */ - public function testLimitCriteria(): void - { - $criteria = new BaseLimitCriteria($this->faker->randomDigitNotNull()); +test('limit criteria', function () { + $criteria = new BaseLimitCriteria(fake()->randomDigitNotNull()); - static::assertInstanceOf(LimitCriteria::class, PagingParser::parse($criteria)); - } + $this->assertInstanceOf(LimitCriteria::class, PagingParser::parse($criteria)); +}); - /** - * The Paging Parser shall parse Offset Criteria. - */ - public function testOffsetCriteria(): void - { - $criteria = new BaseOffsetCriteria($this->faker->randomDigitNotNull()); +test('offset criteria', function () { + $criteria = new BaseOffsetCriteria(fake()->randomDigitNotNull()); - static::assertInstanceOf(OffsetCriteria::class, PagingParser::parse($criteria)); - } -} + $this->assertInstanceOf(OffsetCriteria::class, PagingParser::parse($criteria)); +}); diff --git a/tests/Unit/Scout/Elasticsearch/Api/Parser/SortParserTest.php b/tests/Unit/Scout/Elasticsearch/Api/Parser/SortParserTest.php index 95582eae2..d2c337287 100644 --- a/tests/Unit/Scout/Elasticsearch/Api/Parser/SortParserTest.php +++ b/tests/Unit/Scout/Elasticsearch/Api/Parser/SortParserTest.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Tests\Unit\Scout\Elasticsearch\Api\Parser; - use App\Enums\Http\Api\Sort\Direction; use App\Http\Api\Criteria\Sort\FieldCriteria as BaseFieldCriteria; use App\Http\Api\Criteria\Sort\RandomCriteria; @@ -12,45 +10,28 @@ use App\Http\Api\Scope\GlobalScope; use App\Scout\Elasticsearch\Api\Criteria\Sort\FieldCriteria; use App\Scout\Elasticsearch\Api\Criteria\Sort\RelationCriteria; use App\Scout\Elasticsearch\Api\Parser\SortParser; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Arr; -use Tests\TestCase; -class SortParserTest extends TestCase -{ - use WithFaker; +uses(Illuminate\Foundation\Testing\WithFaker::class); - /** - * The Sort Parser shall parse Relation Criteria. - */ - public function testRelationCriteria(): void - { - $direction = Arr::random(Direction::cases()); +test('relation criteria', function () { + $direction = Arr::random(Direction::cases()); - $criteria = new BaseRelationCriteria(new GlobalScope(), $this->faker->word(), $direction); + $criteria = new BaseRelationCriteria(new GlobalScope(), fake()->word(), $direction); - static::assertInstanceOf(RelationCriteria::class, SortParser::parse($criteria)); - } + $this->assertInstanceOf(RelationCriteria::class, SortParser::parse($criteria)); +}); - /** - * The Sort Parser shall parse Field Criteria. - */ - public function testFieldCriteria(): void - { - $direction = Arr::random(Direction::cases()); +test('field criteria', function () { + $direction = Arr::random(Direction::cases()); - $criteria = new BaseFieldCriteria(new GlobalScope(), $this->faker->word(), $direction); + $criteria = new BaseFieldCriteria(new GlobalScope(), fake()->word(), $direction); - static::assertInstanceOf(FieldCriteria::class, SortParser::parse($criteria)); - } + $this->assertInstanceOf(FieldCriteria::class, SortParser::parse($criteria)); +}); - /** - * The Sort Parser shall not parse Random Criteria. - */ - public function testRandomCriteria(): void - { - $criteria = new RandomCriteria(new GlobalScope()); +test('random criteria', function () { + $criteria = new RandomCriteria(new GlobalScope()); - static::assertNull(SortParser::parse($criteria)); - } -} + $this->assertNull(SortParser::parse($criteria)); +});