From c1e9d9ca728f6ab375243d8ac47b308f93ef47a7 Mon Sep 17 00:00:00 2001 From: Shift Date: Thu, 2 Sep 2021 17:16:26 +0000 Subject: [PATCH 01/14] Add Pest dependencies --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index b3a16da5e..38e5151f4 100644 --- a/composer.json +++ b/composer.json @@ -40,7 +40,8 @@ "laravel/browser-kit-testing": "^6.1", "mockery/mockery": "^1.3.1", "nunomaduro/collision": "^5.0", - "phpunit/phpunit": "^9.3" + "pestphp/pest": "^1.18", + "pestphp/pest-plugin-laravel": "^1.1" }, "autoload": { "files": [ From 03b8d3d9fd6fc66aba536b8086197a7d32398503 Mon Sep 17 00:00:00 2001 From: Shift Date: Thu, 2 Sep 2021 17:16:26 +0000 Subject: [PATCH 02/14] Add base Pest file --- tests/Pest.php | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 tests/Pest.php diff --git a/tests/Pest.php b/tests/Pest.php new file mode 100644 index 000000000..95bd6997d --- /dev/null +++ b/tests/Pest.php @@ -0,0 +1,40 @@ + Date: Thu, 2 Sep 2021 17:16:27 +0000 Subject: [PATCH 03/14] Convert test cases --- tests/Feature/AdminTest.php | 657 ++++++------- tests/Feature/ArticleTest.php | 912 ++++++++---------- tests/Feature/AuthTest.php | 417 ++++---- tests/Feature/DashboardTest.php | 306 +++--- tests/Feature/ForumTest.php | 480 +++++---- tests/Feature/HomeTest.php | 52 +- tests/Feature/ModeratorTest.php | 36 +- tests/Feature/NavigationTest.php | 80 +- tests/Feature/PastebinRedirectTest.php | 27 +- tests/Feature/ProfileTest.php | 116 +-- tests/Feature/ReplyTest.php | 202 ++-- tests/Feature/SettingsTest.php | 273 +++--- tests/Feature/SubscriptionsTest.php | 148 ++- tests/Integration/Jobs/BanUserTest.php | 20 +- tests/Integration/Jobs/CreateArticleTest.php | 60 +- tests/Integration/Jobs/CreateReplyTest.php | 24 +- tests/Integration/Jobs/CreateThreadTest.php | 20 +- tests/Integration/Jobs/DeleteArticleTest.php | 20 +- tests/Integration/Jobs/DeleteThreadTest.php | 32 +- tests/Integration/Jobs/LikeArticleTest.php | 40 +- tests/Integration/Jobs/LikeReplyTest.php | 40 +- tests/Integration/Jobs/LikeThreadTest.php | 40 +- tests/Integration/Jobs/RegisterUserTest.php | 58 +- .../Jobs/SubscribeToSubscriptionAbleTest.php | 24 +- tests/Integration/Jobs/UnbanUserTest.php | 20 +- tests/Integration/Jobs/UnlikeArticleTest.php | 26 +- tests/Integration/Jobs/UnlikeReplyTest.php | 26 +- tests/Integration/Jobs/UnlikeThreadTest.php | 26 +- .../UnsubscribeFromSubscriptionAbleTest.php | 26 +- tests/Integration/Jobs/UpdateArticleTest.php | 54 +- tests/Integration/Jobs/UpdateProfileTest.php | 48 +- tests/Integration/Models/ArticleTest.php | 144 ++- tests/Integration/Models/ReplyTest.php | 28 +- tests/Integration/Models/SubscriptionTest.php | 20 +- tests/Integration/Models/ThreadTest.php | 237 ++--- tests/Integration/Models/UserTest.php | 85 +- tests/Integration/Queries/SearchUsersTest.php | 22 +- tests/Integration/Rules/PasscheckRuleTest.php | 36 +- .../Commands/PostArticleToTwitterTest.php | 229 ++--- .../Unit/Rules/DoesNotContainUrlRuleTest.php | 43 +- tests/Unit/Rules/HttpImageRuleTest.php | 31 +- tests/Unit/Social/GithubUserTest.php | 27 +- tests/Unit/UserTest.php | 17 +- 43 files changed, 2303 insertions(+), 2926 deletions(-) diff --git a/tests/Feature/AdminTest.php b/tests/Feature/AdminTest.php index a072e0155..da4b2323a 100644 --- a/tests/Feature/AdminTest.php +++ b/tests/Feature/AdminTest.php @@ -1,7 +1,5 @@ visit('/admin') - ->seePageIs('/login'); - } - - /** @test */ - public function normal_users_cannot_visit_the_admin_section() - { - $this->login(); - - $this->get('/admin') - ->assertForbidden(); - } - - /** @test */ - public function admins_can_see_the_users_overview() - { - $this->loginAsAdmin(); - $this->assertCanSeeTheUserOverview(); - } - - /** @test */ - public function moderators_can_see_the_users_overview() - { - $this->loginAsModerator(); - $this->assertCanSeeTheUserOverview(); - } - - private function assertCanSeeTheUserOverview() - { - User::factory()->create(['name' => 'Freek Murze']); - User::factory()->create(['name' => 'Frederick Vanbrabant']); - - $this->visit('/admin') - ->see('Freek Murze') - ->see('Frederick Vanbrabant'); - } - - /** @test */ - public function admins_can_ban_a_user() - { - $this->loginAsAdmin(); - $this->assertCanBanUsers(); - } - - /** @test */ - public function moderators_can_ban_a_user() - { - $this->loginAsModerator(); - $this->assertCanBanUsers(); - } - - private function assertCanBanUsers() - { - $user = User::factory()->create(['name' => 'Freek Murze']); - - $this->put('/admin/users/'.$user->username().'/ban') - ->assertRedirectedTo('/user/'.$user->username()); - - $this->notSeeInDatabase('users', ['id' => $user->id(), 'banned_at' => null]); - } - - /** @test */ - public function admins_can_unban_a_user() - { - $this->loginAsAdmin(); - $this->assertCanUnbanUsers(); - } - - /** @test */ - public function moderators_can_unban_a_user() - { - $this->loginAsModerator(); - $this->assertCanUnbanUsers(); - } - - private function assertCanUnbanUsers() - { - $user = User::factory()->create(['name' => 'Freek Murze', 'banned_at' => Carbon::now()]); - - $this->put('/admin/users/'.$user->username().'/unban') - ->assertRedirectedTo('/user/'.$user->username()); - - $this->seeInDatabase('users', ['id' => $user->id(), 'banned_at' => null]); - } - - /** @test */ - public function admins_cannot_ban_other_admins() - { - $this->loginAsAdmin(); - $this->assertCannotBanAdmins(); - } - - /** @test */ - public function moderators_cannot_ban_admins() - { - $this->loginAsModerator(); - $this->assertCannotBanAdmins(); - } - - /** @test */ - public function moderators_cannot_ban_other_moderators() - { - $this->loginAsModerator(); - $this->assertCannotBanModerators(); - } - - private function assertCannotBanAdmins() - { - $this->assertCannotBanUsersByType(User::ADMIN); - } - - private function assertCannotBanModerators() - { - $this->assertCannotBanUsersByType(User::MODERATOR); - } - - private function assertCannotBanUsersByType(int $type) - { - $user = User::factory()->create(['type' => $type]); - - $this->put('/admin/users/'.$user->username().'/ban') - ->assertForbidden(); - } - - /** @test */ - public function admins_can_delete_a_user() - { - $user = User::factory()->create(['name' => 'Freek Murze']); - $thread = Thread::factory()->create(['author_id' => $user->id()]); - Reply::factory()->create(['replyable_id' => $thread->id()]); - Reply::factory()->create(['author_id' => $user->id()]); - - $this->loginAsAdmin(); - - $this->delete('/admin/users/'.$user->username()) - ->assertRedirectedTo('/admin'); - - $this->notSeeInDatabase('users', ['name' => 'Freek Murze']); - - // Make sure associated content is deleted. - $this->notSeeInDatabase('threads', ['author_id' => $user->id()]); - $this->notSeeInDatabase('replies', ['replyable_id' => $thread->id()]); - $this->notSeeInDatabase('replies', ['author_id' => $user->id()]); - } - - /** @test */ - public function admins_cannot_delete_other_admins() - { - $user = User::factory()->create(['type' => User::ADMIN]); - - $this->loginAsAdmin(); - - $this->delete('/admin/users/'.$user->username()) - ->assertForbidden(); - } - - /** @test */ - public function moderators_cannot_delete_users() - { - $user = User::factory()->create(); - - $this->loginAsModerator(); - - $this->delete('/admin/users/'.$user->username()) - ->assertForbidden(); - } - - /** @test */ - public function admins_can_list_submitted_articles() - { - $submittedArticle = Article::factory()->create(['submitted_at' => now()]); - $draftArticle = Article::factory()->create(); - $liveArticle = Article::factory()->create(['submitted_at' => now(), 'approved_at' => now()]); - - $this->loginAsAdmin(); - - $this->get('admin/articles') - ->see($submittedArticle->title()) - ->dontSee($draftArticle->title()) - ->dontSee($liveArticle->title()); - } +uses(BrowserKitTestCase::class); +uses(DatabaseMigrations::class); + +test('requires login', function () { + $this->visit('/admin') + ->seePageIs('/login'); +}); + +test('normal users cannot visit the admin section', function () { + $this->login(); + + $this->get('/admin') + ->assertForbidden(); +}); + +test('admins can see the users overview', function () { + $this->loginAsAdmin(); + assertCanSeeTheUserOverview(); +}); + +test('moderators can see the users overview', function () { + $this->loginAsModerator(); + assertCanSeeTheUserOverview(); +}); + +test('admins can ban a user', function () { + $this->loginAsAdmin(); + assertCanBanUsers(); +}); + +test('moderators can ban a user', function () { + $this->loginAsModerator(); + assertCanBanUsers(); +}); + +test('admins can unban a user', function () { + $this->loginAsAdmin(); + assertCanUnbanUsers(); +}); + +test('moderators can unban a user', function () { + $this->loginAsModerator(); + assertCanUnbanUsers(); +}); + +test('admins cannot ban other admins', function () { + $this->loginAsAdmin(); + assertCannotBanAdmins(); +}); + +test('moderators cannot ban admins', function () { + $this->loginAsModerator(); + assertCannotBanAdmins(); +}); + +test('moderators cannot ban other moderators', function () { + $this->loginAsModerator(); + assertCannotBanModerators(); +}); + +test('admins can delete a user', function () { + $user = User::factory()->create(['name' => 'Freek Murze']); + $thread = Thread::factory()->create(['author_id' => $user->id()]); + Reply::factory()->create(['replyable_id' => $thread->id()]); + Reply::factory()->create(['author_id' => $user->id()]); + + $this->loginAsAdmin(); + + $this->delete('/admin/users/'.$user->username()) + ->assertRedirectedTo('/admin'); + + $this->notSeeInDatabase('users', ['name' => 'Freek Murze']); + + // Make sure associated content is deleted. + $this->notSeeInDatabase('threads', ['author_id' => $user->id()]); + $this->notSeeInDatabase('replies', ['replyable_id' => $thread->id()]); + $this->notSeeInDatabase('replies', ['author_id' => $user->id()]); +}); + +test('admins cannot delete other admins', function () { + $user = User::factory()->create(['type' => User::ADMIN]); + + $this->loginAsAdmin(); + + $this->delete('/admin/users/'.$user->username()) + ->assertForbidden(); +}); + +test('moderators cannot delete users', function () { + $user = User::factory()->create(); + + $this->loginAsModerator(); + + $this->delete('/admin/users/'.$user->username()) + ->assertForbidden(); +}); + +test('admins can list submitted articles', function () { + $submittedArticle = Article::factory()->create(['submitted_at' => now()]); + $draftArticle = Article::factory()->create(); + $liveArticle = Article::factory()->create(['submitted_at' => now(), 'approved_at' => now()]); - /** @test */ - public function moderators_can_list_submitted_articles() - { - $submittedArticle = Article::factory()->create(['submitted_at' => now()]); - $draftArticle = Article::factory()->create(); - $liveArticle = Article::factory()->create(['submitted_at' => now(), 'approved_at' => now()]); + $this->loginAsAdmin(); - $this->loginAsModerator(); + $this->get('admin/articles') + ->see($submittedArticle->title()) + ->dontSee($draftArticle->title()) + ->dontSee($liveArticle->title()); +}); - $this->get('admin/articles') - ->see($submittedArticle->title()) - ->dontSee($draftArticle->title()) - ->dontSee($liveArticle->title()); - } +test('moderators can list submitted articles', function () { + $submittedArticle = Article::factory()->create(['submitted_at' => now()]); + $draftArticle = Article::factory()->create(); + $liveArticle = Article::factory()->create(['submitted_at' => now(), 'approved_at' => now()]); - /** @test */ - public function users_cannot_list_submitted_articles() - { - $this->login(); + $this->loginAsModerator(); - $this->get('admin/articles') - ->assertForbidden(); - } + $this->get('admin/articles') + ->see($submittedArticle->title()) + ->dontSee($draftArticle->title()) + ->dontSee($liveArticle->title()); +}); - /** @test */ - public function guests_cannot_list_submitted_articles() - { - $this->get('admin/articles') - ->assertRedirectedTo('login'); - } +test('users cannot list submitted articles', function () { + $this->login(); - /** @test */ - public function admins_can_view_submitted_articles() - { - $article = Article::factory()->create(['submitted_at' => now()]); + $this->get('admin/articles') + ->assertForbidden(); +}); - $this->loginAsAdmin(); +test('guests cannot list submitted articles', function () { + $this->get('admin/articles') + ->assertRedirectedTo('login'); +}); - $this->get("articles/{$article->slug()}") - ->see('Awaiting Approval'); - } +test('admins can view submitted articles', function () { + $article = Article::factory()->create(['submitted_at' => now()]); - /** @test */ - public function admins_can_approve_articles() - { - $article = Article::factory()->create(['submitted_at' => now()]); + $this->loginAsAdmin(); - $this->loginAsAdmin(); + $this->get("articles/{$article->slug()}") + ->see('Awaiting Approval'); +}); - $this->put("/admin/articles/{$article->slug()}/approve"); +test('admins can approve articles', function () { + $article = Article::factory()->create(['submitted_at' => now()]); - $this->assertNotNull($article->fresh()->approvedAt()); - } + $this->loginAsAdmin(); - /** @test */ - public function moderators_can_approve_articles() - { - $article = Article::factory()->create(['submitted_at' => now()]); + $this->put("/admin/articles/{$article->slug()}/approve"); - $this->loginAsModerator(); + $this->assertNotNull($article->fresh()->approvedAt()); +}); - $this->put("/admin/articles/{$article->slug()}/approve"); +test('moderators can approve articles', function () { + $article = Article::factory()->create(['submitted_at' => now()]); - $this->assertNotNull($article->fresh()->approvedAt()); - } + $this->loginAsModerator(); - /** @test */ - public function users_cannot_approve_articles() - { - $article = Article::factory()->create(['submitted_at' => now()]); + $this->put("/admin/articles/{$article->slug()}/approve"); - $this->login(); + $this->assertNotNull($article->fresh()->approvedAt()); +}); - $this->put("/admin/articles/{$article->slug()}/approve") - ->assertForbidden(); - } +test('users cannot approve articles', function () { + $article = Article::factory()->create(['submitted_at' => now()]); - /** @test */ - public function guests_cannot_approve_articles() - { - $article = Article::factory()->create(['submitted_at' => now()]); + $this->login(); - $this->put("/admin/articles/{$article->slug()}/approve") - ->assertRedirectedTo('/login'); + $this->put("/admin/articles/{$article->slug()}/approve") + ->assertForbidden(); +}); - $this->assertNull($article->fresh()->approvedAt()); - } +test('guests cannot approve articles', function () { + $article = Article::factory()->create(['submitted_at' => now()]); - /** @test */ - public function admins_can_disapprove_articles() - { - $article = Article::factory()->create(['submitted_at' => now(), 'approved_at' => now()]); + $this->put("/admin/articles/{$article->slug()}/approve") + ->assertRedirectedTo('/login'); - $this->loginAsAdmin(); + $this->assertNull($article->fresh()->approvedAt()); +}); - $this->put("/admin/articles/{$article->slug()}/disapprove"); +test('admins can disapprove articles', function () { + $article = Article::factory()->create(['submitted_at' => now(), 'approved_at' => now()]); - $this->assertNull($article->fresh()->approvedAt()); - } + $this->loginAsAdmin(); - /** @test */ - public function moderators_can_disapprove_articles() - { - $article = Article::factory()->create(['submitted_at' => now(), 'approved_at' => now()]); + $this->put("/admin/articles/{$article->slug()}/disapprove"); - $this->loginAsModerator(); + $this->assertNull($article->fresh()->approvedAt()); +}); - $this->put("/admin/articles/{$article->slug()}/disapprove"); +test('moderators can disapprove articles', function () { + $article = Article::factory()->create(['submitted_at' => now(), 'approved_at' => now()]); - $this->assertNull($article->fresh()->approvedAt()); - } + $this->loginAsModerator(); - /** @test */ - public function users_cannot_disapprove_articles() - { - $article = Article::factory()->create(['submitted_at' => now(), 'approved_at' => now()]); + $this->put("/admin/articles/{$article->slug()}/disapprove"); - $this->login(); + $this->assertNull($article->fresh()->approvedAt()); +}); - $this->put("/admin/articles/{$article->slug()}/disapprove") - ->assertForbidden(); - } +test('users cannot disapprove articles', function () { + $article = Article::factory()->create(['submitted_at' => now(), 'approved_at' => now()]); - /** @test */ - public function guests_cannot_disapprove_articles() - { - $article = Article::factory()->create(['submitted_at' => now(), 'approved_at' => now()]); + $this->login(); - $this->put("/admin/articles/{$article->slug()}/disapprove") - ->assertRedirectedTo('/login'); + $this->put("/admin/articles/{$article->slug()}/disapprove") + ->assertForbidden(); +}); - $this->assertNotNull($article->fresh()->approvedAt()); - } +test('guests cannot disapprove articles', function () { + $article = Article::factory()->create(['submitted_at' => now(), 'approved_at' => now()]); - /** @test */ - public function admins_can_pin_articles() - { - $article = Article::factory()->create(['submitted_at' => now(), 'approved_at' => now()]); + $this->put("/admin/articles/{$article->slug()}/disapprove") + ->assertRedirectedTo('/login'); - $this->loginAsAdmin(); + $this->assertNotNull($article->fresh()->approvedAt()); +}); - $this->put("/admin/articles/{$article->slug()}/pinned"); +test('admins can pin articles', function () { + $article = Article::factory()->create(['submitted_at' => now(), 'approved_at' => now()]); - $this->assertTrue($article->fresh()->isPinned()); - } + $this->loginAsAdmin(); - /** @test */ - public function moderators_can_pin_articles() - { - $article = Article::factory()->create(['submitted_at' => now(), 'approved_at' => now()]); + $this->put("/admin/articles/{$article->slug()}/pinned"); - $this->loginAsModerator(); + $this->assertTrue($article->fresh()->isPinned()); +}); - $this->put("/admin/articles/{$article->slug()}/pinned"); +test('moderators can pin articles', function () { + $article = Article::factory()->create(['submitted_at' => now(), 'approved_at' => now()]); - $this->assertTrue($article->fresh()->isPinned()); - } + $this->loginAsModerator(); - /** @test */ - public function users_cannot_pin_articles() - { - $article = Article::factory()->create(['submitted_at' => now(), 'approved_at' => now()]); + $this->put("/admin/articles/{$article->slug()}/pinned"); - $this->login(); + $this->assertTrue($article->fresh()->isPinned()); +}); - $this->put("/admin/articles/{$article->slug()}/pinned"); +test('users cannot pin articles', function () { + $article = Article::factory()->create(['submitted_at' => now(), 'approved_at' => now()]); - $this->assertFalse($article->fresh()->isPinned()); - } + $this->login(); - /** @test */ - public function guests_cannot_pin_articles() - { - $article = Article::factory()->create(['submitted_at' => now(), 'approved_at' => now()]); + $this->put("/admin/articles/{$article->slug()}/pinned"); - $this->put("/admin/articles/{$article->slug()}/pinned"); + $this->assertFalse($article->fresh()->isPinned()); +}); - $this->assertFalse($article->fresh()->isPinned()); - } +test('guests cannot pin articles', function () { + $article = Article::factory()->create(['submitted_at' => now(), 'approved_at' => now()]); - /** @test */ - public function admins_can_unpin_articles() - { - $article = Article::factory()->create([ - 'submitted_at' => now(), - 'approved_at' => now(), - 'is_pinned' => true, - ]); + $this->put("/admin/articles/{$article->slug()}/pinned"); - $this->loginAsAdmin(); + $this->assertFalse($article->fresh()->isPinned()); +}); - $this->put("/admin/articles/{$article->slug()}/pinned"); +test('admins can unpin articles', function () { + $article = Article::factory()->create([ + 'submitted_at' => now(), + 'approved_at' => now(), + 'is_pinned' => true, + ]); - $this->assertFalse($article->fresh()->isPinned()); - } + $this->loginAsAdmin(); - /** @test */ - public function moderators_can_unpin_articles() - { - $article = Article::factory()->create([ - 'submitted_at' => now(), - 'approved_at' => now(), - 'is_pinned' => true, - ]); + $this->put("/admin/articles/{$article->slug()}/pinned"); - $this->loginAsModerator(); + $this->assertFalse($article->fresh()->isPinned()); +}); - $this->put("/admin/articles/{$article->slug()}/pinned"); +test('moderators can unpin articles', function () { + $article = Article::factory()->create([ + 'submitted_at' => now(), + 'approved_at' => now(), + 'is_pinned' => true, + ]); - $this->assertFalse($article->fresh()->isPinned()); - } + $this->loginAsModerator(); - /** @test */ - public function users_cannot_unpin_articles() - { - $article = Article::factory()->create([ - 'submitted_at' => now(), - 'approved_at' => now(), - 'is_pinned' => true, - ]); + $this->put("/admin/articles/{$article->slug()}/pinned"); - $this->login(); + $this->assertFalse($article->fresh()->isPinned()); +}); - $this->put("/admin/articles/{$article->slug()}/pinned"); +test('users cannot unpin articles', function () { + $article = Article::factory()->create([ + 'submitted_at' => now(), + 'approved_at' => now(), + 'is_pinned' => true, + ]); - $this->assertTrue($article->fresh()->isPinned()); - } + $this->login(); - /** @test */ - public function guests_cannot_unpin_articles() - { - $article = Article::factory()->create([ - 'submitted_at' => now(), - 'approved_at' => now(), - 'is_pinned' => true, - ]); + $this->put("/admin/articles/{$article->slug()}/pinned"); - $this->put("/admin/articles/{$article->slug()}/pinned"); + $this->assertTrue($article->fresh()->isPinned()); +}); + +test('guests cannot unpin articles', function () { + $article = Article::factory()->create([ + 'submitted_at' => now(), + 'approved_at' => now(), + 'is_pinned' => true, + ]); + + $this->put("/admin/articles/{$article->slug()}/pinned"); + + $this->assertTrue($article->fresh()->isPinned()); +}); + +// Helpers +function assertCanSeeTheUserOverview() +{ + User::factory()->create(['name' => 'Freek Murze']); + User::factory()->create(['name' => 'Frederick Vanbrabant']); + + $this->visit('/admin') + ->see('Freek Murze') + ->see('Frederick Vanbrabant'); +} + +function assertCanBanUsers() +{ + $user = User::factory()->create(['name' => 'Freek Murze']); + + $this->put('/admin/users/'.$user->username().'/ban') + ->assertRedirectedTo('/user/'.$user->username()); + + $this->notSeeInDatabase('users', ['id' => $user->id(), 'banned_at' => null]); +} + +function assertCanUnbanUsers() +{ + $user = User::factory()->create(['name' => 'Freek Murze', 'banned_at' => Carbon::now()]); + + $this->put('/admin/users/'.$user->username().'/unban') + ->assertRedirectedTo('/user/'.$user->username()); + + $this->seeInDatabase('users', ['id' => $user->id(), 'banned_at' => null]); +} + +function assertCannotBanAdmins() +{ + assertCannotBanUsersByType(User::ADMIN); +} + +function assertCannotBanModerators() +{ + assertCannotBanUsersByType(User::MODERATOR); +} + +function assertCannotBanUsersByType(int $type) +{ + $user = User::factory()->create(['type' => $type]); - $this->assertTrue($article->fresh()->isPinned()); - } + $this->put('/admin/users/'.$user->username().'/ban') + ->assertForbidden(); } diff --git a/tests/Feature/ArticleTest.php b/tests/Feature/ArticleTest.php index 39f016c30..c62165928 100644 --- a/tests/Feature/ArticleTest.php +++ b/tests/Feature/ArticleTest.php @@ -1,7 +1,5 @@ visit('/articles/create') - ->seePageIs('/login'); - } - - /** @test */ - public function users_can_create_an_article() - { - $user = $this->createUser(); - $tag = Tag::factory()->create(['name' => 'Test Tag']); - - $this->loginAs($user); - - $this->post('/articles', [ - 'title' => 'Using database migrations', - 'body' => 'This article will go into depth on working with database migrations.', - 'tags' => [$tag->id()], - 'submitted' => '0', - ]) - ->assertRedirectedTo('/articles/using-database-migrations') - ->assertSessionHas('success', 'Article successfully created!'); - } - - /** @test */ - public function user_gets_submitted_message_when_submitting_new_article_for_approval() - { - $this->login(); - - $this->post('/articles', [ - 'title' => 'Using database migrations', - 'body' => 'This article will go into depth on working with database migrations.', - 'tags' => [], - 'submitted' => '1', - ]) - ->assertRedirectedTo('/articles/using-database-migrations') - ->assertSessionHas('success', 'Thank you for submitting, unfortunately we can\'t accept every submission. You\'ll only hear back from us when we accept your article.'); - } - - /** @test */ - public function users_can_submit_an_article_for_approval() - { - $this->login(); - - $this->post('/articles', [ - 'title' => 'Using database migrations', - 'body' => 'This article will go into depth on working with database migrations.', - 'submitted' => '1', - ]) - ->assertRedirectedTo('/articles/using-database-migrations') - ->followRedirects() - ->dontSee('Draft') - ->see('Awaiting approval'); - } - - /** @test */ - public function users_can_create_a_draft_article() - { - $this->login(); - - $this->post('/articles', [ - 'title' => 'Using database migrations', - 'body' => 'This article will go into depth on working with database migrations.', - 'submitted' => '0', - ]) - ->assertRedirectedTo('/articles/using-database-migrations') - ->followRedirects() - ->see('Draft'); - } - - /** @test */ - public function users_cannot_create_an_article_with_a_title_that_is_too_long() - { - $this->login(); - - $response = $this->post('/articles', [ - 'title' => 'Adding Notifications to make a really engaging UI for Laravel.io users using Livewire, Alpine.js and Tailwind UI', - 'body' => 'The title of this article is too long', - ]); - - $response->assertSessionHas('error', 'Something went wrong. Please review the fields below.'); - $response->assertSessionHasErrors(['title' => 'The title must not be greater than 100 characters.']); - } - - /** @test */ - public function an_article_may_not_contain_an_http_image_url() - { - $this->login(); - - $response = $this->post('/articles', [ - 'title' => 'My First Article', - 'body' => 'This is a really interesting article about images. Here is ![an image](http://example.com/image.jpg).', - ]); - - $response->assertSessionHas('error', 'Something went wrong. Please review the fields below.'); - $response->assertSessionHasErrors(['body' => 'The body field contains at least one image with an HTTP link.']); - } - - /** @test */ - public function guests_can_view_an_article() - { - $article = Article::factory()->create(['slug' => 'my-first-article', 'submitted_at' => now(), 'approved_at' => now()]); - - $this->get('/articles/my-first-article') - ->see($article->title()); - } - - /** @test */ - public function logged_in_users_can_view_an_article() - { - $article = Article::factory()->create(['slug' => 'my-first-article', 'submitted_at' => now(), 'approved_at' => now()]); - - $this->login(); - - $this->get('/articles/my-first-article') - ->see($article->title()); - } - - /** @test */ - public function users_can_edit_an_article() - { - $user = $this->createUser(); - $tag = Tag::factory()->create(['name' => 'Test Tag']); - - Article::factory()->create([ - 'author_id' => $user->id(), - 'slug' => 'my-first-article', - ]); - - $this->loginAs($user); - - $this->put('/articles/my-first-article', [ - 'title' => 'Using database migrations', - 'body' => 'This article will go into depth on working with database migrations.', - 'tags' => [$tag->id()], - 'submitted' => '0', - ]) - ->assertRedirectedTo('/articles/using-database-migrations') - ->assertSessionHas('success', 'Article successfully updated!'); - } - - /** @test */ - public function user_gets_submitted_message_when_submitting_existing_article_for_approval() - { - $user = $this->createUser(); - - Article::factory()->create([ - 'author_id' => $user->id(), - 'slug' => 'my-first-article', - ]); - - $this->loginAs($user); - - $this->put('/articles/my-first-article', [ - 'title' => 'Using database migrations', - 'body' => 'This article will go into depth on working with database migrations.', - 'tags' => [], - 'submitted' => '1', - ]) - ->assertRedirectedTo('/articles/using-database-migrations') - ->assertSessionHas('success', 'Thank you for submitting, unfortunately we can\'t accept every submission. You\'ll only hear back from us when we accept your article.'); - } - - /** @test */ - public function users_can_submit_an_existing_article_for_approval() - { - $user = $this->createUser(); - - Article::factory()->create([ - 'author_id' => $user->id(), - 'slug' => 'my-first-article', - 'submitted_at' => null, - ]); - - $this->loginAs($user); - - $this->put('/articles/my-first-article', [ - 'title' => 'Using database migrations', - 'body' => 'This article will go into depth on working with database migrations.', - 'submitted' => '1', - ]) - ->assertRedirectedTo('/articles/using-database-migrations') - ->followRedirects() - ->dontSee('Draft'); - } - - /** @test */ - public function users_cannot_edit_an_article_with_a_title_that_is_too_long() - { - $user = $this->createUser(); - Article::factory()->create([ - 'author_id' => $user->id(), - 'slug' => 'my-first-article', - ]); - - $this->loginAs($user); - - $response = $this->put('/articles/my-first-article', [ - 'title' => 'Adding Notifications to make a really engaging UI for Laravel.io users using Livewire, Alpine.js and Tailwind UI', - 'body' => 'The title of this article is too long', - ]); - - $response->assertSessionHas('error', 'Something went wrong. Please review the fields below.'); - $response->assertSessionHasErrors(['title' => 'The title must not be greater than 100 characters.']); - } - - /** @test */ - public function an_article_may_not_updated_to_contain_an_http_image_url() - { - $user = $this->createUser(); - Article::factory()->create([ - 'author_id' => $user->id(), - 'slug' => 'my-first-article', - ]); - - $this->loginAs($user); - - $response = $this->put('/articles/my-first-article', [ - 'title' => 'My first article', - 'body' => 'This is a really interesting article about images. Here is ![an image](http://example.com/image.jpg).', - ]); - - $response->assertSessionHas('error', 'Something went wrong. Please review the fields below.'); - $response->assertSessionHasErrors(['body' => 'The body field contains at least one image with an HTTP link.']); - } - - /** @test */ - public function an_already_submitted_article_should_not_have_timestamp_updated_on_update() - { - $user = $this->createUser(); - $article = Article::factory()->create([ - 'author_id' => $user->id(), - 'slug' => 'my-first-article', - 'submitted_at' => '2020-06-19 00:00:00', - ]); - - $this->loginAs($user); - - $this->put('/articles/my-first-article', [ - 'title' => 'My first article', - 'body' => 'Just updating the body of the article', - 'submitted' => true, - ]); - - $this->assertSame('2020-06-19 00:00:00', $article->fresh()->submittedAt()->format('Y-m-d H:i:s')); - } - - /** @test */ - public function users_can_delete_their_own_articles() - { - $user = $this->createUser(); - Article::factory()->create([ - 'author_id' => $user->id(), - 'slug' => 'my-first-article', - ]); - - $this->loginAs($user); - - $this->delete('/articles/my-first-article') - ->assertRedirectedTo('/articles') - ->assertSessionHas('success', 'Article successfully deleted!'); - } - - /** @test */ - public function users_cannot_delete_an_article_they_do_not_own() - { - Article::factory()->create(['slug' => 'my-first-article']); - - $this->login(); - - $this->delete('/articles/my-first-article') - ->assertForbidden(); - } - - /** @test */ - public function canonical_urls_are_rendered() - { - Article::factory()->create(['slug' => 'my-first-article', 'submitted_at' => now(), 'approved_at' => now()]); - - $this->get('/articles/my-first-article') - ->see(''); - } - - /** @test */ - public function custom_canonical_urls_are_rendered() - { - Article::factory()->create([ - 'slug' => 'my-first-article', - 'original_url' => 'https://joedixon.co.uk/my-first-article', - 'submitted_at' => now(), - 'approved_at' => now(), - ]); - - $this->get('/articles/my-first-article') - ->see(''); - } - - /** @test */ - public function draft_articles_cannot_be_viewed_by_guests() - { - Article::factory()->create(['slug' => 'my-first-article', 'submitted_at' => null]); - - $this->get('/articles/my-first-article') - ->assertResponseStatus(404); - } - - /** @test */ - public function draft_articles_can_be_viewed_by_the_article_owner() - { - $user = $this->createUser(); - Article::factory()->create([ - 'author_id' => $user->id(), - 'slug' => 'my-first-article', - 'submitted_at' => null, - ]); - - $this->loginAs($user); - - $this->get('/articles/my-first-article') - ->assertResponseStatus(200) - ->see('Draft'); - } - - /** @test */ - public function draft_articles_cannot_be_viewed_by_logged_in_users() - { - Article::factory()->create([ - 'slug' => 'my-first-article', - 'submitted_at' => null, - ]); - - $this->login(); - - $this->get('/articles/my-first-article') - ->assertResponseStatus(404); - } - - /** @test */ - public function sort_parameters_are_set_correctly() - { - Livewire::test(ShowArticles::class) - ->assertSet('sortBy', 'recent') - ->call('sortBy', 'popular') - ->assertSet('sortBy', 'popular') - ->call('sortBy', 'trending') - ->assertSet('sortBy', 'trending') - ->call('sortBy', 'recent') - ->assertSet('sortBy', 'recent'); - } - - /** @test */ - public function tags_can_be_toggled() - { - $tag = Tag::factory()->create(); - - Livewire::test(ShowArticles::class) - ->call('toggleTag', $tag->slug) - ->assertSet('tag', $tag->slug) - ->call('toggleTag', $tag->slug) - ->assertSet('tag', null); - } - - /** @test */ - public function invalid_sort_parameter_defaults_to_recent() - { - Livewire::test(ShowArticles::class) - ->call('sortBy', 'something-invalid') - ->assertSet('sortBy', 'recent'); - } - - /** @test */ - public function a_user_can_view_their_articles() - { - $user = $this->createUser(); - - $articles = Article::factory()->count(3)->create([ - 'author_id' => $user->id, - ]); - - $this->loginAs($user); - - $this->visit('/articles/authored') - ->see($articles[0]->title()) - ->see($articles[1]->title()) - ->see($articles[2]->title()); - } - - /** @test */ - public function a_user_can_another_users_articles() - { - $articles = Article::factory()->count(3)->create(); - - $this->login(); - - $this->visit('/articles/authored') - ->dontSee($articles[0]->title()) - ->dontSee($articles[1]->title()) - ->dontSee($articles[2]->title()); - } - - /** @test */ - public function a_guest_cannot_see_articles() - { - $this->visit('/articles/authored') - ->seePageIs('/login'); - } - - /** @test */ - public function users_get_a_mail_notification_when_their_article_is_approved() - { - Notification::fake(); - - $user = $this->createUser([ - 'name' => 'Joe Dixon', - 'username' => 'joedixon', - 'email' => 'hello@joedixon.co.uk', - ]); - $article = Article::factory()->create([ - 'slug' => 'my-first-article', - 'submitted_at' => now(), - 'author_id' => $user->id, - ]); - - $this->loginAsAdmin(); - $this->put("/admin/articles/{$article->slug()}/approve"); - - Notification::assertSentTo($user, ArticleApprovedNotification::class); - } - - /** @test */ - public function tags_are_not_rendered_for_unpublished_articles() - { - $tag = Tag::factory()->create(['name' => 'Test Tag']); - $article = Article::factory()->create([ - 'slug' => 'my-first-article', - 'submitted_at' => now(), - ]); - $article->syncTags([$tag->id]); - - $this->get('/articles') - ->dontSee('Test Tag'); - } - - /** @test */ - public function share_image_url_is_rendered_correctly() - { - Article::factory()->create([ - 'slug' => 'my-first-article', - 'submitted_at' => now(), - 'approved_at' => now(), - ]); - - $this->get('/articles/my-first-article') - ->see('articles/my-first-article/social.png') - ->dontSee('images/laravelio-share.png'); - } - - /** @test */ - public function default_share_image_is_used_on_non_article_pages() - { - $this->get('/') - ->see('images/laravelio-share.png') - ->dontSee('articles/my-first-article/social.png'); - } - - /** @test */ - public function user_see_a_tip_if_they_have_not_set_the_twitter_handle() - { - $this->login(['twitter' => null]); - - $this->get('/articles/authored') - ->seeLink('Twitter handle') - ->see('so we can link to your profile when we tweet out your article.'); - } - - /** @test */ - public function user_do_not_see_tip_if_they_have_set_the_twitter_handle() - { - $this->login(); - - $this->get('/articles/authored') - ->dontSeeLink('Twitter handle') - ->dontSee('so we can link to your profile when we tweet out your article.'); - } -} +uses(BrowserKitTestCase::class); +uses(DatabaseMigrations::class); + +test('users cannot create an article when not logged in', function () { + $this->visit('/articles/create') + ->seePageIs('/login'); +}); + +test('users can create an article', function () { + $user = $this->createUser(); + $tag = Tag::factory()->create(['name' => 'Test Tag']); + + $this->loginAs($user); + + $this->post('/articles', [ + 'title' => 'Using database migrations', + 'body' => 'This article will go into depth on working with database migrations.', + 'tags' => [$tag->id()], + 'submitted' => '0', + ]) + ->assertRedirectedTo('/articles/using-database-migrations') + ->assertSessionHas('success', 'Article successfully created!'); +}); + +test('user gets submitted message when submitting new article for approval', function () { + $this->login(); + + $this->post('/articles', [ + 'title' => 'Using database migrations', + 'body' => 'This article will go into depth on working with database migrations.', + 'tags' => [], + 'submitted' => '1', + ]) + ->assertRedirectedTo('/articles/using-database-migrations') + ->assertSessionHas('success', 'Thank you for submitting, unfortunately we can\'t accept every submission. You\'ll only hear back from us when we accept your article.'); +}); + +test('users can submit an article for approval', function () { + $this->login(); + + $this->post('/articles', [ + 'title' => 'Using database migrations', + 'body' => 'This article will go into depth on working with database migrations.', + 'submitted' => '1', + ]) + ->assertRedirectedTo('/articles/using-database-migrations') + ->followRedirects() + ->dontSee('Draft') + ->see('Awaiting approval'); +}); + +test('users can create a draft article', function () { + $this->login(); + + $this->post('/articles', [ + 'title' => 'Using database migrations', + 'body' => 'This article will go into depth on working with database migrations.', + 'submitted' => '0', + ]) + ->assertRedirectedTo('/articles/using-database-migrations') + ->followRedirects() + ->see('Draft'); +}); + +test('users cannot create an article with a title that is too long', function () { + $this->login(); + + $response = $this->post('/articles', [ + 'title' => 'Adding Notifications to make a really engaging UI for Laravel.io users using Livewire, Alpine.js and Tailwind UI', + 'body' => 'The title of this article is too long', + ]); + + $response->assertSessionHas('error', 'Something went wrong. Please review the fields below.'); + $response->assertSessionHasErrors(['title' => 'The title must not be greater than 100 characters.']); +}); + +test('an article may not contain an http image url', function () { + $this->login(); + + $response = $this->post('/articles', [ + 'title' => 'My First Article', + 'body' => 'This is a really interesting article about images. Here is ![an image](http://example.com/image.jpg).', + ]); + + $response->assertSessionHas('error', 'Something went wrong. Please review the fields below.'); + $response->assertSessionHasErrors(['body' => 'The body field contains at least one image with an HTTP link.']); +}); + +test('guests can view an article', function () { + $article = Article::factory()->create(['slug' => 'my-first-article', 'submitted_at' => now(), 'approved_at' => now()]); + + $this->get('/articles/my-first-article') + ->see($article->title()); +}); + +test('logged in users can view an article', function () { + $article = Article::factory()->create(['slug' => 'my-first-article', 'submitted_at' => now(), 'approved_at' => now()]); + + $this->login(); + + $this->get('/articles/my-first-article') + ->see($article->title()); +}); + +test('users can edit an article', function () { + $user = $this->createUser(); + $tag = Tag::factory()->create(['name' => 'Test Tag']); + + Article::factory()->create([ + 'author_id' => $user->id(), + 'slug' => 'my-first-article', + ]); + + $this->loginAs($user); + + $this->put('/articles/my-first-article', [ + 'title' => 'Using database migrations', + 'body' => 'This article will go into depth on working with database migrations.', + 'tags' => [$tag->id()], + 'submitted' => '0', + ]) + ->assertRedirectedTo('/articles/using-database-migrations') + ->assertSessionHas('success', 'Article successfully updated!'); +}); + +test('user gets submitted message when submitting existing article for approval', function () { + $user = $this->createUser(); + + Article::factory()->create([ + 'author_id' => $user->id(), + 'slug' => 'my-first-article', + ]); + + $this->loginAs($user); + + $this->put('/articles/my-first-article', [ + 'title' => 'Using database migrations', + 'body' => 'This article will go into depth on working with database migrations.', + 'tags' => [], + 'submitted' => '1', + ]) + ->assertRedirectedTo('/articles/using-database-migrations') + ->assertSessionHas('success', 'Thank you for submitting, unfortunately we can\'t accept every submission. You\'ll only hear back from us when we accept your article.'); +}); + +test('users can submit an existing article for approval', function () { + $user = $this->createUser(); + + Article::factory()->create([ + 'author_id' => $user->id(), + 'slug' => 'my-first-article', + 'submitted_at' => null, + ]); + + $this->loginAs($user); + + $this->put('/articles/my-first-article', [ + 'title' => 'Using database migrations', + 'body' => 'This article will go into depth on working with database migrations.', + 'submitted' => '1', + ]) + ->assertRedirectedTo('/articles/using-database-migrations') + ->followRedirects() + ->dontSee('Draft'); +}); + +test('users cannot edit an article with a title that is too long', function () { + $user = $this->createUser(); + Article::factory()->create([ + 'author_id' => $user->id(), + 'slug' => 'my-first-article', + ]); + + $this->loginAs($user); + + $response = $this->put('/articles/my-first-article', [ + 'title' => 'Adding Notifications to make a really engaging UI for Laravel.io users using Livewire, Alpine.js and Tailwind UI', + 'body' => 'The title of this article is too long', + ]); + + $response->assertSessionHas('error', 'Something went wrong. Please review the fields below.'); + $response->assertSessionHasErrors(['title' => 'The title must not be greater than 100 characters.']); +}); + +test('an article may not updated to contain an http image url', function () { + $user = $this->createUser(); + Article::factory()->create([ + 'author_id' => $user->id(), + 'slug' => 'my-first-article', + ]); + + $this->loginAs($user); + + $response = $this->put('/articles/my-first-article', [ + 'title' => 'My first article', + 'body' => 'This is a really interesting article about images. Here is ![an image](http://example.com/image.jpg).', + ]); + + $response->assertSessionHas('error', 'Something went wrong. Please review the fields below.'); + $response->assertSessionHasErrors(['body' => 'The body field contains at least one image with an HTTP link.']); +}); + +test('an already submitted article should not have timestamp updated on update', function () { + $user = $this->createUser(); + $article = Article::factory()->create([ + 'author_id' => $user->id(), + 'slug' => 'my-first-article', + 'submitted_at' => '2020-06-19 00:00:00', + ]); + + $this->loginAs($user); + + $this->put('/articles/my-first-article', [ + 'title' => 'My first article', + 'body' => 'Just updating the body of the article', + 'submitted' => true, + ]); + + $this->assertSame('2020-06-19 00:00:00', $article->fresh()->submittedAt()->format('Y-m-d H:i:s')); +}); + +test('users can delete their own articles', function () { + $user = $this->createUser(); + Article::factory()->create([ + 'author_id' => $user->id(), + 'slug' => 'my-first-article', + ]); + + $this->loginAs($user); + + $this->delete('/articles/my-first-article') + ->assertRedirectedTo('/articles') + ->assertSessionHas('success', 'Article successfully deleted!'); +}); + +test('users cannot delete an article they do not own', function () { + Article::factory()->create(['slug' => 'my-first-article']); + + $this->login(); + + $this->delete('/articles/my-first-article') + ->assertForbidden(); +}); + +test('canonical urls are rendered', function () { + Article::factory()->create(['slug' => 'my-first-article', 'submitted_at' => now(), 'approved_at' => now()]); + + $this->get('/articles/my-first-article') + ->see(''); +}); + +test('custom canonical urls are rendered', function () { + Article::factory()->create([ + 'slug' => 'my-first-article', + 'original_url' => 'https://joedixon.co.uk/my-first-article', + 'submitted_at' => now(), + 'approved_at' => now(), + ]); + + $this->get('/articles/my-first-article') + ->see(''); +}); + +test('draft articles cannot be viewed by guests', function () { + Article::factory()->create(['slug' => 'my-first-article', 'submitted_at' => null]); + + $this->get('/articles/my-first-article') + ->assertResponseStatus(404); +}); + +test('draft articles can be viewed by the article owner', function () { + $user = $this->createUser(); + Article::factory()->create([ + 'author_id' => $user->id(), + 'slug' => 'my-first-article', + 'submitted_at' => null, + ]); + + $this->loginAs($user); + + $this->get('/articles/my-first-article') + ->assertResponseStatus(200) + ->see('Draft'); +}); + +test('draft articles cannot be viewed by logged in users', function () { + Article::factory()->create([ + 'slug' => 'my-first-article', + 'submitted_at' => null, + ]); + + $this->login(); + + $this->get('/articles/my-first-article') + ->assertResponseStatus(404); +}); + +test('sort parameters are set correctly', function () { + Livewire::test(ShowArticles::class) + ->assertSet('sortBy', 'recent') + ->call('sortBy', 'popular') + ->assertSet('sortBy', 'popular') + ->call('sortBy', 'trending') + ->assertSet('sortBy', 'trending') + ->call('sortBy', 'recent') + ->assertSet('sortBy', 'recent'); +}); + +test('tags can be toggled', function () { + $tag = Tag::factory()->create(); + + Livewire::test(ShowArticles::class) + ->call('toggleTag', $tag->slug) + ->assertSet('tag', $tag->slug) + ->call('toggleTag', $tag->slug) + ->assertSet('tag', null); +}); + +test('invalid sort parameter defaults to recent', function () { + Livewire::test(ShowArticles::class) + ->call('sortBy', 'something-invalid') + ->assertSet('sortBy', 'recent'); +}); + +test('a user can view their articles', function () { + $user = $this->createUser(); + + $articles = Article::factory()->count(3)->create([ + 'author_id' => $user->id, + ]); + + $this->loginAs($user); + + $this->visit('/articles/authored') + ->see($articles[0]->title()) + ->see($articles[1]->title()) + ->see($articles[2]->title()); +}); + +test('a user can another users articles', function () { + $articles = Article::factory()->count(3)->create(); + + $this->login(); + + $this->visit('/articles/authored') + ->dontSee($articles[0]->title()) + ->dontSee($articles[1]->title()) + ->dontSee($articles[2]->title()); +}); + +test('a guest cannot see articles', function () { + $this->visit('/articles/authored') + ->seePageIs('/login'); +}); + +test('users get a mail notification when their article is approved', function () { + Notification::fake(); + + $user = $this->createUser([ + 'name' => 'Joe Dixon', + 'username' => 'joedixon', + 'email' => 'hello@joedixon.co.uk', + ]); + $article = Article::factory()->create([ + 'slug' => 'my-first-article', + 'submitted_at' => now(), + 'author_id' => $user->id, + ]); + + $this->loginAsAdmin(); + $this->put("/admin/articles/{$article->slug()}/approve"); + + Notification::assertSentTo($user, ArticleApprovedNotification::class); +}); + +test('tags are not rendered for unpublished articles', function () { + $tag = Tag::factory()->create(['name' => 'Test Tag']); + $article = Article::factory()->create([ + 'slug' => 'my-first-article', + 'submitted_at' => now(), + ]); + $article->syncTags([$tag->id]); + + $this->get('/articles') + ->dontSee('Test Tag'); +}); + +test('share image url is rendered correctly', function () { + Article::factory()->create([ + 'slug' => 'my-first-article', + 'submitted_at' => now(), + 'approved_at' => now(), + ]); + + $this->get('/articles/my-first-article') + ->see('articles/my-first-article/social.png') + ->dontSee('images/laravelio-share.png'); +}); + +test('default share image is used on non article pages', function () { + $this->get('/') + ->see('images/laravelio-share.png') + ->dontSee('articles/my-first-article/social.png'); +}); + +test('user see a tip if they have not set the twitter handle', function () { + $this->login(['twitter' => null]); + + $this->get('/articles/authored') + ->seeLink('Twitter handle') + ->see('so we can link to your profile when we tweet out your article.'); +}); + +test('user do not see tip if they have set the twitter handle', function () { + $this->login(); + + $this->get('/articles/authored') + ->dontSeeLink('Twitter handle') + ->dontSee('so we can link to your profile when we tweet out your article.'); +}); diff --git a/tests/Feature/AuthTest.php b/tests/Feature/AuthTest.php index 3a6eae608..e1169b12c 100644 --- a/tests/Feature/AuthTest.php +++ b/tests/Feature/AuthTest.php @@ -1,7 +1,5 @@ ['id' => 123, 'username' => 'johndoe']]); + + $this->visit('/register') + ->type('John Doe', 'name') + ->type('john.doe@example.com', 'email') + ->type('johndoe', 'username') + ->type('123', 'github_id') + ->type('johndoe', 'github_username') + ->check('rules') + ->check('terms') + ->press('Register') + ->seePageIs('/dashboard') + ->see('John Doe'); + + assertLoggedIn(); + + Event::assertDispatched(Registered::class); +}); + +test('registration fails when a required field is not filled in', function () { + session(['githubData' => ['id' => 123]]); + + $this->visit('/register') + ->press('Register') + ->seePageIs('/register') + ->see('The name field is required.') + ->see('The email field is required.') + ->see('The username field is required.') + ->see('The rules must be accepted.'); +}); + +test('registration fails with non alpha dash username', function () { + session(['githubData' => ['id' => 123, 'username' => 'johndoe']]); + + $this->visit('/register') + ->type('John Doe', 'name') + ->type('john.doe@example.com', 'email') + ->type('john foo', 'username') + ->type('123', 'github_id') + ->type('johndoe', 'github_username') + ->check('rules') + ->check('terms') + ->press('Register') + ->seePageIs('/register') + ->see('The username must only contain letters, numbers, dashes and underscores.'); +}); + +test('users can resend the email verification', function () { + $this->login(['email_verified_at' => null]); + + $this->post('/email/resend') + ->assertSessionHas('success', 'Email verification sent to john@example.com. You can change your email address in your profile settings.'); +}); + +test('users do not need to verify their email address twice', function () { + $this->login(); + + $this->post('/email/resend') + ->assertRedirectedTo('/dashboard') + ->assertSessionHas('error', 'Your email address is already verified.'); +}); + +test('users can login', function () { + $this->createUser(); + + $this->visit('/login') + ->type('johndoe', 'username') + ->type('password', 'password') + ->press('Login') + ->seePageIs('/dashboard') + ->see('John Doe'); +}); + +test('login fails when a required field is not filled in', function () { + $this->createUser(); + + $this->visit('/login') + ->press('Login') + ->seePageIs('/login') + ->see('The username field is required.') + ->see('The password field is required.'); +}); + +test('login fails when password is incorrect', function () { + $this->createUser(); + + $this->visit('/login') + ->type('johndoe', 'username') + ->type('invalidpass', 'password') + ->press('Login') + ->seePageIs('/login') + ->see('These credentials do not match our records.'); +}); + +test('login fails when user is banned', function () { + $this->createUser(['banned_at' => Carbon::now()]); + + $this->visit('/login') + ->type('johndoe', 'username') + ->type('password', 'password') + ->press('Login') + ->seePageIs('/') + ->see('This account is banned.'); +}); + +test('users can logout', function () { + $this->login(); + + assertLoggedIn(); + + $this->visit('/logout') + ->seePageIs('/'); + + assertLoggedOut(); +}); + +test('users can request a password reset link', function () { + $this->createUser(); + + $this->visit('/password/reset') + ->type('john@example.com', 'email') + ->press('Send Password Reset Link') + ->see('We have emailed your password reset link!'); +}); + +test('users can reset their password', function () { + $user = $this->createUser(); + + // Insert a password reset token into the database. + $token = $this->app[PasswordBroker::class]->getRepository()->create($user); + + $this->visit('/password/reset/'.$token) + ->type('john@example.com', 'email') + ->type('QFq^$cz#P@MZa5z7', 'password') + ->type('QFq^$cz#P@MZa5z7', 'password_confirmation') + ->press('Reset Password') + ->seePageIs('/dashboard') + ->visit('/logout') + ->visit('/login') + ->type('johndoe', 'username') + ->type('QFq^$cz#P@MZa5z7', 'password') + ->press('Login') + ->seePageIs('/dashboard'); +}); + +test('users cannot reset their password when it has been compromised in data leaks', function () { + $user = $this->createUser(); + + // Insert a password reset token into the database. + $token = $this->app[PasswordBroker::class]->getRepository()->create($user); + + $this->visit('/password/reset/'.$token) + ->type('john@example.com', 'email') + ->type('password', 'password') + ->type('password', 'password_confirmation') + ->press('Reset Password') + ->seePageIs('/password/reset/'.$token) + ->see('The given password has appeared in a data leak. Please choose a different password.'); +}); + +test('unverified users cannot create threads', function () { + $this->login(['email_verified_at' => null]); + + $this->visit('/forum/create-thread') + ->see('Before proceeding, please check your email for a verification link.'); +}); + +// Helpers +function assertLoggedIn(): void +{ + $this->assertTrue(Auth::check()); +} + +function assertLoggedOut(): void { - use DatabaseMigrations; - - /** @test */ - public function users_can_register() - { - Event::fake(); - - session(['githubData' => ['id' => 123, 'username' => 'johndoe']]); - - $this->visit('/register') - ->type('John Doe', 'name') - ->type('john.doe@example.com', 'email') - ->type('johndoe', 'username') - ->type('123', 'github_id') - ->type('johndoe', 'github_username') - ->check('rules') - ->check('terms') - ->press('Register') - ->seePageIs('/dashboard') - ->see('John Doe'); - - $this->assertLoggedIn(); - - Event::assertDispatched(Registered::class); - } - - /** @test */ - public function registration_fails_when_a_required_field_is_not_filled_in() - { - session(['githubData' => ['id' => 123]]); - - $this->visit('/register') - ->press('Register') - ->seePageIs('/register') - ->see('The name field is required.') - ->see('The email field is required.') - ->see('The username field is required.') - ->see('The rules must be accepted.'); - } - - /** @test */ - public function registration_fails_with_non_alpha_dash_username() - { - session(['githubData' => ['id' => 123, 'username' => 'johndoe']]); - - $this->visit('/register') - ->type('John Doe', 'name') - ->type('john.doe@example.com', 'email') - ->type('john foo', 'username') - ->type('123', 'github_id') - ->type('johndoe', 'github_username') - ->check('rules') - ->check('terms') - ->press('Register') - ->seePageIs('/register') - ->see('The username must only contain letters, numbers, dashes and underscores.'); - } - - /** @test */ - public function users_can_resend_the_email_verification() - { - $this->login(['email_verified_at' => null]); - - $this->post('/email/resend') - ->assertSessionHas('success', 'Email verification sent to john@example.com. You can change your email address in your profile settings.'); - } - - /** @test */ - public function users_do_not_need_to_verify_their_email_address_twice() - { - $this->login(); - - $this->post('/email/resend') - ->assertRedirectedTo('/dashboard') - ->assertSessionHas('error', 'Your email address is already verified.'); - } - - // /** @test */ - // public function users_can_verify_their_email_address() - // { - // $user = $this->login(['email_verified_at' => null]); - // - // $id = $user->getKey(); - // $hash = sha1('john@example.com'); - // - // $this->get("/email/verify/$id/$hash") - // ->see('Your email address was successfully verified.'); - // - // $this->assertTrue($user->refresh()->hasVerifiedEmail()); - // } - - // /** @test */ - // public function users_get_a_message_when_an_invalid_has_is_provided() - // { - // $this->createUser(['email_verified_at' => null]); - // - // $this->visit('/email/verify/john@example.com/incorrect') - // ->seePageIs('/') - // ->see('We could not verify your email address. The given email address and code did not match.'); - // } - - /** @test */ - public function users_can_login() - { - $this->createUser(); - - $this->visit('/login') - ->type('johndoe', 'username') - ->type('password', 'password') - ->press('Login') - ->seePageIs('/dashboard') - ->see('John Doe'); - } - - /** @test */ - public function login_fails_when_a_required_field_is_not_filled_in() - { - $this->createUser(); - - $this->visit('/login') - ->press('Login') - ->seePageIs('/login') - ->see('The username field is required.') - ->see('The password field is required.'); - } - - /** @test */ - public function login_fails_when_password_is_incorrect() - { - $this->createUser(); - - $this->visit('/login') - ->type('johndoe', 'username') - ->type('invalidpass', 'password') - ->press('Login') - ->seePageIs('/login') - ->see('These credentials do not match our records.'); - } - - /** @test */ - public function login_fails_when_user_is_banned() - { - $this->createUser(['banned_at' => Carbon::now()]); - - $this->visit('/login') - ->type('johndoe', 'username') - ->type('password', 'password') - ->press('Login') - ->seePageIs('/') - ->see('This account is banned.'); - } - - /** @test */ - public function users_can_logout() - { - $this->login(); - - $this->assertLoggedIn(); - - $this->visit('/logout') - ->seePageIs('/'); - - $this->assertLoggedOut(); - } - - /** @test */ - public function users_can_request_a_password_reset_link() - { - $this->createUser(); - - $this->visit('/password/reset') - ->type('john@example.com', 'email') - ->press('Send Password Reset Link') - ->see('We have emailed your password reset link!'); - } - - /** @test */ - public function users_can_reset_their_password() - { - $user = $this->createUser(); - - // Insert a password reset token into the database. - $token = $this->app[PasswordBroker::class]->getRepository()->create($user); - - $this->visit('/password/reset/'.$token) - ->type('john@example.com', 'email') - ->type('QFq^$cz#P@MZa5z7', 'password') - ->type('QFq^$cz#P@MZa5z7', 'password_confirmation') - ->press('Reset Password') - ->seePageIs('/dashboard') - ->visit('/logout') - ->visit('/login') - ->type('johndoe', 'username') - ->type('QFq^$cz#P@MZa5z7', 'password') - ->press('Login') - ->seePageIs('/dashboard'); - } - - /** @test */ - public function users_cannot_reset_their_password_when_it_has_been_compromised_in_data_leaks() - { - $user = $this->createUser(); - - // Insert a password reset token into the database. - $token = $this->app[PasswordBroker::class]->getRepository()->create($user); - - $this->visit('/password/reset/'.$token) - ->type('john@example.com', 'email') - ->type('password', 'password') - ->type('password', 'password_confirmation') - ->press('Reset Password') - ->seePageIs('/password/reset/'.$token) - ->see('The given password has appeared in a data leak. Please choose a different password.'); - } - - /** @test */ - public function unverified_users_cannot_create_threads() - { - $this->login(['email_verified_at' => null]); - - $this->visit('/forum/create-thread') - ->see('Before proceeding, please check your email for a verification link.'); - } - - private function assertLoggedIn(): void - { - $this->assertTrue(Auth::check()); - } - - private function assertLoggedOut(): void - { - $this->assertFalse(Auth::check()); - } + $this->assertFalse(Auth::check()); } diff --git a/tests/Feature/DashboardTest.php b/tests/Feature/DashboardTest.php index df539d565..bb3811e9e 100644 --- a/tests/Feature/DashboardTest.php +++ b/tests/Feature/DashboardTest.php @@ -1,7 +1,5 @@ visit('/dashboard') - ->seePageIs('/login'); - } - - /** @test */ - public function users_can_see_some_statistics() - { - $user = $this->createUser(); - $thread = Thread::factory()->count(3)->create(['author_id' => $user->id()])->first(); - $reply = Reply::factory()->count(2)->create([ - 'author_id' => $user->id(), - 'replyable_id' => $thread->id(), - ])->first(); - - $thread->markSolution($reply); - - $this->loginAs($user); - - $this->visit('/dashboard') - ->see('3 threads') - ->see('2 replies') - ->see('1 solution'); - } - - /** @test */ - public function users_can_see_notifications() - { - $userOne = $this->createUser(); - - $thread = Thread::factory()->create(['author_id' => $userOne->id()]); - $reply = Reply::factory()->create(['replyable_id' => $thread->id()]); - +uses(BrowserKitTestCase::class); +uses(DatabaseMigrations::class); + +test('requires login', function () { + $this->visit('/dashboard') + ->seePageIs('/login'); +}); + +test('users can see some statistics', function () { + $user = $this->createUser(); + $thread = Thread::factory()->count(3)->create(['author_id' => $user->id()])->first(); + $reply = Reply::factory()->count(2)->create([ + 'author_id' => $user->id(), + 'replyable_id' => $thread->id(), + ])->first(); + + $thread->markSolution($reply); + + $this->loginAs($user); + + $this->visit('/dashboard') + ->see('3 threads') + ->see('2 replies') + ->see('1 solution'); +}); + +test('users can see notifications', function () { + $userOne = $this->createUser(); + + $thread = Thread::factory()->create(['author_id' => $userOne->id()]); + $reply = Reply::factory()->create(['replyable_id' => $thread->id()]); + + $userOne->notifications()->create([ + 'id' => Str::random(), + 'type' => NewReplyNotification::class, + 'data' => [ + 'type' => 'new_reply', + 'reply' => $reply->id(), + 'replyable_id' => $reply->replyable_id, + 'replyable_type' => $reply->replyable_type, + 'replyable_subject' => $reply->replyAble()->replyAbleSubject(), + ], + ]); + + $replyAbleRoute = route('replyable', [$reply->replyable_id, $reply->replyable_type]); + + $this->loginAs($userOne); + + Livewire::test(Notifications::class) + ->assertSee(new HtmlString( + "A new reply was added to \"{$thread->subject()}\".", + )); +}); + +test('users can mark notifications as read', function () { + $userOne = $this->createUser(); + + $thread = Thread::factory()->create(['author_id' => $userOne->id()]); + $reply = Reply::factory()->create(['replyable_id' => $thread->id()]); + + $notification = $userOne->notifications()->create([ + 'id' => Str::random(), + 'type' => NewReplyNotification::class, + 'data' => [ + 'type' => 'new_reply', + 'reply' => $reply->id(), + 'replyable_id' => $reply->replyable_id, + 'replyable_type' => $reply->replyable_type, + 'replyable_subject' => $reply->replyAble()->replyAbleSubject(), + ], + ]); + + $replyAbleRoute = route('replyable', [$reply->replyable_id, $reply->replyable_type]); + + $this->loginAs($userOne); + + Livewire::test(Notifications::class) + ->assertSee(new HtmlString( + "A new reply was added to \"{$thread->subject()}\".", + )) + ->call('markAsRead', $notification->id) + ->assertDontSee(new HtmlString( + "A new reply was added to \"{$thread->subject()}\".", + )) + ->assertEmitted('NotificationMarkedAsRead'); +}); + +test('a non logged in user cannot access notifications', function () { + Livewire::test(Notifications::class) + ->assertForbidden(); +}); + +test('a user cannot mark other users notifications as read', function () { + $userOne = $this->createUser(); + $userTwo = $this->createUser([ + 'name' => 'Jane Doe', + 'username' => 'janedoe', + 'email' => 'jane@example.com', + ]); + + $thread = Thread::factory()->create(['author_id' => $userOne->id()]); + $reply = Reply::factory()->create([ + 'author_id' => $userTwo->id(), + 'replyable_id' => $thread->id(), + ]); + + $notification = $userOne->notifications()->create([ + 'id' => Str::random(), + 'type' => NewReplyNotification::class, + 'data' => [ + 'type' => 'new_reply', + 'reply' => $reply->id(), + 'replyable_id' => $reply->replyable_id, + 'replyable_type' => $reply->replyable_type, + 'replyable_subject' => $reply->replyAble()->replyAbleSubject(), + ], + ]); + + $this->loginAs($userTwo); + + Livewire::test(Notifications::class) + ->call('markAsRead', $notification->id) + ->assertForbidden(); +}); + +test('a user sees the correct number of notifications', function () { + $userOne = $this->createUser(); + $userTwo = $this->createUser([ + 'name' => 'Jane Doe', + 'username' => 'janedoe', + 'email' => 'jane@example.com', + ]); + + $thread = Thread::factory()->create(['author_id' => $userOne->id()]); + $reply = Reply::factory()->create([ + 'author_id' => $userTwo->id(), + 'replyable_id' => $thread->id(), + ]); + + for ($i = 0; $i < 10; $i++) { $userOne->notifications()->create([ 'id' => Str::random(), 'type' => NewReplyNotification::class, @@ -62,127 +161,10 @@ public function users_can_see_notifications() 'replyable_subject' => $reply->replyAble()->replyAbleSubject(), ], ]); - - $replyAbleRoute = route('replyable', [$reply->replyable_id, $reply->replyable_type]); - - $this->loginAs($userOne); - - Livewire::test(Notifications::class) - ->assertSee(new HtmlString( - "A new reply was added to \"{$thread->subject()}\".", - )); } - /** @test */ - public function users_can_mark_notifications_as_read() - { - $userOne = $this->createUser(); - - $thread = Thread::factory()->create(['author_id' => $userOne->id()]); - $reply = Reply::factory()->create(['replyable_id' => $thread->id()]); - - $notification = $userOne->notifications()->create([ - 'id' => Str::random(), - 'type' => NewReplyNotification::class, - 'data' => [ - 'type' => 'new_reply', - 'reply' => $reply->id(), - 'replyable_id' => $reply->replyable_id, - 'replyable_type' => $reply->replyable_type, - 'replyable_subject' => $reply->replyAble()->replyAbleSubject(), - ], - ]); - - $replyAbleRoute = route('replyable', [$reply->replyable_id, $reply->replyable_type]); - - $this->loginAs($userOne); + $this->loginAs($userOne); - Livewire::test(Notifications::class) - ->assertSee(new HtmlString( - "A new reply was added to \"{$thread->subject()}\".", - )) - ->call('markAsRead', $notification->id) - ->assertDontSee(new HtmlString( - "A new reply was added to \"{$thread->subject()}\".", - )) - ->assertEmitted('NotificationMarkedAsRead'); - } - - /** @test */ - public function a_non_logged_in_user_cannot_access_notifications() - { - Livewire::test(Notifications::class) - ->assertForbidden(); - } - - /** @test */ - public function a_user_cannot_mark_other_users_notifications_as_read() - { - $userOne = $this->createUser(); - $userTwo = $this->createUser([ - 'name' => 'Jane Doe', - 'username' => 'janedoe', - 'email' => 'jane@example.com', - ]); - - $thread = Thread::factory()->create(['author_id' => $userOne->id()]); - $reply = Reply::factory()->create([ - 'author_id' => $userTwo->id(), - 'replyable_id' => $thread->id(), - ]); - - $notification = $userOne->notifications()->create([ - 'id' => Str::random(), - 'type' => NewReplyNotification::class, - 'data' => [ - 'type' => 'new_reply', - 'reply' => $reply->id(), - 'replyable_id' => $reply->replyable_id, - 'replyable_type' => $reply->replyable_type, - 'replyable_subject' => $reply->replyAble()->replyAbleSubject(), - ], - ]); - - $this->loginAs($userTwo); - - Livewire::test(Notifications::class) - ->call('markAsRead', $notification->id) - ->assertForbidden(); - } - - /** @test */ - public function a_user_sees_the_correct_number_of_notifications() - { - $userOne = $this->createUser(); - $userTwo = $this->createUser([ - 'name' => 'Jane Doe', - 'username' => 'janedoe', - 'email' => 'jane@example.com', - ]); - - $thread = Thread::factory()->create(['author_id' => $userOne->id()]); - $reply = Reply::factory()->create([ - 'author_id' => $userTwo->id(), - 'replyable_id' => $thread->id(), - ]); - - for ($i = 0; $i < 10; $i++) { - $userOne->notifications()->create([ - 'id' => Str::random(), - 'type' => NewReplyNotification::class, - 'data' => [ - 'type' => 'new_reply', - 'reply' => $reply->id(), - 'replyable_id' => $reply->replyable_id, - 'replyable_type' => $reply->replyable_type, - 'replyable_subject' => $reply->replyAble()->replyAbleSubject(), - ], - ]); - } - - $this->loginAs($userOne); - - Livewire::test(NotificationCount::class) - ->assertSee('10'); - } -} + Livewire::test(NotificationCount::class) + ->assertSee('10'); +}); diff --git a/tests/Feature/ForumTest.php b/tests/Feature/ForumTest.php index 172c203e8..091288e62 100644 --- a/tests/Feature/ForumTest.php +++ b/tests/Feature/ForumTest.php @@ -1,7 +1,5 @@ create(['subject' => 'The first thread']); - Thread::factory()->create(['subject' => 'The second thread']); - - $this->visit('/forum') - ->see('The first thread') - ->see('The second thread'); - } - - /** @test */ - public function users_can_see_when_a_thread_is_resolved() - { - Thread::factory()->create(['subject' => 'The first thread']); - $thread = Thread::factory()->create(['subject' => 'The second thread']); - $reply = Reply::factory()->create(); - $thread->solutionReplyRelation()->associate($reply)->save(); - - $this->visit('/forum') - ->see('The first thread') - ->see('The second thread') - ->see('Resolved') - ->see(route('thread', $thread->slug()).'#'.$thread->solution_reply_id); - } - - /** @test */ - public function users_can_see_a_single_thread() - { - Thread::factory()->create([ - 'subject' => 'The first thread', - 'slug' => 'the-first-thread', - ]); - - $this->visit('/forum/the-first-thread') - ->see('The first thread'); - } - - /** @test */ - public function users_cannot_create_a_thread_when_not_logged_in() - { - $this->visit('/forum/create-thread') - ->seePageIs('/login'); - } - - /** @test */ - public function the_thread_subject_cannot_be_an_url() - { - $tag = Tag::factory()->create(['name' => 'Test Tag']); - - $this->login(); - - $this->post('/forum/create-thread', [ - 'subject' => 'http://example.com Foo title', - 'body' => 'This text explains how to work with Eloquent.', - 'tags' => [$tag->id()], - ]) - ->assertSessionHasErrors(['subject' => 'The subject field cannot contain an url.']); - } - - /** @test */ - public function users_can_create_a_thread() - { - $tag = Tag::factory()->create(['name' => 'Test Tag']); - - $this->login(); - - $this->post('/forum/create-thread', [ - 'subject' => 'How to work with Eloquent?', - 'body' => 'This text explains how to work with Eloquent.', - 'tags' => [$tag->id()], - ]) - ->assertRedirectedTo('/forum/how-to-work-with-eloquent') - ->assertSessionHas('success', 'Thread successfully created!'); - } - - /** @test */ - public function users_can_edit_a_thread() - { - $user = $this->createUser(); - $tag = Tag::factory()->create(['name' => 'Test Tag']); - Thread::factory()->create([ - 'author_id' => $user->id(), - 'slug' => 'my-first-thread', - ]); - - $this->loginAs($user); - - $this->put('/forum/my-first-thread', [ - 'subject' => 'How to work with Eloquent?', - 'body' => 'This text explains how to work with Eloquent.', - 'tags' => [$tag->id()], - ]) - ->assertRedirectedTo('/forum/how-to-work-with-eloquent') - ->assertSessionHas('success', 'Thread successfully updated!'); - } - - /** @test */ - public function users_cannot_edit_a_thread_they_do_not_own() - { - Thread::factory()->create(['slug' => 'my-first-thread']); - - $this->login(); - - $this->get('/forum/my-first-thread/edit') - ->assertForbidden(); - } - - /** @test */ - public function users_cannot_delete_a_thread_they_do_not_own() - { - Thread::factory()->create(['slug' => 'my-first-thread']); - - $this->login(); - - $this->delete('/forum/my-first-thread') - ->assertForbidden(); - } - - /** @test */ - public function users_cannot_create_a_thread_with_a_subject_that_is_too_long() - { - $tag = Tag::factory()->create(['name' => 'Test Tag']); - - $this->login(); - - $response = $this->post('/forum/create-thread', [ - 'subject' => 'How to make Eloquent, Doctrine, Entities and Annotations work together in Laravel?', - 'body' => 'This is a thread with 82 characters in the subject', - 'tags' => [$tag->id()], - ]); - - $response->assertSessionHas('error', 'Something went wrong. Please review the fields below.'); - $response->assertSessionHasErrors(['subject' => 'The subject must not be greater than 60 characters.']); - } - - /** @test */ - public function users_cannot_edit_a_thread_with_a_subject_that_is_too_long() - { - $user = $this->createUser(); - $tag = Tag::factory()->create(['name' => 'Test Tag']); - Thread::factory()->create([ - 'author_id' => $user->id(), - 'slug' => 'my-first-thread', - ]); - - $this->loginAs($user); - - $response = $this->put('/forum/my-first-thread', [ - 'subject' => 'How to make Eloquent, Doctrine, Entities and Annotations work together in Laravel?', - 'body' => 'This is a thread with 82 characters in the subject', - 'tags' => [$tag->id()], - ]); - - $response->assertSessionHas('error', 'Something went wrong. Please review the fields below.'); - $response->assertSessionHasErrors(['subject' => 'The subject must not be greater than 60 characters.']); - } - - /** @test */ - public function a_user_can_toggle_a_like_on_a_thread() - { - $this->login(); - - $thread = Thread::factory()->create(); - - Livewire::test(LikeThread::class, ['thread' => $thread]) - ->assertSee("0\n") - ->call('toggleLike') - ->assertSee("1\n") - ->call('toggleLike') - ->assertSee("0\n"); - } - - /** @test */ - public function a_logged_out_user_cannot_toggle_a_like_on_a_thread() - { - $thread = Thread::factory()->create(); - - Livewire::test(LikeThread::class, ['thread' => $thread]) - ->assertSee("0\n") - ->call('toggleLike') - ->assertSee("0\n"); - } - - /** @test */ - public function a_user_can_toggle_a_like_on_a_reply() - { - $this->login(); - - $reply = Reply::factory()->create(); - - Livewire::test(LikeReply::class, ['reply' => $reply]) - ->assertSee("0\n") - ->call('toggleLike') - ->assertSee("1\n") - ->call('toggleLike') - ->assertSee("0\n"); - } - - /** @test */ - public function a_logged_out_user_cannot_toggle_a_like_on_a_reply() - { - $reply = Reply::factory()->create(); - - Livewire::test(LikeReply::class, ['reply' => $reply]) - ->assertSee("0\n") - ->call('toggleLike') - ->assertSee("0\n"); - } - - /** @test */ - public function user_can_see_standalone_links_in_reply() - { - $thread = Thread::factory()->create(['slug' => 'the-first-thread']); - Reply::factory()->create([ - 'body' => 'https://github.com/laravelio/laravel.io check this cool project', - 'replyable_id' => $thread->id(), - ]); - - $this->visit("/forum/{$thread->slug}") - ->see('<a href=\\"https:\\/\\/github.com\\/laravelio\\/laravel.io\\" rel=\\"nofollow\\" target=\\"_blank\\">https:\\/\\/github.com\\/laravelio\\/laravel.io<\\/a>'); - } - - /** @test */ - public function user_can_see_standalone_links_in_thread() - { - $thread = Thread::factory()->create([ - 'slug' => 'the-first-thread', - 'body' => 'https://github.com/laravelio/laravel.io check this cool project', - ]); - Reply::factory()->create(['replyable_id' => $thread->id()]); - - $this->visit("/forum/{$thread->slug()}") - ->see('<a href=\\"https:\\/\\/github.com\\/laravelio\\/laravel.io\\" rel=\\"nofollow\\" target=\\"_blank\\">https:\\/\\/github.com\\/laravelio\\/laravel.io<\\/a>'); - } - - /** @test */ - public function an_invalid_filter_defaults_to_the_most_recent_threads() - { - Thread::factory()->create(['subject' => 'The first thread']); - Thread::factory()->create(['subject' => 'The second thread']); - - $this->visit('/forum?filter=something-invalid') - ->see('href="http://localhost/forum?filter=recent" aria-current="page"'); - } - - /** @test */ - public function an_invalid_filter_on_tag_view_defaults_to_the_most_recent_threads() - { - $tag = Tag::factory()->create(); - - $this->visit("/forum/tags/{$tag->slug}?filter=something-invalid") - ->see('href="http://localhost/forum/tags/'.$tag->slug.'?filter=recent" aria-current="page"'); - } -} +uses(BrowserKitTestCase::class); +uses(DatabaseMigrations::class); + +test('users can see a list of latest threads', function () { + Thread::factory()->create(['subject' => 'The first thread']); + Thread::factory()->create(['subject' => 'The second thread']); + + $this->visit('/forum') + ->see('The first thread') + ->see('The second thread'); +}); + +test('users can see when a thread is resolved', function () { + Thread::factory()->create(['subject' => 'The first thread']); + $thread = Thread::factory()->create(['subject' => 'The second thread']); + $reply = Reply::factory()->create(); + $thread->solutionReplyRelation()->associate($reply)->save(); + + $this->visit('/forum') + ->see('The first thread') + ->see('The second thread') + ->see('Resolved') + ->see(route('thread', $thread->slug()).'#'.$thread->solution_reply_id); +}); + +test('users can see a single thread', function () { + Thread::factory()->create([ + 'subject' => 'The first thread', + 'slug' => 'the-first-thread', + ]); + + $this->visit('/forum/the-first-thread') + ->see('The first thread'); +}); + +test('users cannot create a thread when not logged in', function () { + $this->visit('/forum/create-thread') + ->seePageIs('/login'); +}); + +test('the thread subject cannot be an url', function () { + $tag = Tag::factory()->create(['name' => 'Test Tag']); + + $this->login(); + + $this->post('/forum/create-thread', [ + 'subject' => 'http://example.com Foo title', + 'body' => 'This text explains how to work with Eloquent.', + 'tags' => [$tag->id()], + ]) + ->assertSessionHasErrors(['subject' => 'The subject field cannot contain an url.']); +}); + +test('users can create a thread', function () { + $tag = Tag::factory()->create(['name' => 'Test Tag']); + + $this->login(); + + $this->post('/forum/create-thread', [ + 'subject' => 'How to work with Eloquent?', + 'body' => 'This text explains how to work with Eloquent.', + 'tags' => [$tag->id()], + ]) + ->assertRedirectedTo('/forum/how-to-work-with-eloquent') + ->assertSessionHas('success', 'Thread successfully created!'); +}); + +test('users can edit a thread', function () { + $user = $this->createUser(); + $tag = Tag::factory()->create(['name' => 'Test Tag']); + Thread::factory()->create([ + 'author_id' => $user->id(), + 'slug' => 'my-first-thread', + ]); + + $this->loginAs($user); + + $this->put('/forum/my-first-thread', [ + 'subject' => 'How to work with Eloquent?', + 'body' => 'This text explains how to work with Eloquent.', + 'tags' => [$tag->id()], + ]) + ->assertRedirectedTo('/forum/how-to-work-with-eloquent') + ->assertSessionHas('success', 'Thread successfully updated!'); +}); + +test('users cannot edit a thread they do not own', function () { + Thread::factory()->create(['slug' => 'my-first-thread']); + + $this->login(); + + $this->get('/forum/my-first-thread/edit') + ->assertForbidden(); +}); + +test('users cannot delete a thread they do not own', function () { + Thread::factory()->create(['slug' => 'my-first-thread']); + + $this->login(); + + $this->delete('/forum/my-first-thread') + ->assertForbidden(); +}); + +test('users cannot create a thread with a subject that is too long', function () { + $tag = Tag::factory()->create(['name' => 'Test Tag']); + + $this->login(); + + $response = $this->post('/forum/create-thread', [ + 'subject' => 'How to make Eloquent, Doctrine, Entities and Annotations work together in Laravel?', + 'body' => 'This is a thread with 82 characters in the subject', + 'tags' => [$tag->id()], + ]); + + $response->assertSessionHas('error', 'Something went wrong. Please review the fields below.'); + $response->assertSessionHasErrors(['subject' => 'The subject must not be greater than 60 characters.']); +}); + +test('users cannot edit a thread with a subject that is too long', function () { + $user = $this->createUser(); + $tag = Tag::factory()->create(['name' => 'Test Tag']); + Thread::factory()->create([ + 'author_id' => $user->id(), + 'slug' => 'my-first-thread', + ]); + + $this->loginAs($user); + + $response = $this->put('/forum/my-first-thread', [ + 'subject' => 'How to make Eloquent, Doctrine, Entities and Annotations work together in Laravel?', + 'body' => 'This is a thread with 82 characters in the subject', + 'tags' => [$tag->id()], + ]); + + $response->assertSessionHas('error', 'Something went wrong. Please review the fields below.'); + $response->assertSessionHasErrors(['subject' => 'The subject must not be greater than 60 characters.']); +}); + +test('a user can toggle a like on a thread', function () { + $this->login(); + + $thread = Thread::factory()->create(); + + Livewire::test(LikeThread::class, ['thread' => $thread]) + ->assertSee("0\n") + ->call('toggleLike') + ->assertSee("1\n") + ->call('toggleLike') + ->assertSee("0\n"); +}); + +test('a logged out user cannot toggle a like on a thread', function () { + $thread = Thread::factory()->create(); + + Livewire::test(LikeThread::class, ['thread' => $thread]) + ->assertSee("0\n") + ->call('toggleLike') + ->assertSee("0\n"); +}); + +test('a user can toggle a like on a reply', function () { + $this->login(); + + $reply = Reply::factory()->create(); + + Livewire::test(LikeReply::class, ['reply' => $reply]) + ->assertSee("0\n") + ->call('toggleLike') + ->assertSee("1\n") + ->call('toggleLike') + ->assertSee("0\n"); +}); + +test('a logged out user cannot toggle a like on a reply', function () { + $reply = Reply::factory()->create(); + + Livewire::test(LikeReply::class, ['reply' => $reply]) + ->assertSee("0\n") + ->call('toggleLike') + ->assertSee("0\n"); +}); + +test('user can see standalone links in reply', function () { + $thread = Thread::factory()->create(['slug' => 'the-first-thread']); + Reply::factory()->create([ + 'body' => 'https://github.com/laravelio/laravel.io check this cool project', + 'replyable_id' => $thread->id(), + ]); + + $this->visit("/forum/{$thread->slug}") + ->see('<a href=\\"https:\\/\\/github.com\\/laravelio\\/laravel.io\\" rel=\\"nofollow\\" target=\\"_blank\\">https:\\/\\/github.com\\/laravelio\\/laravel.io<\\/a>'); +}); + +test('user can see standalone links in thread', function () { + $thread = Thread::factory()->create([ + 'slug' => 'the-first-thread', + 'body' => 'https://github.com/laravelio/laravel.io check this cool project', + ]); + Reply::factory()->create(['replyable_id' => $thread->id()]); + + $this->visit("/forum/{$thread->slug()}") + ->see('<a href=\\"https:\\/\\/github.com\\/laravelio\\/laravel.io\\" rel=\\"nofollow\\" target=\\"_blank\\">https:\\/\\/github.com\\/laravelio\\/laravel.io<\\/a>'); +}); + +test('an invalid filter defaults to the most recent threads', function () { + Thread::factory()->create(['subject' => 'The first thread']); + Thread::factory()->create(['subject' => 'The second thread']); + + $this->visit('/forum?filter=something-invalid') + ->see('href="http://localhost/forum?filter=recent" aria-current="page"'); +}); + +test('an invalid filter on tag view defaults to the most recent threads', function () { + $tag = Tag::factory()->create(); + + $this->visit("/forum/tags/{$tag->slug}?filter=something-invalid") + ->see('href="http://localhost/forum/tags/'.$tag->slug.'?filter=recent" aria-current="page"'); +}); diff --git a/tests/Feature/HomeTest.php b/tests/Feature/HomeTest.php index dd25a51e3..ac623797c 100644 --- a/tests/Feature/HomeTest.php +++ b/tests/Feature/HomeTest.php @@ -1,39 +1,29 @@ visit('/') - ->see('Laravel.io') - ->see('The Laravel Community Portal'); - } +test('users can see the homepage', function () { + $this->visit('/') + ->see('Laravel.io') + ->see('The Laravel Community Portal'); +}); - /** @test */ - public function users_can_see_a_login_and_registration_link_when_logged_out() - { - $this->visit('/') - ->seeLink('Login') - ->seeLink('Register') - ->dontSeeLink('Sign out'); - } +test('users can see a login and registration link when logged out', function () { + $this->visit('/') + ->seeLink('Login') + ->seeLink('Register') + ->dontSeeLink('Sign out'); +}); - /** @test */ - public function users_can_see_a_logout_button_when_logged_in() - { - $this->login(); +test('users can see a logout button when logged in', function () { + $this->login(); - $this->visit('/') - ->seeLink('Sign out') - ->dontSeeLink('Login') - ->dontSeeLink('Register') - ->seeLink('Dashboard', '/dashboard'); - } -} + $this->visit('/') + ->seeLink('Sign out') + ->dontSeeLink('Login') + ->dontSeeLink('Register') + ->seeLink('Dashboard', '/dashboard'); +}); diff --git a/tests/Feature/ModeratorTest.php b/tests/Feature/ModeratorTest.php index 6f1b4ea80..8465f667d 100644 --- a/tests/Feature/ModeratorTest.php +++ b/tests/Feature/ModeratorTest.php @@ -1,33 +1,25 @@ create(); +test('moderators can edit any thread', function () { + $thread = Thread::factory()->create(); - $this->loginAsModerator(); + $this->loginAsModerator(); - $this->visit('/forum/'.$thread->slug().'/edit') - ->assertResponseOk(); - } + $this->visit('/forum/'.$thread->slug().'/edit') + ->assertResponseOk(); +}); - /** @test */ - public function moderators_can_delete_any_thread() - { - $thread = Thread::factory()->create(); +test('moderators can delete any thread', function () { + $thread = Thread::factory()->create(); - $this->loginAsModerator(); + $this->loginAsModerator(); - $this->delete('/forum/'.$thread->slug()) - ->assertRedirectedTo('/forum'); - } -} + $this->delete('/forum/'.$thread->slug()) + ->assertRedirectedTo('/forum'); +}); diff --git a/tests/Feature/NavigationTest.php b/tests/Feature/NavigationTest.php index d7b45dcfe..8c2d61693 100644 --- a/tests/Feature/NavigationTest.php +++ b/tests/Feature/NavigationTest.php @@ -1,7 +1,5 @@ createUser(); - $userTwo = $this->createUser([ - 'name' => 'Jane Doe', - 'username' => 'janedoe', - 'email' => 'jane@example.com', - ]); - - $thread = Thread::factory()->create(['author_id' => $userOne->id()]); - $reply = Reply::factory()->create([ - 'author_id' => $userTwo->id(), - 'replyable_id' => $thread->id(), +uses(BrowserKitTestCase::class); +uses(DatabaseMigrations::class); + +test('a user sees the correct number of notifications', function () { + $userOne = $this->createUser(); + $userTwo = $this->createUser([ + 'name' => 'Jane Doe', + 'username' => 'janedoe', + 'email' => 'jane@example.com', + ]); + + $thread = Thread::factory()->create(['author_id' => $userOne->id()]); + $reply = Reply::factory()->create([ + 'author_id' => $userTwo->id(), + 'replyable_id' => $thread->id(), + ]); + + $this->loginAs($userOne); + + Livewire::test(NotificationIndicator::class) + ->assertSee('hidden'); + + for ($i = 0; $i < 10; $i++) { + $userOne->notifications()->create([ + 'id' => Str::random(), + 'type' => NewReplyNotification::class, + 'data' => [ + 'type' => 'new_reply', + 'reply' => $reply->id(), + 'replyable_id' => $reply->replyable_id, + 'replyable_type' => $reply->replyable_type, + 'replyable_subject' => $reply->replyAble()->replyAbleSubject(), + ], ]); - - $this->loginAs($userOne); - - Livewire::test(NotificationIndicator::class) - ->assertSee('hidden'); - - for ($i = 0; $i < 10; $i++) { - $userOne->notifications()->create([ - 'id' => Str::random(), - 'type' => NewReplyNotification::class, - 'data' => [ - 'type' => 'new_reply', - 'reply' => $reply->id(), - 'replyable_id' => $reply->replyable_id, - 'replyable_type' => $reply->replyable_type, - 'replyable_subject' => $reply->replyAble()->replyAbleSubject(), - ], - ]); - } - - Livewire::test(NotificationIndicator::class) - ->assertSee('rounded-full'); } -} + + Livewire::test(NotificationIndicator::class) + ->assertSee('rounded-full'); +}); diff --git a/tests/Feature/PastebinRedirectTest.php b/tests/Feature/PastebinRedirectTest.php index 4af9e2e07..d98d588ff 100644 --- a/tests/Feature/PastebinRedirectTest.php +++ b/tests/Feature/PastebinRedirectTest.php @@ -1,22 +1,15 @@ get('/bin') - ->assertRedirect('https://paste.laravel.io/'); - } +uses(TestCase::class); + +it('redirects to the paste bin website when accessing the old url', function () { + $this->get('/bin') + ->assertRedirect('https://paste.laravel.io/'); +}); - /** @test */ - public function it_redirects_to_the_paste_bin_website_when_accessing_a_hash() - { - $this->get('/bin/some-hash') - ->assertRedirect('https://paste.laravel.io/some-hash'); - } -} +it('redirects to the paste bin website when accessing a hash', function () { + $this->get('/bin/some-hash') + ->assertRedirect('https://paste.laravel.io/some-hash'); +}); diff --git a/tests/Feature/ProfileTest.php b/tests/Feature/ProfileTest.php index 1ef423383..8fe564939 100644 --- a/tests/Feature/ProfileTest.php +++ b/tests/Feature/ProfileTest.php @@ -1,69 +1,55 @@ createUser(); - - $this->visit('/user/johndoe') - ->see('John Doe'); - } - - /** @test */ - public function admin_buttons_are_not_shown_to_logged_out_users() - { - $this->createUser(); - - $this->visit('/user/johndoe') - ->dontSee('Ban user') - ->dontSee('Unban user') - ->dontSee('Delete user'); - } - - /** @test */ - public function admin_buttons_are_not_shown_to_non_admin_users() - { - $this->login(); - - $this->visit('/user/johndoe') - ->dontSee('Ban user') - ->dontSee('Unban user') - ->dontSee('Delete user'); - } - - /** @test */ - public function admin_buttons_are_shown_to_admin_users() - { - $this->createUser([ - 'username' => 'janedoe', - 'email' => 'jane@example.com', - ]); - $this->loginAsAdmin(); - - $this->visit('/user/janedoe') - ->see('Ban user') - ->see('Delete user'); - } - - /** @test */ - public function delete_button_is_not_shown_to_moderators() - { - $this->createUser([ - 'username' => 'janedoe', - 'email' => 'jane@example.com', - ]); - $this->loginAsModerator(); - - $this->visit('/user/janedoe') - ->see('Ban user') - ->dontSee('Delete user'); - } -} +uses(BrowserKitTestCase::class); +uses(DatabaseMigrations::class); + +test('anyone can see a user profile', function () { + $this->createUser(); + + $this->visit('/user/johndoe') + ->see('John Doe'); +}); + +test('admin buttons are not shown to logged out users', function () { + $this->createUser(); + + $this->visit('/user/johndoe') + ->dontSee('Ban user') + ->dontSee('Unban user') + ->dontSee('Delete user'); +}); + +test('admin buttons are not shown to non admin users', function () { + $this->login(); + + $this->visit('/user/johndoe') + ->dontSee('Ban user') + ->dontSee('Unban user') + ->dontSee('Delete user'); +}); + +test('admin buttons are shown to admin users', function () { + $this->createUser([ + 'username' => 'janedoe', + 'email' => 'jane@example.com', + ]); + $this->loginAsAdmin(); + + $this->visit('/user/janedoe') + ->see('Ban user') + ->see('Delete user'); +}); + +test('delete button is not shown to moderators', function () { + $this->createUser([ + 'username' => 'janedoe', + 'email' => 'jane@example.com', + ]); + $this->loginAsModerator(); + + $this->visit('/user/janedoe') + ->see('Ban user') + ->dontSee('Delete user'); +}); diff --git a/tests/Feature/ReplyTest.php b/tests/Feature/ReplyTest.php index 839ee8307..b0c8b2133 100644 --- a/tests/Feature/ReplyTest.php +++ b/tests/Feature/ReplyTest.php @@ -1,118 +1,98 @@ create(['subject' => 'The first thread', 'slug' => 'the-first-thread']); - - $this->login(); - - $this->post('/replies', [ - 'body' => 'The first reply', - 'replyable_id' => $thread->id, - 'replyable_type' => Thread::TABLE, - ]) - ->assertSessionHas('success', 'Reply successfully added!'); - } - - /** @test */ - public function users_can_edit_a_reply() - { - $user = $this->createUser(); - $thread = Thread::factory()->create(['slug' => 'the-first-thread']); - Reply::factory()->create(['author_id' => $user->id(), 'replyable_id' => $thread->id()]); - - $this->loginAs($user); - - $this->put('/replies/1', [ - 'body' => 'The edited reply', - ]) - ->assertRedirectedTo('/forum/the-first-thread') - ->assertSessionHas('success', 'Reply successfully updated!'); - } - - /** @test */ - public function users_cannot_edit_a_reply_they_do_not_own() - { - Reply::factory()->create(); - - $this->login(); - - $this->get('/replies/1/edit') - ->assertForbidden(); - } - - /** @test */ - public function users_cannot_delete_a_reply_they_do_not_own() - { - Reply::factory()->create(); - - $this->login(); - - $this->delete('/replies/1') - ->assertForbidden(); - } - - /** @test */ - public function users_cannot_mark_a_reply_as_the_solution_of_the_thread_if_they_do_not_own_the_thread() - { - $user = User::factory()->create(); - $thread = Thread::factory()->create(['author_id' => $user->id(), 'slug' => 'the-first-thread']); - $reply = Reply::factory()->create(['replyable_id' => $thread->id()]); - - $this->login(); - - $this->put('/forum/the-first-thread/mark-solution/'.$reply->id()) - ->assertForbidden(); - } - - /** @test */ - public function users_cannot_reply_to_a_thread_if_the_last_reply_is_older_than_six_months() - { - $thread = Thread::factory()->old()->create(); - - $this->login(); - - $this->visit("/forum/{$thread->slug}") - ->dontSee('value="Reply"') - ->seeText( - 'The last reply to this thread was more than six months ago. Please consider opening a new thread if you have a similar question.', - ); - } - - /** @test */ - public function verified_users_can_see_the_reply_input() - { - $thread = Thread::factory()->create(); - - $this->login(); - - $this->visit("/forum/{$thread->slug}") - ->see('name="body"'); - } - - /** @test */ - public function unverified_users_cannot_see_the_reply_input() - { - $thread = Thread::factory()->create(); - - $this->login(['email_verified_at' => null]); - - $this->visit("/forum/{$thread->slug}") - ->dontSee('name="body"') - ->seeText( - 'You\'ll need to verify your account before participating in this thread.', - ); - } -} +uses(BrowserKitTestCase::class); +uses(DatabaseMigrations::class); + +test('users can add a reply to a thread', function () { + $thread = Thread::factory()->create(['subject' => 'The first thread', 'slug' => 'the-first-thread']); + + $this->login(); + + $this->post('/replies', [ + 'body' => 'The first reply', + 'replyable_id' => $thread->id, + 'replyable_type' => Thread::TABLE, + ]) + ->assertSessionHas('success', 'Reply successfully added!'); +}); + +test('users can edit a reply', function () { + $user = $this->createUser(); + $thread = Thread::factory()->create(['slug' => 'the-first-thread']); + Reply::factory()->create(['author_id' => $user->id(), 'replyable_id' => $thread->id()]); + + $this->loginAs($user); + + $this->put('/replies/1', [ + 'body' => 'The edited reply', + ]) + ->assertRedirectedTo('/forum/the-first-thread') + ->assertSessionHas('success', 'Reply successfully updated!'); +}); + +test('users cannot edit a reply they do not own', function () { + Reply::factory()->create(); + + $this->login(); + + $this->get('/replies/1/edit') + ->assertForbidden(); +}); + +test('users cannot delete a reply they do not own', function () { + Reply::factory()->create(); + + $this->login(); + + $this->delete('/replies/1') + ->assertForbidden(); +}); + +test('users cannot mark a reply as the solution of the thread if they do not own the thread', function () { + $user = User::factory()->create(); + $thread = Thread::factory()->create(['author_id' => $user->id(), 'slug' => 'the-first-thread']); + $reply = Reply::factory()->create(['replyable_id' => $thread->id()]); + + $this->login(); + + $this->put('/forum/the-first-thread/mark-solution/'.$reply->id()) + ->assertForbidden(); +}); + +test('users cannot reply to a thread if the last reply is older than six months', function () { + $thread = Thread::factory()->old()->create(); + + $this->login(); + + $this->visit("/forum/{$thread->slug}") + ->dontSee('value="Reply"') + ->seeText( + 'The last reply to this thread was more than six months ago. Please consider opening a new thread if you have a similar question.', + ); +}); + +test('verified users can see the reply input', function () { + $thread = Thread::factory()->create(); + + $this->login(); + + $this->visit("/forum/{$thread->slug}") + ->see('name="body"'); +}); + +test('unverified users cannot see the reply input', function () { + $thread = Thread::factory()->create(); + + $this->login(['email_verified_at' => null]); + + $this->visit("/forum/{$thread->slug}") + ->dontSee('name="body"') + ->seeText( + 'You\'ll need to verify your account before participating in this thread.', + ); +}); diff --git a/tests/Feature/SettingsTest.php b/tests/Feature/SettingsTest.php index ac4596d15..af4a92535 100644 --- a/tests/Feature/SettingsTest.php +++ b/tests/Feature/SettingsTest.php @@ -1,155 +1,134 @@ visit('/settings') + ->seePageIs('/login'); +}); + +test('users can update their profile', function () { + $this->login(); + + $this->visit('/settings') + ->submitForm('Update Profile', [ + 'name' => 'Freek Murze', + 'email' => 'freek@example.com', + 'username' => 'freekmurze', + 'twitter' => 'freektwitter', + 'bio' => 'My bio', + ]) + ->seePageIs('/settings') + ->see('Freek Murze') + ->see('freekmurze') + ->see('freektwitter') + ->see('Settings successfully saved!') + ->see('My bio'); +}); + +test('users cannot choose duplicate usernames or email addresses', function () { + $this->createUser(['email' => 'freek@example.com', 'username' => 'freekmurze']); + + $this->login(); + + $this->visit('/settings') + ->submitForm('Update Profile', [ + 'name' => 'Freek Murze', + 'email' => 'freek@example.com', + 'username' => 'freekmurze', + ]) + ->seePageIs('/settings') + ->see('Something went wrong. Please review the fields below.') + ->see('The email has already been taken.') + ->see('The username has already been taken.'); +}); + +test('users can delete their account', function () { + $this->login(['name' => 'Freek Murze']); + + $this->delete('/settings') + ->assertRedirectedTo('/'); + + $this->notSeeInDatabase('users', ['name' => 'Freek Murze']); +}); + +test('users cannot delete their account', function () { + $this->loginAsAdmin(); + + $this->visit('/settings') + ->dontSee('Delete Account'); +}); + +test('users can update their password', function () { + $this->login(); + + $this->visit('/settings') + ->submitForm('Update Password', [ + 'current_password' => 'password', + 'password' => 'QFq^$cz#P@MZa5z7', + 'password_confirmation' => 'QFq^$cz#P@MZa5z7', + ]) + ->seePageIs('/settings') + ->see('Password successfully changed!'); + + assertPasswordWasHashedAndSaved(); +}); + +test('users cannot update their password when it has been compromised in data leaks', function () { + $this->login(); + + $this->visit('/settings') + ->submitForm('Update Password', [ + 'current_password' => 'password', + 'password' => 'newpassword', + 'password_confirmation' => 'newpassword', + ]) + ->seePageIs('/settings') + ->see('Something went wrong. Please review the fields below.') + ->see('The given password has appeared in a data leak. Please choose a different password.'); +}); + +test('users can set their password when they have none set yet', function () { + $user = User::factory()->passwordless()->create(); + + $this->loginAs($user); + + $this->visit('/settings') + ->submitForm('Update Password', [ + 'password' => 'QFq^$cz#P@MZa5z7', + 'password_confirmation' => 'QFq^$cz#P@MZa5z7', + ]) + ->seePageIs('/settings') + ->see('Password successfully changed!'); + + assertPasswordWasHashedAndSaved(); +}); + +test('twitter is optional', function () { + $user = $this->createUser(['email' => 'freek@example.com', 'username' => 'freekmurze', 'twitter' => 'freektwitter']); + + $this->loginAs($user); + + $this->visit('/settings') + ->submitForm('Update Profile', [ + 'name' => 'Freek Murze', + 'email' => 'freek@example.com', + 'username' => 'freekmurze', + 'twitter' => '', + ]) + ->seePageIs('/settings') + ->dontSee('freektwitter'); + + $this->assertEmpty($user->fresh()->twitter()); +}); + +// Helpers +function assertPasswordWasHashedAndSaved(): void { - use DatabaseMigrations; - - /** @test */ - public function requires_login() - { - $this->visit('/settings') - ->seePageIs('/login'); - } - - /** @test */ - public function users_can_update_their_profile() - { - $this->login(); - - $this->visit('/settings') - ->submitForm('Update Profile', [ - 'name' => 'Freek Murze', - 'email' => 'freek@example.com', - 'username' => 'freekmurze', - 'twitter' => 'freektwitter', - 'bio' => 'My bio', - ]) - ->seePageIs('/settings') - ->see('Freek Murze') - ->see('freekmurze') - ->see('freektwitter') - ->see('Settings successfully saved!') - ->see('My bio'); - } - - /** @test */ - public function users_cannot_choose_duplicate_usernames_or_email_addresses() - { - $this->createUser(['email' => 'freek@example.com', 'username' => 'freekmurze']); - - $this->login(); - - $this->visit('/settings') - ->submitForm('Update Profile', [ - 'name' => 'Freek Murze', - 'email' => 'freek@example.com', - 'username' => 'freekmurze', - ]) - ->seePageIs('/settings') - ->see('Something went wrong. Please review the fields below.') - ->see('The email has already been taken.') - ->see('The username has already been taken.'); - } - - /** @test */ - public function users_can_delete_their_account() - { - $this->login(['name' => 'Freek Murze']); - - $this->delete('/settings') - ->assertRedirectedTo('/'); - - $this->notSeeInDatabase('users', ['name' => 'Freek Murze']); - } - - /** @test */ - public function users_cannot_delete_their_account() - { - $this->loginAsAdmin(); - - $this->visit('/settings') - ->dontSee('Delete Account'); - } - - /** @test */ - public function users_can_update_their_password() - { - $this->login(); - - $this->visit('/settings') - ->submitForm('Update Password', [ - 'current_password' => 'password', - 'password' => 'QFq^$cz#P@MZa5z7', - 'password_confirmation' => 'QFq^$cz#P@MZa5z7', - ]) - ->seePageIs('/settings') - ->see('Password successfully changed!'); - - $this->assertPasswordWasHashedAndSaved(); - } - - /** @test */ - public function users_cannot_update_their_password_when_it_has_been_compromised_in_data_leaks() - { - $this->login(); - - $this->visit('/settings') - ->submitForm('Update Password', [ - 'current_password' => 'password', - 'password' => 'newpassword', - 'password_confirmation' => 'newpassword', - ]) - ->seePageIs('/settings') - ->see('Something went wrong. Please review the fields below.') - ->see('The given password has appeared in a data leak. Please choose a different password.'); - } - - /** @test */ - public function users_can_set_their_password_when_they_have_none_set_yet() - { - $user = User::factory()->passwordless()->create(); - - $this->loginAs($user); - - $this->visit('/settings') - ->submitForm('Update Password', [ - 'password' => 'QFq^$cz#P@MZa5z7', - 'password_confirmation' => 'QFq^$cz#P@MZa5z7', - ]) - ->seePageIs('/settings') - ->see('Password successfully changed!'); - - $this->assertPasswordWasHashedAndSaved(); - } - - /** @test */ - public function twitter_is_optional() - { - $user = $this->createUser(['email' => 'freek@example.com', 'username' => 'freekmurze', 'twitter' => 'freektwitter']); - - $this->loginAs($user); - - $this->visit('/settings') - ->submitForm('Update Profile', [ - 'name' => 'Freek Murze', - 'email' => 'freek@example.com', - 'username' => 'freekmurze', - 'twitter' => '', - ]) - ->seePageIs('/settings') - ->dontSee('freektwitter'); - - $this->assertEmpty($user->fresh()->twitter()); - } - - private function assertPasswordWasHashedAndSaved(): void - { - $this->assertTrue($this->app['hash']->check('QFq^$cz#P@MZa5z7', Auth::user()->getAuthPassword())); - } + $this->assertTrue($this->app['hash']->check('QFq^$cz#P@MZa5z7', Auth::user()->getAuthPassword())); } diff --git a/tests/Feature/SubscriptionsTest.php b/tests/Feature/SubscriptionsTest.php index a5f275a7c..25ac1fcef 100644 --- a/tests/Feature/SubscriptionsTest.php +++ b/tests/Feature/SubscriptionsTest.php @@ -1,7 +1,5 @@ create(); - [$author, $userOne, $userTwo] = User::factory()->times(3)->create(); - Subscription::factory()->create(['user_id' => $userOne->id(), 'subscriptionable_id' => $thread->id()]); - Subscription::factory()->create(['user_id' => $userTwo->id(), 'subscriptionable_id' => $thread->id()]); + $thread = Thread::factory()->create(); + [$author, $userOne, $userTwo] = User::factory()->times(3)->create(); + Subscription::factory()->create(['user_id' => $userOne->id(), 'subscriptionable_id' => $thread->id()]); + Subscription::factory()->create(['user_id' => $userTwo->id(), 'subscriptionable_id' => $thread->id()]); - $this->dispatch(new CreateReply($this->faker->text, $author, $thread)); + $this->dispatch(new CreateReply($this->faker->text, $author, $thread)); - Notification::assertNotSentTo($author, NewReplyNotification::class); - Notification::assertSentTo([$userOne, $userTwo], NewReplyNotification::class); - } + Notification::assertNotSentTo($author, NewReplyNotification::class); + Notification::assertSentTo([$userOne, $userTwo], NewReplyNotification::class); +}); - /** @test */ - public function users_are_automatically_subscribed_to_a_thread_after_creating_it() - { - $user = $this->createUser(); +test('users are automatically subscribed to a thread after creating it', function () { + $user = $this->createUser(); - $thread = $this->dispatch(new CreateThread($this->faker->sentence, $this->faker->text, $user)); + $thread = $this->dispatch(new CreateThread($this->faker->sentence, $this->faker->text, $user)); - $this->assertTrue($thread->hasSubscriber($user)); - } + $this->assertTrue($thread->hasSubscriber($user)); +}); - /** @test */ - public function thread_authors_do_not_receive_a_notification_for_a_thread_they_create() - { - Notification::fake(); +test('thread authors do not receive a notification for a thread they create', function () { + Notification::fake(); - $author = $this->createUser(); + $author = $this->createUser(); - $this->dispatch(new CreateThread($this->faker->sentence, $this->faker->text, $author)); + $this->dispatch(new CreateThread($this->faker->sentence, $this->faker->text, $author)); - Notification::assertNotSentTo($author, NewReplyNotification::class); - } + Notification::assertNotSentTo($author, NewReplyNotification::class); +}); - /** @test */ - public function reply_authors_do_not_receive_a_notification_for_a_thread_they_are_subscribed_to() - { - Notification::fake(); +test('reply authors do not receive a notification for a thread they are subscribed to', function () { + Notification::fake(); - $thread = Thread::factory()->create(); - $author = User::factory()->create(); - Subscription::factory()->create(['user_id' => $author->id(), 'subscriptionable_id' => $thread->id()]); + $thread = Thread::factory()->create(); + $author = User::factory()->create(); + Subscription::factory()->create(['user_id' => $author->id(), 'subscriptionable_id' => $thread->id()]); - $this->dispatch(new CreateReply($this->faker->text, $author, $thread)); + $this->dispatch(new CreateReply($this->faker->text, $author, $thread)); - Notification::assertNotSentTo($author, NewReplyNotification::class); - } + Notification::assertNotSentTo($author, NewReplyNotification::class); +}); - /** @test */ - public function users_are_automatically_subscribed_to_a_thread_after_replying_to_it() - { - $user = $this->createUser(); - $thread = Thread::factory()->create(); +test('users are automatically subscribed to a thread after replying to it', function () { + $user = $this->createUser(); + $thread = Thread::factory()->create(); - $this->dispatch(new CreateReply($this->faker->text, $user, $thread)); + $this->dispatch(new CreateReply($this->faker->text, $user, $thread)); - $this->assertTrue($thread->hasSubscriber($user)); - } + $this->assertTrue($thread->hasSubscriber($user)); +}); - /** @test */ - public function users_can_manually_subscribe_to_threads() - { - Thread::factory()->create(['slug' => $slug = $this->faker->slug]); +test('users can manually subscribe to threads', function () { + Thread::factory()->create(['slug' => $slug = $this->faker->slug]); - $this->login(); + $this->login(); - $this->visit("/forum/$slug") - ->click('Subscribe') - ->seePageIs("/forum/$slug") - ->see("You're now subscribed to this thread."); - } + $this->visit("/forum/$slug") + ->click('Subscribe') + ->seePageIs("/forum/$slug") + ->see("You're now subscribed to this thread."); +}); - /** @test */ - public function users_can_unsubscribe_from_threads() - { - $user = $this->createUser(); - $thread = Thread::factory()->create(['slug' => $slug = $this->faker->slug]); - Subscription::factory()->create(['user_id' => $user->id(), 'subscriptionable_id' => $thread->id()]); +test('users can unsubscribe from threads', function () { + $user = $this->createUser(); + $thread = Thread::factory()->create(['slug' => $slug = $this->faker->slug]); + Subscription::factory()->create(['user_id' => $user->id(), 'subscriptionable_id' => $thread->id()]); - $this->loginAs($user); + $this->loginAs($user); - $this->visit("/forum/$slug") - ->click('Unsubscribe') - ->seePageIs("/forum/$slug") - ->see("You're now unsubscribed from this thread."); - } + $this->visit("/forum/$slug") + ->click('Unsubscribe') + ->seePageIs("/forum/$slug") + ->see("You're now unsubscribed from this thread."); +}); - /** @test */ - public function users_can_unsubscribe_through_a_token_link() - { - $subscription = Subscription::factory()->create(); - $thread = $subscription->subscriptionAble(); +test('users can unsubscribe through a token link', function () { + $subscription = Subscription::factory()->create(); + $thread = $subscription->subscriptionAble(); - $this->visit("/subscriptions/{$subscription->uuid()}/unsubscribe") - ->seePageIs("/forum/{$thread->slug()}") - ->see("You're now unsubscribed from this thread."); + $this->visit("/subscriptions/{$subscription->uuid()}/unsubscribe") + ->seePageIs("/forum/{$thread->slug()}") + ->see("You're now unsubscribed from this thread."); - $this->notSeeInDatabase('subscriptions', ['uuid' => $subscription->uuid()]); - } -} + $this->notSeeInDatabase('subscriptions', ['uuid' => $subscription->uuid()]); +}); diff --git a/tests/Integration/Jobs/BanUserTest.php b/tests/Integration/Jobs/BanUserTest.php index 85ff1048e..4f3b4e7ad 100644 --- a/tests/Integration/Jobs/BanUserTest.php +++ b/tests/Integration/Jobs/BanUserTest.php @@ -1,22 +1,16 @@ createUser(['banned_at' => null]); +it('can ban a user', function () { + $user = $this->createUser(['banned_at' => null]); - $bannedUser = $this->dispatch(new BanUser($user)); + $bannedUser = $this->dispatch(new BanUser($user)); - $this->assertTrue($bannedUser->isBanned()); - } -} + $this->assertTrue($bannedUser->isBanned()); +}); diff --git a/tests/Integration/Jobs/CreateArticleTest.php b/tests/Integration/Jobs/CreateArticleTest.php index 6ac85c668..17e74c335 100644 --- a/tests/Integration/Jobs/CreateArticleTest.php +++ b/tests/Integration/Jobs/CreateArticleTest.php @@ -1,40 +1,32 @@ createUser(); - - $article = $this->dispatch(new CreateArticle('Title', 'Body', $user, false, [ - 'original_url' => 'https://laravel.io', - ])); - - $this->assertEquals('Title', $article->title()); - $this->assertEquals('Body', $article->body()); - $this->assertEquals('https://laravel.io', $article->canonicalUrl()); - $this->assertNull($article->submittedAt()); - $this->assertTrue($article->isNotPublished()); - } - - /** @test */ - public function we_can_create_an_article_and_submit_it_for_approval() - { - $user = $this->createUser(); - - $article = $this->dispatch(new CreateArticle('Title', 'Body', $user, true, [ - 'original_url' => 'https://laravel.io', - ])); - - $this->assertNotNull($article->submittedAt()); - } -} +uses(TestCase::class); +uses(DatabaseMigrations::class); + +test('we can create a draft article', function () { + $user = $this->createUser(); + + $article = $this->dispatch(new CreateArticle('Title', 'Body', $user, false, [ + 'original_url' => 'https://laravel.io', + ])); + + $this->assertEquals('Title', $article->title()); + $this->assertEquals('Body', $article->body()); + $this->assertEquals('https://laravel.io', $article->canonicalUrl()); + $this->assertNull($article->submittedAt()); + $this->assertTrue($article->isNotPublished()); +}); + +test('we can create an article and submit it for approval', function () { + $user = $this->createUser(); + + $article = $this->dispatch(new CreateArticle('Title', 'Body', $user, true, [ + 'original_url' => 'https://laravel.io', + ])); + + $this->assertNotNull($article->submittedAt()); +}); diff --git a/tests/Integration/Jobs/CreateReplyTest.php b/tests/Integration/Jobs/CreateReplyTest.php index 2d469bcca..81873c8c6 100644 --- a/tests/Integration/Jobs/CreateReplyTest.php +++ b/tests/Integration/Jobs/CreateReplyTest.php @@ -1,27 +1,21 @@ createUser(); - $thread = Thread::factory()->create(); +test('we can create a reply', function () { + $user = $this->createUser(); + $thread = Thread::factory()->create(); - $this->expectsEvents(ReplyWasCreated::class); + $this->expectsEvents(ReplyWasCreated::class); - $reply = $this->dispatch(new CreateReply('Foo', $user, $thread)); + $reply = $this->dispatch(new CreateReply('Foo', $user, $thread)); - $this->assertEquals('Foo', $reply->body()); - } -} + $this->assertEquals('Foo', $reply->body()); +}); diff --git a/tests/Integration/Jobs/CreateThreadTest.php b/tests/Integration/Jobs/CreateThreadTest.php index ce39480ce..b07cccd87 100644 --- a/tests/Integration/Jobs/CreateThreadTest.php +++ b/tests/Integration/Jobs/CreateThreadTest.php @@ -1,22 +1,16 @@ createUser(); +test('we can create a thread', function () { + $user = $this->createUser(); - $thread = $this->dispatch(new CreateThread('Subject', 'Body', $user)); + $thread = $this->dispatch(new CreateThread('Subject', 'Body', $user)); - $this->assertEquals('Subject', $thread->subject()); - } -} + $this->assertEquals('Subject', $thread->subject()); +}); diff --git a/tests/Integration/Jobs/DeleteArticleTest.php b/tests/Integration/Jobs/DeleteArticleTest.php index 2b6988a3e..debe0203d 100644 --- a/tests/Integration/Jobs/DeleteArticleTest.php +++ b/tests/Integration/Jobs/DeleteArticleTest.php @@ -1,23 +1,17 @@ create(); +test('an article can be deleted', function () { + $article = Article::factory()->create(); - $this->dispatch(new DeleteArticle($article)); + $this->dispatch(new DeleteArticle($article)); - $this->assertDatabaseMissing('articles', ['id' => $article->id()]); - } -} + $this->assertDatabaseMissing('articles', ['id' => $article->id()]); +}); diff --git a/tests/Integration/Jobs/DeleteThreadTest.php b/tests/Integration/Jobs/DeleteThreadTest.php index 534903278..5167dc879 100644 --- a/tests/Integration/Jobs/DeleteThreadTest.php +++ b/tests/Integration/Jobs/DeleteThreadTest.php @@ -1,7 +1,5 @@ create(); - $reply = Reply::factory()->create(['replyable_id' => $thread->id()]); - Like::factory()->thread()->create(['likeable_id' => $thread->id()]); - Like::factory()->reply()->create(['likeable_id' => $reply->id()]); +test('we can delete a thread and its replies', function () { + $thread = Thread::factory()->create(); + $reply = Reply::factory()->create(['replyable_id' => $thread->id()]); + Like::factory()->thread()->create(['likeable_id' => $thread->id()]); + Like::factory()->reply()->create(['likeable_id' => $reply->id()]); - $this->dispatch(new DeleteThread($thread)); + $this->dispatch(new DeleteThread($thread)); - $this->assertDatabaseMissing('threads', ['id' => $thread->id()]); - $this->assertDatabaseMissing('replies', ['replyable_id' => $thread->id()]); - $this->assertDatabaseMissing('likes', ['likeable_type' => 'threads', 'likeable_id' => $thread->id()]); - $this->assertDatabaseMissing('likes', ['likeable_type' => 'replies', 'likeable_id' => $reply->id()]); - } -} + $this->assertDatabaseMissing('threads', ['id' => $thread->id()]); + $this->assertDatabaseMissing('replies', ['replyable_id' => $thread->id()]); + $this->assertDatabaseMissing('likes', ['likeable_type' => 'threads', 'likeable_id' => $thread->id()]); + $this->assertDatabaseMissing('likes', ['likeable_type' => 'replies', 'likeable_id' => $reply->id()]); +}); diff --git a/tests/Integration/Jobs/LikeArticleTest.php b/tests/Integration/Jobs/LikeArticleTest.php index 36aa352ca..a6b3b1672 100644 --- a/tests/Integration/Jobs/LikeArticleTest.php +++ b/tests/Integration/Jobs/LikeArticleTest.php @@ -1,7 +1,5 @@ create(); - $article = Article::factory()->create(); +test('we can like an article', function () { + $user = User::factory()->create(); + $article = Article::factory()->create(); - $this->dispatch(new LikeArticle($article, $user)); + $this->dispatch(new LikeArticle($article, $user)); - $this->assertTrue($article->fresh()->isLikedBy($user)); - } + $this->assertTrue($article->fresh()->isLikedBy($user)); +}); - /** @test */ - public function we_cannot_like_an_article_twice() - { - $user = User::factory()->create(); - $article = Article::factory()->create(); +test('we cannot like an article twice', function () { + $user = User::factory()->create(); + $article = Article::factory()->create(); - $this->dispatch(new LikeArticle($article, $user)); + $this->dispatch(new LikeArticle($article, $user)); - $this->assertTrue($article->fresh()->isLikedBy($user)); + $this->assertTrue($article->fresh()->isLikedBy($user)); - $this->expectException(CannotLikeItem::class); + $this->expectException(CannotLikeItem::class); - $this->dispatch(new LikeArticle($article, $user)); - } -} + $this->dispatch(new LikeArticle($article, $user)); +}); diff --git a/tests/Integration/Jobs/LikeReplyTest.php b/tests/Integration/Jobs/LikeReplyTest.php index 5af70c6a4..353e75023 100644 --- a/tests/Integration/Jobs/LikeReplyTest.php +++ b/tests/Integration/Jobs/LikeReplyTest.php @@ -1,7 +1,5 @@ create(); - $reply = Reply::factory()->create(); +test('we can like a reply', function () { + $user = User::factory()->create(); + $reply = Reply::factory()->create(); - $this->dispatch(new LikeReply($reply, $user)); + $this->dispatch(new LikeReply($reply, $user)); - $this->assertTrue($reply->fresh()->isLikedBy($user)); - } + $this->assertTrue($reply->fresh()->isLikedBy($user)); +}); - /** @test */ - public function we_cannot_like_a_reply_twice() - { - $user = User::factory()->create(); - $reply = Reply::factory()->create(); +test('we cannot like a reply twice', function () { + $user = User::factory()->create(); + $reply = Reply::factory()->create(); - $this->dispatch(new LikeReply($reply, $user)); + $this->dispatch(new LikeReply($reply, $user)); - $this->assertTrue($reply->fresh()->isLikedBy($user)); + $this->assertTrue($reply->fresh()->isLikedBy($user)); - $this->expectException(CannotLikeItem::class); + $this->expectException(CannotLikeItem::class); - $this->dispatch(new LikeReply($reply, $user)); - } -} + $this->dispatch(new LikeReply($reply, $user)); +}); diff --git a/tests/Integration/Jobs/LikeThreadTest.php b/tests/Integration/Jobs/LikeThreadTest.php index 87cd26410..23b92cf2d 100644 --- a/tests/Integration/Jobs/LikeThreadTest.php +++ b/tests/Integration/Jobs/LikeThreadTest.php @@ -1,7 +1,5 @@ create(); - $thread = Thread::factory()->create(); +test('we can like a thread', function () { + $user = User::factory()->create(); + $thread = Thread::factory()->create(); - $this->dispatch(new LikeThread($thread, $user)); + $this->dispatch(new LikeThread($thread, $user)); - $this->assertTrue($thread->fresh()->isLikedBy($user)); - } + $this->assertTrue($thread->fresh()->isLikedBy($user)); +}); - /** @test */ - public function we_cannot_like_a_thread_twice() - { - $user = User::factory()->create(); - $thread = Thread::factory()->create(); +test('we cannot like a thread twice', function () { + $user = User::factory()->create(); + $thread = Thread::factory()->create(); - $this->dispatch(new LikeThread($thread, $user)); + $this->dispatch(new LikeThread($thread, $user)); - $this->assertTrue($thread->fresh()->isLikedBy($user)); + $this->assertTrue($thread->fresh()->isLikedBy($user)); - $this->expectException(CannotLikeItem::class); + $this->expectException(CannotLikeItem::class); - $this->dispatch(new LikeThread($thread, $user)); - } -} + $this->dispatch(new LikeThread($thread, $user)); +}); diff --git a/tests/Integration/Jobs/RegisterUserTest.php b/tests/Integration/Jobs/RegisterUserTest.php index 4e8efd479..97a6bc3db 100644 --- a/tests/Integration/Jobs/RegisterUserTest.php +++ b/tests/Integration/Jobs/RegisterUserTest.php @@ -1,41 +1,31 @@ dispatch( - new RegisterUser('John Doe', 'john@example.com', 'johndoe', 'password', '123', 'johndoe'), - ); - - $this->assertEquals('John Doe', $user->name()); - } - - /** @test */ - public function we_cannot_create_a_user_with_the_same_email_address() - { - $this->expectException(CannotCreateUser::class); - - $this->dispatch(new RegisterUser('John Doe', 'john@example.com', 'johndoe', '', 'password', '123', 'johndoe')); - $this->dispatch(new RegisterUser('John Doe', 'john@example.com', 'john', '', 'password', '123', 'johndoe')); - } - - /** @test */ - public function we_cannot_create_a_user_with_the_same_username() - { - $this->expectException(CannotCreateUser::class); - - $this->dispatch(new RegisterUser('John Doe', 'john@example.com', 'johndoe', '', 'password', '123', 'johndoe')); - $this->dispatch(new RegisterUser('John Doe', 'doe@example.com', 'johndoe', '', 'password', '123', 'johndoe')); - } -} +uses(TestCase::class); +uses(DatabaseMigrations::class); + +test('we can create a user', function () { + $user = $this->dispatch( + new RegisterUser('John Doe', 'john@example.com', 'johndoe', 'password', '123', 'johndoe'), + ); + + $this->assertEquals('John Doe', $user->name()); +}); + +test('we cannot create a user with the same email address', function () { + $this->expectException(CannotCreateUser::class); + + $this->dispatch(new RegisterUser('John Doe', 'john@example.com', 'johndoe', '', 'password', '123', 'johndoe')); + $this->dispatch(new RegisterUser('John Doe', 'john@example.com', 'john', '', 'password', '123', 'johndoe')); +}); + +test('we cannot create a user with the same username', function () { + $this->expectException(CannotCreateUser::class); + + $this->dispatch(new RegisterUser('John Doe', 'john@example.com', 'johndoe', '', 'password', '123', 'johndoe')); + $this->dispatch(new RegisterUser('John Doe', 'doe@example.com', 'johndoe', '', 'password', '123', 'johndoe')); +}); diff --git a/tests/Integration/Jobs/SubscribeToSubscriptionAbleTest.php b/tests/Integration/Jobs/SubscribeToSubscriptionAbleTest.php index 35e9f1902..47f62965f 100644 --- a/tests/Integration/Jobs/SubscribeToSubscriptionAbleTest.php +++ b/tests/Integration/Jobs/SubscribeToSubscriptionAbleTest.php @@ -1,26 +1,20 @@ createUser(); - $thread = Thread::factory()->create(); +it('can subscribe a user to a thread', function () { + $user = $this->createUser(); + $thread = Thread::factory()->create(); - $this->assertFalse($thread->hasSubscriber($user)); + $this->assertFalse($thread->hasSubscriber($user)); - $this->dispatch(new SubscribeToSubscriptionAble($user, $thread)); + $this->dispatch(new SubscribeToSubscriptionAble($user, $thread)); - $this->assertTrue($thread->hasSubscriber($user)); - } -} + $this->assertTrue($thread->hasSubscriber($user)); +}); diff --git a/tests/Integration/Jobs/UnbanUserTest.php b/tests/Integration/Jobs/UnbanUserTest.php index 72862d433..282d73fc2 100644 --- a/tests/Integration/Jobs/UnbanUserTest.php +++ b/tests/Integration/Jobs/UnbanUserTest.php @@ -1,23 +1,17 @@ createUser(['banned_at' => Carbon::yesterday()]); +it('can unban a user', function () { + $user = $this->createUser(['banned_at' => Carbon::yesterday()]); - $unbannedUser = $this->dispatch(new UnbanUser($user)); + $unbannedUser = $this->dispatch(new UnbanUser($user)); - $this->assertFalse($unbannedUser->isBanned()); - } -} + $this->assertFalse($unbannedUser->isBanned()); +}); diff --git a/tests/Integration/Jobs/UnlikeArticleTest.php b/tests/Integration/Jobs/UnlikeArticleTest.php index aba195399..79cf8c1b4 100644 --- a/tests/Integration/Jobs/UnlikeArticleTest.php +++ b/tests/Integration/Jobs/UnlikeArticleTest.php @@ -1,28 +1,22 @@ create(); - $article = Article::factory()->create(); +test('we can unlike an article', function () { + $user = User::factory()->create(); + $article = Article::factory()->create(); - $article->likedBy($user); - $this->assertTrue($article->fresh()->isLikedBy($user)); + $article->likedBy($user); + $this->assertTrue($article->fresh()->isLikedBy($user)); - $this->dispatch(new UnlikeArticle($article, $user)); + $this->dispatch(new UnlikeArticle($article, $user)); - $this->assertFalse($article->fresh()->isLikedBy($user)); - } -} + $this->assertFalse($article->fresh()->isLikedBy($user)); +}); diff --git a/tests/Integration/Jobs/UnlikeReplyTest.php b/tests/Integration/Jobs/UnlikeReplyTest.php index d5c351436..57cf178da 100644 --- a/tests/Integration/Jobs/UnlikeReplyTest.php +++ b/tests/Integration/Jobs/UnlikeReplyTest.php @@ -1,28 +1,22 @@ create(); - $reply = Reply::factory()->create(); +test('we can unlike a reply', function () { + $user = User::factory()->create(); + $reply = Reply::factory()->create(); - $reply->likedBy($user); - $this->assertTrue($reply->fresh()->isLikedBy($user)); + $reply->likedBy($user); + $this->assertTrue($reply->fresh()->isLikedBy($user)); - $this->dispatch(new UnlikeReply($reply, $user)); + $this->dispatch(new UnlikeReply($reply, $user)); - $this->assertFalse($reply->fresh()->isLikedBy($user)); - } -} + $this->assertFalse($reply->fresh()->isLikedBy($user)); +}); diff --git a/tests/Integration/Jobs/UnlikeThreadTest.php b/tests/Integration/Jobs/UnlikeThreadTest.php index 933213ade..6d29bee87 100644 --- a/tests/Integration/Jobs/UnlikeThreadTest.php +++ b/tests/Integration/Jobs/UnlikeThreadTest.php @@ -1,28 +1,22 @@ create(); - $thread = Thread::factory()->create(); +test('we can unlike a thread', function () { + $user = User::factory()->create(); + $thread = Thread::factory()->create(); - $thread->likedBy($user); - $this->assertTrue($thread->fresh()->isLikedBy($user)); + $thread->likedBy($user); + $this->assertTrue($thread->fresh()->isLikedBy($user)); - $this->dispatch(new UnlikeThread($thread, $user)); + $this->dispatch(new UnlikeThread($thread, $user)); - $this->assertFalse($thread->fresh()->isLikedBy($user)); - } -} + $this->assertFalse($thread->fresh()->isLikedBy($user)); +}); diff --git a/tests/Integration/Jobs/UnsubscribeFromSubscriptionAbleTest.php b/tests/Integration/Jobs/UnsubscribeFromSubscriptionAbleTest.php index 13069e2c1..9d8f617ef 100644 --- a/tests/Integration/Jobs/UnsubscribeFromSubscriptionAbleTest.php +++ b/tests/Integration/Jobs/UnsubscribeFromSubscriptionAbleTest.php @@ -1,28 +1,22 @@ createUser(); - $thread = Thread::factory()->create(); - Subscription::factory()->create(['user_id' => $user->id(), 'subscriptionable_id' => $thread->id()]); +it('can unsubscribe a user from a thread', function () { + $user = $this->createUser(); + $thread = Thread::factory()->create(); + Subscription::factory()->create(['user_id' => $user->id(), 'subscriptionable_id' => $thread->id()]); - $this->assertTrue($thread->hasSubscriber($user)); + $this->assertTrue($thread->hasSubscriber($user)); - $this->dispatch(new UnsubscribeFromSubscriptionAble($user, $thread)); + $this->dispatch(new UnsubscribeFromSubscriptionAble($user, $thread)); - $this->assertFalse($thread->hasSubscriber($user)); - } -} + $this->assertFalse($thread->hasSubscriber($user)); +}); diff --git a/tests/Integration/Jobs/UpdateArticleTest.php b/tests/Integration/Jobs/UpdateArticleTest.php index 225de09a2..f9922a15e 100644 --- a/tests/Integration/Jobs/UpdateArticleTest.php +++ b/tests/Integration/Jobs/UpdateArticleTest.php @@ -1,48 +1,38 @@ createUser(); - $article = Article::factory()->create(['author_id' => $user->id()]); +test('we can update an article', function () { + $user = $this->createUser(); + $article = Article::factory()->create(['author_id' => $user->id()]); - $article = $this->dispatch(new UpdateArticle($article, 'Title', 'Body', false)); + $article = $this->dispatch(new UpdateArticle($article, 'Title', 'Body', false)); - $this->assertEquals('Title', $article->title()); - $this->assertEquals('Body', $article->body()); - } + $this->assertEquals('Title', $article->title()); + $this->assertEquals('Body', $article->body()); +}); - /** @test */ - public function we_can_submit_an_existing_article_for_approval() - { - $user = $this->createUser(); - $article = Article::factory()->create(['author_id' => $user->id()]); +test('we can submit an existing article for approval', function () { + $user = $this->createUser(); + $article = Article::factory()->create(['author_id' => $user->id()]); - $article = $this->dispatch(new UpdateArticle($article, 'Title', 'Body', true)); + $article = $this->dispatch(new UpdateArticle($article, 'Title', 'Body', true)); - $this->assertNotNull($article->submittedAt()); - } + $this->assertNotNull($article->submittedAt()); +}); - /** @test */ - public function we_cannot_update_the_submission_time_when_saving_changes() - { - $user = $this->createUser(); - $article = Article::factory()->create(['author_id' => $user->id(), 'submitted_at' => '2020-06-20 00:00:00']); +test('we cannot update the submission time when saving changes', function () { + $user = $this->createUser(); + $article = Article::factory()->create(['author_id' => $user->id(), 'submitted_at' => '2020-06-20 00:00:00']); - $article = $this->dispatch(new UpdateArticle($article, 'Title', 'Body', false)); + $article = $this->dispatch(new UpdateArticle($article, 'Title', 'Body', false)); - $this->assertSame('2020-06-20 00:00:00', $article->submittedAt()->format('Y-m-d H:i:s')); - $this->assertTrue($article->isNotPublished()); - } -} + $this->assertSame('2020-06-20 00:00:00', $article->submittedAt()->format('Y-m-d H:i:s')); + $this->assertTrue($article->isNotPublished()); +}); diff --git a/tests/Integration/Jobs/UpdateProfileTest.php b/tests/Integration/Jobs/UpdateProfileTest.php index 98c53ea43..62e0a9355 100644 --- a/tests/Integration/Jobs/UpdateProfileTest.php +++ b/tests/Integration/Jobs/UpdateProfileTest.php @@ -1,46 +1,38 @@ createUser(); +test('we can update a user profile', function () { + $user = $this->createUser(); - Event::fake(); + Event::fake(); - $updatedUser = $this->dispatch(new UpdateProfile($user, ['bio' => 'my bio', 'name' => 'John Doe Junior'])); + $updatedUser = $this->dispatch(new UpdateProfile($user, ['bio' => 'my bio', 'name' => 'John Doe Junior'])); - $this->assertEquals('my bio', $updatedUser->bio()); - $this->assertEquals('John Doe Junior', $updatedUser->name()); - $this->assertDatabaseMissing('users', ['id' => $user->id, 'email_verified_at' => null]); + $this->assertEquals('my bio', $updatedUser->bio()); + $this->assertEquals('John Doe Junior', $updatedUser->name()); + $this->assertDatabaseMissing('users', ['id' => $user->id, 'email_verified_at' => null]); - Event::assertNotDispatched(EmailAddressWasChanged::class); - } + Event::assertNotDispatched(EmailAddressWasChanged::class); +}); - /** @test */ - public function changing_the_email_address_emits_an_event() - { - $user = $this->createUser(); +test('changing the email address emits an event', function () { + $user = $this->createUser(); - Event::fake(); + Event::fake(); - $this->dispatch(new UpdateProfile($user, ['email' => 'foo@example.com'])); + $this->dispatch(new UpdateProfile($user, ['email' => 'foo@example.com'])); - $this->assertDatabaseHas('users', ['id' => $user->id, 'email_verified_at' => null]); + $this->assertDatabaseHas('users', ['id' => $user->id, 'email_verified_at' => null]); - Event::assertDispatched(EmailAddressWasChanged::class, function (EmailAddressWasChanged $event) { - return $event->user->email === 'foo@example.com'; - }); - } -} + Event::assertDispatched(EmailAddressWasChanged::class, function (EmailAddressWasChanged $event) { + return $event->user->email === 'foo@example.com'; + }); +}); diff --git a/tests/Integration/Models/ArticleTest.php b/tests/Integration/Models/ArticleTest.php index 413e33aad..8dfb9b59d 100644 --- a/tests/Integration/Models/ArticleTest.php +++ b/tests/Integration/Models/ArticleTest.php @@ -1,84 +1,74 @@ count(2)->create(); - $articles = Article::factory()->count(3)->create(); - - // Like the second article twice. - $articles[1]->likedBy($users[0]); - $articles[1]->likedBy($users[1]); - - // Like the first article once. - $articles[0]->likedBy($users[0]); - - $popularArticles = Article::popular()->get(); - - $this->assertEquals($articles[1]->title, $popularArticles[0]->title); - $this->assertEquals($articles[0]->title, $popularArticles[1]->title); - $this->assertEquals($articles[2]->title, $popularArticles[2]->title); - } - - /** @test */ - public function we_can_get_trending_articles() - { - $users = User::factory()->count(3)->create(); - $articles = Article::factory()->count(3)->create(); - - // Like the first article by two users. - $articles[0]->likedBy($users[0]); - $articles[0]->likedBy($users[1]); - - // Update the like timestamp outside of the trending window. - $articles[0]->likesRelation()->update(['created_at' => now()->subWeeks(2)]); - $articles[0]->unsetRelation('likesRelation'); - - // Like the remaining articles once, but inside the trending window. - $articles[1]->likedBy($users[0]); - $articles[2]->likedBy($users[0]); - - $trendingArticles = Article::trending()->get(); - - // The first article has more likes, but outside the trending window - // so should be returned last. - $this->assertEquals($articles[1]->title, $trendingArticles[0]->title); - $this->assertEquals($articles[2]->title, $trendingArticles[1]->title); - $this->assertEquals($articles[0]->title, $trendingArticles[2]->title); - } - - /** @test */ - public function pinned_articles_are_returned_first() - { - $articleOne = Article::factory()->create([ - 'submitted_at' => now(), - 'approved_at' => now(), - ]); - $articleTwo = Article::factory()->create([ - 'submitted_at' => now()->subDay(), - 'approved_at' => now(), - ]); - $articleThree = Article::factory()->create([ - 'submitted_at' => now()->subDays(3), - 'approved_at' => now(), - 'is_pinned' => true, - ]); - - $recentArticles = Article::recent()->get(); - - $this->assertEquals($articleThree->title, $recentArticles[0]->title); - $this->assertEquals($articleOne->title, $recentArticles[1]->title); - $this->assertEquals($articleTwo->title, $recentArticles[2]->title); - } -} +uses(TestCase::class); +uses(RefreshDatabase::class); + +test('we can get most popular articles', function () { + $users = User::factory()->count(2)->create(); + $articles = Article::factory()->count(3)->create(); + + // Like the second article twice. + $articles[1]->likedBy($users[0]); + $articles[1]->likedBy($users[1]); + + // Like the first article once. + $articles[0]->likedBy($users[0]); + + $popularArticles = Article::popular()->get(); + + $this->assertEquals($articles[1]->title, $popularArticles[0]->title); + $this->assertEquals($articles[0]->title, $popularArticles[1]->title); + $this->assertEquals($articles[2]->title, $popularArticles[2]->title); +}); + +test('we can get trending articles', function () { + $users = User::factory()->count(3)->create(); + $articles = Article::factory()->count(3)->create(); + + // Like the first article by two users. + $articles[0]->likedBy($users[0]); + $articles[0]->likedBy($users[1]); + + // Update the like timestamp outside of the trending window. + $articles[0]->likesRelation()->update(['created_at' => now()->subWeeks(2)]); + $articles[0]->unsetRelation('likesRelation'); + + // Like the remaining articles once, but inside the trending window. + $articles[1]->likedBy($users[0]); + $articles[2]->likedBy($users[0]); + + $trendingArticles = Article::trending()->get(); + + // The first article has more likes, but outside the trending window + // so should be returned last. + $this->assertEquals($articles[1]->title, $trendingArticles[0]->title); + $this->assertEquals($articles[2]->title, $trendingArticles[1]->title); + $this->assertEquals($articles[0]->title, $trendingArticles[2]->title); +}); + +test('pinned articles are returned first', function () { + $articleOne = Article::factory()->create([ + 'submitted_at' => now(), + 'approved_at' => now(), + ]); + $articleTwo = Article::factory()->create([ + 'submitted_at' => now()->subDay(), + 'approved_at' => now(), + ]); + $articleThree = Article::factory()->create([ + 'submitted_at' => now()->subDays(3), + 'approved_at' => now(), + 'is_pinned' => true, + ]); + + $recentArticles = Article::recent()->get(); + + $this->assertEquals($articleThree->title, $recentArticles[0]->title); + $this->assertEquals($articleOne->title, $recentArticles[1]->title); + $this->assertEquals($articleTwo->title, $recentArticles[2]->title); +}); diff --git a/tests/Integration/Models/ReplyTest.php b/tests/Integration/Models/ReplyTest.php index 8b16ce253..0114d7f2e 100644 --- a/tests/Integration/Models/ReplyTest.php +++ b/tests/Integration/Models/ReplyTest.php @@ -1,30 +1,24 @@ createUser(); +test('we can like and unlike reply', function () { + $user = $this->createUser(); - $reply = Reply::factory()->create(); + $reply = Reply::factory()->create(); - $this->assertFalse($reply->isLikedBy($user)); + $this->assertFalse($reply->isLikedBy($user)); - $reply->likedBy($user); + $reply->likedBy($user); - $this->assertTrue($reply->isLikedBy($user)); + $this->assertTrue($reply->isLikedBy($user)); - $reply->dislikedBy($user); + $reply->dislikedBy($user); - $this->assertFalse($reply->isLikedBy($user)); - } -} + $this->assertFalse($reply->isLikedBy($user)); +}); diff --git a/tests/Integration/Models/SubscriptionTest.php b/tests/Integration/Models/SubscriptionTest.php index ffb5ef5cd..3caec3324 100644 --- a/tests/Integration/Models/SubscriptionTest.php +++ b/tests/Integration/Models/SubscriptionTest.php @@ -1,22 +1,16 @@ create()->uuid(); +it('can get a subscription by its uuid', function () { + $uuid = Subscription::factory()->create()->uuid(); - $subscription = Subscription::findByUuidOrFail($uuid); + $subscription = Subscription::findByUuidOrFail($uuid); - $this->assertEquals($uuid, $subscription->uuid()); - } -} + $this->assertEquals($uuid, $subscription->uuid()); +}); diff --git a/tests/Integration/Models/ThreadTest.php b/tests/Integration/Models/ThreadTest.php index a1b30cce8..21c57295a 100644 --- a/tests/Integration/Models/ThreadTest.php +++ b/tests/Integration/Models/ThreadTest.php @@ -1,185 +1,158 @@ create(['slug' => 'foo']); - /** @test */ - public function it_can_find_by_slug() - { - Thread::factory()->create(['slug' => 'foo']); + $this->assertInstanceOf(Thread::class, Thread::findBySlug('foo')); +}); - $this->assertInstanceOf(Thread::class, Thread::findBySlug('foo')); - } +it('can give an excerpt of its body', function () { + $thread = Thread::factory()->make(['body' => 'This is a pretty long text.']); - /** @test */ - public function it_can_give_an_excerpt_of_its_body() - { - $thread = Thread::factory()->make(['body' => 'This is a pretty long text.']); + $this->assertEquals('This is...', $thread->excerpt(7)); +}); - $this->assertEquals('This is...', $thread->excerpt(7)); - } +test('html in excerpts is html encoded', function () { + $thread = Thread::factory()->make(['body' => '

Thread body

']); - /** @test */ - public function html_in_excerpts_is_html_encoded() - { - $thread = Thread::factory()->make(['body' => '

Thread body

']); + $this->assertEquals("<p>Thread body</p>\n", $thread->excerpt()); +}); - $this->assertEquals("<p>Thread body</p>\n", $thread->excerpt()); - } +test('its conversation is old when the oldest reply was six months ago', function () { + $thread = Thread::factory()->create(); + $thread->repliesRelation()->save(Reply::factory()->make(['created_at' => now()->subMonths(7)])); - /** @test */ - public function its_conversation_is_old_when_the_oldest_reply_was_six_months_ago() - { - $thread = Thread::factory()->create(); - $thread->repliesRelation()->save(Reply::factory()->make(['created_at' => now()->subMonths(7)])); + $this->assertTrue($thread->isConversationOld()); - $this->assertTrue($thread->isConversationOld()); + $thread = Thread::factory()->create(); + $thread->repliesRelation()->save(Reply::factory()->make()); - $thread = Thread::factory()->create(); - $thread->repliesRelation()->save(Reply::factory()->make()); + $this->assertFalse($thread->isConversationOld()); +}); - $this->assertFalse($thread->isConversationOld()); - } +test('its conversation is old when there are no replies but the creation date was six months ago', function () { + $thread = Thread::factory()->create(['created_at' => now()->subMonths(7)]); - /** @test */ - public function its_conversation_is_old_when_there_are_no_replies_but_the_creation_date_was_six_months_ago() - { - $thread = Thread::factory()->create(['created_at' => now()->subMonths(7)]); + $this->assertTrue($thread->isConversationOld()); - $this->assertTrue($thread->isConversationOld()); + $thread = Thread::factory()->create(); - $thread = Thread::factory()->create(); + $this->assertFalse($thread->isConversationOld()); +}); - $this->assertFalse($thread->isConversationOld()); - } +test('we can mark and unmark a reply as the solution', function () { + $thread = Thread::factory()->create(); + $reply = Reply::factory()->create(['replyable_id' => $thread->id()]); - /** @test */ - public function we_can_mark_and_unmark_a_reply_as_the_solution() - { - $thread = Thread::factory()->create(); - $reply = Reply::factory()->create(['replyable_id' => $thread->id()]); + $this->assertFalse($thread->isSolutionReply($reply)); - $this->assertFalse($thread->isSolutionReply($reply)); + $thread->markSolution($reply); - $thread->markSolution($reply); + $this->assertTrue($thread->isSolutionReply($reply)); - $this->assertTrue($thread->isSolutionReply($reply)); + $thread->unmarkSolution(); - $thread->unmarkSolution(); + $this->assertFalse($thread->isSolutionReply($reply)); +}); - $this->assertFalse($thread->isSolutionReply($reply)); - } +it('can retrieve the latest threads in a correct order', function () { + $threadUpdatedYesterday = createThreadFromYesterday(); + $threadFromToday = createThreadFromToday(); + $threadFromTwoDaysAgo = createThreadFromTwoDaysAgo(); - /** @test */ - public function it_can_retrieve_the_latest_threads_in_a_correct_order() - { - $threadUpdatedYesterday = $this->createThreadFromYesterday(); - $threadFromToday = $this->createThreadFromToday(); - $threadFromTwoDaysAgo = $this->createThreadFromTwoDaysAgo(); + $threads = Thread::feed(); - $threads = Thread::feed(); + $this->assertTrue($threadFromToday->is($threads->first()), 'First thread is incorrect'); + $this->assertTrue($threadUpdatedYesterday->is($threads->slice(1)->first()), 'Second thread is incorrect'); + $this->assertTrue($threadFromTwoDaysAgo->is($threads->last()), 'Last thread is incorrect'); +}); - $this->assertTrue($threadFromToday->is($threads->first()), 'First thread is incorrect'); - $this->assertTrue($threadUpdatedYesterday->is($threads->slice(1)->first()), 'Second thread is incorrect'); - $this->assertTrue($threadFromTwoDaysAgo->is($threads->last()), 'Last thread is incorrect'); - } +it('can retrieve only resolved threads', function () { + createThreadFromToday(); + $resolvedThread = createResolvedThread(); - /** @test */ - public function it_can_retrieve_only_resolved_threads() - { - $this->createThreadFromToday(); - $resolvedThread = $this->createResolvedThread(); + $threads = Thread::feedQuery()->resolved()->get(); - $threads = Thread::feedQuery()->resolved()->get(); + $this->assertCount(1, $threads); + $this->assertTrue($resolvedThread->is($threads->first())); +}); - $this->assertCount(1, $threads); - $this->assertTrue($resolvedThread->is($threads->first())); - } +it('can retrieve only active threads', function () { + createThreadFromToday(); + $activeThread = createActiveThread(); - /** @test */ - public function it_can_retrieve_only_active_threads() - { - $this->createThreadFromToday(); - $activeThread = $this->createActiveThread(); + $threads = Thread::feedQuery()->active()->get(); - $threads = Thread::feedQuery()->active()->get(); + $this->assertCount(1, $threads); + $this->assertTrue($activeThread->is($threads->first())); +}); - $this->assertCount(1, $threads); - $this->assertTrue($activeThread->is($threads->first())); - } +it('generates a slug when valid url characters provided', function () { + $thread = Thread::factory()->make(['slug' => 'Help with eloquent']); - /** @test */ - public function it_generates_a_slug_when_valid_url_characters_provided() - { - $thread = Thread::factory()->make(['slug' => 'Help with eloquent']); + $this->assertEquals('help-with-eloquent', $thread->slug()); +}); - $this->assertEquals('help-with-eloquent', $thread->slug()); - } +it('generates a unique slug when valid url characters provided', function () { + $threadOne = Thread::factory()->create(['slug' => 'Help with eloquent']); + $threadTwo = Thread::factory()->create(['slug' => 'Help with eloquent']); - /** @test */ - public function it_generates_a_unique_slug_when_valid_url_characters_provided() - { - $threadOne = Thread::factory()->create(['slug' => 'Help with eloquent']); - $threadTwo = Thread::factory()->create(['slug' => 'Help with eloquent']); + $this->assertEquals('help-with-eloquent-1', $threadTwo->slug()); +}); - $this->assertEquals('help-with-eloquent-1', $threadTwo->slug()); - } +it('generates a slug when invalid url characters provided', function () { + $thread = Thread::factory()->make(['slug' => '한글 테스트']); - /** @test */ - public function it_generates_a_slug_when_invalid_url_characters_provided() - { - $thread = Thread::factory()->make(['slug' => '한글 테스트']); + // When providing a slug with invalid url characters, a random 5 character string is returned. + $this->assertMatchesRegularExpression('/\w{5}/', $thread->slug()); +}); - // When providing a slug with invalid url characters, a random 5 character string is returned. - $this->assertMatchesRegularExpression('/\w{5}/', $thread->slug()); - } +// Helpers +function createThreadFromToday(): Thread +{ + $today = Carbon::now(); - private function createThreadFromToday(): Thread - { - $today = Carbon::now(); + return Thread::factory()->create(['created_at' => $today]); +} - return Thread::factory()->create(['created_at' => $today]); - } +function createThreadFromYesterday(): Thread +{ + $yesterday = Carbon::yesterday(); - private function createThreadFromYesterday(): Thread - { - $yesterday = Carbon::yesterday(); + return Thread::factory()->create(['created_at' => $yesterday]); +} - return Thread::factory()->create(['created_at' => $yesterday]); - } +function createThreadFromTwoDaysAgo(): Thread +{ + $twoDaysAgo = Carbon::now()->subDay(2); - private function createThreadFromTwoDaysAgo(): Thread - { - $twoDaysAgo = Carbon::now()->subDay(2); + return Thread::factory()->create(['created_at' => $twoDaysAgo]); +} - return Thread::factory()->create(['created_at' => $twoDaysAgo]); - } +function createResolvedThread() +{ + $thread = createThreadFromToday(); + $reply = Reply::factory()->create(); + $thread->markSolution($reply); - private function createResolvedThread() - { - $thread = $this->createThreadFromToday(); - $reply = Reply::factory()->create(); - $thread->markSolution($reply); + return $thread; +} - return $thread; - } +function createActiveThread() +{ + $thread = createThreadFromToday(); + $reply = Reply::factory()->create(); + $reply->to($thread); + $reply->save(); - private function createActiveThread() - { - $thread = $this->createThreadFromToday(); - $reply = Reply::factory()->create(); - $reply->to($thread); - $reply->save(); - - return $thread; - } + return $thread; } diff --git a/tests/Integration/Models/UserTest.php b/tests/Integration/Models/UserTest.php index 1341dba27..5d9e2f872 100644 --- a/tests/Integration/Models/UserTest.php +++ b/tests/Integration/Models/UserTest.php @@ -1,70 +1,57 @@ createUser(['username' => 'johndoe']); +it('can find by username', function () { + $this->createUser(['username' => 'johndoe']); - $this->assertInstanceOf(User::class, User::findByUsername('johndoe')); - } + $this->assertInstanceOf(User::class, User::findByUsername('johndoe')); +}); - /** @test */ - public function it_can_find_by_email_address() - { - $this->createUser(['email' => 'john@example.com']); +it('can find by email address', function () { + $this->createUser(['email' => 'john@example.com']); - $this->assertInstanceOf(User::class, User::findByEmailAddress('john@example.com')); - } + $this->assertInstanceOf(User::class, User::findByEmailAddress('john@example.com')); +}); - /** @test */ - public function it_can_return_the_amount_of_solutions_that_were_given() - { - $user = User::factory()->create(); - $this->createTwoSolutionReplies($user); +it('can return the amount of solutions that were given', function () { + $user = User::factory()->create(); + createTwoSolutionReplies($user); - $this->assertEquals(2, $user->countSolutions()); - } + $this->assertEquals(2, $user->countSolutions()); +}); - /** @test */ - public function it_can_determine_if_a_given_user_is_the_logged_in_user() - { - $user = $this->login(); +it('can determine if a given user is the logged in user', function () { + $user = $this->login(); - $this->assertTrue($user->isLoggedInUser()); - } + $this->assertTrue($user->isLoggedInUser()); +}); - /** @test */ - public function it_can_determine_if_a_given_user_is_not_the_logged_in_user() - { - $user = $this->createUser(); - $this->login([ - 'username' => 'janedoe', - 'email' => 'jane@example.com', - ]); +it('can determine if a given user is not the logged in user', function () { + $user = $this->createUser(); + $this->login([ + 'username' => 'janedoe', + 'email' => 'jane@example.com', + ]); - $this->assertFalse($user->isLoggedInUser()); - } + $this->assertFalse($user->isLoggedInUser()); +}); - private function createTwoSolutionReplies(User $user) - { - $thread = Thread::factory()->create(); - $reply = Reply::factory()->create(['replyable_id' => $thread->id(), 'author_id' => $user->id()]); - $thread->markSolution($reply); +// Helpers +function createTwoSolutionReplies(User $user) +{ + $thread = Thread::factory()->create(); + $reply = Reply::factory()->create(['replyable_id' => $thread->id(), 'author_id' => $user->id()]); + $thread->markSolution($reply); - $thread = Thread::factory()->create(); - $reply = Reply::factory()->create(['replyable_id' => $thread->id(), 'author_id' => $user->id()]); - $thread->markSolution($reply); - } + $thread = Thread::factory()->create(); + $reply = Reply::factory()->create(['replyable_id' => $thread->id(), 'author_id' => $user->id()]); + $thread->markSolution($reply); } diff --git a/tests/Integration/Queries/SearchUsersTest.php b/tests/Integration/Queries/SearchUsersTest.php index 3b690b630..bd88c0e73 100644 --- a/tests/Integration/Queries/SearchUsersTest.php +++ b/tests/Integration/Queries/SearchUsersTest.php @@ -1,23 +1,17 @@ create(['name' => 'Freek Murze', 'email' => 'freek@freek.com']); - User::factory()->create(['name' => 'Frederick Vanbrabant', 'email' => 'vanbra@vanbra.com']); +it('can search by name or email or username', function () { + User::factory()->create(['name' => 'Freek Murze', 'email' => 'freek@freek.com']); + User::factory()->create(['name' => 'Frederick Vanbrabant', 'email' => 'vanbra@vanbra.com']); - $this->assertCount(2, SearchUsers::get('fre')); - $this->assertCount(1, SearchUsers::get('van')); - } -} + $this->assertCount(2, SearchUsers::get('fre')); + $this->assertCount(1, SearchUsers::get('van')); +}); diff --git a/tests/Integration/Rules/PasscheckRuleTest.php b/tests/Integration/Rules/PasscheckRuleTest.php index e6bd7445b..2d2608b96 100644 --- a/tests/Integration/Rules/PasscheckRuleTest.php +++ b/tests/Integration/Rules/PasscheckRuleTest.php @@ -1,34 +1,26 @@ login(['password' => bcrypt('foo')]); - $rule = new PasscheckRule(); +it('passes when the password is correct', function () { + $this->login(['password' => bcrypt('foo')]); + $rule = new PasscheckRule(); - $result = $rule->passes('password', 'foo'); + $result = $rule->passes('password', 'foo'); - $this->assertTrue($result); - } + $this->assertTrue($result); +}); - /** @test */ - public function it_fails_when_the_password_is_incorrect() - { - $this->login(); - $rule = new PasscheckRule(); +it('fails when the password is incorrect', function () { + $this->login(); + $rule = new PasscheckRule(); - $result = $rule->passes('password', 'foo'); + $result = $rule->passes('password', 'foo'); - $this->assertFalse($result); - } -} + $this->assertFalse($result); +}); diff --git a/tests/Unit/Commands/PostArticleToTwitterTest.php b/tests/Unit/Commands/PostArticleToTwitterTest.php index 60bfd460e..22315b365 100644 --- a/tests/Unit/Commands/PostArticleToTwitterTest.php +++ b/tests/Unit/Commands/PostArticleToTwitterTest.php @@ -1,7 +1,5 @@ create([ - 'title' => 'My First Article', - 'submitted_at' => now(), - 'approved_at' => now(), - ]); - - (new PostArticleToTwitter())->handle(new AnonymousNotifiable()); - - Notification::assertSentTo( - new AnonymousNotifiable(), - PostArticleToTwitterNotification::class, - function ($notification, $channels, $notifiable) use ($article) { - $tweet = $notification->generateTweet(); - - return - Str::contains($tweet, 'My First Article') && - Str::contains($tweet, route('articles.show', $article->slug())); - }, - ); - - $this->assertTrue($article->fresh()->isShared()); - } - - /** @test */ - public function articles_are_shared_with_twitter_handle() - { - $user = $this->createUser([ - 'twitter' => '_joedixon', - ]); - - Article::factory()->create([ - 'author_id' => $user->id(), - 'submitted_at' => now(), - 'approved_at' => now(), - ]); - - (new PostArticleToTwitter())->handle(new AnonymousNotifiable()); - - Notification::assertSentTo( - new AnonymousNotifiable(), - PostArticleToTwitterNotification::class, - function ($notification, $channels, $notifiable) { - return Str::contains($notification->generateTweet(), '@_joedixon'); - }, - ); - } - - /** @test */ - public function articles_are_shared_with_name_when_no_twitter_handle() - { - $user = $this->createUser([ - 'name' => 'Joe Dixon', - 'twitter' => null, - ]); - - Article::factory()->create([ - 'author_id' => $user->id(), - 'submitted_at' => now(), - 'approved_at' => now(), - ]); - - (new PostArticleToTwitter())->handle(new AnonymousNotifiable()); - - Notification::assertSentTo( - new AnonymousNotifiable(), - PostArticleToTwitterNotification::class, - function ($notification, $channels, $notifiable) { - return Str::contains($notification->generateTweet(), 'Joe Dixon'); - }, - ); - } - - /** @test */ - public function already_shared_articles_are_not_shared_again() - { - Article::factory()->create([ - 'submitted_at' => now(), - 'approved_at' => now(), - 'shared_at' => now(), - ]); - - (new PostArticleToTwitter())->handle(new AnonymousNotifiable()); - - Notification::assertNothingSent(); - } - - /** @test */ - public function unapproved_articles_are_not_shared() - { - Article::factory()->create([ - 'submitted_at' => now(), - ]); - - (new PostArticleToTwitter())->handle(new AnonymousNotifiable()); - - Notification::assertNothingSent(); - } - - /** @test */ - public function unsubmitted_articles_are_not_shared() - { - Article::factory()->create(); - - (new PostArticleToTwitter())->handle(new AnonymousNotifiable()); - - Notification::assertNothingSent(); - } -} +uses(TestCase::class); +uses(DatabaseMigrations::class); + +beforeEach(function () { + Notification::fake(); +}); + +test('published articles can be shared on twitter', function () { + $article = Article::factory()->create([ + 'title' => 'My First Article', + 'submitted_at' => now(), + 'approved_at' => now(), + ]); + + (new PostArticleToTwitter())->handle(new AnonymousNotifiable()); + + Notification::assertSentTo( + new AnonymousNotifiable(), + PostArticleToTwitterNotification::class, + function ($notification, $channels, $notifiable) use ($article) { + $tweet = $notification->generateTweet(); + + return + Str::contains($tweet, 'My First Article') && + Str::contains($tweet, route('articles.show', $article->slug())); + }, + ); + + $this->assertTrue($article->fresh()->isShared()); +}); + +test('articles are shared with twitter handle', function () { + $user = $this->createUser([ + 'twitter' => '_joedixon', + ]); + + Article::factory()->create([ + 'author_id' => $user->id(), + 'submitted_at' => now(), + 'approved_at' => now(), + ]); + + (new PostArticleToTwitter())->handle(new AnonymousNotifiable()); + + Notification::assertSentTo( + new AnonymousNotifiable(), + PostArticleToTwitterNotification::class, + function ($notification, $channels, $notifiable) { + return Str::contains($notification->generateTweet(), '@_joedixon'); + }, + ); +}); + +test('articles are shared with name when no twitter handle', function () { + $user = $this->createUser([ + 'name' => 'Joe Dixon', + 'twitter' => null, + ]); + + Article::factory()->create([ + 'author_id' => $user->id(), + 'submitted_at' => now(), + 'approved_at' => now(), + ]); + + (new PostArticleToTwitter())->handle(new AnonymousNotifiable()); + + Notification::assertSentTo( + new AnonymousNotifiable(), + PostArticleToTwitterNotification::class, + function ($notification, $channels, $notifiable) { + return Str::contains($notification->generateTweet(), 'Joe Dixon'); + }, + ); +}); + +test('already shared articles are not shared again', function () { + Article::factory()->create([ + 'submitted_at' => now(), + 'approved_at' => now(), + 'shared_at' => now(), + ]); + + (new PostArticleToTwitter())->handle(new AnonymousNotifiable()); + + Notification::assertNothingSent(); +}); + +test('unapproved articles are not shared', function () { + Article::factory()->create([ + 'submitted_at' => now(), + ]); + + (new PostArticleToTwitter())->handle(new AnonymousNotifiable()); + + Notification::assertNothingSent(); +}); + +test('unsubmitted articles are not shared', function () { + Article::factory()->create(); + + (new PostArticleToTwitter())->handle(new AnonymousNotifiable()); + + Notification::assertNothingSent(); +}); diff --git a/tests/Unit/Rules/DoesNotContainUrlRuleTest.php b/tests/Unit/Rules/DoesNotContainUrlRuleTest.php index c9c43578d..16a15483d 100644 --- a/tests/Unit/Rules/DoesNotContainUrlRuleTest.php +++ b/tests/Unit/Rules/DoesNotContainUrlRuleTest.php @@ -1,33 +1,22 @@ assertFalse( - (new DoesNotContainUrlRule())->passes('foo', 'This is a string http://example.com with an url in it.'), - ); - } - /** @test */ - public function it_passes_when_no_url_is_present() - { - $this->assertTrue( - (new DoesNotContainUrlRule())->passes('foo', 'This is a string without an url in it.'), - ); - } +it('detects a url in a string', function () { + $this->assertFalse( + (new DoesNotContainUrlRule())->passes('foo', 'This is a string http://example.com with an url in it.'), + ); +}); + +it('passes when no url is present', function () { + $this->assertTrue( + (new DoesNotContainUrlRule())->passes('foo', 'This is a string without an url in it.'), + ); +}); - /** @test */ - public function it_passes_when_extra_spaces_are_present() - { - $this->assertTrue( - (new DoesNotContainUrlRule())->passes('foo', 'This is a string with extra spaces.'), - ); - } -} +it('passes when extra spaces are present', function () { + $this->assertTrue( + (new DoesNotContainUrlRule())->passes('foo', 'This is a string with extra spaces.'), + ); +}); diff --git a/tests/Unit/Rules/HttpImageRuleTest.php b/tests/Unit/Rules/HttpImageRuleTest.php index efbc32ce2..f57950468 100644 --- a/tests/Unit/Rules/HttpImageRuleTest.php +++ b/tests/Unit/Rules/HttpImageRuleTest.php @@ -1,25 +1,16 @@ assertTrue( - (new HttpImageRule())->passes('body', 'some text ![](https://link.com)'), - ); - } - /** @test */ - public function it_fails_when_http_links_are_detected() - { - $this->assertFalse( - (new HttpImageRule())->passes('body', 'some text ![](http://link.com)'), - ); - } -} +it('passes when no http links are detected', function () { + $this->assertTrue( + (new HttpImageRule())->passes('body', 'some text ![](https://link.com)'), + ); +}); + +it('fails when http links are detected', function () { + $this->assertFalse( + (new HttpImageRule())->passes('body', 'some text ![](http://link.com)'), + ); +}); diff --git a/tests/Unit/Social/GithubUserTest.php b/tests/Unit/Social/GithubUserTest.php index 4f39e3aa3..6bdf9476c 100644 --- a/tests/Unit/Social/GithubUserTest.php +++ b/tests/Unit/Social/GithubUserTest.php @@ -1,26 +1,17 @@ Carbon::now()->subWeeks(3)]); - $this->assertFalse($user->isTooYoung()); - } +it('can determine if the user is older than two weeks', function () { + $user = new GithubUser(['created_at' => Carbon::now()->subWeeks(3)]); + + $this->assertFalse($user->isTooYoung()); +}); - /** @test */ - public function it_can_determine_if_the_user_is_younger_than_two_weeks() - { - $user = new GithubUser(['created_at' => Carbon::now()->subWeek()]); +it('can determine if the user is younger than two weeks', function () { + $user = new GithubUser(['created_at' => Carbon::now()->subWeek()]); - $this->assertTrue($user->isTooYoung()); - } -} + $this->assertTrue($user->isTooYoung()); +}); diff --git a/tests/Unit/UserTest.php b/tests/Unit/UserTest.php index ddcf3f218..aebbe15f7 100644 --- a/tests/Unit/UserTest.php +++ b/tests/Unit/UserTest.php @@ -1,17 +1,10 @@ 'foo']); - $this->assertTrue($user->hasPassword()); - } -} +it('can determine if it has a password set', function () { + $user = new User(['password' => 'foo']); + + $this->assertTrue($user->hasPassword()); +}); From 7df880dcbe2a6ca57fbc77e999f79871e480ac5e Mon Sep 17 00:00:00 2001 From: Shift Date: Thu, 2 Sep 2021 17:16:29 +0000 Subject: [PATCH 04/14] Adopt expectation API --- tests/Feature/AdminTest.php | 22 ++++++------ tests/Feature/ArticleTest.php | 2 +- tests/Feature/AuthTest.php | 4 +-- tests/Feature/SettingsTest.php | 4 +-- tests/Feature/SubscriptionsTest.php | 4 +-- tests/Integration/Jobs/BanUserTest.php | 2 +- tests/Integration/Jobs/CreateArticleTest.php | 10 +++--- tests/Integration/Jobs/CreateReplyTest.php | 2 +- tests/Integration/Jobs/CreateThreadTest.php | 2 +- tests/Integration/Jobs/LikeArticleTest.php | 4 +-- tests/Integration/Jobs/LikeReplyTest.php | 4 +-- tests/Integration/Jobs/LikeThreadTest.php | 4 +-- tests/Integration/Jobs/RegisterUserTest.php | 2 +- .../Jobs/SubscribeToSubscriptionAbleTest.php | 4 +-- tests/Integration/Jobs/UnbanUserTest.php | 2 +- tests/Integration/Jobs/UnlikeArticleTest.php | 4 +-- tests/Integration/Jobs/UnlikeReplyTest.php | 4 +-- tests/Integration/Jobs/UnlikeThreadTest.php | 4 +-- .../UnsubscribeFromSubscriptionAbleTest.php | 4 +-- tests/Integration/Jobs/UpdateArticleTest.php | 8 ++--- tests/Integration/Jobs/UpdateProfileTest.php | 4 +-- tests/Integration/Models/ArticleTest.php | 18 +++++----- tests/Integration/Models/ReplyTest.php | 6 ++-- tests/Integration/Models/SubscriptionTest.php | 2 +- tests/Integration/Models/ThreadTest.php | 34 +++++++++---------- tests/Integration/Models/UserTest.php | 10 +++--- tests/Integration/Queries/SearchUsersTest.php | 4 +-- tests/Integration/Rules/PasscheckRuleTest.php | 4 +-- .../Commands/PostArticleToTwitterTest.php | 2 +- tests/Unit/Social/GithubUserTest.php | 4 +-- tests/Unit/UserTest.php | 2 +- 31 files changed, 93 insertions(+), 93 deletions(-) diff --git a/tests/Feature/AdminTest.php b/tests/Feature/AdminTest.php index da4b2323a..e3040f8e9 100644 --- a/tests/Feature/AdminTest.php +++ b/tests/Feature/AdminTest.php @@ -186,7 +186,7 @@ $this->put("/admin/articles/{$article->slug()}/approve") ->assertRedirectedTo('/login'); - $this->assertNull($article->fresh()->approvedAt()); + expect($article->fresh()->approvedAt())->toBeNull(); }); test('admins can disapprove articles', function () { @@ -196,7 +196,7 @@ $this->put("/admin/articles/{$article->slug()}/disapprove"); - $this->assertNull($article->fresh()->approvedAt()); + expect($article->fresh()->approvedAt())->toBeNull(); }); test('moderators can disapprove articles', function () { @@ -206,7 +206,7 @@ $this->put("/admin/articles/{$article->slug()}/disapprove"); - $this->assertNull($article->fresh()->approvedAt()); + expect($article->fresh()->approvedAt())->toBeNull(); }); test('users cannot disapprove articles', function () { @@ -234,7 +234,7 @@ $this->put("/admin/articles/{$article->slug()}/pinned"); - $this->assertTrue($article->fresh()->isPinned()); + expect($article->fresh()->isPinned())->toBeTrue(); }); test('moderators can pin articles', function () { @@ -244,7 +244,7 @@ $this->put("/admin/articles/{$article->slug()}/pinned"); - $this->assertTrue($article->fresh()->isPinned()); + expect($article->fresh()->isPinned())->toBeTrue(); }); test('users cannot pin articles', function () { @@ -254,7 +254,7 @@ $this->put("/admin/articles/{$article->slug()}/pinned"); - $this->assertFalse($article->fresh()->isPinned()); + expect($article->fresh()->isPinned())->toBeFalse(); }); test('guests cannot pin articles', function () { @@ -262,7 +262,7 @@ $this->put("/admin/articles/{$article->slug()}/pinned"); - $this->assertFalse($article->fresh()->isPinned()); + expect($article->fresh()->isPinned())->toBeFalse(); }); test('admins can unpin articles', function () { @@ -276,7 +276,7 @@ $this->put("/admin/articles/{$article->slug()}/pinned"); - $this->assertFalse($article->fresh()->isPinned()); + expect($article->fresh()->isPinned())->toBeFalse(); }); test('moderators can unpin articles', function () { @@ -290,7 +290,7 @@ $this->put("/admin/articles/{$article->slug()}/pinned"); - $this->assertFalse($article->fresh()->isPinned()); + expect($article->fresh()->isPinned())->toBeFalse(); }); test('users cannot unpin articles', function () { @@ -304,7 +304,7 @@ $this->put("/admin/articles/{$article->slug()}/pinned"); - $this->assertTrue($article->fresh()->isPinned()); + expect($article->fresh()->isPinned())->toBeTrue(); }); test('guests cannot unpin articles', function () { @@ -316,7 +316,7 @@ $this->put("/admin/articles/{$article->slug()}/pinned"); - $this->assertTrue($article->fresh()->isPinned()); + expect($article->fresh()->isPinned())->toBeTrue(); }); // Helpers diff --git a/tests/Feature/ArticleTest.php b/tests/Feature/ArticleTest.php index c62165928..e8954301d 100644 --- a/tests/Feature/ArticleTest.php +++ b/tests/Feature/ArticleTest.php @@ -226,7 +226,7 @@ 'submitted' => true, ]); - $this->assertSame('2020-06-19 00:00:00', $article->fresh()->submittedAt()->format('Y-m-d H:i:s')); + expect($article->fresh()->submittedAt()->format('Y-m-d H:i:s'))->toBe('2020-06-19 00:00:00'); }); test('users can delete their own articles', function () { diff --git a/tests/Feature/AuthTest.php b/tests/Feature/AuthTest.php index e1169b12c..59530864b 100644 --- a/tests/Feature/AuthTest.php +++ b/tests/Feature/AuthTest.php @@ -183,10 +183,10 @@ // Helpers function assertLoggedIn(): void { - $this->assertTrue(Auth::check()); + expect(Auth::check())->toBeTrue(); } function assertLoggedOut(): void { - $this->assertFalse(Auth::check()); + expect(Auth::check())->toBeFalse(); } diff --git a/tests/Feature/SettingsTest.php b/tests/Feature/SettingsTest.php index af4a92535..2ed704663 100644 --- a/tests/Feature/SettingsTest.php +++ b/tests/Feature/SettingsTest.php @@ -124,11 +124,11 @@ ->seePageIs('/settings') ->dontSee('freektwitter'); - $this->assertEmpty($user->fresh()->twitter()); + expect($user->fresh()->twitter())->toBeEmpty(); }); // Helpers function assertPasswordWasHashedAndSaved(): void { - $this->assertTrue($this->app['hash']->check('QFq^$cz#P@MZa5z7', Auth::user()->getAuthPassword())); + expect($this->app['hash']->check('QFq^$cz#P@MZa5z7', Auth::user()->getAuthPassword()))->toBeTrue(); } diff --git a/tests/Feature/SubscriptionsTest.php b/tests/Feature/SubscriptionsTest.php index 25ac1fcef..30cc139f8 100644 --- a/tests/Feature/SubscriptionsTest.php +++ b/tests/Feature/SubscriptionsTest.php @@ -33,7 +33,7 @@ $thread = $this->dispatch(new CreateThread($this->faker->sentence, $this->faker->text, $user)); - $this->assertTrue($thread->hasSubscriber($user)); + expect($thread->hasSubscriber($user))->toBeTrue(); }); test('thread authors do not receive a notification for a thread they create', function () { @@ -64,7 +64,7 @@ $this->dispatch(new CreateReply($this->faker->text, $user, $thread)); - $this->assertTrue($thread->hasSubscriber($user)); + expect($thread->hasSubscriber($user))->toBeTrue(); }); test('users can manually subscribe to threads', function () { diff --git a/tests/Integration/Jobs/BanUserTest.php b/tests/Integration/Jobs/BanUserTest.php index 4f3b4e7ad..67a95e7b2 100644 --- a/tests/Integration/Jobs/BanUserTest.php +++ b/tests/Integration/Jobs/BanUserTest.php @@ -12,5 +12,5 @@ $bannedUser = $this->dispatch(new BanUser($user)); - $this->assertTrue($bannedUser->isBanned()); + expect($bannedUser->isBanned())->toBeTrue(); }); diff --git a/tests/Integration/Jobs/CreateArticleTest.php b/tests/Integration/Jobs/CreateArticleTest.php index 17e74c335..93cbc7d9c 100644 --- a/tests/Integration/Jobs/CreateArticleTest.php +++ b/tests/Integration/Jobs/CreateArticleTest.php @@ -14,11 +14,11 @@ 'original_url' => 'https://laravel.io', ])); - $this->assertEquals('Title', $article->title()); - $this->assertEquals('Body', $article->body()); - $this->assertEquals('https://laravel.io', $article->canonicalUrl()); - $this->assertNull($article->submittedAt()); - $this->assertTrue($article->isNotPublished()); + expect($article->title())->toEqual('Title'); + expect($article->body())->toEqual('Body'); + expect($article->canonicalUrl())->toEqual('https://laravel.io'); + expect($article->submittedAt())->toBeNull(); + expect($article->isNotPublished())->toBeTrue(); }); test('we can create an article and submit it for approval', function () { diff --git a/tests/Integration/Jobs/CreateReplyTest.php b/tests/Integration/Jobs/CreateReplyTest.php index 81873c8c6..9f2b49ab8 100644 --- a/tests/Integration/Jobs/CreateReplyTest.php +++ b/tests/Integration/Jobs/CreateReplyTest.php @@ -17,5 +17,5 @@ $reply = $this->dispatch(new CreateReply('Foo', $user, $thread)); - $this->assertEquals('Foo', $reply->body()); + expect($reply->body())->toEqual('Foo'); }); diff --git a/tests/Integration/Jobs/CreateThreadTest.php b/tests/Integration/Jobs/CreateThreadTest.php index b07cccd87..135b50648 100644 --- a/tests/Integration/Jobs/CreateThreadTest.php +++ b/tests/Integration/Jobs/CreateThreadTest.php @@ -12,5 +12,5 @@ $thread = $this->dispatch(new CreateThread('Subject', 'Body', $user)); - $this->assertEquals('Subject', $thread->subject()); + expect($thread->subject())->toEqual('Subject'); }); diff --git a/tests/Integration/Jobs/LikeArticleTest.php b/tests/Integration/Jobs/LikeArticleTest.php index a6b3b1672..8548125e8 100644 --- a/tests/Integration/Jobs/LikeArticleTest.php +++ b/tests/Integration/Jobs/LikeArticleTest.php @@ -16,7 +16,7 @@ $this->dispatch(new LikeArticle($article, $user)); - $this->assertTrue($article->fresh()->isLikedBy($user)); + expect($article->fresh()->isLikedBy($user))->toBeTrue(); }); test('we cannot like an article twice', function () { @@ -25,7 +25,7 @@ $this->dispatch(new LikeArticle($article, $user)); - $this->assertTrue($article->fresh()->isLikedBy($user)); + expect($article->fresh()->isLikedBy($user))->toBeTrue(); $this->expectException(CannotLikeItem::class); diff --git a/tests/Integration/Jobs/LikeReplyTest.php b/tests/Integration/Jobs/LikeReplyTest.php index 353e75023..83ff7d133 100644 --- a/tests/Integration/Jobs/LikeReplyTest.php +++ b/tests/Integration/Jobs/LikeReplyTest.php @@ -16,7 +16,7 @@ $this->dispatch(new LikeReply($reply, $user)); - $this->assertTrue($reply->fresh()->isLikedBy($user)); + expect($reply->fresh()->isLikedBy($user))->toBeTrue(); }); test('we cannot like a reply twice', function () { @@ -25,7 +25,7 @@ $this->dispatch(new LikeReply($reply, $user)); - $this->assertTrue($reply->fresh()->isLikedBy($user)); + expect($reply->fresh()->isLikedBy($user))->toBeTrue(); $this->expectException(CannotLikeItem::class); diff --git a/tests/Integration/Jobs/LikeThreadTest.php b/tests/Integration/Jobs/LikeThreadTest.php index 23b92cf2d..b2971d338 100644 --- a/tests/Integration/Jobs/LikeThreadTest.php +++ b/tests/Integration/Jobs/LikeThreadTest.php @@ -16,7 +16,7 @@ $this->dispatch(new LikeThread($thread, $user)); - $this->assertTrue($thread->fresh()->isLikedBy($user)); + expect($thread->fresh()->isLikedBy($user))->toBeTrue(); }); test('we cannot like a thread twice', function () { @@ -25,7 +25,7 @@ $this->dispatch(new LikeThread($thread, $user)); - $this->assertTrue($thread->fresh()->isLikedBy($user)); + expect($thread->fresh()->isLikedBy($user))->toBeTrue(); $this->expectException(CannotLikeItem::class); diff --git a/tests/Integration/Jobs/RegisterUserTest.php b/tests/Integration/Jobs/RegisterUserTest.php index 97a6bc3db..d04d861cd 100644 --- a/tests/Integration/Jobs/RegisterUserTest.php +++ b/tests/Integration/Jobs/RegisterUserTest.php @@ -13,7 +13,7 @@ new RegisterUser('John Doe', 'john@example.com', 'johndoe', 'password', '123', 'johndoe'), ); - $this->assertEquals('John Doe', $user->name()); + expect($user->name())->toEqual('John Doe'); }); test('we cannot create a user with the same email address', function () { diff --git a/tests/Integration/Jobs/SubscribeToSubscriptionAbleTest.php b/tests/Integration/Jobs/SubscribeToSubscriptionAbleTest.php index 47f62965f..ca0010358 100644 --- a/tests/Integration/Jobs/SubscribeToSubscriptionAbleTest.php +++ b/tests/Integration/Jobs/SubscribeToSubscriptionAbleTest.php @@ -12,9 +12,9 @@ $user = $this->createUser(); $thread = Thread::factory()->create(); - $this->assertFalse($thread->hasSubscriber($user)); + expect($thread->hasSubscriber($user))->toBeFalse(); $this->dispatch(new SubscribeToSubscriptionAble($user, $thread)); - $this->assertTrue($thread->hasSubscriber($user)); + expect($thread->hasSubscriber($user))->toBeTrue(); }); diff --git a/tests/Integration/Jobs/UnbanUserTest.php b/tests/Integration/Jobs/UnbanUserTest.php index 282d73fc2..c5ab0063a 100644 --- a/tests/Integration/Jobs/UnbanUserTest.php +++ b/tests/Integration/Jobs/UnbanUserTest.php @@ -13,5 +13,5 @@ $unbannedUser = $this->dispatch(new UnbanUser($user)); - $this->assertFalse($unbannedUser->isBanned()); + expect($unbannedUser->isBanned())->toBeFalse(); }); diff --git a/tests/Integration/Jobs/UnlikeArticleTest.php b/tests/Integration/Jobs/UnlikeArticleTest.php index 79cf8c1b4..20a7bf007 100644 --- a/tests/Integration/Jobs/UnlikeArticleTest.php +++ b/tests/Integration/Jobs/UnlikeArticleTest.php @@ -14,9 +14,9 @@ $article = Article::factory()->create(); $article->likedBy($user); - $this->assertTrue($article->fresh()->isLikedBy($user)); + expect($article->fresh()->isLikedBy($user))->toBeTrue(); $this->dispatch(new UnlikeArticle($article, $user)); - $this->assertFalse($article->fresh()->isLikedBy($user)); + expect($article->fresh()->isLikedBy($user))->toBeFalse(); }); diff --git a/tests/Integration/Jobs/UnlikeReplyTest.php b/tests/Integration/Jobs/UnlikeReplyTest.php index 57cf178da..3be3a0e42 100644 --- a/tests/Integration/Jobs/UnlikeReplyTest.php +++ b/tests/Integration/Jobs/UnlikeReplyTest.php @@ -14,9 +14,9 @@ $reply = Reply::factory()->create(); $reply->likedBy($user); - $this->assertTrue($reply->fresh()->isLikedBy($user)); + expect($reply->fresh()->isLikedBy($user))->toBeTrue(); $this->dispatch(new UnlikeReply($reply, $user)); - $this->assertFalse($reply->fresh()->isLikedBy($user)); + expect($reply->fresh()->isLikedBy($user))->toBeFalse(); }); diff --git a/tests/Integration/Jobs/UnlikeThreadTest.php b/tests/Integration/Jobs/UnlikeThreadTest.php index 6d29bee87..2e5cb4208 100644 --- a/tests/Integration/Jobs/UnlikeThreadTest.php +++ b/tests/Integration/Jobs/UnlikeThreadTest.php @@ -14,9 +14,9 @@ $thread = Thread::factory()->create(); $thread->likedBy($user); - $this->assertTrue($thread->fresh()->isLikedBy($user)); + expect($thread->fresh()->isLikedBy($user))->toBeTrue(); $this->dispatch(new UnlikeThread($thread, $user)); - $this->assertFalse($thread->fresh()->isLikedBy($user)); + expect($thread->fresh()->isLikedBy($user))->toBeFalse(); }); diff --git a/tests/Integration/Jobs/UnsubscribeFromSubscriptionAbleTest.php b/tests/Integration/Jobs/UnsubscribeFromSubscriptionAbleTest.php index 9d8f617ef..202149f03 100644 --- a/tests/Integration/Jobs/UnsubscribeFromSubscriptionAbleTest.php +++ b/tests/Integration/Jobs/UnsubscribeFromSubscriptionAbleTest.php @@ -14,9 +14,9 @@ $thread = Thread::factory()->create(); Subscription::factory()->create(['user_id' => $user->id(), 'subscriptionable_id' => $thread->id()]); - $this->assertTrue($thread->hasSubscriber($user)); + expect($thread->hasSubscriber($user))->toBeTrue(); $this->dispatch(new UnsubscribeFromSubscriptionAble($user, $thread)); - $this->assertFalse($thread->hasSubscriber($user)); + expect($thread->hasSubscriber($user))->toBeFalse(); }); diff --git a/tests/Integration/Jobs/UpdateArticleTest.php b/tests/Integration/Jobs/UpdateArticleTest.php index f9922a15e..46a75e80b 100644 --- a/tests/Integration/Jobs/UpdateArticleTest.php +++ b/tests/Integration/Jobs/UpdateArticleTest.php @@ -14,8 +14,8 @@ $article = $this->dispatch(new UpdateArticle($article, 'Title', 'Body', false)); - $this->assertEquals('Title', $article->title()); - $this->assertEquals('Body', $article->body()); + expect($article->title())->toEqual('Title'); + expect($article->body())->toEqual('Body'); }); test('we can submit an existing article for approval', function () { @@ -33,6 +33,6 @@ $article = $this->dispatch(new UpdateArticle($article, 'Title', 'Body', false)); - $this->assertSame('2020-06-20 00:00:00', $article->submittedAt()->format('Y-m-d H:i:s')); - $this->assertTrue($article->isNotPublished()); + expect($article->submittedAt()->format('Y-m-d H:i:s'))->toBe('2020-06-20 00:00:00'); + expect($article->isNotPublished())->toBeTrue(); }); diff --git a/tests/Integration/Jobs/UpdateProfileTest.php b/tests/Integration/Jobs/UpdateProfileTest.php index 62e0a9355..055db6411 100644 --- a/tests/Integration/Jobs/UpdateProfileTest.php +++ b/tests/Integration/Jobs/UpdateProfileTest.php @@ -16,8 +16,8 @@ $updatedUser = $this->dispatch(new UpdateProfile($user, ['bio' => 'my bio', 'name' => 'John Doe Junior'])); - $this->assertEquals('my bio', $updatedUser->bio()); - $this->assertEquals('John Doe Junior', $updatedUser->name()); + expect($updatedUser->bio())->toEqual('my bio'); + expect($updatedUser->name())->toEqual('John Doe Junior'); $this->assertDatabaseMissing('users', ['id' => $user->id, 'email_verified_at' => null]); Event::assertNotDispatched(EmailAddressWasChanged::class); diff --git a/tests/Integration/Models/ArticleTest.php b/tests/Integration/Models/ArticleTest.php index 8dfb9b59d..7e335aeec 100644 --- a/tests/Integration/Models/ArticleTest.php +++ b/tests/Integration/Models/ArticleTest.php @@ -21,9 +21,9 @@ $popularArticles = Article::popular()->get(); - $this->assertEquals($articles[1]->title, $popularArticles[0]->title); - $this->assertEquals($articles[0]->title, $popularArticles[1]->title); - $this->assertEquals($articles[2]->title, $popularArticles[2]->title); + expect($popularArticles[0]->title)->toEqual($articles[1]->title); + expect($popularArticles[1]->title)->toEqual($articles[0]->title); + expect($popularArticles[2]->title)->toEqual($articles[2]->title); }); test('we can get trending articles', function () { @@ -46,9 +46,9 @@ // The first article has more likes, but outside the trending window // so should be returned last. - $this->assertEquals($articles[1]->title, $trendingArticles[0]->title); - $this->assertEquals($articles[2]->title, $trendingArticles[1]->title); - $this->assertEquals($articles[0]->title, $trendingArticles[2]->title); + expect($trendingArticles[0]->title)->toEqual($articles[1]->title); + expect($trendingArticles[1]->title)->toEqual($articles[2]->title); + expect($trendingArticles[2]->title)->toEqual($articles[0]->title); }); test('pinned articles are returned first', function () { @@ -68,7 +68,7 @@ $recentArticles = Article::recent()->get(); - $this->assertEquals($articleThree->title, $recentArticles[0]->title); - $this->assertEquals($articleOne->title, $recentArticles[1]->title); - $this->assertEquals($articleTwo->title, $recentArticles[2]->title); + expect($recentArticles[0]->title)->toEqual($articleThree->title); + expect($recentArticles[1]->title)->toEqual($articleOne->title); + expect($recentArticles[2]->title)->toEqual($articleTwo->title); }); diff --git a/tests/Integration/Models/ReplyTest.php b/tests/Integration/Models/ReplyTest.php index 0114d7f2e..cf240a2b2 100644 --- a/tests/Integration/Models/ReplyTest.php +++ b/tests/Integration/Models/ReplyTest.php @@ -12,13 +12,13 @@ $reply = Reply::factory()->create(); - $this->assertFalse($reply->isLikedBy($user)); + expect($reply->isLikedBy($user))->toBeFalse(); $reply->likedBy($user); - $this->assertTrue($reply->isLikedBy($user)); + expect($reply->isLikedBy($user))->toBeTrue(); $reply->dislikedBy($user); - $this->assertFalse($reply->isLikedBy($user)); + expect($reply->isLikedBy($user))->toBeFalse(); }); diff --git a/tests/Integration/Models/SubscriptionTest.php b/tests/Integration/Models/SubscriptionTest.php index 3caec3324..c7577d681 100644 --- a/tests/Integration/Models/SubscriptionTest.php +++ b/tests/Integration/Models/SubscriptionTest.php @@ -12,5 +12,5 @@ $subscription = Subscription::findByUuidOrFail($uuid); - $this->assertEquals($uuid, $subscription->uuid()); + expect($subscription->uuid())->toEqual($uuid); }); diff --git a/tests/Integration/Models/ThreadTest.php b/tests/Integration/Models/ThreadTest.php index 21c57295a..fa79ccf14 100644 --- a/tests/Integration/Models/ThreadTest.php +++ b/tests/Integration/Models/ThreadTest.php @@ -12,56 +12,56 @@ it('can find by slug', function () { Thread::factory()->create(['slug' => 'foo']); - $this->assertInstanceOf(Thread::class, Thread::findBySlug('foo')); + expect(Thread::findBySlug('foo'))->toBeInstanceOf(Thread::class); }); it('can give an excerpt of its body', function () { $thread = Thread::factory()->make(['body' => 'This is a pretty long text.']); - $this->assertEquals('This is...', $thread->excerpt(7)); + expect($thread->excerpt(7))->toEqual('This is...'); }); test('html in excerpts is html encoded', function () { $thread = Thread::factory()->make(['body' => '

Thread body

']); - $this->assertEquals("<p>Thread body</p>\n", $thread->excerpt()); + expect($thread->excerpt())->toEqual("<p>Thread body</p>\n"); }); test('its conversation is old when the oldest reply was six months ago', function () { $thread = Thread::factory()->create(); $thread->repliesRelation()->save(Reply::factory()->make(['created_at' => now()->subMonths(7)])); - $this->assertTrue($thread->isConversationOld()); + expect($thread->isConversationOld())->toBeTrue(); $thread = Thread::factory()->create(); $thread->repliesRelation()->save(Reply::factory()->make()); - $this->assertFalse($thread->isConversationOld()); + expect($thread->isConversationOld())->toBeFalse(); }); test('its conversation is old when there are no replies but the creation date was six months ago', function () { $thread = Thread::factory()->create(['created_at' => now()->subMonths(7)]); - $this->assertTrue($thread->isConversationOld()); + expect($thread->isConversationOld())->toBeTrue(); $thread = Thread::factory()->create(); - $this->assertFalse($thread->isConversationOld()); + expect($thread->isConversationOld())->toBeFalse(); }); test('we can mark and unmark a reply as the solution', function () { $thread = Thread::factory()->create(); $reply = Reply::factory()->create(['replyable_id' => $thread->id()]); - $this->assertFalse($thread->isSolutionReply($reply)); + expect($thread->isSolutionReply($reply))->toBeFalse(); $thread->markSolution($reply); - $this->assertTrue($thread->isSolutionReply($reply)); + expect($thread->isSolutionReply($reply))->toBeTrue(); $thread->unmarkSolution(); - $this->assertFalse($thread->isSolutionReply($reply)); + expect($thread->isSolutionReply($reply))->toBeFalse(); }); it('can retrieve the latest threads in a correct order', function () { @@ -82,8 +82,8 @@ $threads = Thread::feedQuery()->resolved()->get(); - $this->assertCount(1, $threads); - $this->assertTrue($resolvedThread->is($threads->first())); + expect($threads)->toHaveCount(1); + expect($resolvedThread->is($threads->first()))->toBeTrue(); }); it('can retrieve only active threads', function () { @@ -92,28 +92,28 @@ $threads = Thread::feedQuery()->active()->get(); - $this->assertCount(1, $threads); - $this->assertTrue($activeThread->is($threads->first())); + expect($threads)->toHaveCount(1); + expect($activeThread->is($threads->first()))->toBeTrue(); }); it('generates a slug when valid url characters provided', function () { $thread = Thread::factory()->make(['slug' => 'Help with eloquent']); - $this->assertEquals('help-with-eloquent', $thread->slug()); + expect($thread->slug())->toEqual('help-with-eloquent'); }); it('generates a unique slug when valid url characters provided', function () { $threadOne = Thread::factory()->create(['slug' => 'Help with eloquent']); $threadTwo = Thread::factory()->create(['slug' => 'Help with eloquent']); - $this->assertEquals('help-with-eloquent-1', $threadTwo->slug()); + expect($threadTwo->slug())->toEqual('help-with-eloquent-1'); }); it('generates a slug when invalid url characters provided', function () { $thread = Thread::factory()->make(['slug' => '한글 테스트']); // When providing a slug with invalid url characters, a random 5 character string is returned. - $this->assertMatchesRegularExpression('/\w{5}/', $thread->slug()); + expect($thread->slug())->toMatch('/\w{5}/'); }); // Helpers diff --git a/tests/Integration/Models/UserTest.php b/tests/Integration/Models/UserTest.php index 5d9e2f872..c86be2091 100644 --- a/tests/Integration/Models/UserTest.php +++ b/tests/Integration/Models/UserTest.php @@ -12,26 +12,26 @@ it('can find by username', function () { $this->createUser(['username' => 'johndoe']); - $this->assertInstanceOf(User::class, User::findByUsername('johndoe')); + expect(User::findByUsername('johndoe'))->toBeInstanceOf(User::class); }); it('can find by email address', function () { $this->createUser(['email' => 'john@example.com']); - $this->assertInstanceOf(User::class, User::findByEmailAddress('john@example.com')); + expect(User::findByEmailAddress('john@example.com'))->toBeInstanceOf(User::class); }); it('can return the amount of solutions that were given', function () { $user = User::factory()->create(); createTwoSolutionReplies($user); - $this->assertEquals(2, $user->countSolutions()); + expect($user->countSolutions())->toEqual(2); }); it('can determine if a given user is the logged in user', function () { $user = $this->login(); - $this->assertTrue($user->isLoggedInUser()); + expect($user->isLoggedInUser())->toBeTrue(); }); it('can determine if a given user is not the logged in user', function () { @@ -41,7 +41,7 @@ 'email' => 'jane@example.com', ]); - $this->assertFalse($user->isLoggedInUser()); + expect($user->isLoggedInUser())->toBeFalse(); }); // Helpers diff --git a/tests/Integration/Queries/SearchUsersTest.php b/tests/Integration/Queries/SearchUsersTest.php index bd88c0e73..5a98051f2 100644 --- a/tests/Integration/Queries/SearchUsersTest.php +++ b/tests/Integration/Queries/SearchUsersTest.php @@ -12,6 +12,6 @@ User::factory()->create(['name' => 'Freek Murze', 'email' => 'freek@freek.com']); User::factory()->create(['name' => 'Frederick Vanbrabant', 'email' => 'vanbra@vanbra.com']); - $this->assertCount(2, SearchUsers::get('fre')); - $this->assertCount(1, SearchUsers::get('van')); + expect(SearchUsers::get('fre'))->toHaveCount(2); + expect(SearchUsers::get('van'))->toHaveCount(1); }); diff --git a/tests/Integration/Rules/PasscheckRuleTest.php b/tests/Integration/Rules/PasscheckRuleTest.php index 2d2608b96..88e19b89a 100644 --- a/tests/Integration/Rules/PasscheckRuleTest.php +++ b/tests/Integration/Rules/PasscheckRuleTest.php @@ -13,7 +13,7 @@ $result = $rule->passes('password', 'foo'); - $this->assertTrue($result); + expect($result)->toBeTrue(); }); it('fails when the password is incorrect', function () { @@ -22,5 +22,5 @@ $result = $rule->passes('password', 'foo'); - $this->assertFalse($result); + expect($result)->toBeFalse(); }); diff --git a/tests/Unit/Commands/PostArticleToTwitterTest.php b/tests/Unit/Commands/PostArticleToTwitterTest.php index 22315b365..dde0f36c3 100644 --- a/tests/Unit/Commands/PostArticleToTwitterTest.php +++ b/tests/Unit/Commands/PostArticleToTwitterTest.php @@ -37,7 +37,7 @@ function ($notification, $channels, $notifiable) use ($article) { }, ); - $this->assertTrue($article->fresh()->isShared()); + expect($article->fresh()->isShared())->toBeTrue(); }); test('articles are shared with twitter handle', function () { diff --git a/tests/Unit/Social/GithubUserTest.php b/tests/Unit/Social/GithubUserTest.php index 6bdf9476c..2ecb50ffd 100644 --- a/tests/Unit/Social/GithubUserTest.php +++ b/tests/Unit/Social/GithubUserTest.php @@ -7,11 +7,11 @@ it('can determine if the user is older than two weeks', function () { $user = new GithubUser(['created_at' => Carbon::now()->subWeeks(3)]); - $this->assertFalse($user->isTooYoung()); + expect($user->isTooYoung())->toBeFalse(); }); it('can determine if the user is younger than two weeks', function () { $user = new GithubUser(['created_at' => Carbon::now()->subWeek()]); - $this->assertTrue($user->isTooYoung()); + expect($user->isTooYoung())->toBeTrue(); }); diff --git a/tests/Unit/UserTest.php b/tests/Unit/UserTest.php index aebbe15f7..3f3fd301a 100644 --- a/tests/Unit/UserTest.php +++ b/tests/Unit/UserTest.php @@ -6,5 +6,5 @@ it('can determine if it has a password set', function () { $user = new User(['password' => 'foo']); - $this->assertTrue($user->hasPassword()); + expect($user->hasPassword())->toBeTrue(); }); From ca035bc71ec24587f2638c11452750025bef22fa Mon Sep 17 00:00:00 2001 From: Shift Date: Thu, 2 Sep 2021 17:16:40 +0000 Subject: [PATCH 05/14] Shift cleanup --- tests/Unit/Rules/DoesNotContainUrlRuleTest.php | 1 - tests/Unit/Rules/HttpImageRuleTest.php | 1 - tests/Unit/Social/GithubUserTest.php | 1 - tests/Unit/UserTest.php | 1 - 4 files changed, 4 deletions(-) diff --git a/tests/Unit/Rules/DoesNotContainUrlRuleTest.php b/tests/Unit/Rules/DoesNotContainUrlRuleTest.php index 16a15483d..6280a6163 100644 --- a/tests/Unit/Rules/DoesNotContainUrlRuleTest.php +++ b/tests/Unit/Rules/DoesNotContainUrlRuleTest.php @@ -2,7 +2,6 @@ use App\Rules\DoesNotContainUrlRule; - it('detects a url in a string', function () { $this->assertFalse( (new DoesNotContainUrlRule())->passes('foo', 'This is a string http://example.com with an url in it.'), diff --git a/tests/Unit/Rules/HttpImageRuleTest.php b/tests/Unit/Rules/HttpImageRuleTest.php index f57950468..ed20a0b66 100644 --- a/tests/Unit/Rules/HttpImageRuleTest.php +++ b/tests/Unit/Rules/HttpImageRuleTest.php @@ -2,7 +2,6 @@ use App\Rules\HttpImageRule; - it('passes when no http links are detected', function () { $this->assertTrue( (new HttpImageRule())->passes('body', 'some text ![](https://link.com)'), diff --git a/tests/Unit/Social/GithubUserTest.php b/tests/Unit/Social/GithubUserTest.php index 2ecb50ffd..939175927 100644 --- a/tests/Unit/Social/GithubUserTest.php +++ b/tests/Unit/Social/GithubUserTest.php @@ -3,7 +3,6 @@ use App\Social\GithubUser; use Carbon\Carbon; - it('can determine if the user is older than two weeks', function () { $user = new GithubUser(['created_at' => Carbon::now()->subWeeks(3)]); diff --git a/tests/Unit/UserTest.php b/tests/Unit/UserTest.php index 3f3fd301a..08afe8ea1 100644 --- a/tests/Unit/UserTest.php +++ b/tests/Unit/UserTest.php @@ -2,7 +2,6 @@ use App\Models\User; - it('can determine if it has a password set', function () { $user = new User(['password' => 'foo']); From f1e7da096b44234186624ecc7b4a6ef0555bb680 Mon Sep 17 00:00:00 2001 From: Jason McCreary Date: Thu, 2 Sep 2021 14:04:51 -0400 Subject: [PATCH 06/14] Update GitHub Actions --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index a2ac5bb9e..38df12315 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -27,7 +27,7 @@ jobs: run: npm run production - name: Execute tests - run: vendor/bin/phpunit --verbose + run: vendor/bin/pest - name: Deploy if: github.ref == 'refs/heads/main' From faadcdb4baf5a83c21b1a543be2a5c56fcbb3b50 Mon Sep 17 00:00:00 2001 From: Jason McCreary Date: Thu, 2 Sep 2021 14:04:57 -0400 Subject: [PATCH 07/14] composer update --- composer.lock | 1559 ++++++++++++++++++++++++++++++------------------- 1 file changed, 963 insertions(+), 596 deletions(-) diff --git a/composer.lock b/composer.lock index 047f429c5..0e1a95cac 100644 --- a/composer.lock +++ b/composer.lock @@ -4,20 +4,20 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "80fa0ab8bfa1b8c47cbfc1f26f396309", + "content-hash": "ec3992c5edd5a581f1a218ab89539765", "packages": [ { "name": "abraham/twitteroauth", - "version": "2.0.1", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/abraham/twitteroauth.git", - "reference": "af6d0ba772731d4f83524fccb24281fe6149ef43" + "reference": "5a424e80a1200674451844fbaae8a0098a316a01" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/abraham/twitteroauth/zipball/af6d0ba772731d4f83524fccb24281fe6149ef43", - "reference": "af6d0ba772731d4f83524fccb24281fe6149ef43", + "url": "https://api.github.com/repos/abraham/twitteroauth/zipball/5a424e80a1200674451844fbaae8a0098a316a01", + "reference": "5a424e80a1200674451844fbaae8a0098a316a01", "shasum": "" }, "require": { @@ -29,7 +29,7 @@ "php-vcr/php-vcr": "^1", "php-vcr/phpunit-testlistener-vcr": "dev-php-8", "phpmd/phpmd": "^2", - "phpunit/phpunit": "^8", + "phpunit/phpunit": "^8 || ^9", "squizlabs/php_codesniffer": "^3" }, "type": "library", @@ -65,20 +65,20 @@ "issues": "https://github.com/abraham/twitteroauth/issues", "source": "https://github.com/abraham/twitteroauth" }, - "time": "2020-12-02T01:37:06+00:00" + "time": "2021-06-11T02:56:14+00:00" }, { "name": "algolia/algoliasearch-client-php", - "version": "3.0.2", + "version": "3.1.0", "source": { "type": "git", "url": "https://github.com/algolia/algoliasearch-client-php.git", - "reference": "421abbfb085c8ae74d298a6f259ebfd69897e625" + "reference": "42793a97c99a68adfe8e39eadadd970b5196f208" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/algolia/algoliasearch-client-php/zipball/421abbfb085c8ae74d298a6f259ebfd69897e625", - "reference": "421abbfb085c8ae74d298a6f259ebfd69897e625", + "url": "https://api.github.com/repos/algolia/algoliasearch-client-php/zipball/42793a97c99a68adfe8e39eadadd970b5196f208", + "reference": "42793a97c99a68adfe8e39eadadd970b5196f208", "shasum": "" }, "require": { @@ -137,22 +137,22 @@ ], "support": { "issues": "https://github.com/algolia/algoliasearch-client-php/issues", - "source": "https://github.com/algolia/algoliasearch-client-php/tree/3.0.2" + "source": "https://github.com/algolia/algoliasearch-client-php/tree/3.1.0" }, - "time": "2021-05-04T09:15:35+00:00" + "time": "2021-08-31T14:17:19+00:00" }, { "name": "algolia/scout-extended", - "version": "v1.18.0", + "version": "v1.20.0", "source": { "type": "git", "url": "https://github.com/algolia/scout-extended.git", - "reference": "f0434c48ff667dbcffe98796f4438f049bbc987b" + "reference": "fbce0d96b7fc56591020ddfdb915b8b9fdd9d794" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/algolia/scout-extended/zipball/f0434c48ff667dbcffe98796f4438f049bbc987b", - "reference": "f0434c48ff667dbcffe98796f4438f049bbc987b", + "url": "https://api.github.com/repos/algolia/scout-extended/zipball/fbce0d96b7fc56591020ddfdb915b8b9fdd9d794", + "reference": "fbce0d96b7fc56591020ddfdb915b8b9fdd9d794", "shasum": "" }, "require": { @@ -218,9 +218,9 @@ ], "support": { "issues": "https://github.com/algolia/scout-extended/issues", - "source": "https://github.com/algolia/scout-extended/tree/v1.18.0" + "source": "https://github.com/algolia/scout-extended/tree/v1.20.0" }, - "time": "2021-04-30T13:16:19+00:00" + "time": "2021-07-08T14:08:13+00:00" }, { "name": "asm89/stack-cors", @@ -280,16 +280,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.180.2", + "version": "3.191.9", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "88b91af651a9affd384b184332a4d52d69ab7c81" + "reference": "67a1a0814a8e38c89d834d6cf9379752795c68fe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/88b91af651a9affd384b184332a4d52d69ab7c81", - "reference": "88b91af651a9affd384b184332a4d52d69ab7c81", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/67a1a0814a8e38c89d834d6cf9379752795c68fe", + "reference": "67a1a0814a8e38c89d834d6cf9379752795c68fe", "shasum": "" }, "require": { @@ -364,22 +364,22 @@ "support": { "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.180.2" + "source": "https://github.com/aws/aws-sdk-php/tree/3.191.9" }, - "time": "2021-05-05T02:47:28+00:00" + "time": "2021-09-01T18:19:52+00:00" }, { "name": "blade-ui-kit/blade-heroicons", - "version": "v1.1.0", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/blade-ui-kit/blade-heroicons.git", - "reference": "fcb102a569f085cb369d6a725f04f4b539fefd11" + "reference": "99d82616a72e36492edc9b95c6a2112d8632e9a7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/blade-ui-kit/blade-heroicons/zipball/fcb102a569f085cb369d6a725f04f4b539fefd11", - "reference": "fcb102a569f085cb369d6a725f04f4b539fefd11", + "url": "https://api.github.com/repos/blade-ui-kit/blade-heroicons/zipball/99d82616a72e36492edc9b95c6a2112d8632e9a7", + "reference": "99d82616a72e36492edc9b95c6a2112d8632e9a7", "shasum": "" }, "require": { @@ -423,7 +423,7 @@ ], "support": { "issues": "https://github.com/blade-ui-kit/blade-heroicons/issues", - "source": "https://github.com/blade-ui-kit/blade-heroicons/tree/v1.1.0" + "source": "https://github.com/blade-ui-kit/blade-heroicons/tree/1.2.0" }, "funding": [ { @@ -435,20 +435,20 @@ "type": "github" } ], - "time": "2021-04-25T13:40:51+00:00" + "time": "2021-05-05T14:59:46+00:00" }, { "name": "blade-ui-kit/blade-icons", - "version": "1.0.2", + "version": "1.1.2", "source": { "type": "git", "url": "https://github.com/blade-ui-kit/blade-icons.git", - "reference": "716c3991efb77389046785ff87a9565aceda8657" + "reference": "548869bc820a25f803530c82028482aefe08115f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/blade-ui-kit/blade-icons/zipball/716c3991efb77389046785ff87a9565aceda8657", - "reference": "716c3991efb77389046785ff87a9565aceda8657", + "url": "https://api.github.com/repos/blade-ui-kit/blade-icons/zipball/548869bc820a25f803530c82028482aefe08115f", + "reference": "548869bc820a25f803530c82028482aefe08115f", "shasum": "" }, "require": { @@ -456,13 +456,18 @@ "illuminate/filesystem": "^8.0", "illuminate/support": "^8.0", "illuminate/view": "^8.0", - "php": "^7.4|^8.0" + "php": "^7.4|^8.0", + "symfony/console": "^5.3", + "symfony/finder": "^5.3" }, "require-dev": { "mockery/mockery": "^1.3", "orchestra/testbench": "^6.0", "phpunit/phpunit": "^9.0" }, + "bin": [ + "bin/blade-icons-generate" + ], "type": "library", "extra": { "laravel": { @@ -511,7 +516,7 @@ "type": "github" } ], - "time": "2021-04-03T19:08:34+00:00" + "time": "2021-08-11T10:09:06+00:00" }, { "name": "blade-ui-kit/blade-ui-kit", @@ -593,16 +598,16 @@ }, { "name": "blade-ui-kit/blade-zondicons", - "version": "1.0.0", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/blade-ui-kit/blade-zondicons.git", - "reference": "d207278fbc13d7bd04b94e2276fbcbee0c0d739a" + "reference": "d5ad1d793f695a149c1a95a1069d0960fa46e5c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/blade-ui-kit/blade-zondicons/zipball/d207278fbc13d7bd04b94e2276fbcbee0c0d739a", - "reference": "d207278fbc13d7bd04b94e2276fbcbee0c0d739a", + "url": "https://api.github.com/repos/blade-ui-kit/blade-zondicons/zipball/d5ad1d793f695a149c1a95a1069d0960fa46e5c7", + "reference": "d5ad1d793f695a149c1a95a1069d0960fa46e5c7", "shasum": "" }, "require": { @@ -658,20 +663,20 @@ "type": "github" } ], - "time": "2021-03-21T16:20:42+00:00" + "time": "2021-05-05T15:06:37+00:00" }, { "name": "brick/math", - "version": "0.9.2", + "version": "0.9.3", "source": { "type": "git", "url": "https://github.com/brick/math.git", - "reference": "dff976c2f3487d42c1db75a3b180e2b9f0e72ce0" + "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/brick/math/zipball/dff976c2f3487d42c1db75a3b180e2b9f0e72ce0", - "reference": "dff976c2f3487d42c1db75a3b180e2b9f0e72ce0", + "url": "https://api.github.com/repos/brick/math/zipball/ca57d18f028f84f777b2168cd1911b0dee2343ae", + "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae", "shasum": "" }, "require": { @@ -681,7 +686,7 @@ "require-dev": { "php-coveralls/php-coveralls": "^2.2", "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.0", - "vimeo/psalm": "4.3.2" + "vimeo/psalm": "4.9.2" }, "type": "library", "autoload": { @@ -706,28 +711,32 @@ ], "support": { "issues": "https://github.com/brick/math/issues", - "source": "https://github.com/brick/math/tree/0.9.2" + "source": "https://github.com/brick/math/tree/0.9.3" }, "funding": [ + { + "url": "https://github.com/BenMorel", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/brick/math", "type": "tidelift" } ], - "time": "2021-01-20T22:51:39+00:00" + "time": "2021-08-15T20:50:18+00:00" }, { "name": "composer/ca-bundle", - "version": "1.2.9", + "version": "1.2.10", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "78a0e288fdcebf92aa2318a8d3656168da6ac1a5" + "reference": "9fdb22c2e97a614657716178093cd1da90a64aa8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/78a0e288fdcebf92aa2318a8d3656168da6ac1a5", - "reference": "78a0e288fdcebf92aa2318a8d3656168da6ac1a5", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/9fdb22c2e97a614657716178093cd1da90a64aa8", + "reference": "9fdb22c2e97a614657716178093cd1da90a64aa8", "shasum": "" }, "require": { @@ -774,7 +783,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/ca-bundle/issues", - "source": "https://github.com/composer/ca-bundle/tree/1.2.9" + "source": "https://github.com/composer/ca-bundle/tree/1.2.10" }, "funding": [ { @@ -790,20 +799,20 @@ "type": "tidelift" } ], - "time": "2021-01-12T12:10:35+00:00" + "time": "2021-06-07T13:58:28+00:00" }, { "name": "composer/package-versions-deprecated", - "version": "1.11.99.1", + "version": "1.11.99.3", "source": { "type": "git", "url": "https://github.com/composer/package-versions-deprecated.git", - "reference": "7413f0b55a051e89485c5cb9f765fe24bb02a7b6" + "reference": "fff576ac850c045158a250e7e27666e146e78d18" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/7413f0b55a051e89485c5cb9f765fe24bb02a7b6", - "reference": "7413f0b55a051e89485c5cb9f765fe24bb02a7b6", + "url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/fff576ac850c045158a250e7e27666e146e78d18", + "reference": "fff576ac850c045158a250e7e27666e146e78d18", "shasum": "" }, "require": { @@ -847,7 +856,7 @@ "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", "support": { "issues": "https://github.com/composer/package-versions-deprecated/issues", - "source": "https://github.com/composer/package-versions-deprecated/tree/1.11.99.1" + "source": "https://github.com/composer/package-versions-deprecated/tree/1.11.99.3" }, "funding": [ { @@ -863,28 +872,27 @@ "type": "tidelift" } ], - "time": "2020-11-11T10:22:58+00:00" + "time": "2021-08-17T13:49:14+00:00" }, { "name": "doctrine/cache", - "version": "1.11.0", + "version": "2.1.1", "source": { "type": "git", "url": "https://github.com/doctrine/cache.git", - "reference": "a9c1b59eba5a08ca2770a76eddb88922f504e8e0" + "reference": "331b4d5dbaeab3827976273e9356b3b453c300ce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/cache/zipball/a9c1b59eba5a08ca2770a76eddb88922f504e8e0", - "reference": "a9c1b59eba5a08ca2770a76eddb88922f504e8e0", + "url": "https://api.github.com/repos/doctrine/cache/zipball/331b4d5dbaeab3827976273e9356b3b453c300ce", + "reference": "331b4d5dbaeab3827976273e9356b3b453c300ce", "shasum": "" }, "require": { "php": "~7.1 || ^8.0" }, "conflict": { - "doctrine/common": ">2.2,<2.4", - "psr/cache": ">=3" + "doctrine/common": ">2.2,<2.4" }, "require-dev": { "alcaeus/mongo-php-adapter": "^1.1", @@ -893,8 +901,9 @@ "mongodb/mongodb": "^1.1", "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", "predis/predis": "~1.0", - "psr/cache": "^1.0 || ^2.0", - "symfony/cache": "^4.4 || ^5.2" + "psr/cache": "^1.0 || ^2.0 || ^3.0", + "symfony/cache": "^4.4 || ^5.2 || ^6.0@dev", + "symfony/var-exporter": "^4.4 || ^5.2 || ^6.0@dev" }, "suggest": { "alcaeus/mongo-php-adapter": "Required to use legacy MongoDB driver" @@ -946,7 +955,7 @@ ], "support": { "issues": "https://github.com/doctrine/cache/issues", - "source": "https://github.com/doctrine/cache/tree/1.11.0" + "source": "https://github.com/doctrine/cache/tree/2.1.1" }, "funding": [ { @@ -962,38 +971,39 @@ "type": "tidelift" } ], - "time": "2021-04-13T14:46:17+00:00" + "time": "2021-07-17T14:49:29+00:00" }, { "name": "doctrine/dbal", - "version": "3.1.0", + "version": "3.1.1", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "5ba62e7e40df119424866064faf2cef66cb5232a" + "reference": "8e0fde2b90e3f61361013d1e928621beeea07bc0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/5ba62e7e40df119424866064faf2cef66cb5232a", - "reference": "5ba62e7e40df119424866064faf2cef66cb5232a", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/8e0fde2b90e3f61361013d1e928621beeea07bc0", + "reference": "8e0fde2b90e3f61361013d1e928621beeea07bc0", "shasum": "" }, "require": { "composer/package-versions-deprecated": "^1.11.99", - "doctrine/cache": "^1.0", + "doctrine/cache": "^1.0|^2.0", "doctrine/deprecations": "^0.5.3", "doctrine/event-manager": "^1.0", "php": "^7.3 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "8.2.0", + "doctrine/coding-standard": "9.0.0", "jetbrains/phpstorm-stubs": "2020.2", "phpstan/phpstan": "0.12.81", "phpstan/phpstan-strict-rules": "^0.12.2", - "phpunit/phpunit": "9.5.0", + "phpunit/phpunit": "9.5.5", "psalm/plugin-phpunit": "0.13.0", "squizlabs/php_codesniffer": "3.6.0", - "symfony/console": "^2.0.5|^3.0|^4.0|^5.0", + "symfony/cache": "^5.2|^6.0", + "symfony/console": "^2.0.5|^3.0|^4.0|^5.0|^6.0", "vimeo/psalm": "4.6.4" }, "suggest": { @@ -1054,7 +1064,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/3.1.0" + "source": "https://github.com/doctrine/dbal/tree/3.1.1" }, "funding": [ { @@ -1070,7 +1080,7 @@ "type": "tidelift" } ], - "time": "2021-04-19T17:51:23+00:00" + "time": "2021-06-19T17:59:55+00:00" }, { "name": "doctrine/deprecations", @@ -1515,16 +1525,16 @@ }, { "name": "facade/flare-client-php", - "version": "1.8.0", + "version": "1.8.1", "source": { "type": "git", "url": "https://github.com/facade/flare-client-php.git", - "reference": "69742118c037f34ee1ef86dc605be4a105d9e984" + "reference": "47b639dc02bcfdfc4ebb83de703856fa01e35f5f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/facade/flare-client-php/zipball/69742118c037f34ee1ef86dc605be4a105d9e984", - "reference": "69742118c037f34ee1ef86dc605be4a105d9e984", + "url": "https://api.github.com/repos/facade/flare-client-php/zipball/47b639dc02bcfdfc4ebb83de703856fa01e35f5f", + "reference": "47b639dc02bcfdfc4ebb83de703856fa01e35f5f", "shasum": "" }, "require": { @@ -1568,7 +1578,7 @@ ], "support": { "issues": "https://github.com/facade/flare-client-php/issues", - "source": "https://github.com/facade/flare-client-php/tree/1.8.0" + "source": "https://github.com/facade/flare-client-php/tree/1.8.1" }, "funding": [ { @@ -1576,20 +1586,20 @@ "type": "github" } ], - "time": "2021-04-30T11:11:50+00:00" + "time": "2021-05-31T19:23:29+00:00" }, { "name": "facade/ignition", - "version": "2.9.0", + "version": "2.12.0", "source": { "type": "git", "url": "https://github.com/facade/ignition.git", - "reference": "e7db3b601ce742568b92648818ef903904d20164" + "reference": "74dcc32a2895a126d1e5f2cd3bbab499cac66db1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/facade/ignition/zipball/e7db3b601ce742568b92648818ef903904d20164", - "reference": "e7db3b601ce742568b92648818ef903904d20164", + "url": "https://api.github.com/repos/facade/ignition/zipball/74dcc32a2895a126d1e5f2cd3bbab499cac66db1", + "reference": "74dcc32a2895a126d1e5f2cd3bbab499cac66db1", "shasum": "" }, "require": { @@ -1597,7 +1607,6 @@ "ext-mbstring": "*", "facade/flare-client-php": "^1.6", "facade/ignition-contracts": "^1.0.2", - "filp/whoops": "^2.4", "illuminate/support": "^7.0|^8.0", "monolog/monolog": "^2.0", "php": "^7.2.5|^8.0", @@ -1653,7 +1662,7 @@ "issues": "https://github.com/facade/ignition/issues", "source": "https://github.com/facade/ignition" }, - "time": "2021-05-05T06:45:12+00:00" + "time": "2021-08-24T09:53:54+00:00" }, { "name": "facade/ignition-contracts", @@ -1766,77 +1775,6 @@ }, "time": "2020-10-22T13:48:01+00:00" }, - { - "name": "filp/whoops", - "version": "2.12.1", - "source": { - "type": "git", - "url": "https://github.com/filp/whoops.git", - "reference": "c13c0be93cff50f88bbd70827d993026821914dd" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/filp/whoops/zipball/c13c0be93cff50f88bbd70827d993026821914dd", - "reference": "c13c0be93cff50f88bbd70827d993026821914dd", - "shasum": "" - }, - "require": { - "php": "^5.5.9 || ^7.0 || ^8.0", - "psr/log": "^1.0.1" - }, - "require-dev": { - "mockery/mockery": "^0.9 || ^1.0", - "phpunit/phpunit": "^4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.3", - "symfony/var-dumper": "^2.6 || ^3.0 || ^4.0 || ^5.0" - }, - "suggest": { - "symfony/var-dumper": "Pretty print complex values better with var-dumper available", - "whoops/soap": "Formats errors as SOAP responses" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.7-dev" - } - }, - "autoload": { - "psr-4": { - "Whoops\\": "src/Whoops/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Filipe Dobreira", - "homepage": "https://github.com/filp", - "role": "Developer" - } - ], - "description": "php error handling for cool kids", - "homepage": "https://filp.github.io/whoops/", - "keywords": [ - "error", - "exception", - "handling", - "library", - "throwable", - "whoops" - ], - "support": { - "issues": "https://github.com/filp/whoops/issues", - "source": "https://github.com/filp/whoops/tree/2.12.1" - }, - "funding": [ - { - "url": "https://github.com/denis-sokolov", - "type": "github" - } - ], - "time": "2021-04-25T12:00:00+00:00" - }, { "name": "fruitcake/laravel-cors", "version": "v2.0.4", @@ -1916,31 +1854,26 @@ }, { "name": "graham-campbell/result-type", - "version": "v1.0.1", + "version": "v1.0.2", "source": { "type": "git", "url": "https://github.com/GrahamCampbell/Result-Type.git", - "reference": "7e279d2cd5d7fbb156ce46daada972355cea27bb" + "reference": "84afea85c6841deeea872f36249a206e878a5de0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/7e279d2cd5d7fbb156ce46daada972355cea27bb", - "reference": "7e279d2cd5d7fbb156ce46daada972355cea27bb", + "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/84afea85c6841deeea872f36249a206e878a5de0", + "reference": "84afea85c6841deeea872f36249a206e878a5de0", "shasum": "" }, "require": { - "php": "^7.0|^8.0", - "phpoption/phpoption": "^1.7.3" + "php": "^7.0 || ^8.0", + "phpoption/phpoption": "^1.8" }, "require-dev": { - "phpunit/phpunit": "^6.5|^7.5|^8.5|^9.0" + "phpunit/phpunit": "^6.5.14 || ^7.5.20 || ^8.5.19 || ^9.5.8" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, "autoload": { "psr-4": { "GrahamCampbell\\ResultType\\": "src/" @@ -1953,7 +1886,7 @@ "authors": [ { "name": "Graham Campbell", - "email": "graham@alt-three.com" + "email": "hello@gjcampbell.co.uk" } ], "description": "An Implementation Of The Result Type", @@ -1966,7 +1899,7 @@ ], "support": { "issues": "https://github.com/GrahamCampbell/Result-Type/issues", - "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.0.1" + "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.0.2" }, "funding": [ { @@ -1978,7 +1911,7 @@ "type": "tidelift" } ], - "time": "2020-04-13T13:17:36+00:00" + "time": "2021-08-28T21:34:50+00:00" }, { "name": "guzzlehttp/guzzle", @@ -2266,26 +2199,26 @@ }, { "name": "intervention/image", - "version": "2.5.1", + "version": "2.6.1", "source": { "type": "git", "url": "https://github.com/Intervention/image.git", - "reference": "abbf18d5ab8367f96b3205ca3c89fb2fa598c69e" + "reference": "0925f10b259679b5d8ca58f3a2add9255ffcda45" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Intervention/image/zipball/abbf18d5ab8367f96b3205ca3c89fb2fa598c69e", - "reference": "abbf18d5ab8367f96b3205ca3c89fb2fa598c69e", + "url": "https://api.github.com/repos/Intervention/image/zipball/0925f10b259679b5d8ca58f3a2add9255ffcda45", + "reference": "0925f10b259679b5d8ca58f3a2add9255ffcda45", "shasum": "" }, "require": { "ext-fileinfo": "*", - "guzzlehttp/psr7": "~1.1", + "guzzlehttp/psr7": "~1.1 || ^2.0", "php": ">=5.4.0" }, "require-dev": { "mockery/mockery": "~0.9.2", - "phpunit/phpunit": "^4.8 || ^5.7" + "phpunit/phpunit": "^4.8 || ^5.7 || ^7.5.15" }, "suggest": { "ext-gd": "to use GD library based image processing.", @@ -2334,9 +2267,19 @@ ], "support": { "issues": "https://github.com/Intervention/image/issues", - "source": "https://github.com/Intervention/image/tree/master" + "source": "https://github.com/Intervention/image/tree/2.6.1" }, - "time": "2019-11-02T09:15:47+00:00" + "funding": [ + { + "url": "https://www.paypal.me/interventionphp", + "type": "custom" + }, + { + "url": "https://github.com/Intervention", + "type": "github" + } + ], + "time": "2021-07-22T14:31:53+00:00" }, { "name": "intervention/imagecache", @@ -2506,16 +2449,16 @@ }, { "name": "laravel/framework", - "version": "v8.40.0", + "version": "v8.58.0", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "a654897ad7f97aea9d7ef292803939798c4a02a4" + "reference": "1b819bf99d87bd543a4d4895e5b3350f61ea7a23" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/a654897ad7f97aea9d7ef292803939798c4a02a4", - "reference": "a654897ad7f97aea9d7ef292803939798c4a02a4", + "url": "https://api.github.com/repos/laravel/framework/zipball/1b819bf99d87bd543a4d4895e5b3350f61ea7a23", + "reference": "1b819bf99d87bd543a4d4895e5b3350f61ea7a23", "shasum": "" }, "require": { @@ -2525,7 +2468,7 @@ "ext-json": "*", "ext-mbstring": "*", "ext-openssl": "*", - "league/commonmark": "^1.3", + "league/commonmark": "^1.3|^2.0", "league/flysystem": "^1.1", "monolog/monolog": "^2.0", "nesbot/carbon": "^2.31", @@ -2588,20 +2531,20 @@ "illuminate/view": "self.version" }, "require-dev": { - "aws/aws-sdk-php": "^3.155", + "aws/aws-sdk-php": "^3.189.0", "doctrine/dbal": "^2.6|^3.0", "filp/whoops": "^2.8", "guzzlehttp/guzzle": "^6.5.5|^7.0.1", "league/flysystem-cached-adapter": "^1.0", "mockery/mockery": "^1.4.2", - "orchestra/testbench-core": "^6.8", + "orchestra/testbench-core": "^6.23", "pda/pheanstalk": "^4.0", "phpunit/phpunit": "^8.5.8|^9.3.3", - "predis/predis": "^1.1.1", + "predis/predis": "^1.1.2", "symfony/cache": "^5.1.4" }, "suggest": { - "aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage and SES mail driver (^3.155).", + "aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage and SES mail driver (^3.189.0).", "brianium/paratest": "Required to run tests in parallel (^6.0).", "doctrine/dbal": "Required to rename columns and drop SQLite columns (^2.6|^3.0).", "ext-ftp": "Required to use the Flysystem FTP driver.", @@ -2623,7 +2566,7 @@ "phpunit/phpunit": "Required to use assertions and run tests (^8.5.8|^9.3.3).", "predis/predis": "Required to use the predis connector (^1.1.2).", "psr/http-message": "Required to allow Storage::put to accept a StreamInterface (^1.0).", - "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^4.0|^5.0).", + "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^4.0|^5.0|^6.0).", "symfony/cache": "Required to PSR-6 cache bridge (^5.1.4).", "symfony/filesystem": "Required to enable support for relative symbolic links (^5.1.4).", "symfony/psr-http-message-bridge": "Required to use PSR-7 bridging features (^2.0).", @@ -2670,20 +2613,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2021-04-28T14:38:56+00:00" + "time": "2021-08-31T13:55:57+00:00" }, { "name": "laravel/horizon", - "version": "v5.7.6", + "version": "v5.7.12", "source": { "type": "git", "url": "https://github.com/laravel/horizon.git", - "reference": "24ffd819df749ef11a4eb20e14150b671d4f5717" + "reference": "98e2a6efac1a79ae08a9cce84bef32f236f6f800" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/horizon/zipball/24ffd819df749ef11a4eb20e14150b671d4f5717", - "reference": "24ffd819df749ef11a4eb20e14150b671d4f5717", + "url": "https://api.github.com/repos/laravel/horizon/zipball/98e2a6efac1a79ae08a9cce84bef32f236f6f800", + "reference": "98e2a6efac1a79ae08a9cce84bef32f236f6f800", "shasum": "" }, "require": { @@ -2745,22 +2688,22 @@ ], "support": { "issues": "https://github.com/laravel/horizon/issues", - "source": "https://github.com/laravel/horizon/tree/v5.7.6" + "source": "https://github.com/laravel/horizon/tree/v5.7.12" }, - "time": "2021-04-27T18:00:46+00:00" + "time": "2021-08-31T14:56:54+00:00" }, { "name": "laravel/scout", - "version": "v9.0.0", + "version": "v9.2.8", "source": { "type": "git", "url": "https://github.com/laravel/scout.git", - "reference": "aec8fb9df550cb9b1aade83a848ca0b3665ac416" + "reference": "0db23cc68de62b3b25b909c0d57b33c4ed585af4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/scout/zipball/aec8fb9df550cb9b1aade83a848ca0b3665ac416", - "reference": "aec8fb9df550cb9b1aade83a848ca0b3665ac416", + "url": "https://api.github.com/repos/laravel/scout/zipball/0db23cc68de62b3b25b909c0d57b33c4ed585af4", + "reference": "0db23cc68de62b3b25b909c0d57b33c4ed585af4", "shasum": "" }, "require": { @@ -2774,7 +2717,7 @@ "php": "^7.3|^8.0" }, "require-dev": { - "meilisearch/meilisearch-php": "^0.17", + "meilisearch/meilisearch-php": "^0.19", "mockery/mockery": "^1.0", "orchestra/testbench": "^6.17", "phpunit/phpunit": "^9.3" @@ -2819,20 +2762,20 @@ "issues": "https://github.com/laravel/scout/issues", "source": "https://github.com/laravel/scout" }, - "time": "2021-04-27T18:32:11+00:00" + "time": "2021-08-31T15:13:52+00:00" }, { "name": "laravel/socialite", - "version": "v5.2.3", + "version": "v5.2.5", "source": { "type": "git", "url": "https://github.com/laravel/socialite.git", - "reference": "1960802068f81e44b2ae9793932181cf1cb91b5c" + "reference": "fd0f6a3dd963ca480b598649b54f92d81a43617f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/socialite/zipball/1960802068f81e44b2ae9793932181cf1cb91b5c", - "reference": "1960802068f81e44b2ae9793932181cf1cb91b5c", + "url": "https://api.github.com/repos/laravel/socialite/zipball/fd0f6a3dd963ca480b598649b54f92d81a43617f", + "reference": "fd0f6a3dd963ca480b598649b54f92d81a43617f", "shasum": "" }, "require": { @@ -2888,26 +2831,27 @@ "issues": "https://github.com/laravel/socialite/issues", "source": "https://github.com/laravel/socialite" }, - "time": "2021-04-06T14:38:16+00:00" + "time": "2021-08-31T15:16:26+00:00" }, { "name": "laravel/ui", - "version": "v3.2.1", + "version": "v3.3.0", "source": { "type": "git", "url": "https://github.com/laravel/ui.git", - "reference": "e2478cd0342a92ec1c8c77422553bda8ee004fd0" + "reference": "07d725813350c695c779382cbd6dac0ab8665537" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/ui/zipball/e2478cd0342a92ec1c8c77422553bda8ee004fd0", - "reference": "e2478cd0342a92ec1c8c77422553bda8ee004fd0", + "url": "https://api.github.com/repos/laravel/ui/zipball/07d725813350c695c779382cbd6dac0ab8665537", + "reference": "07d725813350c695c779382cbd6dac0ab8665537", "shasum": "" }, "require": { - "illuminate/console": "^8.0", - "illuminate/filesystem": "^8.0", - "illuminate/support": "^8.0", + "illuminate/console": "^8.42", + "illuminate/filesystem": "^8.42", + "illuminate/support": "^8.42", + "illuminate/validation": "^8.42", "php": "^7.3|^8.0" }, "type": "library", @@ -2943,9 +2887,9 @@ "ui" ], "support": { - "source": "https://github.com/laravel/ui/tree/v3.2.1" + "source": "https://github.com/laravel/ui/tree/v3.3.0" }, - "time": "2021-04-27T18:17:41+00:00" + "time": "2021-05-25T16:45:33+00:00" }, { "name": "league/commonmark", @@ -3050,16 +2994,16 @@ }, { "name": "league/flysystem", - "version": "1.1.4", + "version": "1.1.5", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "f3ad69181b8afed2c9edf7be5a2918144ff4ea32" + "reference": "18634df356bfd4119fe3d6156bdb990c414c14ea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/f3ad69181b8afed2c9edf7be5a2918144ff4ea32", - "reference": "f3ad69181b8afed2c9edf7be5a2918144ff4ea32", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/18634df356bfd4119fe3d6156bdb990c414c14ea", + "reference": "18634df356bfd4119fe3d6156bdb990c414c14ea", "shasum": "" }, "require": { @@ -3132,7 +3076,7 @@ ], "support": { "issues": "https://github.com/thephpleague/flysystem/issues", - "source": "https://github.com/thephpleague/flysystem/tree/1.1.4" + "source": "https://github.com/thephpleague/flysystem/tree/1.1.5" }, "funding": [ { @@ -3140,7 +3084,7 @@ "type": "other" } ], - "time": "2021-06-23T21:56:05+00:00" + "time": "2021-08-17T13:49:42+00:00" }, { "name": "league/flysystem-aws-s3-v3", @@ -3251,22 +3195,23 @@ }, { "name": "league/oauth1-client", - "version": "v1.9.0", + "version": "v1.10.0", "source": { "type": "git", "url": "https://github.com/thephpleague/oauth1-client.git", - "reference": "1e7e6be2dc543bf466236fb171e5b20e1b06aee6" + "reference": "88dd16b0cff68eb9167bfc849707d2c40ad91ddc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/oauth1-client/zipball/1e7e6be2dc543bf466236fb171e5b20e1b06aee6", - "reference": "1e7e6be2dc543bf466236fb171e5b20e1b06aee6", + "url": "https://api.github.com/repos/thephpleague/oauth1-client/zipball/88dd16b0cff68eb9167bfc849707d2c40ad91ddc", + "reference": "88dd16b0cff68eb9167bfc849707d2c40ad91ddc", "shasum": "" }, "require": { "ext-json": "*", "ext-openssl": "*", "guzzlehttp/guzzle": "^6.0|^7.0", + "guzzlehttp/psr7": "^1.7|^2.0", "php": ">=7.1||>=8.0" }, "require-dev": { @@ -3320,22 +3265,22 @@ ], "support": { "issues": "https://github.com/thephpleague/oauth1-client/issues", - "source": "https://github.com/thephpleague/oauth1-client/tree/v1.9.0" + "source": "https://github.com/thephpleague/oauth1-client/tree/v1.10.0" }, - "time": "2021-01-20T01:40:53+00:00" + "time": "2021-08-15T23:05:49+00:00" }, { "name": "livewire/livewire", - "version": "v2.4.4", + "version": "v2.5.5", "source": { "type": "git", "url": "https://github.com/livewire/livewire.git", - "reference": "33101c83b75728651b9e668a4559f97def7c9138" + "reference": "de192292d68276d831e5fd9824c80c3b78a21ddf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/livewire/livewire/zipball/33101c83b75728651b9e668a4559f97def7c9138", - "reference": "33101c83b75728651b9e668a4559f97def7c9138", + "url": "https://api.github.com/repos/livewire/livewire/zipball/de192292d68276d831e5fd9824c80c3b78a21ddf", + "reference": "de192292d68276d831e5fd9824c80c3b78a21ddf", "shasum": "" }, "require": { @@ -3386,7 +3331,7 @@ "description": "A front-end framework for Laravel.", "support": { "issues": "https://github.com/livewire/livewire/issues", - "source": "https://github.com/livewire/livewire/tree/v2.4.4" + "source": "https://github.com/livewire/livewire/tree/v2.5.5" }, "funding": [ { @@ -3394,22 +3339,25 @@ "type": "github" } ], - "time": "2021-04-28T15:31:15+00:00" + "time": "2021-07-13T05:03:28+00:00" }, { "name": "lorisleiva/cron-translator", - "version": "v0.2.0", + "version": "v0.2.1", "source": { "type": "git", "url": "https://github.com/lorisleiva/cron-translator.git", - "reference": "764996770558dddc7def8619095391a4ec8048f2" + "reference": "49dc8dc551fd6e11242f170459438470174af308" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/lorisleiva/cron-translator/zipball/764996770558dddc7def8619095391a4ec8048f2", - "reference": "764996770558dddc7def8619095391a4ec8048f2", + "url": "https://api.github.com/repos/lorisleiva/cron-translator/zipball/49dc8dc551fd6e11242f170459438470174af308", + "reference": "49dc8dc551fd6e11242f170459438470174af308", "shasum": "" }, + "require": { + "php": "^7.3 || ^8.0" + }, "require-dev": { "phpunit/phpunit": "^8.0" }, @@ -3439,7 +3387,7 @@ ], "support": { "issues": "https://github.com/lorisleiva/cron-translator/issues", - "source": "https://github.com/lorisleiva/cron-translator/tree/v0.2.0" + "source": "https://github.com/lorisleiva/cron-translator/tree/v0.2.1" }, "funding": [ { @@ -3447,7 +3395,7 @@ "type": "github" } ], - "time": "2021-01-20T10:55:08+00:00" + "time": "2021-07-28T10:20:21+00:00" }, { "name": "mockery/mockery", @@ -3523,16 +3471,16 @@ }, { "name": "monolog/monolog", - "version": "2.2.0", + "version": "2.3.2", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "1cb1cde8e8dd0f70cc0fe51354a59acad9302084" + "reference": "71312564759a7db5b789296369c1a264efc43aad" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/1cb1cde8e8dd0f70cc0fe51354a59acad9302084", - "reference": "1cb1cde8e8dd0f70cc0fe51354a59acad9302084", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/71312564759a7db5b789296369c1a264efc43aad", + "reference": "71312564759a7db5b789296369c1a264efc43aad", "shasum": "" }, "require": { @@ -3551,7 +3499,7 @@ "php-amqplib/php-amqplib": "~2.4", "php-console/php-console": "^3.1.3", "phpspec/prophecy": "^1.6.1", - "phpstan/phpstan": "^0.12.59", + "phpstan/phpstan": "^0.12.91", "phpunit/phpunit": "^8.5", "predis/predis": "^1.1", "rollbar/rollbar": "^1.3", @@ -3603,7 +3551,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/2.2.0" + "source": "https://github.com/Seldaek/monolog/tree/2.3.2" }, "funding": [ { @@ -3615,20 +3563,20 @@ "type": "tidelift" } ], - "time": "2020-12-14T13:15:25+00:00" + "time": "2021-07-23T07:42:52+00:00" }, { "name": "mtdowling/jmespath.php", - "version": "2.6.0", + "version": "2.6.1", "source": { "type": "git", "url": "https://github.com/jmespath/jmespath.php.git", - "reference": "42dae2cbd13154083ca6d70099692fef8ca84bfb" + "reference": "9b87907a81b87bc76d19a7fb2d61e61486ee9edb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/42dae2cbd13154083ca6d70099692fef8ca84bfb", - "reference": "42dae2cbd13154083ca6d70099692fef8ca84bfb", + "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/9b87907a81b87bc76d19a7fb2d61e61486ee9edb", + "reference": "9b87907a81b87bc76d19a7fb2d61e61486ee9edb", "shasum": "" }, "require": { @@ -3636,7 +3584,7 @@ "symfony/polyfill-mbstring": "^1.17" }, "require-dev": { - "composer/xdebug-handler": "^1.4", + "composer/xdebug-handler": "^1.4 || ^2.0", "phpunit/phpunit": "^4.8.36 || ^7.5.15" }, "bin": [ @@ -3674,28 +3622,29 @@ ], "support": { "issues": "https://github.com/jmespath/jmespath.php/issues", - "source": "https://github.com/jmespath/jmespath.php/tree/2.6.0" + "source": "https://github.com/jmespath/jmespath.php/tree/2.6.1" }, - "time": "2020-07-31T21:01:56+00:00" + "time": "2021-06-14T00:11:39+00:00" }, { "name": "nesbot/carbon", - "version": "2.47.0", + "version": "2.52.0", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "606262fd8888b75317ba9461825a24fc34001e1e" + "reference": "369c0e2737c56a0f39c946dd261855255a6fccbe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/606262fd8888b75317ba9461825a24fc34001e1e", - "reference": "606262fd8888b75317ba9461825a24fc34001e1e", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/369c0e2737c56a0f39c946dd261855255a6fccbe", + "reference": "369c0e2737c56a0f39c946dd261855255a6fccbe", "shasum": "" }, "require": { "ext-json": "*", "php": "^7.1.8 || ^8.0", "symfony/polyfill-mbstring": "^1.0", + "symfony/polyfill-php80": "^1.16", "symfony/translation": "^3.4 || ^4.0 || ^5.0" }, "require-dev": { @@ -3714,8 +3663,8 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.x-dev", - "dev-3.x": "3.x-dev" + "dev-3.x": "3.x-dev", + "dev-master": "2.x-dev" }, "laravel": { "providers": [ @@ -3741,15 +3690,15 @@ { "name": "Brian Nesbitt", "email": "brian@nesbot.com", - "homepage": "http://nesbot.com" + "homepage": "https://markido.com" }, { "name": "kylekatarnls", - "homepage": "http://github.com/kylekatarnls" + "homepage": "https://github.com/kylekatarnls" } ], "description": "An API extension for DateTime that supports 281 different languages.", - "homepage": "http://carbon.nesbot.com", + "homepage": "https://carbon.nesbot.com", "keywords": [ "date", "datetime", @@ -3769,20 +3718,20 @@ "type": "tidelift" } ], - "time": "2021-04-13T21:54:02+00:00" + "time": "2021-08-14T19:10:52+00:00" }, { "name": "ohdearapp/ohdear-php-sdk", - "version": "3.1.2", + "version": "3.2.1", "source": { "type": "git", "url": "https://github.com/ohdearapp/ohdear-php-sdk.git", - "reference": "b5e7561947e04428e022c3d9271a0859a6d9c930" + "reference": "5867f1382a6ffcd15aa840b8be6db4572bb19e72" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ohdearapp/ohdear-php-sdk/zipball/b5e7561947e04428e022c3d9271a0859a6d9c930", - "reference": "b5e7561947e04428e022c3d9271a0859a6d9c930", + "url": "https://api.github.com/repos/ohdearapp/ohdear-php-sdk/zipball/5867f1382a6ffcd15aa840b8be6db4572bb19e72", + "reference": "5867f1382a6ffcd15aa840b8be6db4572bb19e72", "shasum": "" }, "require": { @@ -3823,9 +3772,9 @@ ], "support": { "issues": "https://github.com/ohdearapp/ohdear-php-sdk/issues", - "source": "https://github.com/ohdearapp/ohdear-php-sdk/tree/3.1.2" + "source": "https://github.com/ohdearapp/ohdear-php-sdk/tree/3.2.1" }, - "time": "2021-03-02T13:05:05+00:00" + "time": "2021-08-12T19:06:07+00:00" }, { "name": "opis/closure", @@ -3894,29 +3843,29 @@ }, { "name": "phpoption/phpoption", - "version": "1.7.5", + "version": "1.8.0", "source": { "type": "git", "url": "https://github.com/schmittjoh/php-option.git", - "reference": "994ecccd8f3283ecf5ac33254543eb0ac946d525" + "reference": "5455cb38aed4523f99977c4a12ef19da4bfe2a28" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/994ecccd8f3283ecf5ac33254543eb0ac946d525", - "reference": "994ecccd8f3283ecf5ac33254543eb0ac946d525", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/5455cb38aed4523f99977c4a12ef19da4bfe2a28", + "reference": "5455cb38aed4523f99977c4a12ef19da4bfe2a28", "shasum": "" }, "require": { - "php": "^5.5.9 || ^7.0 || ^8.0" + "php": "^7.0 || ^8.0" }, "require-dev": { "bamarni/composer-bin-plugin": "^1.4.1", - "phpunit/phpunit": "^4.8.35 || ^5.7.27 || ^6.5.6 || ^7.0 || ^8.0 || ^9.0" + "phpunit/phpunit": "^6.5.14 || ^7.0.20 || ^8.5.19 || ^9.5.8" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.7-dev" + "dev-master": "1.8-dev" } }, "autoload": { @@ -3935,7 +3884,7 @@ }, { "name": "Graham Campbell", - "email": "graham@alt-three.com" + "email": "hello@gjcampbell.co.uk" } ], "description": "Option Type for PHP", @@ -3947,7 +3896,7 @@ ], "support": { "issues": "https://github.com/schmittjoh/php-option/issues", - "source": "https://github.com/schmittjoh/php-option/tree/1.7.5" + "source": "https://github.com/schmittjoh/php-option/tree/1.8.0" }, "funding": [ { @@ -3959,7 +3908,7 @@ "type": "tidelift" } ], - "time": "2020-07-20T17:29:33+00:00" + "time": "2021-08-28T21:27:29+00:00" }, { "name": "predis/predis", @@ -4377,20 +4326,21 @@ }, { "name": "ramsey/collection", - "version": "1.1.3", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/ramsey/collection.git", - "reference": "28a5c4ab2f5111db6a60b2b4ec84057e0f43b9c1" + "reference": "eaca1dc1054ddd10cbd83c1461907bee6fb528fa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/collection/zipball/28a5c4ab2f5111db6a60b2b4ec84057e0f43b9c1", - "reference": "28a5c4ab2f5111db6a60b2b4ec84057e0f43b9c1", + "url": "https://api.github.com/repos/ramsey/collection/zipball/eaca1dc1054ddd10cbd83c1461907bee6fb528fa", + "reference": "eaca1dc1054ddd10cbd83c1461907bee6fb528fa", "shasum": "" }, "require": { - "php": "^7.2 || ^8" + "php": "^7.3 || ^8", + "symfony/polyfill-php81": "^1.23" }, "require-dev": { "captainhook/captainhook": "^5.3", @@ -4400,6 +4350,7 @@ "hamcrest/hamcrest-php": "^2", "jangregor/phpstan-prophecy": "^0.8", "mockery/mockery": "^1.3", + "phpspec/prophecy-phpunit": "^2.0", "phpstan/extension-installer": "^1", "phpstan/phpstan": "^0.12.32", "phpstan/phpstan-mockery": "^0.12.5", @@ -4427,7 +4378,7 @@ "homepage": "https://benramsey.com" } ], - "description": "A PHP 7.2+ library for representing and manipulating collections.", + "description": "A PHP library for representing and manipulating collections.", "keywords": [ "array", "collection", @@ -4438,7 +4389,7 @@ ], "support": { "issues": "https://github.com/ramsey/collection/issues", - "source": "https://github.com/ramsey/collection/tree/1.1.3" + "source": "https://github.com/ramsey/collection/tree/1.2.1" }, "funding": [ { @@ -4450,20 +4401,20 @@ "type": "tidelift" } ], - "time": "2021-01-21T17:40:04+00:00" + "time": "2021-08-06T03:41:06+00:00" }, { "name": "ramsey/uuid", - "version": "4.1.1", + "version": "4.2.1", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "cd4032040a750077205918c86049aa0f43d22947" + "reference": "fe665a03df4f056aa65af552a96e1976df8c8dae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/cd4032040a750077205918c86049aa0f43d22947", - "reference": "cd4032040a750077205918c86049aa0f43d22947", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/fe665a03df4f056aa65af552a96e1976df8c8dae", + "reference": "fe665a03df4f056aa65af552a96e1976df8c8dae", "shasum": "" }, "require": { @@ -4477,26 +4428,26 @@ "rhumsaa/uuid": "self.version" }, "require-dev": { - "codeception/aspect-mock": "^3", - "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7.0", + "captainhook/captainhook": "^5.10", + "captainhook/plugin-composer": "^5.3", + "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", "doctrine/annotations": "^1.8", - "goaop/framework": "^2", + "ergebnis/composer-normalize": "^2.15", "mockery/mockery": "^1.3", "moontoast/math": "^1.1", "paragonie/random-lib": "^2", + "php-mock/php-mock": "^2.2", "php-mock/php-mock-mockery": "^1.3", - "php-mock/php-mock-phpunit": "^2.5", "php-parallel-lint/php-parallel-lint": "^1.1", - "phpbench/phpbench": "^0.17.1", + "phpbench/phpbench": "^1.0", "phpstan/extension-installer": "^1.0", "phpstan/phpstan": "^0.12", "phpstan/phpstan-mockery": "^0.12", "phpstan/phpstan-phpunit": "^0.12", - "phpunit/phpunit": "^8.5", - "psy/psysh": "^0.10.0", - "slevomat/coding-standard": "^6.0", + "phpunit/phpunit": "^8.5 || ^9", + "slevomat/coding-standard": "^7.0", "squizlabs/php_codesniffer": "^3.5", - "vimeo/psalm": "3.9.4" + "vimeo/psalm": "^4.9" }, "suggest": { "ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.", @@ -4509,7 +4460,10 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.x-dev" + "dev-main": "4.x-dev" + }, + "captainhook": { + "force-install": true } }, "autoload": { @@ -4525,7 +4479,6 @@ "MIT" ], "description": "A PHP library for generating and working with universally unique identifiers (UUIDs).", - "homepage": "https://github.com/ramsey/uuid", "keywords": [ "guid", "identifier", @@ -4533,16 +4486,19 @@ ], "support": { "issues": "https://github.com/ramsey/uuid/issues", - "rss": "https://github.com/ramsey/uuid/releases.atom", - "source": "https://github.com/ramsey/uuid" + "source": "https://github.com/ramsey/uuid/tree/4.2.1" }, "funding": [ { "url": "https://github.com/ramsey", "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/ramsey/uuid", + "type": "tidelift" } ], - "time": "2020-08-18T17:17:46+00:00" + "time": "2021-08-11T01:06:55+00:00" }, { "name": "riimu/kit-phpencoder", @@ -4601,16 +4557,16 @@ }, { "name": "spatie/laravel-feed", - "version": "3.1.3", + "version": "3.2.1", "source": { "type": "git", "url": "https://github.com/spatie/laravel-feed.git", - "reference": "2fcbb3684e4c141b821de842c03f71ff8715e89e" + "reference": "f0d15c878220a69db0f1f94cc2113a0e0e3358dd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/laravel-feed/zipball/2fcbb3684e4c141b821de842c03f71ff8715e89e", - "reference": "2fcbb3684e4c141b821de842c03f71ff8715e89e", + "url": "https://api.github.com/repos/spatie/laravel-feed/zipball/f0d15c878220a69db0f1f94cc2113a0e0e3358dd", + "reference": "f0d15c878220a69db0f1f94cc2113a0e0e3358dd", "shasum": "" }, "require": { @@ -4673,7 +4629,7 @@ ], "support": { "issues": "https://github.com/spatie/laravel-feed/issues", - "source": "https://github.com/spatie/laravel-feed/tree/3.1.3" + "source": "https://github.com/spatie/laravel-feed/tree/3.2.1" }, "funding": [ { @@ -4681,20 +4637,20 @@ "type": "github" } ], - "time": "2021-03-12T16:15:31+00:00" + "time": "2021-05-27T06:44:53+00:00" }, { "name": "spatie/laravel-package-tools", - "version": "1.6.3", + "version": "1.9.0", "source": { "type": "git", "url": "https://github.com/spatie/laravel-package-tools.git", - "reference": "97b53951e9623b3e38babf274c335913bf320a1a" + "reference": "cf4c4cec220575e2864c6082842d76822421f1b1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/laravel-package-tools/zipball/97b53951e9623b3e38babf274c335913bf320a1a", - "reference": "97b53951e9623b3e38babf274c335913bf320a1a", + "url": "https://api.github.com/repos/spatie/laravel-package-tools/zipball/cf4c4cec220575e2864c6082842d76822421f1b1", + "reference": "cf4c4cec220575e2864c6082842d76822421f1b1", "shasum": "" }, "require": { @@ -4733,7 +4689,7 @@ ], "support": { "issues": "https://github.com/spatie/laravel-package-tools/issues", - "source": "https://github.com/spatie/laravel-package-tools/tree/1.6.3" + "source": "https://github.com/spatie/laravel-package-tools/tree/1.9.0" }, "funding": [ { @@ -4741,7 +4697,7 @@ "type": "github" } ], - "time": "2021-04-27T06:17:34+00:00" + "time": "2021-05-23T15:12:33+00:00" }, { "name": "spatie/laravel-robots-middleware", @@ -4805,29 +4761,30 @@ }, { "name": "spatie/laravel-schedule-monitor", - "version": "2.2.1", + "version": "2.4.3", "source": { "type": "git", "url": "https://github.com/spatie/laravel-schedule-monitor.git", - "reference": "715ff63157234cce660151956cb6dd6c7af12ea3" + "reference": "b3d562545a7500a18ed1d169b345a2d2e4efb503" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/laravel-schedule-monitor/zipball/715ff63157234cce660151956cb6dd6c7af12ea3", - "reference": "715ff63157234cce660151956cb6dd6c7af12ea3", + "url": "https://api.github.com/repos/spatie/laravel-schedule-monitor/zipball/b3d562545a7500a18ed1d169b345a2d2e4efb503", + "reference": "b3d562545a7500a18ed1d169b345a2d2e4efb503", "shasum": "" }, "require": { "illuminate/bus": "^8.0", "lorisleiva/cron-translator": "^0.2.0", "nesbot/carbon": "^2.41.3", - "php": "^7.4|^8.0" + "php": "^7.4|^8.0", + "spatie/laravel-package-tools": "^1.9" }, "require-dev": { "laravel/legacy-factories": "^1.0.4", "mockery/mockery": "^1.4", "ohdearapp/ohdear-php-sdk": "^3.0", - "orchestra/testbench": "^6.0", + "orchestra/testbench": "^6.8", "phpunit/phpunit": "^9.3", "spatie/phpunit-snapshot-assertions": "^4.2", "spatie/test-time": "^1.2", @@ -4869,7 +4826,7 @@ ], "support": { "issues": "https://github.com/spatie/laravel-schedule-monitor/issues", - "source": "https://github.com/spatie/laravel-schedule-monitor/tree/2.2.1" + "source": "https://github.com/spatie/laravel-schedule-monitor/tree/2.4.3" }, "funding": [ { @@ -4877,7 +4834,7 @@ "type": "github" } ], - "time": "2021-03-29T10:44:13+00:00" + "time": "2021-08-02T15:10:49+00:00" }, { "name": "swiftmailer/swiftmailer", @@ -4956,27 +4913,29 @@ }, { "name": "symfony/console", - "version": "v5.2.7", + "version": "v5.3.7", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "90374b8ed059325b49a29b55b3f8bb4062c87629" + "reference": "8b1008344647462ae6ec57559da166c2bfa5e16a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/90374b8ed059325b49a29b55b3f8bb4062c87629", - "reference": "90374b8ed059325b49a29b55b3f8bb4062c87629", + "url": "https://api.github.com/repos/symfony/console/zipball/8b1008344647462ae6ec57559da166c2bfa5e16a", + "reference": "8b1008344647462ae6ec57559da166c2bfa5e16a", "shasum": "" }, "require": { "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", "symfony/polyfill-mbstring": "~1.0", "symfony/polyfill-php73": "^1.8", - "symfony/polyfill-php80": "^1.15", + "symfony/polyfill-php80": "^1.16", "symfony/service-contracts": "^1.1|^2", "symfony/string": "^5.1" }, "conflict": { + "psr/log": ">=3", "symfony/dependency-injection": "<4.4", "symfony/dotenv": "<5.1", "symfony/event-dispatcher": "<4.4", @@ -4984,10 +4943,10 @@ "symfony/process": "<4.4" }, "provide": { - "psr/log-implementation": "1.0" + "psr/log-implementation": "1.0|2.0" }, "require-dev": { - "psr/log": "~1.0", + "psr/log": "^1|^2", "symfony/config": "^4.4|^5.0", "symfony/dependency-injection": "^4.4|^5.0", "symfony/event-dispatcher": "^4.4|^5.0", @@ -5033,7 +4992,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.2.7" + "source": "https://github.com/symfony/console/tree/v5.3.7" }, "funding": [ { @@ -5049,24 +5008,25 @@ "type": "tidelift" } ], - "time": "2021-04-19T14:07:32+00:00" + "time": "2021-08-25T20:02:16+00:00" }, { "name": "symfony/css-selector", - "version": "v5.2.7", + "version": "v5.3.4", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "59a684f5ac454f066ecbe6daecce6719aed283fb" + "reference": "7fb120adc7f600a59027775b224c13a33530dd90" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/59a684f5ac454f066ecbe6daecce6719aed283fb", - "reference": "59a684f5ac454f066ecbe6daecce6719aed283fb", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/7fb120adc7f600a59027775b224c13a33530dd90", + "reference": "7fb120adc7f600a59027775b224c13a33530dd90", "shasum": "" }, "require": { - "php": ">=7.2.5" + "php": ">=7.2.5", + "symfony/polyfill-php80": "^1.16" }, "type": "library", "autoload": { @@ -5098,7 +5058,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v5.3.0-BETA1" + "source": "https://github.com/symfony/css-selector/tree/v5.3.4" }, "funding": [ { @@ -5114,7 +5074,7 @@ "type": "tidelift" } ], - "time": "2021-04-07T16:07:52+00:00" + "time": "2021-07-21T12:38:00+00:00" }, { "name": "symfony/deprecation-contracts", @@ -5185,22 +5145,21 @@ }, { "name": "symfony/error-handler", - "version": "v5.2.7", + "version": "v5.3.7", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "ea3ddbf67615e883ca7c33a4de61213789846782" + "reference": "3bc60d0fba00ae8d1eaa9eb5ab11a2bbdd1fc321" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/ea3ddbf67615e883ca7c33a4de61213789846782", - "reference": "ea3ddbf67615e883ca7c33a4de61213789846782", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/3bc60d0fba00ae8d1eaa9eb5ab11a2bbdd1fc321", + "reference": "3bc60d0fba00ae8d1eaa9eb5ab11a2bbdd1fc321", "shasum": "" }, "require": { "php": ">=7.2.5", - "psr/log": "^1.0", - "symfony/polyfill-php80": "^1.15", + "psr/log": "^1|^2|^3", "symfony/var-dumper": "^4.4|^5.0" }, "require-dev": { @@ -5234,7 +5193,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v5.2.7" + "source": "https://github.com/symfony/error-handler/tree/v5.3.7" }, "funding": [ { @@ -5250,27 +5209,27 @@ "type": "tidelift" } ], - "time": "2021-04-07T15:57:33+00:00" + "time": "2021-08-28T15:07:08+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v5.2.4", + "version": "v5.3.7", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "d08d6ec121a425897951900ab692b612a61d6240" + "reference": "ce7b20d69c66a20939d8952b617506a44d102130" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/d08d6ec121a425897951900ab692b612a61d6240", - "reference": "d08d6ec121a425897951900ab692b612a61d6240", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/ce7b20d69c66a20939d8952b617506a44d102130", + "reference": "ce7b20d69c66a20939d8952b617506a44d102130", "shasum": "" }, "require": { "php": ">=7.2.5", "symfony/deprecation-contracts": "^2.1", "symfony/event-dispatcher-contracts": "^2", - "symfony/polyfill-php80": "^1.15" + "symfony/polyfill-php80": "^1.16" }, "conflict": { "symfony/dependency-injection": "<4.4" @@ -5280,7 +5239,7 @@ "symfony/event-dispatcher-implementation": "2.0" }, "require-dev": { - "psr/log": "~1.0", + "psr/log": "^1|^2|^3", "symfony/config": "^4.4|^5.0", "symfony/dependency-injection": "^4.4|^5.0", "symfony/error-handler": "^4.4|^5.0", @@ -5319,7 +5278,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v5.2.4" + "source": "https://github.com/symfony/event-dispatcher/tree/v5.3.7" }, "funding": [ { @@ -5335,7 +5294,7 @@ "type": "tidelift" } ], - "time": "2021-02-18T17:12:37+00:00" + "time": "2021-08-04T21:20:46+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -5418,20 +5377,21 @@ }, { "name": "symfony/finder", - "version": "v5.2.4", + "version": "v5.3.7", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "0d639a0943822626290d169965804f79400e6a04" + "reference": "a10000ada1e600d109a6c7632e9ac42e8bf2fb93" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/0d639a0943822626290d169965804f79400e6a04", - "reference": "0d639a0943822626290d169965804f79400e6a04", + "url": "https://api.github.com/repos/symfony/finder/zipball/a10000ada1e600d109a6c7632e9ac42e8bf2fb93", + "reference": "a10000ada1e600d109a6c7632e9ac42e8bf2fb93", "shasum": "" }, "require": { - "php": ">=7.2.5" + "php": ">=7.2.5", + "symfony/polyfill-php80": "^1.16" }, "type": "library", "autoload": { @@ -5459,7 +5419,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v5.2.4" + "source": "https://github.com/symfony/finder/tree/v5.3.7" }, "funding": [ { @@ -5475,7 +5435,7 @@ "type": "tidelift" } ], - "time": "2021-02-15T18:55:04+00:00" + "time": "2021-08-04T21:20:46+00:00" }, { "name": "symfony/http-client-contracts", @@ -5557,23 +5517,23 @@ }, { "name": "symfony/http-foundation", - "version": "v5.2.7", + "version": "v5.3.7", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "a416487a73bb9c9d120e9ba3a60547f4a3fb7a1f" + "reference": "e36c8e5502b4f3f0190c675f1c1f1248a64f04e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/a416487a73bb9c9d120e9ba3a60547f4a3fb7a1f", - "reference": "a416487a73bb9c9d120e9ba3a60547f4a3fb7a1f", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/e36c8e5502b4f3f0190c675f1c1f1248a64f04e5", + "reference": "e36c8e5502b4f3f0190c675f1c1f1248a64f04e5", "shasum": "" }, "require": { "php": ">=7.2.5", "symfony/deprecation-contracts": "^2.1", "symfony/polyfill-mbstring": "~1.1", - "symfony/polyfill-php80": "^1.15" + "symfony/polyfill-php80": "^1.16" }, "require-dev": { "predis/predis": "~1.0", @@ -5610,7 +5570,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v5.2.7" + "source": "https://github.com/symfony/http-foundation/tree/v5.3.7" }, "funding": [ { @@ -5626,40 +5586,40 @@ "type": "tidelift" } ], - "time": "2021-05-01T13:46:24+00:00" + "time": "2021-08-27T11:20:35+00:00" }, { "name": "symfony/http-kernel", - "version": "v5.2.7", + "version": "v5.3.7", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "1e9f6879f070f718e0055fbac232a56f67b8b6bd" + "reference": "a3a78e37935a527b50376c22ac1cec35b57fe787" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/1e9f6879f070f718e0055fbac232a56f67b8b6bd", - "reference": "1e9f6879f070f718e0055fbac232a56f67b8b6bd", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/a3a78e37935a527b50376c22ac1cec35b57fe787", + "reference": "a3a78e37935a527b50376c22ac1cec35b57fe787", "shasum": "" }, "require": { "php": ">=7.2.5", - "psr/log": "~1.0", + "psr/log": "^1|^2", "symfony/deprecation-contracts": "^2.1", "symfony/error-handler": "^4.4|^5.0", "symfony/event-dispatcher": "^5.0", "symfony/http-client-contracts": "^1.1|^2", - "symfony/http-foundation": "^4.4|^5.0", + "symfony/http-foundation": "^5.3.7", "symfony/polyfill-ctype": "^1.8", "symfony/polyfill-php73": "^1.9", - "symfony/polyfill-php80": "^1.15" + "symfony/polyfill-php80": "^1.16" }, "conflict": { "symfony/browser-kit": "<4.4", "symfony/cache": "<5.0", "symfony/config": "<5.0", "symfony/console": "<4.4", - "symfony/dependency-injection": "<5.1.8", + "symfony/dependency-injection": "<5.3", "symfony/doctrine-bridge": "<5.0", "symfony/form": "<5.0", "symfony/http-client": "<5.0", @@ -5671,7 +5631,7 @@ "twig/twig": "<2.13" }, "provide": { - "psr/log-implementation": "1.0" + "psr/log-implementation": "1.0|2.0" }, "require-dev": { "psr/cache": "^1.0|^2.0|^3.0", @@ -5679,7 +5639,7 @@ "symfony/config": "^5.0", "symfony/console": "^4.4|^5.0", "symfony/css-selector": "^4.4|^5.0", - "symfony/dependency-injection": "^5.1.8", + "symfony/dependency-injection": "^5.3", "symfony/dom-crawler": "^4.4|^5.0", "symfony/expression-language": "^4.4|^5.0", "symfony/finder": "^4.4|^5.0", @@ -5722,7 +5682,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v5.2.7" + "source": "https://github.com/symfony/http-kernel/tree/v5.3.7" }, "funding": [ { @@ -5738,20 +5698,20 @@ "type": "tidelift" } ], - "time": "2021-05-01T14:53:15+00:00" + "time": "2021-08-30T12:37:19+00:00" }, { "name": "symfony/mime", - "version": "v5.2.7", + "version": "v5.3.7", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "7af452bf51c46f18da00feb32e1ad36db9426515" + "reference": "ae887cb3b044658676129f5e97aeb7e9eb69c2d8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/7af452bf51c46f18da00feb32e1ad36db9426515", - "reference": "7af452bf51c46f18da00feb32e1ad36db9426515", + "url": "https://api.github.com/repos/symfony/mime/zipball/ae887cb3b044658676129f5e97aeb7e9eb69c2d8", + "reference": "ae887cb3b044658676129f5e97aeb7e9eb69c2d8", "shasum": "" }, "require": { @@ -5759,7 +5719,7 @@ "symfony/deprecation-contracts": "^2.1", "symfony/polyfill-intl-idn": "^1.10", "symfony/polyfill-mbstring": "^1.0", - "symfony/polyfill-php80": "^1.15" + "symfony/polyfill-php80": "^1.16" }, "conflict": { "egulias/email-validator": "~3.0.0", @@ -5805,7 +5765,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v5.2.7" + "source": "https://github.com/symfony/mime/tree/v5.3.7" }, "funding": [ { @@ -5821,20 +5781,20 @@ "type": "tidelift" } ], - "time": "2021-04-29T20:47:09+00:00" + "time": "2021-08-20T11:40:01+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.22.1", + "version": "v1.23.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "c6c942b1ac76c82448322025e084cadc56048b4e" + "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/c6c942b1ac76c82448322025e084cadc56048b4e", - "reference": "c6c942b1ac76c82448322025e084cadc56048b4e", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/46cd95797e9df938fdd2b03693b5fca5e64b01ce", + "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce", "shasum": "" }, "require": { @@ -5846,7 +5806,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.22-dev" + "dev-main": "1.23-dev" }, "thanks": { "name": "symfony/polyfill", @@ -5884,7 +5844,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.22.1" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.23.0" }, "funding": [ { @@ -5900,20 +5860,20 @@ "type": "tidelift" } ], - "time": "2021-01-07T16:49:33+00:00" + "time": "2021-02-19T12:13:01+00:00" }, { "name": "symfony/polyfill-iconv", - "version": "v1.22.1", + "version": "v1.23.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-iconv.git", - "reference": "06fb361659649bcfd6a208a0f1fcaf4e827ad342" + "reference": "63b5bb7db83e5673936d6e3b8b3e022ff6474933" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/06fb361659649bcfd6a208a0f1fcaf4e827ad342", - "reference": "06fb361659649bcfd6a208a0f1fcaf4e827ad342", + "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/63b5bb7db83e5673936d6e3b8b3e022ff6474933", + "reference": "63b5bb7db83e5673936d6e3b8b3e022ff6474933", "shasum": "" }, "require": { @@ -5925,7 +5885,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.22-dev" + "dev-main": "1.23-dev" }, "thanks": { "name": "symfony/polyfill", @@ -5964,7 +5924,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-iconv/tree/v1.22.1" + "source": "https://github.com/symfony/polyfill-iconv/tree/v1.23.0" }, "funding": [ { @@ -5980,20 +5940,20 @@ "type": "tidelift" } ], - "time": "2021-01-22T09:19:47+00:00" + "time": "2021-05-27T09:27:20+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.22.1", + "version": "v1.23.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "5601e09b69f26c1828b13b6bb87cb07cddba3170" + "reference": "16880ba9c5ebe3642d1995ab866db29270b36535" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/5601e09b69f26c1828b13b6bb87cb07cddba3170", - "reference": "5601e09b69f26c1828b13b6bb87cb07cddba3170", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/16880ba9c5ebe3642d1995ab866db29270b36535", + "reference": "16880ba9c5ebe3642d1995ab866db29270b36535", "shasum": "" }, "require": { @@ -6005,7 +5965,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.22-dev" + "dev-main": "1.23-dev" }, "thanks": { "name": "symfony/polyfill", @@ -6045,7 +6005,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.22.1" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.23.1" }, "funding": [ { @@ -6061,20 +6021,20 @@ "type": "tidelift" } ], - "time": "2021-01-22T09:19:47+00:00" + "time": "2021-05-27T12:26:48+00:00" }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.22.1", + "version": "v1.23.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "2d63434d922daf7da8dd863e7907e67ee3031483" + "reference": "65bd267525e82759e7d8c4e8ceea44f398838e65" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/2d63434d922daf7da8dd863e7907e67ee3031483", - "reference": "2d63434d922daf7da8dd863e7907e67ee3031483", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/65bd267525e82759e7d8c4e8ceea44f398838e65", + "reference": "65bd267525e82759e7d8c4e8ceea44f398838e65", "shasum": "" }, "require": { @@ -6088,7 +6048,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.22-dev" + "dev-main": "1.23-dev" }, "thanks": { "name": "symfony/polyfill", @@ -6132,7 +6092,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.22.1" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.23.0" }, "funding": [ { @@ -6148,20 +6108,20 @@ "type": "tidelift" } ], - "time": "2021-01-22T09:19:47+00:00" + "time": "2021-05-27T09:27:20+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.22.1", + "version": "v1.23.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "43a0283138253ed1d48d352ab6d0bdb3f809f248" + "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/43a0283138253ed1d48d352ab6d0bdb3f809f248", - "reference": "43a0283138253ed1d48d352ab6d0bdb3f809f248", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8590a5f561694770bdcd3f9b5c69dde6945028e8", + "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8", "shasum": "" }, "require": { @@ -6173,7 +6133,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.22-dev" + "dev-main": "1.23-dev" }, "thanks": { "name": "symfony/polyfill", @@ -6216,7 +6176,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.22.1" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.23.0" }, "funding": [ { @@ -6232,20 +6192,20 @@ "type": "tidelift" } ], - "time": "2021-01-22T09:19:47+00:00" + "time": "2021-02-19T12:13:01+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.22.1", + "version": "v1.23.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "5232de97ee3b75b0360528dae24e73db49566ab1" + "reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/5232de97ee3b75b0360528dae24e73db49566ab1", - "reference": "5232de97ee3b75b0360528dae24e73db49566ab1", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9174a3d80210dca8daa7f31fec659150bbeabfc6", + "reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6", "shasum": "" }, "require": { @@ -6257,7 +6217,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.22-dev" + "dev-main": "1.23-dev" }, "thanks": { "name": "symfony/polyfill", @@ -6296,7 +6256,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.22.1" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.23.1" }, "funding": [ { @@ -6312,20 +6272,20 @@ "type": "tidelift" } ], - "time": "2021-01-22T09:19:47+00:00" + "time": "2021-05-27T12:26:48+00:00" }, { "name": "symfony/polyfill-php72", - "version": "v1.22.1", + "version": "v1.23.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9" + "reference": "9a142215a36a3888e30d0a9eeea9766764e96976" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9", - "reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/9a142215a36a3888e30d0a9eeea9766764e96976", + "reference": "9a142215a36a3888e30d0a9eeea9766764e96976", "shasum": "" }, "require": { @@ -6334,7 +6294,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.22-dev" + "dev-main": "1.23-dev" }, "thanks": { "name": "symfony/polyfill", @@ -6372,7 +6332,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php72/tree/v1.22.1" + "source": "https://github.com/symfony/polyfill-php72/tree/v1.23.0" }, "funding": [ { @@ -6388,20 +6348,20 @@ "type": "tidelift" } ], - "time": "2021-01-07T16:49:33+00:00" + "time": "2021-05-27T09:17:38+00:00" }, { "name": "symfony/polyfill-php73", - "version": "v1.22.1", + "version": "v1.23.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "a678b42e92f86eca04b7fa4c0f6f19d097fb69e2" + "reference": "fba8933c384d6476ab14fb7b8526e5287ca7e010" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/a678b42e92f86eca04b7fa4c0f6f19d097fb69e2", - "reference": "a678b42e92f86eca04b7fa4c0f6f19d097fb69e2", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fba8933c384d6476ab14fb7b8526e5287ca7e010", + "reference": "fba8933c384d6476ab14fb7b8526e5287ca7e010", "shasum": "" }, "require": { @@ -6410,7 +6370,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.22-dev" + "dev-main": "1.23-dev" }, "thanks": { "name": "symfony/polyfill", @@ -6451,7 +6411,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.22.1" + "source": "https://github.com/symfony/polyfill-php73/tree/v1.23.0" }, "funding": [ { @@ -6467,20 +6427,20 @@ "type": "tidelift" } ], - "time": "2021-01-07T16:49:33+00:00" + "time": "2021-02-19T12:13:01+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.22.1", + "version": "v1.23.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91" + "reference": "1100343ed1a92e3a38f9ae122fc0eb21602547be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/dc3063ba22c2a1fd2f45ed856374d79114998f91", - "reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/1100343ed1a92e3a38f9ae122fc0eb21602547be", + "reference": "1100343ed1a92e3a38f9ae122fc0eb21602547be", "shasum": "" }, "require": { @@ -6489,7 +6449,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.22-dev" + "dev-main": "1.23-dev" }, "thanks": { "name": "symfony/polyfill", @@ -6534,7 +6494,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.22.1" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.23.1" }, "funding": [ { @@ -6550,25 +6510,104 @@ "type": "tidelift" } ], - "time": "2021-01-07T16:49:33+00:00" + "time": "2021-07-28T13:41:28+00:00" + }, + { + "name": "symfony/polyfill-php81", + "version": "v1.23.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php81.git", + "reference": "e66119f3de95efc359483f810c4c3e6436279436" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/e66119f3de95efc359483f810c4c3e6436279436", + "reference": "e66119f3de95efc359483f810c4c3e6436279436", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php81\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php81/tree/v1.23.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-05-21T13:25:03+00:00" }, { "name": "symfony/process", - "version": "v5.2.7", + "version": "v5.3.7", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "98cb8eeb72e55d4196dd1e36f1f16e7b3a9a088e" + "reference": "38f26c7d6ed535217ea393e05634cb0b244a1967" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/98cb8eeb72e55d4196dd1e36f1f16e7b3a9a088e", - "reference": "98cb8eeb72e55d4196dd1e36f1f16e7b3a9a088e", + "url": "https://api.github.com/repos/symfony/process/zipball/38f26c7d6ed535217ea393e05634cb0b244a1967", + "reference": "38f26c7d6ed535217ea393e05634cb0b244a1967", "shasum": "" }, "require": { "php": ">=7.2.5", - "symfony/polyfill-php80": "^1.15" + "symfony/polyfill-php80": "^1.16" }, "type": "library", "autoload": { @@ -6596,7 +6635,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v5.3.0-BETA1" + "source": "https://github.com/symfony/process/tree/v5.3.7" }, "funding": [ { @@ -6612,36 +6651,37 @@ "type": "tidelift" } ], - "time": "2021-04-08T10:27:02+00:00" + "time": "2021-08-04T21:20:46+00:00" }, { "name": "symfony/routing", - "version": "v5.2.7", + "version": "v5.3.7", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "3f0cab2e95b5e92226f34c2c1aa969d3fc41f48c" + "reference": "be865017746fe869007d94220ad3f5297951811b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/3f0cab2e95b5e92226f34c2c1aa969d3fc41f48c", - "reference": "3f0cab2e95b5e92226f34c2c1aa969d3fc41f48c", + "url": "https://api.github.com/repos/symfony/routing/zipball/be865017746fe869007d94220ad3f5297951811b", + "reference": "be865017746fe869007d94220ad3f5297951811b", "shasum": "" }, "require": { "php": ">=7.2.5", "symfony/deprecation-contracts": "^2.1", - "symfony/polyfill-php80": "^1.15" + "symfony/polyfill-php80": "^1.16" }, "conflict": { - "symfony/config": "<5.0", + "doctrine/annotations": "<1.12", + "symfony/config": "<5.3", "symfony/dependency-injection": "<4.4", "symfony/yaml": "<4.4" }, "require-dev": { - "doctrine/annotations": "^1.10.4", - "psr/log": "~1.0", - "symfony/config": "^5.0", + "doctrine/annotations": "^1.12", + "psr/log": "^1|^2|^3", + "symfony/config": "^5.3", "symfony/dependency-injection": "^4.4|^5.0", "symfony/expression-language": "^4.4|^5.0", "symfony/http-foundation": "^4.4|^5.0", @@ -6685,7 +6725,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v5.2.7" + "source": "https://github.com/symfony/routing/tree/v5.3.7" }, "funding": [ { @@ -6701,7 +6741,7 @@ "type": "tidelift" } ], - "time": "2021-04-11T22:55:21+00:00" + "time": "2021-08-04T21:42:42+00:00" }, { "name": "symfony/service-contracts", @@ -6784,16 +6824,16 @@ }, { "name": "symfony/string", - "version": "v5.2.6", + "version": "v5.3.7", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "ad0bd91bce2054103f5eaa18ebeba8d3bc2a0572" + "reference": "8d224396e28d30f81969f083a58763b8b9ceb0a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/ad0bd91bce2054103f5eaa18ebeba8d3bc2a0572", - "reference": "ad0bd91bce2054103f5eaa18ebeba8d3bc2a0572", + "url": "https://api.github.com/repos/symfony/string/zipball/8d224396e28d30f81969f083a58763b8b9ceb0a5", + "reference": "8d224396e28d30f81969f083a58763b8b9ceb0a5", "shasum": "" }, "require": { @@ -6847,7 +6887,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.2.6" + "source": "https://github.com/symfony/string/tree/v5.3.7" }, "funding": [ { @@ -6863,26 +6903,27 @@ "type": "tidelift" } ], - "time": "2021-03-17T17:12:15+00:00" + "time": "2021-08-26T08:00:08+00:00" }, { "name": "symfony/translation", - "version": "v5.2.7", + "version": "v5.3.7", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "e37ece5242564bceea54d709eafc948377ec9749" + "reference": "4d595a6d15fd3a2c67f6f31d14d15d3b7356d7a6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/e37ece5242564bceea54d709eafc948377ec9749", - "reference": "e37ece5242564bceea54d709eafc948377ec9749", + "url": "https://api.github.com/repos/symfony/translation/zipball/4d595a6d15fd3a2c67f6f31d14d15d3b7356d7a6", + "reference": "4d595a6d15fd3a2c67f6f31d14d15d3b7356d7a6", "shasum": "" }, "require": { "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php80": "^1.15", + "symfony/polyfill-php80": "^1.16", "symfony/translation-contracts": "^2.3" }, "conflict": { @@ -6896,13 +6937,14 @@ "symfony/translation-implementation": "2.3" }, "require-dev": { - "psr/log": "~1.0", + "psr/log": "^1|^2|^3", "symfony/config": "^4.4|^5.0", "symfony/console": "^4.4|^5.0", "symfony/dependency-injection": "^5.0", "symfony/finder": "^4.4|^5.0", "symfony/http-kernel": "^5.0", "symfony/intl": "^4.4|^5.0", + "symfony/polyfill-intl-icu": "^1.21", "symfony/service-contracts": "^1.1.2|^2", "symfony/yaml": "^4.4|^5.0" }, @@ -6940,7 +6982,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v5.2.7" + "source": "https://github.com/symfony/translation/tree/v5.3.7" }, "funding": [ { @@ -6956,7 +6998,7 @@ "type": "tidelift" } ], - "time": "2021-04-01T08:15:21+00:00" + "time": "2021-08-26T08:22:53+00:00" }, { "name": "symfony/translation-contracts", @@ -7038,22 +7080,22 @@ }, { "name": "symfony/var-dumper", - "version": "v5.2.7", + "version": "v5.3.7", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "27cb9f7cfa3853c736425c7233a8f68814b19636" + "reference": "3ad5af4aed07d0a0201bbcfc42658fe6c5b2fb8f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/27cb9f7cfa3853c736425c7233a8f68814b19636", - "reference": "27cb9f7cfa3853c736425c7233a8f68814b19636", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/3ad5af4aed07d0a0201bbcfc42658fe6c5b2fb8f", + "reference": "3ad5af4aed07d0a0201bbcfc42658fe6c5b2fb8f", "shasum": "" }, "require": { "php": ">=7.2.5", "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php80": "^1.15" + "symfony/polyfill-php80": "^1.16" }, "conflict": { "phpunit/phpunit": "<5.4.3", @@ -7106,7 +7148,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v5.2.7" + "source": "https://github.com/symfony/var-dumper/tree/v5.3.7" }, "funding": [ { @@ -7122,7 +7164,7 @@ "type": "tidelift" } ], - "time": "2021-04-19T14:07:32+00:00" + "time": "2021-08-04T23:19:25+00:00" }, { "name": "tijsverkoyen/css-to-inline-styles", @@ -7446,16 +7488,16 @@ "packages-dev": [ { "name": "barryvdh/laravel-debugbar", - "version": "v3.5.5", + "version": "v3.6.2", "source": { "type": "git", "url": "https://github.com/barryvdh/laravel-debugbar.git", - "reference": "6420113d90bb746423fa70b9940e9e7c26ebc121" + "reference": "70b89754913fd89fef16d0170a91dbc2a5cd633a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/6420113d90bb746423fa70b9940e9e7c26ebc121", - "reference": "6420113d90bb746423fa70b9940e9e7c26ebc121", + "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/70b89754913fd89fef16d0170a91dbc2a5cd633a", + "reference": "70b89754913fd89fef16d0170a91dbc2a5cd633a", "shasum": "" }, "require": { @@ -7515,28 +7557,32 @@ ], "support": { "issues": "https://github.com/barryvdh/laravel-debugbar/issues", - "source": "https://github.com/barryvdh/laravel-debugbar/tree/v3.5.5" + "source": "https://github.com/barryvdh/laravel-debugbar/tree/v3.6.2" }, "funding": [ + { + "url": "https://fruitcake.nl", + "type": "custom" + }, { "url": "https://github.com/barryvdh", "type": "github" } ], - "time": "2021-04-07T11:19:20+00:00" + "time": "2021-06-14T14:29:26+00:00" }, { "name": "brianium/paratest", - "version": "v6.3.0", + "version": "v6.3.1", "source": { "type": "git", "url": "https://github.com/paratestphp/paratest.git", - "reference": "268d5b2b4237c0abf76c4aa9633ad8580be01e1e" + "reference": "3d81e35876f6497467310b123583cca6bd4c38f2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paratestphp/paratest/zipball/268d5b2b4237c0abf76c4aa9633ad8580be01e1e", - "reference": "268d5b2b4237c0abf76c4aa9633ad8580be01e1e", + "url": "https://api.github.com/repos/paratestphp/paratest/zipball/3d81e35876f6497467310b123583cca6bd4c38f2", + "reference": "3d81e35876f6497467310b123583cca6bd4c38f2", "shasum": "" }, "require": { @@ -7548,25 +7594,25 @@ "phpunit/php-code-coverage": "^9.2.6", "phpunit/php-file-iterator": "^3.0.5", "phpunit/php-timer": "^5.0.3", - "phpunit/phpunit": "^9.5.4", + "phpunit/phpunit": "^9.5.8", "sebastian/environment": "^5.1.3", - "symfony/console": "^4.4.21 || ^5.2.6", - "symfony/process": "^4.4.21 || ^5.2.4" + "symfony/console": "^4.4.23 || ^5.3.6", + "symfony/process": "^4.4.22 || ^5.3.4" }, "require-dev": { "doctrine/coding-standard": "^9.0.0", "ekino/phpstan-banned-code": "^0.4.0", "ergebnis/phpstan-rules": "^0.15.3", "ext-posix": "*", - "infection/infection": "^0.21.5", - "phpstan/phpstan": "^0.12.84", + "infection/infection": "^0.24", + "phpstan/phpstan": "^0.12.94", "phpstan/phpstan-deprecation-rules": "^0.12.6", - "phpstan/phpstan-phpunit": "^0.12.18", - "phpstan/phpstan-strict-rules": "^0.12.9", + "phpstan/phpstan-phpunit": "^0.12.21", + "phpstan/phpstan-strict-rules": "^0.12.10", "squizlabs/php_codesniffer": "^3.6.0", - "symfony/filesystem": "^5.2.6", + "symfony/filesystem": "^5.3.4", "thecodingmachine/phpstan-strict-rules": "^0.12.1", - "vimeo/psalm": "^4.7.1" + "vimeo/psalm": "^4.9.2" }, "bin": [ "bin/paratest" @@ -7605,7 +7651,7 @@ ], "support": { "issues": "https://github.com/paratestphp/paratest/issues", - "source": "https://github.com/paratestphp/paratest/tree/v6.3.0" + "source": "https://github.com/paratestphp/paratest/tree/v6.3.1" }, "funding": [ { @@ -7617,7 +7663,7 @@ "type": "paypal" } ], - "time": "2021-04-27T09:24:27+00:00" + "time": "2021-08-10T07:38:58+00:00" }, { "name": "doctrine/instantiator", @@ -7690,16 +7736,16 @@ }, { "name": "fakerphp/faker", - "version": "v1.14.1", + "version": "v1.15.0", "source": { "type": "git", "url": "https://github.com/FakerPHP/Faker.git", - "reference": "ed22aee8d17c7b396f74a58b1e7fefa4f90d5ef1" + "reference": "89c6201c74db25fa759ff16e78a4d8f32547770e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/ed22aee8d17c7b396f74a58b1e7fefa4f90d5ef1", - "reference": "ed22aee8d17c7b396f74a58b1e7fefa4f90d5ef1", + "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/89c6201c74db25fa759ff16e78a4d8f32547770e", + "reference": "89c6201c74db25fa759ff16e78a4d8f32547770e", "shasum": "" }, "require": { @@ -7749,9 +7795,80 @@ ], "support": { "issues": "https://github.com/FakerPHP/Faker/issues", - "source": "https://github.com/FakerPHP/Faker/tree/v.1.14.1" + "source": "https://github.com/FakerPHP/Faker/tree/v1.15.0" + }, + "time": "2021-07-06T20:39:40+00:00" + }, + { + "name": "filp/whoops", + "version": "2.14.1", + "source": { + "type": "git", + "url": "https://github.com/filp/whoops.git", + "reference": "15ead64e9828f0fc90932114429c4f7923570cb1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/filp/whoops/zipball/15ead64e9828f0fc90932114429c4f7923570cb1", + "reference": "15ead64e9828f0fc90932114429c4f7923570cb1", + "shasum": "" + }, + "require": { + "php": "^5.5.9 || ^7.0 || ^8.0", + "psr/log": "^1.0.1" + }, + "require-dev": { + "mockery/mockery": "^0.9 || ^1.0", + "phpunit/phpunit": "^4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.3", + "symfony/var-dumper": "^2.6 || ^3.0 || ^4.0 || ^5.0" + }, + "suggest": { + "symfony/var-dumper": "Pretty print complex values better with var-dumper available", + "whoops/soap": "Formats errors as SOAP responses" }, - "time": "2021-03-30T06:27:33+00:00" + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Whoops\\": "src/Whoops/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Filipe Dobreira", + "homepage": "https://github.com/filp", + "role": "Developer" + } + ], + "description": "php error handling for cool kids", + "homepage": "https://filp.github.io/whoops/", + "keywords": [ + "error", + "exception", + "handling", + "library", + "throwable", + "whoops" + ], + "support": { + "issues": "https://github.com/filp/whoops/issues", + "source": "https://github.com/filp/whoops/tree/2.14.1" + }, + "funding": [ + { + "url": "https://github.com/denis-sokolov", + "type": "github" + } + ], + "time": "2021-08-29T12:00:00+00:00" }, { "name": "laravel/browser-kit-testing", @@ -7821,16 +7938,16 @@ }, { "name": "maximebf/debugbar", - "version": "v1.16.5", + "version": "v1.17.1", "source": { "type": "git", "url": "https://github.com/maximebf/php-debugbar.git", - "reference": "6d51ee9e94cff14412783785e79a4e7ef97b9d62" + "reference": "0a3532556be0145603f8a9de23e76dc28eed7054" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/6d51ee9e94cff14412783785e79a4e7ef97b9d62", - "reference": "6d51ee9e94cff14412783785e79a4e7ef97b9d62", + "url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/0a3532556be0145603f8a9de23e76dc28eed7054", + "reference": "0a3532556be0145603f8a9de23e76dc28eed7054", "shasum": "" }, "require": { @@ -7849,7 +7966,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.16-dev" + "dev-master": "1.17-dev" } }, "autoload": { @@ -7880,9 +7997,9 @@ ], "support": { "issues": "https://github.com/maximebf/php-debugbar/issues", - "source": "https://github.com/maximebf/php-debugbar/tree/v1.16.5" + "source": "https://github.com/maximebf/php-debugbar/tree/v1.17.1" }, - "time": "2020-12-07T11:07:24+00:00" + "time": "2021-08-01T09:19:02+00:00" }, { "name": "myclabs/deep-copy", @@ -7944,16 +8061,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.10.5", + "version": "v4.12.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "4432ba399e47c66624bc73c8c0f811e5c109576f" + "reference": "6608f01670c3cc5079e18c1dab1104e002579143" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/4432ba399e47c66624bc73c8c0f811e5c109576f", - "reference": "4432ba399e47c66624bc73c8c0f811e5c109576f", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/6608f01670c3cc5079e18c1dab1104e002579143", + "reference": "6608f01670c3cc5079e18c1dab1104e002579143", "shasum": "" }, "require": { @@ -7994,22 +8111,22 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.10.5" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.12.0" }, - "time": "2021-05-03T19:11:20+00:00" + "time": "2021-07-21T10:44:31+00:00" }, { "name": "nunomaduro/collision", - "version": "v5.4.0", + "version": "v5.9.0", "source": { "type": "git", "url": "https://github.com/nunomaduro/collision.git", - "reference": "41b7e9999133d5082700d31a1d0977161df8322a" + "reference": "63456f5c3e8c4bc52bd573e5c85674d64d84fd43" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/collision/zipball/41b7e9999133d5082700d31a1d0977161df8322a", - "reference": "41b7e9999133d5082700d31a1d0977161df8322a", + "url": "https://api.github.com/repos/nunomaduro/collision/zipball/63456f5c3e8c4bc52bd573e5c85674d64d84fd43", + "reference": "63456f5c3e8c4bc52bd573e5c85674d64d84fd43", "shasum": "" }, "require": { @@ -8021,12 +8138,12 @@ "require-dev": { "brianium/paratest": "^6.1", "fideloper/proxy": "^4.4.1", - "friendsofphp/php-cs-fixer": "^2.17.3", + "friendsofphp/php-cs-fixer": "^3.0", "fruitcake/laravel-cors": "^2.0.3", - "laravel/framework": "^9.0", + "laravel/framework": "^8.0 || ^9.0", "nunomaduro/larastan": "^0.6.2", "nunomaduro/mock-final-classes": "^1.0", - "orchestra/testbench": "^7.0", + "orchestra/testbench": "^6.0 || ^7.0", "phpstan/phpstan": "^0.12.64", "phpunit/phpunit": "^9.5.0" }, @@ -8084,20 +8201,270 @@ "type": "patreon" } ], - "time": "2021-04-09T13:38:32+00:00" + "time": "2021-08-26T15:32:09+00:00" + }, + { + "name": "pestphp/pest", + "version": "v1.18.0", + "source": { + "type": "git", + "url": "https://github.com/pestphp/pest.git", + "reference": "60c06365233f8b7f6958799529f42cea7f9fbaf8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pestphp/pest/zipball/60c06365233f8b7f6958799529f42cea7f9fbaf8", + "reference": "60c06365233f8b7f6958799529f42cea7f9fbaf8", + "shasum": "" + }, + "require": { + "nunomaduro/collision": "^5.4.0|^6.0", + "pestphp/pest-plugin": "^1.0.0", + "php": "^7.3 || ^8.0", + "phpunit/phpunit": "^9.5.5" + }, + "require-dev": { + "illuminate/console": "^8.47.0", + "illuminate/support": "^8.47.0", + "laravel/dusk": "^6.15.0", + "pestphp/pest-dev-tools": "dev-master", + "pestphp/pest-plugin-parallel": "^1.0" + }, + "bin": [ + "bin/pest" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + }, + "pest": { + "plugins": [ + "Pest\\Plugins\\Coverage", + "Pest\\Plugins\\Init", + "Pest\\Plugins\\Version" + ] + }, + "laravel": { + "providers": [ + "Pest\\Laravel\\PestServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Pest\\": "src/" + }, + "files": [ + "src/Functions.php", + "src/Pest.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "An 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/v1.18.0" + }, + "funding": [ + { + "url": "https://github.com/lukeraymonddowning", + "type": "github" + }, + { + "url": "https://github.com/nunomaduro", + "type": "github" + }, + { + "url": "https://github.com/octoper", + "type": "github" + }, + { + "url": "https://github.com/olivernybroe", + "type": "github" + }, + { + "url": "https://github.com/owenvoke", + "type": "github" + }, + { + "url": "https://www.patreon.com/nunomaduro", + "type": "patreon" + } + ], + "time": "2021-08-29T23:05:26+00:00" + }, + { + "name": "pestphp/pest-plugin", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/pestphp/pest-plugin.git", + "reference": "fc8519de148699fe612d9c669be60554cd2db4fa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pestphp/pest-plugin/zipball/fc8519de148699fe612d9c669be60554cd2db4fa", + "reference": "fc8519de148699fe612d9c669be60554cd2db4fa", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.1 || ^2.0", + "php": "^7.3 || ^8.0" + }, + "conflict": { + "pestphp/pest": "<1.0" + }, + "require-dev": { + "composer/composer": "^1.10.19", + "pestphp/pest": "^1.0", + "pestphp/pest-dev-tools": "dev-master" + }, + "type": "composer-plugin", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + }, + "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/v1.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": "2021-01-03T15:53:42+00:00" + }, + { + "name": "pestphp/pest-plugin-laravel", + "version": "v1.1.0", + "source": { + "type": "git", + "url": "https://github.com/pestphp/pest-plugin-laravel.git", + "reference": "bacc1ef1f537cf9adf692b6930e54f607ae530ad" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pestphp/pest-plugin-laravel/zipball/bacc1ef1f537cf9adf692b6930e54f607ae530ad", + "reference": "bacc1ef1f537cf9adf692b6930e54f607ae530ad", + "shasum": "" + }, + "require": { + "laravel/framework": "^7.0 || ^8.0", + "pestphp/pest": "^1.7", + "php": "^7.3 || ^8.0" + }, + "require-dev": { + "orchestra/testbench": "^5.12.1 || ^6.7.2", + "pestphp/pest-dev-tools": "dev-master" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Pest\\Laravel\\": "src/" + }, + "files": [ + "src/Autoload.php" + ] + }, + "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/v1.1.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": "2021-07-07T09:11:42+00:00" }, { "name": "phar-io/manifest", - "version": "2.0.1", + "version": "2.0.3", "source": { "type": "git", "url": "https://github.com/phar-io/manifest.git", - "reference": "85265efd3af7ba3ca4b2a2c34dbfc5788dd29133" + "reference": "97803eca37d319dfa7826cc2437fc020857acb53" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/85265efd3af7ba3ca4b2a2c34dbfc5788dd29133", - "reference": "85265efd3af7ba3ca4b2a2c34dbfc5788dd29133", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", + "reference": "97803eca37d319dfa7826cc2437fc020857acb53", "shasum": "" }, "require": { @@ -8142,9 +8509,9 @@ "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", "support": { "issues": "https://github.com/phar-io/manifest/issues", - "source": "https://github.com/phar-io/manifest/tree/master" + "source": "https://github.com/phar-io/manifest/tree/2.0.3" }, - "time": "2020-06-27T14:33:11+00:00" + "time": "2021-07-20T11:28:43+00:00" }, { "name": "phar-io/version", @@ -8742,16 +9109,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.5.4", + "version": "9.5.9", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "c73c6737305e779771147af66c96ca6a7ed8a741" + "reference": "ea8c2dfb1065eb35a79b3681eee6e6fb0a6f273b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c73c6737305e779771147af66c96ca6a7ed8a741", - "reference": "c73c6737305e779771147af66c96ca6a7ed8a741", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/ea8c2dfb1065eb35a79b3681eee6e6fb0a6f273b", + "reference": "ea8c2dfb1065eb35a79b3681eee6e6fb0a6f273b", "shasum": "" }, "require": { @@ -8763,7 +9130,7 @@ "ext-xml": "*", "ext-xmlwriter": "*", "myclabs/deep-copy": "^1.10.1", - "phar-io/manifest": "^2.0.1", + "phar-io/manifest": "^2.0.3", "phar-io/version": "^3.0.2", "php": ">=7.3", "phpspec/prophecy": "^1.12.1", @@ -8781,7 +9148,7 @@ "sebastian/global-state": "^5.0.1", "sebastian/object-enumerator": "^4.0.3", "sebastian/resource-operations": "^3.0.3", - "sebastian/type": "^2.3", + "sebastian/type": "^2.3.4", "sebastian/version": "^3.0.2" }, "require-dev": { @@ -8829,7 +9196,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.4" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.9" }, "funding": [ { @@ -8841,7 +9208,7 @@ "type": "github" } ], - "time": "2021-03-23T07:16:29+00:00" + "time": "2021-08-31T06:47:40+00:00" }, { "name": "sebastian/cli-parser", @@ -9349,16 +9716,16 @@ }, { "name": "sebastian/global-state", - "version": "5.0.2", + "version": "5.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "a90ccbddffa067b51f574dea6eb25d5680839455" + "reference": "23bd5951f7ff26f12d4e3242864df3e08dec4e49" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/a90ccbddffa067b51f574dea6eb25d5680839455", - "reference": "a90ccbddffa067b51f574dea6eb25d5680839455", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/23bd5951f7ff26f12d4e3242864df3e08dec4e49", + "reference": "23bd5951f7ff26f12d4e3242864df3e08dec4e49", "shasum": "" }, "require": { @@ -9401,7 +9768,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.2" + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.3" }, "funding": [ { @@ -9409,7 +9776,7 @@ "type": "github" } ], - "time": "2020-10-26T15:55:19+00:00" + "time": "2021-06-11T13:31:12+00:00" }, { "name": "sebastian/lines-of-code", @@ -9700,16 +10067,16 @@ }, { "name": "sebastian/type", - "version": "2.3.1", + "version": "2.3.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "81cd61ab7bbf2de744aba0ea61fae32f721df3d2" + "reference": "b8cd8a1c753c90bc1a0f5372170e3e489136f914" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/81cd61ab7bbf2de744aba0ea61fae32f721df3d2", - "reference": "81cd61ab7bbf2de744aba0ea61fae32f721df3d2", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/b8cd8a1c753c90bc1a0f5372170e3e489136f914", + "reference": "b8cd8a1c753c90bc1a0f5372170e3e489136f914", "shasum": "" }, "require": { @@ -9744,7 +10111,7 @@ "homepage": "https://github.com/sebastianbergmann/type", "support": { "issues": "https://github.com/sebastianbergmann/type/issues", - "source": "https://github.com/sebastianbergmann/type/tree/2.3.1" + "source": "https://github.com/sebastianbergmann/type/tree/2.3.4" }, "funding": [ { @@ -9752,7 +10119,7 @@ "type": "github" } ], - "time": "2020-10-26T13:18:59+00:00" + "time": "2021-06-15T12:49:02+00:00" }, { "name": "sebastian/version", @@ -9809,22 +10176,21 @@ }, { "name": "symfony/debug", - "version": "v4.4.22", + "version": "v4.4.27", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", - "reference": "45b2136377cca5f10af858968d6079a482bca473" + "reference": "2f9160e92eb64c95da7368c867b663a8e34e980c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/45b2136377cca5f10af858968d6079a482bca473", - "reference": "45b2136377cca5f10af858968d6079a482bca473", + "url": "https://api.github.com/repos/symfony/debug/zipball/2f9160e92eb64c95da7368c867b663a8e34e980c", + "reference": "2f9160e92eb64c95da7368c867b663a8e34e980c", "shasum": "" }, "require": { "php": ">=7.1.3", - "psr/log": "~1.0", - "symfony/polyfill-php80": "^1.15" + "psr/log": "^1|^2|^3" }, "conflict": { "symfony/http-kernel": "<3.4" @@ -9858,7 +10224,7 @@ "description": "Provides tools to ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/debug/tree/v4.4.22" + "source": "https://github.com/symfony/debug/tree/v4.4.27" }, "funding": [ { @@ -9874,27 +10240,28 @@ "type": "tidelift" } ], - "time": "2021-04-02T07:50:12+00:00" + "time": "2021-07-22T07:21:39+00:00" }, { "name": "symfony/dom-crawler", - "version": "v5.2.4", + "version": "v5.3.7", "source": { "type": "git", "url": "https://github.com/symfony/dom-crawler.git", - "reference": "400e265163f65aceee7e904ef532e15228de674b" + "reference": "c7eef3a60ccfdd8eafe07f81652e769ac9c7146c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/400e265163f65aceee7e904ef532e15228de674b", - "reference": "400e265163f65aceee7e904ef532e15228de674b", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/c7eef3a60ccfdd8eafe07f81652e769ac9c7146c", + "reference": "c7eef3a60ccfdd8eafe07f81652e769ac9c7146c", "shasum": "" }, "require": { "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php80": "^1.15" + "symfony/polyfill-php80": "^1.16" }, "conflict": { "masterminds/html5": "<2.6" @@ -9932,7 +10299,7 @@ "description": "Eases DOM navigation for HTML and XML documents", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dom-crawler/tree/v5.2.4" + "source": "https://github.com/symfony/dom-crawler/tree/v5.3.7" }, "funding": [ { @@ -9948,20 +10315,20 @@ "type": "tidelift" } ], - "time": "2021-02-15T18:55:04+00:00" + "time": "2021-08-29T19:32:13+00:00" }, { "name": "theseer/tokenizer", - "version": "1.2.0", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "75a63c33a8577608444246075ea0af0d052e452a" + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/75a63c33a8577608444246075ea0af0d052e452a", - "reference": "75a63c33a8577608444246075ea0af0d052e452a", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", "shasum": "" }, "require": { @@ -9990,7 +10357,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/master" + "source": "https://github.com/theseer/tokenizer/tree/1.2.1" }, "funding": [ { @@ -9998,7 +10365,7 @@ "type": "github" } ], - "time": "2020-07-12T23:59:07+00:00" + "time": "2021-07-28T10:34:58+00:00" } ], "aliases": [], From 2790d26edba1dce1b40e9d20e857d281374bc53f Mon Sep 17 00:00:00 2001 From: Jason McCreary Date: Thu, 2 Sep 2021 14:05:32 -0400 Subject: [PATCH 08/14] Include missing import --- tests/Feature/AdminTest.php | 1 + tests/Feature/ArticleTest.php | 1 + tests/Feature/AuthTest.php | 1 + tests/Feature/DashboardTest.php | 1 + tests/Feature/ForumTest.php | 1 + tests/Feature/HomeTest.php | 1 + tests/Feature/ModeratorTest.php | 1 + tests/Feature/NavigationTest.php | 1 + tests/Feature/ProfileTest.php | 1 + tests/Feature/ReplyTest.php | 1 + tests/Feature/SettingsTest.php | 1 + tests/Feature/SubscriptionsTest.php | 1 + 12 files changed, 12 insertions(+) diff --git a/tests/Feature/AdminTest.php b/tests/Feature/AdminTest.php index e3040f8e9..a7aa7e4e7 100644 --- a/tests/Feature/AdminTest.php +++ b/tests/Feature/AdminTest.php @@ -6,6 +6,7 @@ use App\Models\User; use Carbon\Carbon; use Illuminate\Foundation\Testing\DatabaseMigrations; +use Tests\Feature\BrowserKitTestCase; uses(BrowserKitTestCase::class); uses(DatabaseMigrations::class); diff --git a/tests/Feature/ArticleTest.php b/tests/Feature/ArticleTest.php index e8954301d..f15a5d0dc 100644 --- a/tests/Feature/ArticleTest.php +++ b/tests/Feature/ArticleTest.php @@ -7,6 +7,7 @@ use Illuminate\Foundation\Testing\DatabaseMigrations; use Illuminate\Support\Facades\Notification; use Livewire\Livewire; +use Tests\Feature\BrowserKitTestCase; uses(BrowserKitTestCase::class); uses(DatabaseMigrations::class); diff --git a/tests/Feature/AuthTest.php b/tests/Feature/AuthTest.php index 59530864b..bfebc26f4 100644 --- a/tests/Feature/AuthTest.php +++ b/tests/Feature/AuthTest.php @@ -6,6 +6,7 @@ use Illuminate\Foundation\Testing\DatabaseMigrations; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Event; +use Tests\Feature\BrowserKitTestCase; uses(BrowserKitTestCase::class); uses(DatabaseMigrations::class); diff --git a/tests/Feature/DashboardTest.php b/tests/Feature/DashboardTest.php index bb3811e9e..d964f7a74 100644 --- a/tests/Feature/DashboardTest.php +++ b/tests/Feature/DashboardTest.php @@ -9,6 +9,7 @@ use Illuminate\Support\HtmlString; use Illuminate\Support\Str; use Livewire\Livewire; +use Tests\Feature\BrowserKitTestCase; uses(BrowserKitTestCase::class); uses(DatabaseMigrations::class); diff --git a/tests/Feature/ForumTest.php b/tests/Feature/ForumTest.php index 091288e62..ad9260a45 100644 --- a/tests/Feature/ForumTest.php +++ b/tests/Feature/ForumTest.php @@ -7,6 +7,7 @@ use App\Models\Thread; use Illuminate\Foundation\Testing\DatabaseMigrations; use Livewire\Livewire; +use Tests\Feature\BrowserKitTestCase; uses(BrowserKitTestCase::class); uses(DatabaseMigrations::class); diff --git a/tests/Feature/HomeTest.php b/tests/Feature/HomeTest.php index ac623797c..0920d970b 100644 --- a/tests/Feature/HomeTest.php +++ b/tests/Feature/HomeTest.php @@ -1,6 +1,7 @@ Date: Thu, 2 Sep 2021 14:05:44 -0400 Subject: [PATCH 09/14] Use facade --- tests/Feature/SettingsTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/Feature/SettingsTest.php b/tests/Feature/SettingsTest.php index c36bea144..d689380a6 100644 --- a/tests/Feature/SettingsTest.php +++ b/tests/Feature/SettingsTest.php @@ -3,6 +3,7 @@ use App\Models\User; use Illuminate\Foundation\Testing\DatabaseMigrations; use Illuminate\Support\Facades\Auth; +use Illuminate\Support\Facades\Hash; use Tests\Feature\BrowserKitTestCase; uses(BrowserKitTestCase::class); @@ -131,5 +132,5 @@ // Helpers function assertPasswordWasHashedAndSaved(): void { - expect($this->app['hash']->check('QFq^$cz#P@MZa5z7', Auth::user()->getAuthPassword()))->toBeTrue(); + expect(Hash::check('QFq^$cz#P@MZa5z7', Auth::user()->getAuthPassword()))->toBeTrue(); } From 84d41fa2843626000374c193dc774c6f9ad74b91 Mon Sep 17 00:00:00 2001 From: Joe Dixon Date: Mon, 20 Sep 2021 13:49:13 +0100 Subject: [PATCH 10/14] Use test() in helpers --- tests/Feature/AdminTest.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/Feature/AdminTest.php b/tests/Feature/AdminTest.php index a7aa7e4e7..5837e1cdd 100644 --- a/tests/Feature/AdminTest.php +++ b/tests/Feature/AdminTest.php @@ -1,12 +1,12 @@ create(['name' => 'Freek Murze']); User::factory()->create(['name' => 'Frederick Vanbrabant']); - $this->visit('/admin') + test()->visit('/admin') ->see('Freek Murze') ->see('Frederick Vanbrabant'); } @@ -335,20 +335,20 @@ function assertCanBanUsers() { $user = User::factory()->create(['name' => 'Freek Murze']); - $this->put('/admin/users/'.$user->username().'/ban') + test()->put('/admin/users/'.$user->username().'/ban') ->assertRedirectedTo('/user/'.$user->username()); - $this->notSeeInDatabase('users', ['id' => $user->id(), 'banned_at' => null]); + test()->notSeeInDatabase('users', ['id' => $user->id(), 'banned_at' => null]); } function assertCanUnbanUsers() { $user = User::factory()->create(['name' => 'Freek Murze', 'banned_at' => Carbon::now()]); - $this->put('/admin/users/'.$user->username().'/unban') + test()->put('/admin/users/'.$user->username().'/unban') ->assertRedirectedTo('/user/'.$user->username()); - $this->seeInDatabase('users', ['id' => $user->id(), 'banned_at' => null]); + test()->seeInDatabase('users', ['id' => $user->id(), 'banned_at' => null]); } function assertCannotBanAdmins() @@ -365,6 +365,6 @@ function assertCannotBanUsersByType(int $type) { $user = User::factory()->create(['type' => $type]); - $this->put('/admin/users/'.$user->username().'/ban') + test()->put('/admin/users/'.$user->username().'/ban') ->assertForbidden(); } From b17e7513fd45d1397e7d2ffd31c0671687bca348 Mon Sep 17 00:00:00 2001 From: Joe Dixon Date: Mon, 20 Sep 2021 13:51:30 +0100 Subject: [PATCH 11/14] Apply style fixes --- tests/Feature/AdminTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/Feature/AdminTest.php b/tests/Feature/AdminTest.php index 5837e1cdd..ad63bc6dd 100644 --- a/tests/Feature/AdminTest.php +++ b/tests/Feature/AdminTest.php @@ -1,12 +1,12 @@ Date: Wed, 6 Oct 2021 20:30:14 +0100 Subject: [PATCH 12/14] Update formatting --- tests/Feature/AdminTest.php | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/tests/Feature/AdminTest.php b/tests/Feature/AdminTest.php index ad63bc6dd..28a520ba3 100644 --- a/tests/Feature/AdminTest.php +++ b/tests/Feature/AdminTest.php @@ -1,12 +1,12 @@ loginAsAdmin(); + assertCanSeeTheUserOverview(); }); test('moderators can see the users overview', function () { $this->loginAsModerator(); + assertCanSeeTheUserOverview(); }); test('admins can ban a user', function () { $this->loginAsAdmin(); + assertCanBanUsers(); }); test('moderators can ban a user', function () { $this->loginAsModerator(); + assertCanBanUsers(); }); test('admins can unban a user', function () { $this->loginAsAdmin(); + assertCanUnbanUsers(); }); test('moderators can unban a user', function () { $this->loginAsModerator(); + assertCanUnbanUsers(); }); test('admins cannot ban other admins', function () { $this->loginAsAdmin(); + assertCannotBanAdmins(); }); test('moderators cannot ban admins', function () { $this->loginAsModerator(); + assertCannotBanAdmins(); }); test('moderators cannot ban other moderators', function () { $this->loginAsModerator(); + assertCannotBanModerators(); }); From b47df6cb1ed7e0c96509437ab3515ee36dec2e7a Mon Sep 17 00:00:00 2001 From: Joe Dixon Date: Wed, 6 Oct 2021 20:35:29 +0100 Subject: [PATCH 13/14] Use standard class --- tests/Feature/BrowserKitTestCase.php | 8 ++++---- tests/TestCase.php | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/Feature/BrowserKitTestCase.php b/tests/Feature/BrowserKitTestCase.php index 5ba6e501b..440a6a9fd 100644 --- a/tests/Feature/BrowserKitTestCase.php +++ b/tests/Feature/BrowserKitTestCase.php @@ -2,13 +2,13 @@ namespace Tests\Feature; -use Illuminate\Foundation\Testing\WithFaker; -use Laravel\BrowserKitTesting\TestCase as BaseTestCase; -use Tests\CreatesApplication; use Tests\CreatesUsers; use Tests\HttpAssertions; +use Tests\CreatesApplication; +use Illuminate\Foundation\Testing\WithFaker; +use Laravel\BrowserKitTesting\TestCase as BaseTestCase; -abstract class BrowserKitTestCase extends BaseTestCase +class BrowserKitTestCase extends BaseTestCase { use CreatesApplication; use CreatesUsers; diff --git a/tests/TestCase.php b/tests/TestCase.php index 560ebdf72..0b23e420f 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -4,7 +4,7 @@ use Illuminate\Foundation\Testing\TestCase as IlluminateTestCase; -abstract class TestCase extends IlluminateTestCase +class TestCase extends IlluminateTestCase { use CreatesApplication; use CreatesUsers; From 43fa200cd5e46f85cb20b363cc2492335113055a Mon Sep 17 00:00:00 2001 From: Joe Dixon Date: Wed, 6 Oct 2021 20:42:40 +0100 Subject: [PATCH 14/14] Apply stycleci fixes --- tests/Feature/AdminTest.php | 10 +++++----- tests/Feature/BrowserKitTestCase.php | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/Feature/AdminTest.php b/tests/Feature/AdminTest.php index 28a520ba3..6eb6053b3 100644 --- a/tests/Feature/AdminTest.php +++ b/tests/Feature/AdminTest.php @@ -1,12 +1,12 @@ loginAsModerator(); - + assertCannotBanModerators(); }); diff --git a/tests/Feature/BrowserKitTestCase.php b/tests/Feature/BrowserKitTestCase.php index 440a6a9fd..f65f622e1 100644 --- a/tests/Feature/BrowserKitTestCase.php +++ b/tests/Feature/BrowserKitTestCase.php @@ -2,11 +2,11 @@ namespace Tests\Feature; -use Tests\CreatesUsers; -use Tests\HttpAssertions; -use Tests\CreatesApplication; use Illuminate\Foundation\Testing\WithFaker; use Laravel\BrowserKitTesting\TestCase as BaseTestCase; +use Tests\CreatesApplication; +use Tests\CreatesUsers; +use Tests\HttpAssertions; class BrowserKitTestCase extends BaseTestCase {