diff --git a/src/resources/vue/Meet/Room.vue b/src/resources/vue/Meet/Room.vue index e1fdbdc7..f7d5e9a3 100644 --- a/src/resources/vue/Meet/Room.vue +++ b/src/resources/vue/Meet/Room.vue @@ -1,576 +1,581 @@ Set up your session - + None {{ mic.label }} None {{ cam.label }} - JOIN NOW I'm the owner JOIN Room closed × The session has been closed by the room owner. diff --git a/src/tests/Browser.php b/src/tests/Browser.php index 5ff93f83..33d6cbf3 100644 --- a/src/tests/Browser.php +++ b/src/tests/Browser.php @@ -1,258 +1,266 @@ resolver->findOrFail($selector); $value = (string) $element->getAttribute($attribute); Assert::assertRegExp($regexp, $value, "No expected text in [$selector][$attribute]. Found: $value"); return $this; } /** * Assert number of (visible) elements */ public function assertElementsCount($selector, $expected_count, $visible = true) { $elements = $this->elements($selector); $count = count($elements); if ($visible) { foreach ($elements as $element) { if (!$element->isDisplayed()) { $count--; } } } Assert::assertEquals($expected_count, $count, "Count of [$selector] elements is not $expected_count"); return $this; } /** * Assert Tip element content */ public function assertTip($selector, $content) { return $this->click($selector) ->withinBody(function ($browser) use ($content) { $browser->waitFor('div.tooltip .tooltip-inner') ->assertSeeIn('div.tooltip .tooltip-inner', $content); }) ->click($selector); } /** * Assert Toast element content (and close it) */ public function assertToast(string $type, string $message, $title = null) { return $this->withinBody(function ($browser) use ($type, $title, $message) { $browser->with(new Toast($type), function (Browser $browser) use ($title, $message) { $browser->assertToastTitle($title) ->assertToastMessage($message) ->closeToast(); }); }); } /** * Assert specified error page is displayed. */ public function assertErrorPage(int $error_code) { $this->with(new Error($error_code), function ($browser) { // empty, assertions will be made by the Error component itself }); return $this; } /** * Assert that the given element has specified class assigned. */ public function assertHasClass($selector, $class_name) { $element = $this->resolver->findOrFail($selector); $classes = explode(' ', (string) $element->getAttribute('class')); Assert::assertContains($class_name, $classes, "[$selector] has no class '{$class_name}'"); return $this; } /** * Assert that the given element is readonly */ public function assertReadonly($selector) { $element = $this->resolver->findOrFail($selector); $value = $element->getAttribute('readonly'); Assert::assertTrue($value == 'true', "Element [$selector] is not readonly"); return $this; } /** * Assert that the given element is not readonly */ public function assertNotReadonly($selector) { $element = $this->resolver->findOrFail($selector); $value = $element->getAttribute('readonly'); Assert::assertTrue($value != 'true', "Element [$selector] is not readonly"); return $this; } /** * Assert that the given element contains specified text, * no matter it's displayed or not. */ public function assertText($selector, $text) { $element = $this->resolver->findOrFail($selector); if ($text === '') { Assert::assertTrue((string) $element->getText() === $text, "Element's text is not empty [$selector]"); } else { Assert::assertTrue(strpos($element->getText(), $text) !== false, "No expected text in [$selector]"); } return $this; } /** * Assert that the given element contains specified text, * no matter it's displayed or not - using a regular expression. */ public function assertTextRegExp($selector, $regexp) { $element = $this->resolver->findOrFail($selector); Assert::assertRegExp($regexp, $element->getText(), "No expected text in [$selector]"); return $this; } /** * Remove all toast messages */ public function clearToasts() { $this->script("jQuery('.toast-container > *').remove()"); return $this; } + /** + * Wait until a button becomes enabled and click it + */ + public function clickWhenEnabled($selector) + { + return $this->waitFor($selector . ':not([disabled])')->click($selector); + } + /** * Check if in Phone mode */ public static function isPhone() { return getenv('TESTS_MODE') == 'phone'; } /** * Check if in Tablet mode */ public static function isTablet() { return getenv('TESTS_MODE') == 'tablet'; } /** * Check if in Desktop mode */ public static function isDesktop() { return !self::isPhone() && !self::isTablet(); } /** * Returns content of a downloaded file */ public function readDownloadedFile($filename, $sleep = 5) { $filename = __DIR__ . "/Browser/downloads/$filename"; // Give the browser a chance to finish download if (!file_exists($filename) && $sleep) { sleep($sleep); } Assert::assertFileExists($filename); return file_get_contents($filename); } /** * Removes downloaded file */ public function removeDownloadedFile($filename) { @unlink(__DIR__ . "/Browser/downloads/$filename"); return $this; } /** * Clears the input field and related vue v-model data. */ public function vueClear($selector) { if ($this->resolver->prefix != 'body') { $selector = $this->resolver->prefix . ' ' . $selector; } // The existing clear(), and type() with empty string do not work. // We have to clear the field and dispatch 'input' event programatically. $this->script( "var element = document.querySelector('$selector');" . "element.value = '';" . "element.dispatchEvent(new Event('input'))" ); return $this; } /** * Execute code within body context. * Useful to execute code that selects elements outside of a component context */ public function withinBody($callback) { if ($this->resolver->prefix != 'body') { $orig_prefix = $this->resolver->prefix; $this->resolver->prefix = 'body'; } call_user_func($callback, $this); if (isset($orig_prefix)) { $this->resolver->prefix = $orig_prefix; } return $this; } } diff --git a/src/tests/Browser/Meet/RoomControlsTest.php b/src/tests/Browser/Meet/RoomControlsTest.php index 7afbc43a..9684116e 100644 --- a/src/tests/Browser/Meet/RoomControlsTest.php +++ b/src/tests/Browser/Meet/RoomControlsTest.php @@ -1,397 +1,397 @@ clearBetaEntitlements(); } public function tearDown(): void { $this->clearBetaEntitlements(); parent::tearDown(); } /** * Test fullscreen buttons * * @group openvidu */ public function testFullscreen(): void { // TODO: This test does not work in headless mode $this->markTestIncomplete(); /* // Make sure there's no session yet $room = Room::where('name', 'john')->first(); if ($room->session_id) { $room->session_id = null; $room->save(); } $this->assignBetaEntitlement('john@kolab.org', 'meet'); $this->browse(function (Browser $browser) { // Join the room as an owner (authenticate) $browser->visit(new RoomPage('john')) ->click('@setup-button') ->assertMissing('@toolbar') ->assertMissing('@menu') ->assertMissing('@session') ->assertMissing('@chat') ->assertMissing('@setup-form') ->assertVisible('@login-form') ->submitLogon('john@kolab.org', 'simple123') ->waitFor('@setup-form') ->assertMissing('@login-form') ->waitUntilMissing('@setup-status-message.loading') ->click('@setup-button') ->waitFor('@session') // Test fullscreen for the whole room ->click('@menu button.link-fullscreen.closed') ->assertVisible('@toolbar') ->assertVisible('@session') ->assertMissing('nav') ->assertMissing('@menu button.link-fullscreen.closed') ->click('@menu button.link-fullscreen.open') ->assertVisible('nav') // Test fullscreen for the participant video ->click('@session button.link-fullscreen.closed') ->assertVisible('@session') ->assertMissing('@toolbar') ->assertMissing('nav') ->assertMissing('@session button.link-fullscreen.closed') ->click('@session button.link-fullscreen.open') ->assertVisible('nav') ->assertVisible('@toolbar'); }); */ } /** * Test nickname and muting audio/video * * @group openvidu */ public function testNicknameAndMuting(): void { // Make sure there's no session yet $room = Room::where('name', 'john')->first(); if ($room->session_id) { $room->session_id = null; $room->save(); } $this->assignBetaEntitlement('john@kolab.org', 'meet'); $this->browse(function (Browser $owner, Browser $guest) { // Join the room as an owner (authenticate) $owner->visit(new RoomPage('john')) ->click('@setup-button') ->submitLogon('john@kolab.org', 'simple123') ->waitFor('@setup-form') ->waitUntilMissing('@setup-status-message.loading') ->type('@setup-nickname-input', 'john') - ->click('@setup-button') + ->keys('@setup-nickname-input', '{enter}') // Test form submit with Enter key ->waitFor('@session'); // In another browser act as a guest $guest->visit(new RoomPage('john')) ->waitFor('@setup-form') ->waitUntilMissing('@setup-status-message.loading') ->assertMissing('@setup-status-message') ->assertSeeIn('@setup-button', "JOIN") // Join the room, disable cam/mic ->select('@setup-mic-select', '') //->select('@setup-cam-select', '') - ->click('@setup-button') + ->clickWhenEnabled('@setup-button') ->waitFor('@session'); // Assert current UI state $owner->assertToolbar([ 'audio' => RoomPage::BUTTON_ACTIVE | RoomPage::BUTTON_ENABLED, 'video' => RoomPage::BUTTON_ACTIVE | RoomPage::BUTTON_ENABLED, 'screen' => RoomPage::BUTTON_INACTIVE | RoomPage::BUTTON_ENABLED, 'chat' => RoomPage::BUTTON_INACTIVE | RoomPage::BUTTON_ENABLED, 'fullscreen' => RoomPage::BUTTON_ACTIVE | RoomPage::BUTTON_ENABLED, 'security' => RoomPage::BUTTON_ACTIVE | RoomPage::BUTTON_ENABLED, 'logout' => RoomPage::BUTTON_ACTIVE | RoomPage::BUTTON_ENABLED, ]) ->whenAvailable('div.meet-video.self', function (Browser $browser) { - $browser->assertVisible('video') + $browser->waitFor('video') ->assertAudioMuted('video', true) ->assertSeeIn('.meet-nickname', 'john') ->assertVisible('.controls button.link-fullscreen') ->assertMissing('.controls button.link-audio') ->assertMissing('.status .status-audio') ->assertMissing('.status .status-video'); }) ->whenAvailable('div.meet-video:not(.self)', function (Browser $browser) { - $browser->assertVisible('video') + $browser->waitFor('video') ->assertVisible('.meet-nickname') ->assertVisible('.controls button.link-fullscreen') ->assertVisible('.controls button.link-audio') ->assertVisible('.status .status-audio') ->assertMissing('.status .status-video'); }) ->assertElementsCount('@session div.meet-video', 2); // Assert current UI state $guest->assertToolbar([ 'audio' => RoomPage::BUTTON_INACTIVE | RoomPage::BUTTON_ENABLED, 'video' => RoomPage::BUTTON_ACTIVE | RoomPage::BUTTON_ENABLED, 'screen' => RoomPage::BUTTON_INACTIVE | RoomPage::BUTTON_ENABLED, 'chat' => RoomPage::BUTTON_INACTIVE | RoomPage::BUTTON_ENABLED, 'fullscreen' => RoomPage::BUTTON_ACTIVE | RoomPage::BUTTON_ENABLED, 'logout' => RoomPage::BUTTON_ACTIVE | RoomPage::BUTTON_ENABLED, ]) ->whenAvailable('div.meet-video:not(.self)', function (Browser $browser) { - $browser->assertVisible('video') + $browser->waitFor('video') ->assertSeeIn('.meet-nickname', 'john') ->assertVisible('.controls button.link-fullscreen') ->assertVisible('.controls button.link-audio') ->assertMissing('.status .status-audio') ->assertMissing('.status .status-video'); }) ->whenAvailable('div.meet-video.self', function (Browser $browser) { - $browser->assertVisible('video') + $browser->waitFor('video') ->assertVisible('.controls button.link-fullscreen') ->assertMissing('.controls button.link-audio') ->assertVisible('.status .status-audio') ->assertMissing('.status .status-video'); }) ->assertElementsCount('@session div.meet-video', 2); // Test nickname change propagation // Use script() because type() does not work with this contenteditable widget $guest->setNickname('div.meet-video.self', 'guest'); $owner->waitFor('div.meet-video:not(.self) .meet-nickname') ->assertSeeIn('div.meet-video:not(.self) .meet-nickname', 'guest'); // Test muting audio $owner->click('@menu button.link-audio') ->assertToolbarButtonState('audio', RoomPage::BUTTON_INACTIVE | RoomPage::BUTTON_ENABLED) ->assertVisible('div.meet-video.self .status .status-audio'); // FIXME: It looks that we can't just check the element state // We might consider using OpenVidu API to make sure $guest->waitFor('div.meet-video:not(.self) .status .status-audio'); // Test unmuting audio $owner->click('@menu button.link-audio') ->assertToolbarButtonState('audio', RoomPage::BUTTON_ACTIVE | RoomPage::BUTTON_ENABLED) ->assertMissing('div.meet-video.self .status .status-audio'); $guest->waitUntilMissing('div.meet-video:not(.self) .status .status-audio'); // Test muting video $owner->click('@menu button.link-video') ->assertToolbarButtonState('video', RoomPage::BUTTON_INACTIVE | RoomPage::BUTTON_ENABLED) ->assertVisible('div.meet-video.self .status .status-video'); // FIXME: It looks that we can't just check the element state // We might consider using OpenVidu API to make sure $guest->waitFor('div.meet-video:not(.self) .status .status-video'); // Test unmuting video $owner->click('@menu button.link-video') ->assertToolbarButtonState('video', RoomPage::BUTTON_ACTIVE | RoomPage::BUTTON_ENABLED) ->assertMissing('div.meet-video.self .status .status-video'); $guest->waitUntilMissing('div.meet-video:not(.self) .status .status-video'); // Test muting other user $guest->with('div.meet-video:not(.self)', function (Browser $browser) { $browser->click('.controls button.link-audio') ->assertAudioMuted('video', true) ->assertVisible('.controls button.link-audio.text-danger') ->click('.controls button.link-audio') ->assertAudioMuted('video', false) ->assertVisible('.controls button.link-audio:not(.text-danger)'); }); }); } /** * Test text chat * * @group openvidu */ public function testChat(): void { // Make sure there's no session yet $room = Room::where('name', 'john')->first(); if ($room->session_id) { $room->session_id = null; $room->save(); } $this->assignBetaEntitlement('john@kolab.org', 'meet'); $this->browse(function (Browser $owner, Browser $guest) { // Join the room as an owner $owner->visit(new RoomPage('john')) ->waitFor('@setup-form') ->waitUntilMissing('@setup-status-message.loading') ->type('@setup-nickname-input', 'john') - ->click('@setup-button') + ->clickWhenEnabled('@setup-button') ->waitFor('@session'); // In another browser act as a guest $guest->visit(new RoomPage('john')) ->waitFor('@setup-form') ->waitUntilMissing('@setup-status-message.loading') ->assertMissing('@setup-status-message') ->assertSeeIn('@setup-button', "JOIN") // Join the room, disable cam/mic ->select('@setup-mic-select', '') // ->select('@setup-cam-select', '') - ->click('@setup-button') + ->clickWhenEnabled('@setup-button') ->waitFor('@session'); // Test chat elements $owner->click('@menu button.link-chat') ->assertToolbarButtonState('chat', RoomPage::BUTTON_ACTIVE | RoomPage::BUTTON_ENABLED) ->assertVisible('@chat') ->assertVisible('@session') ->assertFocused('@chat-input') ->assertElementsCount('@chat-list .message', 0) ->keys('@chat-input', 'test1', '{enter}') ->assertValue('@chat-input', '') ->assertElementsCount('@chat-list .message', 1) ->assertSeeIn('@chat-list .message .nickname', 'john') ->assertSeeIn('@chat-list .message div:last-child', 'test1'); $guest->waitFor('@menu button.link-chat .badge') ->assertSeeIn('@menu button.link-chat .badge', '1') ->click('@menu button.link-chat') ->assertToolbarButtonState('chat', RoomPage::BUTTON_ACTIVE | RoomPage::BUTTON_ENABLED) ->assertMissing('@menu button.link-chat .badge') ->assertVisible('@chat') ->assertVisible('@session') ->assertElementsCount('@chat-list .message', 1) ->assertSeeIn('@chat-list .message .nickname', 'john') ->assertSeeIn('@chat-list .message div:last-child', 'test1'); // Test the number of (hidden) incoming messages $guest->click('@menu button.link-chat') ->assertMissing('@chat'); $owner->keys('@chat-input', 'test2', '{enter}', 'test3', '{enter}') ->assertElementsCount('@chat-list .message', 1) ->assertSeeIn('@chat-list .message .nickname', 'john') ->assertElementsCount('@chat-list .message div', 4) ->assertSeeIn('@chat-list .message div:last-child', 'test3'); $guest->waitFor('@menu button.link-chat .badge') ->assertSeeIn('@menu button.link-chat .badge', '2') ->click('@menu button.link-chat') ->assertElementsCount('@chat-list .message', 1) ->assertSeeIn('@chat-list .message .nickname', 'john') ->assertSeeIn('@chat-list .message div:last-child', 'test3') ->keys('@chat-input', 'guest1', '{enter}') ->assertElementsCount('@chat-list .message', 2) ->assertMissing('@chat-list .message:last-child .nickname') ->assertSeeIn('@chat-list .message:last-child div:last-child', 'guest1'); $owner->assertElementsCount('@chat-list .message', 2) ->assertMissing('@chat-list .message:last-child .nickname') ->assertSeeIn('@chat-list .message:last-child div:last-child', 'guest1'); // Test nickname change is propagated to chat messages $guest->setNickname('div.meet-video.self', 'guest') ->keys('@chat-input', 'guest2', '{enter}') ->assertElementsCount('@chat-list .message', 2) ->assertSeeIn('@chat-list .message:last-child .nickname', 'guest') ->assertSeeIn('@chat-list .message:last-child div:last-child', 'guest2'); $owner->assertElementsCount('@chat-list .message', 2) ->assertSeeIn('@chat-list .message:last-child .nickname', 'guest') ->assertSeeIn('@chat-list .message:last-child div:last-child', 'guest2'); // TODO: Test text chat features, e.g. link handling }); } /** * Test screen sharing * * @group openvidu */ public function testShareScreen(): void { // Make sure there's no session yet $room = Room::where('name', 'john')->first(); if ($room->session_id) { $room->session_id = null; $room->save(); } $this->assignBetaEntitlement('john@kolab.org', 'meet'); $this->browse(function (Browser $owner, Browser $guest) { // Join the room as an owner $owner->visit(new RoomPage('john')) ->waitFor('@setup-form') ->waitUntilMissing('@setup-status-message.loading') ->type('@setup-nickname-input', 'john') - ->click('@setup-button') + ->clickWhenEnabled('@setup-button') ->waitFor('@session'); // In another browser act as a guest $guest->visit(new RoomPage('john')) ->waitFor('@setup-form') ->waitUntilMissing('@setup-status-message.loading') // Join the room, disable cam/mic ->select('@setup-mic-select', '') ->select('@setup-cam-select', '') - ->click('@setup-button') + ->clickWhenEnabled('@setup-button') ->waitFor('@session'); // Test screen sharing $owner->assertToolbarButtonState('screen', RoomPage::BUTTON_INACTIVE | RoomPage::BUTTON_ENABLED) ->assertElementsCount('@session div.meet-video', 1) ->click('@menu button.link-screen') ->whenAvailable('div.meet-video:not(.self)', function (Browser $browser) { - $browser->assertVisible('video') + $browser->waitFor('video') ->assertSeeIn('.meet-nickname', 'john') ->assertVisible('.controls button.link-fullscreen') ->assertVisible('.controls button.link-audio') ->assertVisible('.status .status-audio') ->assertMissing('.status .status-video'); }) ->assertElementsCount('@session div.meet-video', 2) ->assertElementsCount('@subscribers .meet-subscriber', 1) ->assertToolbarButtonState('screen', RoomPage::BUTTON_ACTIVE | RoomPage::BUTTON_ENABLED); $guest ->whenAvailable('div.meet-video:nth-child(3)', function (Browser $browser) { - $browser->assertVisible('video') + $browser->waitFor('video') ->assertSeeIn('.meet-nickname', 'john') ->assertVisible('.controls button.link-fullscreen') ->assertVisible('.controls button.link-audio') ->assertVisible('.status .status-audio') ->assertMissing('.status .status-video'); }) ->assertElementsCount('@session div.meet-video', 2) ->assertElementsCount('@subscribers .meet-subscriber', 1); }); } } diff --git a/src/tests/Browser/Meet/RoomSecurityTest.php b/src/tests/Browser/Meet/RoomSecurityTest.php index c76c17b9..6dfc6dc5 100644 --- a/src/tests/Browser/Meet/RoomSecurityTest.php +++ b/src/tests/Browser/Meet/RoomSecurityTest.php @@ -1,250 +1,250 @@ clearBetaEntitlements(); $this->assignBetaEntitlement('john@kolab.org', 'meet'); $room = Room::where('name', 'john')->first(); $room->setSettings(['password' => null, 'locked' => null]); } public function tearDown(): void { $this->clearBetaEntitlements(); $room = Room::where('name', 'john')->first(); $room->setSettings(['password' => null, 'locked' => null]); parent::tearDown(); } /** * Test password protected room * * @group openvidu */ public function testRoomPassword(): void { $this->browse(function (Browser $owner, Browser $guest) { // Make sure there's no session yet $room = Room::where('name', 'john')->first(); if ($room->session_id) { $room->session_id = null; $room->save(); } // Join the room as an owner (authenticate) $owner->visit(new RoomPage('john')) ->click('@setup-button') ->submitLogon('john@kolab.org', 'simple123') ->waitFor('@setup-form') ->waitUntilMissing('@setup-status-message.loading') ->assertMissing('@setup-password-input') - ->click('@setup-button') + ->clickWhenEnabled('@setup-button') ->waitFor('@session') // Enter Security option dialog ->click('@menu button.link-security') ->with(new Dialog('#security-options-dialog'), function (Browser $browser) use ($room) { $browser->assertSeeIn('@title', 'Security options') ->assertSeeIn('@button-action', 'Close') ->assertElementsCount('.modal-footer button', 1) ->assertSeeIn('#password-input .label', 'Password:') ->assertSeeIn('#password-input-text.text-muted', 'none') ->assertVisible('#password-input + small') ->assertSeeIn('#password-set-btn', 'Set password') ->assertElementsCount('#password-input button', 1) ->assertMissing('#password-input input') // Test setting a password ->click('#password-set-btn') ->assertMissing('#password-input-text') ->assertVisible('#password-input input') ->assertValue('#password-input input', '') ->assertSeeIn('#password-input #password-save-btn', 'Save') ->assertElementsCount('#password-input button', 1) ->type('#password-input input', 'pass') ->click('#password-input #password-save-btn') ->assertToast(Toast::TYPE_SUCCESS, 'Room configuration updated successfully.') ->assertMissing('#password-input input') ->assertSeeIn('#password-input-text:not(.text-muted)', 'pass') ->assertSeeIn('#password-clear-btn.btn-outline-danger', 'Clear password') ->assertElementsCount('#password-input button', 1) ->click('@button-action'); $this->assertSame('pass', $room->fresh()->getSetting('password')); }); // In another browser act as a guest, expect password required $guest->visit(new RoomPage('john')) ->waitFor('@setup-form') ->waitUntilMissing('@setup-status-message.loading') ->assertSeeIn('@setup-status-message', "Please, provide a valid password.") ->assertVisible('@setup-form .input-group:nth-child(4) svg') ->assertAttribute('@setup-form .input-group:nth-child(4) .input-group-text', 'title', 'Password') ->assertAttribute('@setup-password-input', 'placeholder', 'Password') ->assertValue('@setup-password-input', '') ->assertSeeIn('@setup-button', "JOIN") // Try to join w/o password - ->click('@setup-button') + ->clickWhenEnabled('@setup-button') ->waitFor('#setup-password.is-invalid') // Try to join with a valid password ->type('#setup-password', 'pass') - ->click('@setup-button') + ->clickWhenEnabled('@setup-button') ->waitFor('@session'); // Test removing the password $owner->click('@menu button.link-security') ->with(new Dialog('#security-options-dialog'), function (Browser $browser) use ($room) { $browser->assertSeeIn('@title', 'Security options') ->assertSeeIn('#password-input-text:not(.text-muted)', 'pass') ->assertSeeIn('#password-clear-btn.btn-outline-danger', 'Clear password') ->assertElementsCount('#password-input button', 1) ->click('#password-clear-btn') ->assertToast(Toast::TYPE_SUCCESS, "Room configuration updated successfully.") ->assertMissing('#password-input input') ->assertSeeIn('#password-input-text.text-muted', 'none') ->assertSeeIn('#password-set-btn', 'Set password') ->assertElementsCount('#password-input button', 1) ->click('@button-action'); $this->assertSame(null, $room->fresh()->getSetting('password')); }); }); } /** * Test locked room * * @group openvidu */ public function testLockedRoom(): void { $this->browse(function (Browser $owner, Browser $guest) { // Make sure there's no session yet $room = Room::where('name', 'john')->first(); if ($room->session_id) { $room->session_id = null; $room->save(); } // Join the room as an owner (authenticate) $owner->visit(new RoomPage('john')) // ->click('@setup-button') // ->submitLogon('john@kolab.org', 'simple123') ->waitFor('@setup-form') ->waitUntilMissing('@setup-status-message.loading') ->type('@setup-nickname-input', 'John') - ->click('@setup-button') + ->clickWhenEnabled('@setup-button') ->waitFor('@session') // Enter Security option dialog ->click('@menu button.link-security') ->with(new Dialog('#security-options-dialog'), function (Browser $browser) use ($room) { $browser->assertSeeIn('@title', 'Security options') ->assertSeeIn('#room-lock label', 'Locked room:') ->assertVisible('#room-lock input[type=checkbox]:not(:checked)') ->assertVisible('#room-lock + small') // Test setting the lock ->click('#room-lock input') ->assertToast(Toast::TYPE_SUCCESS, "Room configuration updated successfully.") ->click('@button-action'); $this->assertSame('true', $room->fresh()->getSetting('locked')); }); // In another browser act as a guest $guest->visit(new RoomPage('john')) ->waitFor('@setup-form') ->waitUntilMissing('@setup-status-message.loading') ->assertButtonEnabled('@setup-button') ->assertSeeIn('@setup-button.btn-success', 'JOIN NOW') // try without the nickname - ->click('@setup-button') + ->clickWhenEnabled('@setup-button') ->waitFor('@setup-nickname-input.is-invalid') ->assertSeeIn( '@setup-status-message', "The room is locked. Please, enter your name and try again." ) ->assertMissing('@setup-password-input') ->assertButtonEnabled('@setup-button') ->assertSeeIn('@setup-button.btn-success', 'JOIN NOW') ->type('@setup-nickname-input', 'Guest') - ->click('@setup-button') + ->clickWhenEnabled('@setup-button') ->assertMissing('@setup-nickname-input.is-invalid') ->waitForText("Waiting for permission to join the room.") ->assertButtonDisabled('@setup-button'); // Test denying the request (this will also test custom toasts) $owner ->whenAvailable(new Toast(Toast::TYPE_CUSTOM), function ($browser) { $browser->assertToastTitle('Join request') ->assertVisible('.toast-header svg.fa-user') ->assertSeeIn('@message', 'Guest requested to join.') ->assertAttributeRegExp('@message img', 'src', '|^data:image|') ->assertSeeIn('@message button.accept.btn-success', 'Accept') ->assertSeeIn('@message button.deny.btn-danger', 'Deny') ->click('@message button.deny'); }) ->waitUntilMissing('.toast') // wait 10 seconds to make sure the request message does not show up again ->pause(10 * 1000) ->assertMissing('.toast'); // Test accepting the request $guest->refresh() ->waitFor('@setup-form') ->waitUntilMissing('@setup-status-message.loading') ->type('@setup-nickname-input', 'guest') - ->click('@setup-button') + ->clickWhenEnabled('@setup-button') ->waitForText("Waiting for permission to join the room.") ->assertButtonDisabled('@setup-button'); $owner ->whenAvailable(new Toast(Toast::TYPE_CUSTOM), function ($browser) { $browser->assertToastTitle('Join request') ->assertSeeIn('@message', 'guest requested to join.') ->click('@message button.accept'); }); // Guest automatically anters the room $guest->waitFor('@session', 12) // make sure he has no access to the Options menu ->waitFor('@session .meet-video:not(.self)') ->assertSeeIn('@session .meet-video:not(.self) .meet-nickname', 'John') // TODO: Assert title and icon ->click('@session .meet-video:not(.self) .meet-nickname') ->pause(100) ->assertMissing('.dropdown-menu'); // Test dismissing the participant $owner->click('@session .meet-video:not(.self) .meet-nickname') ->waitFor('@session .meet-video:not(.self) .dropdown-menu') ->assertSeeIn('@session .meet-video:not(.self) .dropdown-menu > .action-dismiss', 'Dismiss') ->click('@session .meet-video:not(.self) .dropdown-menu > .action-dismiss') ->waitUntilMissing('.dropdown-menu') ->waitUntilMissing('@session .meet-video:not(.self)'); // Expect a "end of session" dialog on the participant side $guest->with(new Dialog('#leave-dialog'), function (Browser $browser) { $browser->assertSeeIn('@title', 'Room closed') ->assertSeeIn('@body', "The session has been closed by the room owner.") ->assertMissing('@button-cancel') ->assertSeeIn('@button-action', 'Close'); }); }); } } diff --git a/src/tests/Browser/Meet/RoomSetupTest.php b/src/tests/Browser/Meet/RoomSetupTest.php index fc9881d6..160da948 100644 --- a/src/tests/Browser/Meet/RoomSetupTest.php +++ b/src/tests/Browser/Meet/RoomSetupTest.php @@ -1,373 +1,373 @@ clearBetaEntitlements(); } public function tearDown(): void { $this->clearBetaEntitlements(); parent::tearDown(); } /** * Test non-existing room * * @group openvidu */ public function testRoomNonExistingRoom(): void { $this->browse(function (Browser $browser) { $browser->visit(new RoomPage('unknown')) ->within(new Menu(), function ($browser) { $browser->assertMenuItems(['signup', 'explore', 'blog', 'support', 'login']); }); if ($browser->isDesktop()) { $browser->within(new Menu('footer'), function ($browser) { $browser->assertMenuItems(['signup', 'explore', 'blog', 'support', 'tos', 'login']); }); } else { $browser->assertMissing('#footer-menu .navbar-nav'); } // FIXME: Maybe it would be better to just display the usual 404 Not Found error page? $browser->assertMissing('@toolbar') ->assertMissing('@menu') ->assertMissing('@session') ->assertMissing('@chat') ->assertMissing('@login-form') ->assertVisible('@setup-form') ->assertSeeIn('@setup-status-message', "The room does not exist.") ->assertButtonDisabled('@setup-button'); }); } /** * Test the room setup page * * @group openvidu */ public function testRoomSetup(): void { // Make sure there's no session yet $room = Room::where('name', 'john')->first(); if ($room->session_id) { $room->session_id = null; $room->save(); } $this->assignBetaEntitlement('john@kolab.org', 'meet'); $this->browse(function (Browser $browser) { $browser->visit(new RoomPage('john')) ->within(new Menu(), function ($browser) { $browser->assertMenuItems(['signup', 'explore', 'blog', 'support', 'login']); }); if ($browser->isDesktop()) { $browser->within(new Menu('footer'), function ($browser) { $browser->assertMenuItems(['signup', 'explore', 'blog', 'support', 'tos', 'login']); }); } else { $browser->assertMissing('#footer-menu .navbar-nav'); } // Note: I've found out that if I have another Chrome instance running // that uses media, here the media devices will not be available // TODO: Test enabling/disabling cam/mic in the setup widget $browser->assertMissing('@toolbar') ->assertMissing('@menu') ->assertMissing('@session') ->assertMissing('@chat') ->assertMissing('@login-form') ->assertVisible('@setup-form') ->assertSeeIn('@setup-title', 'Set up your session') ->assertVisible('@setup-video') ->assertVisible('@setup-form .input-group:nth-child(1) svg') ->assertAttribute('@setup-form .input-group:nth-child(1) .input-group-text', 'title', 'Microphone') ->assertVisible('@setup-mic-select') ->assertVisible('@setup-form .input-group:nth-child(2) svg') ->assertAttribute('@setup-form .input-group:nth-child(2) .input-group-text', 'title', 'Camera') ->assertVisible('@setup-cam-select') ->assertVisible('@setup-form .input-group:nth-child(3) svg') ->assertAttribute('@setup-form .input-group:nth-child(3) .input-group-text', 'title', 'Nickname') ->assertValue('@setup-nickname-input', '') ->assertAttribute('@setup-nickname-input', 'placeholder', 'Your name') ->assertMissing('@setup-password-input') ->assertSeeIn( '@setup-status-message', "The room is closed. Please, wait for the owner to start the session." ) ->assertSeeIn('@setup-button', "I'm the owner"); }); } /** * Test two users in a room (joining/leaving and some basic functionality) * * @group openvidu * @depends testRoomSetup */ public function testTwoUsersInARoom(): void { $this->assignBetaEntitlement('john@kolab.org', 'meet'); $this->browse(function (Browser $browser, Browser $guest) { // In one browser window act as a guest $guest->visit(new RoomPage('john')) ->assertMissing('@toolbar') ->assertMissing('@menu') ->assertMissing('@session') ->assertMissing('@chat') ->assertMissing('@login-form') ->waitFor('@setup-form') ->waitUntilMissing('@setup-status-message.loading') ->assertSeeIn( '@setup-status-message', "The room is closed. Please, wait for the owner to start the session." ) ->assertSeeIn('@setup-button', "I'm the owner"); // In another window join the room as the owner (authenticate) $browser->on(new RoomPage('john')) ->assertSeeIn('@setup-button', "I'm the owner") - ->click('@setup-button') + ->clickWhenEnabled('@setup-button') ->assertMissing('@toolbar') ->assertMissing('@menu') ->assertMissing('@session') ->assertMissing('@chat') ->assertMissing('@setup-form') ->assertVisible('@login-form') ->submitLogon('john@kolab.org', 'simple123') ->waitFor('@setup-form') ->assertMissing('@login-form') ->waitUntilMissing('@setup-status-message.loading') ->waitFor('@setup-status-message') ->assertSeeIn('@setup-status-message', "The room is closed. It will be open for others after you join.") ->assertSeeIn('@setup-button', "JOIN") ->type('@setup-nickname-input', 'john') // Join the room (click the button twice, to make sure it does not // produce redundant participants/subscribers in the room) - ->click('@setup-button') + ->clickWhenEnabled('@setup-button') ->pause(10) ->click('@setup-button') ->waitFor('@session') ->assertMissing('@setup-form') ->whenAvailable('div.meet-video.self', function (Browser $browser) { - $browser->assertVisible('video') + $browser->waitFor('video') ->assertSeeIn('.meet-nickname', 'john') ->assertVisible('.controls button.link-fullscreen') ->assertMissing('.controls button.link-audio') ->assertMissing('.status .status-audio') ->assertMissing('.status .status-video'); }) ->within(new Menu(), function ($browser) { $browser->assertMenuItems(['explore', 'blog', 'support', 'dashboard', 'logout']); }); if ($browser->isDesktop()) { $browser->within(new Menu('footer'), function ($browser) { $browser->assertMenuItems(['explore', 'blog', 'support', 'tos', 'dashboard', 'logout']); }); } // After the owner "opened the room" guest should be able to join $guest->waitUntilMissing('@setup-status-message', 10) ->assertSeeIn('@setup-button', "JOIN") // Join the room, disable cam/mic ->select('@setup-mic-select', '') //->select('@setup-cam-select', '') - ->click('@setup-button') + ->clickWhenEnabled('@setup-button') ->waitFor('@session') ->assertMissing('@setup-form') ->whenAvailable('div.meet-video.self', function (Browser $browser) { - $browser->assertVisible('video') + $browser->waitFor('video') ->assertVisible('.meet-nickname') ->assertVisible('.controls button.link-fullscreen') ->assertMissing('.controls button.link-audio') ->assertVisible('.status .status-audio') ->assertMissing('.status .status-video'); }) ->whenAvailable('div.meet-video:not(.self)', function (Browser $browser) { - $browser->assertVisible('video') + $browser->waitFor('video') ->assertSeeIn('.meet-nickname', 'john') ->assertVisible('.controls button.link-fullscreen') ->assertVisible('.controls button.link-audio') ->assertMissing('.status .status-audio') ->assertMissing('.status .status-video'); }) ->assertElementsCount('@session div.meet-video', 2) ->within(new Menu(), function ($browser) { $browser->assertMenuItems(['explore', 'blog', 'support', 'signup', 'login']); }); if ($guest->isDesktop()) { $guest->within(new Menu('footer'), function ($browser) { $browser->assertMenuItems(['explore', 'blog', 'support', 'tos', 'signup', 'login']); }); } // Check guest's elements in the owner's window $browser ->whenAvailable('div.meet-video:not(.self)', function (Browser $browser) { - $browser->assertVisible('video') + $browser->waitFor('video') ->assertVisible('.meet-nickname') ->assertVisible('.controls button.link-fullscreen') ->assertVisible('.controls button.link-audio') ->assertVisible('.status .status-audio') ->assertMissing('.status .status-video'); }) ->assertElementsCount('@session div.meet-video', 2); // Test leaving the room // Guest is leaving $guest->click('@menu button.link-logout') ->waitForLocation('/login'); // Expect the participant removed from other users windows $browser->waitUntilMissing('@session div.meet-video:not(.self)'); // Join the room as guest again $guest->visit(new RoomPage('john')) ->assertMissing('@toolbar') ->assertMissing('@menu') ->assertMissing('@session') ->assertMissing('@chat') ->assertMissing('@login-form') ->waitFor('@setup-form') ->waitUntilMissing('@setup-status-message.loading') ->assertMissing('@setup-status-message') ->assertSeeIn('@setup-button', "JOIN") // Join the room, disable cam/mic ->select('@setup-mic-select', '') //->select('@setup-cam-select', '') - ->click('@setup-button') + ->clickWhenEnabled('@setup-button') ->waitFor('@session'); // Leave the room as the room owner // TODO: Test leaving the room by closing the browser window, // it should not destroy the session $browser->click('@menu button.link-logout') ->waitForLocation('/dashboard'); // Expect other participants be informed about the end of the session $guest->with(new Dialog('#leave-dialog'), function (Browser $browser) { $browser->assertSeeIn('@title', 'Room closed') ->assertSeeIn('@body', "The session has been closed by the room owner.") ->assertMissing('@button-cancel') ->assertSeeIn('@button-action', 'Close') ->click('@button-action'); }) ->assertMissing('#leave-dialog') ->waitForLocation('/login'); }); } /** * Test two subscribers-only users in a room * * @group openvidu * @depends testTwoUsersInARoom */ public function testSubscribers(): void { $this->assignBetaEntitlement('john@kolab.org', 'meet'); $this->browse(function (Browser $browser, Browser $guest) { // Join the room as the owner $browser->visit(new RoomPage('john')) ->waitFor('@setup-form') ->waitUntilMissing('@setup-status-message.loading') ->waitFor('@setup-status-message') ->type('@setup-nickname-input', 'john') ->select('@setup-mic-select', '') ->select('@setup-cam-select', '') - ->click('@setup-button') + ->clickWhenEnabled('@setup-button') ->waitFor('@session') ->assertMissing('@setup-form') ->whenAvailable('@subscribers .meet-subscriber.self', function (Browser $browser) { $browser->assertSeeIn('.meet-nickname', 'john'); }) ->assertElementsCount('@session div.meet-video', 0) ->assertElementsCount('@session video', 0) ->assertElementsCount('@session .meet-subscriber', 1) ->assertToolbar([ 'audio' => RoomPage::BUTTON_INACTIVE | RoomPage::BUTTON_DISABLED, 'video' => RoomPage::BUTTON_INACTIVE | RoomPage::BUTTON_DISABLED, 'screen' => RoomPage::BUTTON_INACTIVE | RoomPage::BUTTON_DISABLED, 'chat' => RoomPage::BUTTON_INACTIVE | RoomPage::BUTTON_ENABLED, 'fullscreen' => RoomPage::BUTTON_ACTIVE | RoomPage::BUTTON_ENABLED, 'security' => RoomPage::BUTTON_ACTIVE | RoomPage::BUTTON_ENABLED, 'logout' => RoomPage::BUTTON_ACTIVE | RoomPage::BUTTON_ENABLED, ]); // After the owner "opened the room" guest should be able to join // In one browser window act as a guest $guest->visit(new RoomPage('john')) ->waitUntilMissing('@setup-status-message', 10) ->assertSeeIn('@setup-button', "JOIN") // Join the room, disable cam/mic ->select('@setup-mic-select', '') ->select('@setup-cam-select', '') - ->click('@setup-button') + ->clickWhenEnabled('@setup-button') ->waitFor('@session') ->assertMissing('@setup-form') ->whenAvailable('@subscribers .meet-subscriber.self', function (Browser $browser) { $browser->assertVisible('.meet-nickname'); }) ->whenAvailable('@subscribers .meet-subscriber:not(.self)', function (Browser $browser) { $browser->assertSeeIn('.meet-nickname', 'john'); }) ->assertElementsCount('@session div.meet-video', 0) ->assertElementsCount('@session video', 0) ->assertElementsCount('@session div.meet-subscriber', 2) ->assertToolbar([ 'audio' => RoomPage::BUTTON_INACTIVE | RoomPage::BUTTON_DISABLED, 'video' => RoomPage::BUTTON_INACTIVE | RoomPage::BUTTON_DISABLED, 'screen' => RoomPage::BUTTON_INACTIVE | RoomPage::BUTTON_DISABLED, 'chat' => RoomPage::BUTTON_INACTIVE | RoomPage::BUTTON_ENABLED, 'fullscreen' => RoomPage::BUTTON_ACTIVE | RoomPage::BUTTON_ENABLED, 'logout' => RoomPage::BUTTON_ACTIVE | RoomPage::BUTTON_ENABLED, ]); // Check guest's elements in the owner's window $browser ->whenAvailable('@subscribers .meet-subscriber:not(.self)', function (Browser $browser) { $browser->assertVisible('.meet-nickname'); }) ->assertElementsCount('@session div.meet-video', 0) ->assertElementsCount('@session video', 0) ->assertElementsCount('@session .meet-subscriber', 2); // Test leaving the room // Guest is leaving $guest->click('@menu button.link-logout') ->waitForLocation('/login'); // Expect the participant removed from other users windows $browser->waitUntilMissing('@session .meet-subscriber:not(.self)'); }); } }
The session has been closed by the room owner.
') - ->click('@setup-button') + ->clickWhenEnabled('@setup-button') ->assertMissing('@setup-nickname-input.is-invalid') ->waitForText("Waiting for permission to join the room.") ->assertButtonDisabled('@setup-button'); // Test denying the request (this will also test custom toasts) $owner ->whenAvailable(new Toast(Toast::TYPE_CUSTOM), function ($browser) { $browser->assertToastTitle('Join request') ->assertVisible('.toast-header svg.fa-user') ->assertSeeIn('@message', 'Guest
requested to join.') ->assertAttributeRegExp('@message img', 'src', '|^data:image|') ->assertSeeIn('@message button.accept.btn-success', 'Accept') ->assertSeeIn('@message button.deny.btn-danger', 'Deny') ->click('@message button.deny'); }) ->waitUntilMissing('.toast') // wait 10 seconds to make sure the request message does not show up again ->pause(10 * 1000) ->assertMissing('.toast'); // Test accepting the request $guest->refresh() ->waitFor('@setup-form') ->waitUntilMissing('@setup-status-message.loading') ->type('@setup-nickname-input', 'guest') - ->click('@setup-button') + ->clickWhenEnabled('@setup-button') ->waitForText("Waiting for permission to join the room.") ->assertButtonDisabled('@setup-button'); $owner ->whenAvailable(new Toast(Toast::TYPE_CUSTOM), function ($browser) { $browser->assertToastTitle('Join request') ->assertSeeIn('@message', 'guest requested to join.') ->click('@message button.accept'); }); // Guest automatically anters the room $guest->waitFor('@session', 12) // make sure he has no access to the Options menu ->waitFor('@session .meet-video:not(.self)') ->assertSeeIn('@session .meet-video:not(.self) .meet-nickname', 'John') // TODO: Assert title and icon ->click('@session .meet-video:not(.self) .meet-nickname') ->pause(100) ->assertMissing('.dropdown-menu'); // Test dismissing the participant $owner->click('@session .meet-video:not(.self) .meet-nickname') ->waitFor('@session .meet-video:not(.self) .dropdown-menu') ->assertSeeIn('@session .meet-video:not(.self) .dropdown-menu > .action-dismiss', 'Dismiss') ->click('@session .meet-video:not(.self) .dropdown-menu > .action-dismiss') ->waitUntilMissing('.dropdown-menu') ->waitUntilMissing('@session .meet-video:not(.self)'); // Expect a "end of session" dialog on the participant side $guest->with(new Dialog('#leave-dialog'), function (Browser $browser) { $browser->assertSeeIn('@title', 'Room closed') ->assertSeeIn('@body', "The session has been closed by the room owner.") ->assertMissing('@button-cancel') ->assertSeeIn('@button-action', 'Close'); }); }); } } diff --git a/src/tests/Browser/Meet/RoomSetupTest.php b/src/tests/Browser/Meet/RoomSetupTest.php index fc9881d6..160da948 100644 --- a/src/tests/Browser/Meet/RoomSetupTest.php +++ b/src/tests/Browser/Meet/RoomSetupTest.php @@ -1,373 +1,373 @@ clearBetaEntitlements(); } public function tearDown(): void { $this->clearBetaEntitlements(); parent::tearDown(); } /** * Test non-existing room * * @group openvidu */ public function testRoomNonExistingRoom(): void { $this->browse(function (Browser $browser) { $browser->visit(new RoomPage('unknown')) ->within(new Menu(), function ($browser) { $browser->assertMenuItems(['signup', 'explore', 'blog', 'support', 'login']); }); if ($browser->isDesktop()) { $browser->within(new Menu('footer'), function ($browser) { $browser->assertMenuItems(['signup', 'explore', 'blog', 'support', 'tos', 'login']); }); } else { $browser->assertMissing('#footer-menu .navbar-nav'); } // FIXME: Maybe it would be better to just display the usual 404 Not Found error page? $browser->assertMissing('@toolbar') ->assertMissing('@menu') ->assertMissing('@session') ->assertMissing('@chat') ->assertMissing('@login-form') ->assertVisible('@setup-form') ->assertSeeIn('@setup-status-message', "The room does not exist.") ->assertButtonDisabled('@setup-button'); }); } /** * Test the room setup page * * @group openvidu */ public function testRoomSetup(): void { // Make sure there's no session yet $room = Room::where('name', 'john')->first(); if ($room->session_id) { $room->session_id = null; $room->save(); } $this->assignBetaEntitlement('john@kolab.org', 'meet'); $this->browse(function (Browser $browser) { $browser->visit(new RoomPage('john')) ->within(new Menu(), function ($browser) { $browser->assertMenuItems(['signup', 'explore', 'blog', 'support', 'login']); }); if ($browser->isDesktop()) { $browser->within(new Menu('footer'), function ($browser) { $browser->assertMenuItems(['signup', 'explore', 'blog', 'support', 'tos', 'login']); }); } else { $browser->assertMissing('#footer-menu .navbar-nav'); } // Note: I've found out that if I have another Chrome instance running // that uses media, here the media devices will not be available // TODO: Test enabling/disabling cam/mic in the setup widget $browser->assertMissing('@toolbar') ->assertMissing('@menu') ->assertMissing('@session') ->assertMissing('@chat') ->assertMissing('@login-form') ->assertVisible('@setup-form') ->assertSeeIn('@setup-title', 'Set up your session') ->assertVisible('@setup-video') ->assertVisible('@setup-form .input-group:nth-child(1) svg') ->assertAttribute('@setup-form .input-group:nth-child(1) .input-group-text', 'title', 'Microphone') ->assertVisible('@setup-mic-select') ->assertVisible('@setup-form .input-group:nth-child(2) svg') ->assertAttribute('@setup-form .input-group:nth-child(2) .input-group-text', 'title', 'Camera') ->assertVisible('@setup-cam-select') ->assertVisible('@setup-form .input-group:nth-child(3) svg') ->assertAttribute('@setup-form .input-group:nth-child(3) .input-group-text', 'title', 'Nickname') ->assertValue('@setup-nickname-input', '') ->assertAttribute('@setup-nickname-input', 'placeholder', 'Your name') ->assertMissing('@setup-password-input') ->assertSeeIn( '@setup-status-message', "The room is closed. Please, wait for the owner to start the session." ) ->assertSeeIn('@setup-button', "I'm the owner"); }); } /** * Test two users in a room (joining/leaving and some basic functionality) * * @group openvidu * @depends testRoomSetup */ public function testTwoUsersInARoom(): void { $this->assignBetaEntitlement('john@kolab.org', 'meet'); $this->browse(function (Browser $browser, Browser $guest) { // In one browser window act as a guest $guest->visit(new RoomPage('john')) ->assertMissing('@toolbar') ->assertMissing('@menu') ->assertMissing('@session') ->assertMissing('@chat') ->assertMissing('@login-form') ->waitFor('@setup-form') ->waitUntilMissing('@setup-status-message.loading') ->assertSeeIn( '@setup-status-message', "The room is closed. Please, wait for the owner to start the session." ) ->assertSeeIn('@setup-button', "I'm the owner"); // In another window join the room as the owner (authenticate) $browser->on(new RoomPage('john')) ->assertSeeIn('@setup-button', "I'm the owner") - ->click('@setup-button') + ->clickWhenEnabled('@setup-button') ->assertMissing('@toolbar') ->assertMissing('@menu') ->assertMissing('@session') ->assertMissing('@chat') ->assertMissing('@setup-form') ->assertVisible('@login-form') ->submitLogon('john@kolab.org', 'simple123') ->waitFor('@setup-form') ->assertMissing('@login-form') ->waitUntilMissing('@setup-status-message.loading') ->waitFor('@setup-status-message') ->assertSeeIn('@setup-status-message', "The room is closed. It will be open for others after you join.") ->assertSeeIn('@setup-button', "JOIN") ->type('@setup-nickname-input', 'john') // Join the room (click the button twice, to make sure it does not // produce redundant participants/subscribers in the room) - ->click('@setup-button') + ->clickWhenEnabled('@setup-button') ->pause(10) ->click('@setup-button') ->waitFor('@session') ->assertMissing('@setup-form') ->whenAvailable('div.meet-video.self', function (Browser $browser) { - $browser->assertVisible('video') + $browser->waitFor('video') ->assertSeeIn('.meet-nickname', 'john') ->assertVisible('.controls button.link-fullscreen') ->assertMissing('.controls button.link-audio') ->assertMissing('.status .status-audio') ->assertMissing('.status .status-video'); }) ->within(new Menu(), function ($browser) { $browser->assertMenuItems(['explore', 'blog', 'support', 'dashboard', 'logout']); }); if ($browser->isDesktop()) { $browser->within(new Menu('footer'), function ($browser) { $browser->assertMenuItems(['explore', 'blog', 'support', 'tos', 'dashboard', 'logout']); }); } // After the owner "opened the room" guest should be able to join $guest->waitUntilMissing('@setup-status-message', 10) ->assertSeeIn('@setup-button', "JOIN") // Join the room, disable cam/mic ->select('@setup-mic-select', '') //->select('@setup-cam-select', '') - ->click('@setup-button') + ->clickWhenEnabled('@setup-button') ->waitFor('@session') ->assertMissing('@setup-form') ->whenAvailable('div.meet-video.self', function (Browser $browser) { - $browser->assertVisible('video') + $browser->waitFor('video') ->assertVisible('.meet-nickname') ->assertVisible('.controls button.link-fullscreen') ->assertMissing('.controls button.link-audio') ->assertVisible('.status .status-audio') ->assertMissing('.status .status-video'); }) ->whenAvailable('div.meet-video:not(.self)', function (Browser $browser) { - $browser->assertVisible('video') + $browser->waitFor('video') ->assertSeeIn('.meet-nickname', 'john') ->assertVisible('.controls button.link-fullscreen') ->assertVisible('.controls button.link-audio') ->assertMissing('.status .status-audio') ->assertMissing('.status .status-video'); }) ->assertElementsCount('@session div.meet-video', 2) ->within(new Menu(), function ($browser) { $browser->assertMenuItems(['explore', 'blog', 'support', 'signup', 'login']); }); if ($guest->isDesktop()) { $guest->within(new Menu('footer'), function ($browser) { $browser->assertMenuItems(['explore', 'blog', 'support', 'tos', 'signup', 'login']); }); } // Check guest's elements in the owner's window $browser ->whenAvailable('div.meet-video:not(.self)', function (Browser $browser) { - $browser->assertVisible('video') + $browser->waitFor('video') ->assertVisible('.meet-nickname') ->assertVisible('.controls button.link-fullscreen') ->assertVisible('.controls button.link-audio') ->assertVisible('.status .status-audio') ->assertMissing('.status .status-video'); }) ->assertElementsCount('@session div.meet-video', 2); // Test leaving the room // Guest is leaving $guest->click('@menu button.link-logout') ->waitForLocation('/login'); // Expect the participant removed from other users windows $browser->waitUntilMissing('@session div.meet-video:not(.self)'); // Join the room as guest again $guest->visit(new RoomPage('john')) ->assertMissing('@toolbar') ->assertMissing('@menu') ->assertMissing('@session') ->assertMissing('@chat') ->assertMissing('@login-form') ->waitFor('@setup-form') ->waitUntilMissing('@setup-status-message.loading') ->assertMissing('@setup-status-message') ->assertSeeIn('@setup-button', "JOIN") // Join the room, disable cam/mic ->select('@setup-mic-select', '') //->select('@setup-cam-select', '') - ->click('@setup-button') + ->clickWhenEnabled('@setup-button') ->waitFor('@session'); // Leave the room as the room owner // TODO: Test leaving the room by closing the browser window, // it should not destroy the session $browser->click('@menu button.link-logout') ->waitForLocation('/dashboard'); // Expect other participants be informed about the end of the session $guest->with(new Dialog('#leave-dialog'), function (Browser $browser) { $browser->assertSeeIn('@title', 'Room closed') ->assertSeeIn('@body', "The session has been closed by the room owner.") ->assertMissing('@button-cancel') ->assertSeeIn('@button-action', 'Close') ->click('@button-action'); }) ->assertMissing('#leave-dialog') ->waitForLocation('/login'); }); } /** * Test two subscribers-only users in a room * * @group openvidu * @depends testTwoUsersInARoom */ public function testSubscribers(): void { $this->assignBetaEntitlement('john@kolab.org', 'meet'); $this->browse(function (Browser $browser, Browser $guest) { // Join the room as the owner $browser->visit(new RoomPage('john')) ->waitFor('@setup-form') ->waitUntilMissing('@setup-status-message.loading') ->waitFor('@setup-status-message') ->type('@setup-nickname-input', 'john') ->select('@setup-mic-select', '') ->select('@setup-cam-select', '') - ->click('@setup-button') + ->clickWhenEnabled('@setup-button') ->waitFor('@session') ->assertMissing('@setup-form') ->whenAvailable('@subscribers .meet-subscriber.self', function (Browser $browser) { $browser->assertSeeIn('.meet-nickname', 'john'); }) ->assertElementsCount('@session div.meet-video', 0) ->assertElementsCount('@session video', 0) ->assertElementsCount('@session .meet-subscriber', 1) ->assertToolbar([ 'audio' => RoomPage::BUTTON_INACTIVE | RoomPage::BUTTON_DISABLED, 'video' => RoomPage::BUTTON_INACTIVE | RoomPage::BUTTON_DISABLED, 'screen' => RoomPage::BUTTON_INACTIVE | RoomPage::BUTTON_DISABLED, 'chat' => RoomPage::BUTTON_INACTIVE | RoomPage::BUTTON_ENABLED, 'fullscreen' => RoomPage::BUTTON_ACTIVE | RoomPage::BUTTON_ENABLED, 'security' => RoomPage::BUTTON_ACTIVE | RoomPage::BUTTON_ENABLED, 'logout' => RoomPage::BUTTON_ACTIVE | RoomPage::BUTTON_ENABLED, ]); // After the owner "opened the room" guest should be able to join // In one browser window act as a guest $guest->visit(new RoomPage('john')) ->waitUntilMissing('@setup-status-message', 10) ->assertSeeIn('@setup-button', "JOIN") // Join the room, disable cam/mic ->select('@setup-mic-select', '') ->select('@setup-cam-select', '') - ->click('@setup-button') + ->clickWhenEnabled('@setup-button') ->waitFor('@session') ->assertMissing('@setup-form') ->whenAvailable('@subscribers .meet-subscriber.self', function (Browser $browser) { $browser->assertVisible('.meet-nickname'); }) ->whenAvailable('@subscribers .meet-subscriber:not(.self)', function (Browser $browser) { $browser->assertSeeIn('.meet-nickname', 'john'); }) ->assertElementsCount('@session div.meet-video', 0) ->assertElementsCount('@session video', 0) ->assertElementsCount('@session div.meet-subscriber', 2) ->assertToolbar([ 'audio' => RoomPage::BUTTON_INACTIVE | RoomPage::BUTTON_DISABLED, 'video' => RoomPage::BUTTON_INACTIVE | RoomPage::BUTTON_DISABLED, 'screen' => RoomPage::BUTTON_INACTIVE | RoomPage::BUTTON_DISABLED, 'chat' => RoomPage::BUTTON_INACTIVE | RoomPage::BUTTON_ENABLED, 'fullscreen' => RoomPage::BUTTON_ACTIVE | RoomPage::BUTTON_ENABLED, 'logout' => RoomPage::BUTTON_ACTIVE | RoomPage::BUTTON_ENABLED, ]); // Check guest's elements in the owner's window $browser ->whenAvailable('@subscribers .meet-subscriber:not(.self)', function (Browser $browser) { $browser->assertVisible('.meet-nickname'); }) ->assertElementsCount('@session div.meet-video', 0) ->assertElementsCount('@session video', 0) ->assertElementsCount('@session .meet-subscriber', 2); // Test leaving the room // Guest is leaving $guest->click('@menu button.link-logout') ->waitForLocation('/login'); // Expect the participant removed from other users windows $browser->waitUntilMissing('@session .meet-subscriber:not(.self)'); }); } }