the browser-facing portion of osu!
at master 4.6 kB view raw
1<?php 2 3// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0. 4// See the LICENCE file in the repository root for full licence text. 5 6namespace Tests\Browser; 7 8use App\Models\Beatmap; 9use App\Models\BeatmapDiscussion; 10use App\Models\BeatmapDiscussionPost; 11use App\Models\Beatmapset; 12use App\Models\User; 13use Laravel\Dusk\Browser; 14use Tests\DuskTestCase; 15 16class BeatmapDiscussionPostsTest extends DuskTestCase 17{ 18 private const NEW_REPLY_SELECTOR = '.beatmap-discussion-post--new-reply'; 19 private const RESOLVE_BUTTON_SELECTOR = '.btn-osu-big[data-action=reply_resolve]'; 20 21 private Beatmap $beatmap; 22 private BeatmapDiscussion $beatmapDiscussion; 23 private Beatmapset $beatmapset; 24 private User $mapper; 25 private User $user; 26 27 public function testConcurrentPostAfterResolve() 28 { 29 $this->browse(function (Browser $first, Browser $second) { 30 // Setup both browsers. 31 $this->visitDiscussionPageAsUser($first, $this->mapper); 32 $this->visitDiscussionPageAsUser($second, $this->user); 33 34 // Write a reply... 35 $this->writeReply($first, 'Fixed'); 36 $this->writeReply($second, 'Hey!'); 37 38 // And send the replies. 39 $this->postReply($first, 'resolve'); 40 $this->postReply($second, 'reply'); 41 42 $first->pause(2000); 43 $second->pause(2000); 44 45 $this->assertSame(true, $this->beatmapDiscussion->fresh()->resolved); 46 }); 47 } 48 49 protected function writeReply(Browser $browser, $reply) 50 { 51 $browser->with(static::NEW_REPLY_SELECTOR, function (Browser $newReply) use ($reply) { 52 $newReply->press(trans('beatmap_discussions.reply.open.user')) 53 ->waitFor('textarea') 54 ->type('textarea', $reply); 55 }); 56 } 57 58 protected function postReply(Browser $browser, $action) 59 { 60 $browser->with(static::NEW_REPLY_SELECTOR, function (Browser $newReply) use ($action) { 61 switch ($action) { 62 case 'resolve': 63 // button may be covered by dev banner; 64 // ->element->($selector)->getLocationOnScreenOnceScrolledIntoView() uses { block: 'end', inline: 'nearest' } which isn't enough. 65 $newReply->scrollIntoView(static::RESOLVE_BUTTON_SELECTOR); 66 $newReply->element(static::RESOLVE_BUTTON_SELECTOR)->click(); 67 break; 68 default: 69 $newReply->keys('textarea', '{enter}'); 70 break; 71 } 72 }); 73 } 74 75 protected function visitDiscussionPageAsUser(Browser $browser, User $user): void 76 { 77 $browser->loginAs($user) 78 ->visit('/_dusk/verify') 79 ->visitRoute('beatmapsets.discussions.show', [ 80 'discussion' => $this->beatmapDiscussion->getKey(), 81 ]); 82 } 83 84 protected function deleteUser(User $user): void 85 { 86 $user->userProfileCustomization()->forceDelete(); 87 $user->forceDelete(); 88 } 89 90 protected function cleanup(): void 91 { 92 // Delete all models we created. 93 $this->beatmapDiscussion->beatmapDiscussionPosts()->forceDelete(); 94 $this->beatmapDiscussion->forceDelete(); 95 $this->beatmap->forceDelete(); 96 $this->beatmapset->events()->forceDelete(); 97 $this->beatmapset->forceDelete(); 98 $this->deleteUser($this->user); 99 $this->deleteUser($this->mapper); 100 } 101 102 protected function setUp(): void 103 { 104 parent::setUp(); 105 106 $this->mapper = User::factory()->withPlays()->create(); 107 $this->user = User::factory()->withPlays()->create(); 108 109 $this->beatmapset = Beatmapset::factory()->create([ 110 'user_id' => $this->mapper, 111 ]); 112 $this->beatmap = $this->beatmapset->beatmaps()->save(Beatmap::factory()->make([ 113 'user_id' => $this->mapper, 114 ])); 115 $this->beatmapDiscussion = BeatmapDiscussion::factory()->timeline()->create([ 116 'beatmapset_id' => $this->beatmapset, 117 'beatmap_id' => $this->beatmap, 118 'user_id' => $this->user, 119 ]); 120 $post = BeatmapDiscussionPost::factory()->timeline()->make([ 121 'user_id' => $this->user, 122 ]); 123 $this->beatmapDiscussion->beatmapDiscussionPosts()->save($post); 124 125 $this->beforeApplicationDestroyed(function () { 126 // Similar case to SanityTest, cleanup the models we created during the test. 127 $this->cleanup(); 128 }); 129 } 130}