Changeset View
Changeset View
Standalone View
Standalone View
src/tests/Browser/Meet/RoomsTest.php
<?php | <?php | ||||
namespace Tests\Browser\Meet; | namespace Tests\Browser\Meet; | ||||
use App\Sku; | use App\Meet\Room; | ||||
use Tests\Browser; | use Tests\Browser; | ||||
use Tests\Browser\Components\Toast; | use Tests\Browser\Components\Toast; | ||||
use Tests\Browser\Pages\Dashboard; | use Tests\Browser\Pages\Dashboard; | ||||
use Tests\Browser\Pages\Home; | use Tests\Browser\Pages\Home; | ||||
use Tests\Browser\Pages\Meet\Room as RoomPage; | use Tests\Browser\Pages\Meet\Room as RoomPage; | ||||
use Tests\Browser\Pages\Meet\RoomInfo; | |||||
use Tests\Browser\Pages\Meet\RoomList; | |||||
use Tests\Browser\Pages\UserInfo; | use Tests\Browser\Pages\UserInfo; | ||||
use Tests\TestCaseDusk; | use Tests\TestCaseDusk; | ||||
class RoomsTest extends TestCaseDusk | class RoomsTest extends TestCaseDusk | ||||
{ | { | ||||
/** | /** | ||||
* {@inheritDoc} | * {@inheritDoc} | ||||
*/ | */ | ||||
public function setUp(): void | public function setUp(): void | ||||
{ | { | ||||
parent::setUp(); | parent::setUp(); | ||||
$this->clearMeetEntitlements(); | $this->clearMeetEntitlements(); | ||||
Room::withTrashed()->whereNotIn('name', ['jack', 'john'])->forceDelete(); | |||||
} | } | ||||
/** | /** | ||||
* {@inheritDoc} | * {@inheritDoc} | ||||
*/ | */ | ||||
public function tearDown(): void | public function tearDown(): void | ||||
{ | { | ||||
$this->clearMeetEntitlements(); | $this->clearMeetEntitlements(); | ||||
Room::withTrashed()->whereNotIn('name', ['jack', 'john'])->forceDelete(); | |||||
$room = Room::where('name', 'jack')->first(); | |||||
$room->setConfig([ | |||||
'password' => '', | |||||
'locked' => false, | |||||
'nomedia' => false, | |||||
'acl' => ['jack@kolab.org, full'] | |||||
]); | |||||
parent::tearDown(); | parent::tearDown(); | ||||
} | } | ||||
/** | /** | ||||
* Test rooms page (unauthenticated and unauthorized) | * Test rooms page (unauthenticated and unauthorized) | ||||
* | |||||
* @group meet | |||||
*/ | */ | ||||
public function testRoomsUnauth(): void | public function testRoomsUnauth(): void | ||||
{ | { | ||||
// Test that the page requires authentication | // Test that the page requires authentication | ||||
$this->browse(function (Browser $browser) { | $this->browse(function (Browser $browser) { | ||||
$browser->visit('/rooms') | $browser->visit('/rooms') | ||||
->on(new Home()) | ->on(new Home()) | ||||
// User has no 'meet' entitlement yet, expect redirect to error page | // User has no 'meet' entitlement yet, expect redirect to error page | ||||
->submitLogon('john@kolab.org', 'simple123', false) | ->submitLogon('john@kolab.org', 'simple123', false) | ||||
->waitFor('#app > #error-page') | ->waitFor('#app > #error-page') | ||||
->assertSeeIn('#error-page .code', '403') | ->assertSeeIn('#error-page .code', '403') | ||||
->assertSeeIn('#error-page .message', 'Access denied'); | ->assertSeeIn('#error-page .message', 'Access denied'); | ||||
}); | }); | ||||
} | } | ||||
/** | /** | ||||
* Test rooms page | * Test rooms list page | ||||
* | * | ||||
* @group meet | * @group meet | ||||
*/ | */ | ||||
public function testRooms(): void | public function testRooms(): void | ||||
{ | { | ||||
$this->browse(function (Browser $browser) { | $this->browse(function (Browser $browser) { | ||||
$href = \config('app.url') . '/meet/john'; | |||||
$john = $this->getTestUser('john@kolab.org'); | $john = $this->getTestUser('john@kolab.org'); | ||||
// User has no 'meet' entitlement yet | // User has no 'meet' entitlement yet | ||||
$browser->visit('/login') | $browser->visit('/login') | ||||
->on(new Home()) | ->on(new Home()) | ||||
->submitLogon('john@kolab.org', 'simple123', true) | ->submitLogon('john@kolab.org', 'simple123', true) | ||||
->on(new Dashboard()) | ->on(new Dashboard()) | ||||
->assertMissing('@links a.link-chat'); | ->assertMissing('@links a.link-chat'); | ||||
// Goto user subscriptions, and enable 'meet' subscription | // Goto user subscriptions, and enable 'meet' subscription | ||||
$browser->visit('/user/' . $john->id) | $browser->visit('/user/' . $john->id) | ||||
->on(new UserInfo()) | ->on(new UserInfo()) | ||||
->whenAvailable('@skus', function ($browser) { | ->waitFor('@skus') | ||||
$browser->click('#sku-input-meet'); | ->scrollTo('#sku-input-meet')->pause(500) | ||||
}) | ->click('#sku-input-meet') | ||||
->scrollTo('#general button[type=submit]')->pause(200) | |||||
->click('#general button[type=submit]') | ->click('#general button[type=submit]') | ||||
->assertToast(Toast::TYPE_SUCCESS, 'User data updated successfully.') | ->assertToast(Toast::TYPE_SUCCESS, 'User data updated successfully.') | ||||
->click('.navbar-brand') | ->click('.navbar-brand') | ||||
->on(new Dashboard()) | ->on(new Dashboard()) | ||||
->assertSeeIn('@links a.link-chat', 'Video chat') | ->assertSeeIn('@links a.link-chat', 'Video chat') | ||||
// Make sure the element also exists on Dashboard page load | // Make sure the element also exists on Dashboard page load | ||||
->refresh() | ->refresh() | ||||
->on(new Dashboard()) | ->on(new Dashboard()) | ||||
->assertSeeIn('@links a.link-chat', 'Video chat'); | ->assertSeeIn('@links a.link-chat', 'Video chat'); | ||||
// Test Video chat page | // Test Video chat page | ||||
$browser->click('@links a.link-chat') | $browser->click('@links a.link-chat') | ||||
->waitFor('#meet-rooms') | ->on(new RoomList()) | ||||
->waitFor('.card-text a') | ->whenAvailable('@table', function ($browser) { | ||||
->assertSeeIn('.card-title', 'Voice & Video Conferencing') | $browser->assertElementsCount('tbody tr', 2) | ||||
->assertSeeIn('.card-text a', $href) | ->assertElementsCount('thead th', 3) | ||||
->assertAttribute('.card-text a', 'href', '/meet/john') | ->with('tbody tr:nth-child(1)', function ($browser) { | ||||
->click('.card-text a') | $browser->assertSeeIn('td:nth-child(1) a', 'jack') | ||||
->on(new RoomPage('john')) | ->assertSeeIn('td:nth-child(2) a', "Jack's room") | ||||
->assertVisible('td.buttons button.button-link') | |||||
->assertAttribute('td.buttons button.button-link', 'title', 'Enter the room'); | |||||
}) | |||||
->with('tbody tr:nth-child(2)', function ($browser) { | |||||
$browser->assertSeeIn('td:nth-child(1) a', 'john') | |||||
->assertSeeIn('td:nth-child(2) a', "John's room") | |||||
->assertVisible('td.buttons button.button-link') | |||||
->assertAttribute('td.buttons button.button-link', 'title', 'Enter the room'); | |||||
}) | |||||
->click('tbody tr:nth-child(2) button.button-link'); | |||||
}); | |||||
$newWindow = collect($browser->driver->getWindowHandles())->last(); | |||||
$browser->driver->switchTo()->window($newWindow); | |||||
$browser->on(new RoomPage('john')) | |||||
// check that entering the room skips the logon form | // check that entering the room skips the logon form | ||||
->assertMissing('@toolbar') | ->assertMissing('@toolbar') | ||||
->assertMissing('@menu') | ->assertMissing('@menu') | ||||
->assertMissing('@session') | ->assertMissing('@session') | ||||
->assertMissing('@chat') | ->assertMissing('@chat') | ||||
->assertMissing('@login-form') | ->assertMissing('@login-form') | ||||
->assertVisible('@setup-form') | ->assertVisible('@setup-form') | ||||
->assertSeeIn('@setup-status-message', "The room is closed. It will be open for others after you join.") | ->assertSeeIn('@setup-status-message', "The room is closed. It will be open for others after you join.") | ||||
->assertSeeIn('@setup-button', "JOIN") | ->assertSeeIn('@setup-button', "JOIN") | ||||
->click('@setup-button') | ->click('@setup-button') | ||||
->waitFor('@session') | ->waitFor('@session') | ||||
->assertMissing('@setup-form'); | ->assertMissing('@setup-form'); | ||||
}); | }); | ||||
} | } | ||||
/** | |||||
* Test rooms create and edit and delete | |||||
*/ | |||||
public function testRoomCreateAndEditAndDelete(): void | |||||
{ | |||||
$john = $this->getTestUser('john@kolab.org'); | |||||
$this->assignMeetEntitlement($john); | |||||
$this->browse(function (Browser $browser) { | |||||
// Test room creation | |||||
$browser->visit(new RoomList()) | |||||
->assertSeeIn('button.room-new', 'Create room') | |||||
->click('button.room-new') | |||||
->on(new RoomInfo()) | |||||
->assertVisible('@intro p') | |||||
->assertElementsCount('@nav li', 1) | |||||
->assertSeeIn('@nav li a', 'General') | |||||
->with('@general form', function ($browser) { | |||||
$browser->assertSeeIn('.row:nth-child(1) label', 'Description') | |||||
->assertFocused('.row:nth-child(1) input') | |||||
->type('.row:nth-child(1) input', 'test123'); | |||||
}) | |||||
->click('@general button[type=submit]') | |||||
->assertToast(Toast::TYPE_SUCCESS, "Room created successfully.") | |||||
->on(new RoomList()) | |||||
->whenAvailable('@table', function ($browser) { | |||||
$browser->assertElementsCount('tbody tr', 3); | |||||
}); | |||||
$room = Room::where('description', 'test123')->first(); | |||||
// Test room editing | |||||
$browser->click("a[href=\"/room/{$room->id}\"]") | |||||
->on(new RoomInfo()) | |||||
->assertSeeIn('.card-title', "Room: {$room->name}") | |||||
->assertVisible('@intro p') | |||||
->assertVisible("@intro a[href=\"/meet/{$room->name}\"]") | |||||
->assertElementsCount('@nav li', 2) | |||||
->assertSeeIn('@nav li:first-child a', 'General') | |||||
->with('@general form', function ($browser) { | |||||
$browser->assertSeeIn('.row:nth-child(1) label', 'Description') | |||||
->assertFocused('.row:nth-child(1) input') | |||||
->type('.row:nth-child(1) input', 'test321') | |||||
->assertSeeIn('.row:nth-child(2) label', 'Subscriptions') | |||||
->with('@skus', function ($browser) { | |||||
$browser->assertElementsCount('tbody tr', 1) | |||||
->assertSeeIn('tbody tr:nth-child(1) td.name', 'Conference room') | |||||
->assertSeeIn('tbody tr:nth-child(1) td.price', '0,00 CHF/month') | |||||
->assertChecked('tbody tr:nth-child(1) td.selection input') | |||||
->assertDisabled('tbody tr:nth-child(1) td.selection input') | |||||
->assertTip( | |||||
'tbody tr:nth-child(1) td.buttons button', | |||||
'Audio & Video Conference room' | |||||
); | |||||
}); | |||||
}) | |||||
->click('@general button[type=submit]') | |||||
->assertToast(Toast::TYPE_SUCCESS, "Room updated successfully.") | |||||
->on(new RoomList()); | |||||
$room->refresh(); | |||||
$this->assertSame('test321', $room->description); | |||||
// Test room settings editing | |||||
$browser->click("a[href=\"/room/{$room->id}\"]") | |||||
->on(new RoomInfo()) | |||||
->assertSeeIn('@nav li:last-child a', 'Settings') | |||||
->click('@nav li:last-child a') | |||||
->with('@settings form', function ($browser) { | |||||
$browser->assertSeeIn('.row:nth-child(1) label', 'Password') | |||||
->assertValue('.row:nth-child(1) input', '') | |||||
->assertVisible('.row:nth-child(1) .form-text') | |||||
->assertSeeIn('.row:nth-child(2) label', 'Locked room') | |||||
->assertNotChecked('.row:nth-child(2) input') | |||||
->assertVisible('.row:nth-child(2) .form-text') | |||||
->assertSeeIn('.row:nth-child(3) label', 'Subscribers only') | |||||
->assertNotChecked('.row:nth-child(3) input') | |||||
->assertVisible('.row:nth-child(3) .form-text') | |||||
->assertSeeIn('.row:nth-child(4) label', 'Moderators') | |||||
->assertVisible('.row:nth-child(4) .form-text') | |||||
->type('#acl .input-group:first-child input', 'jack') | |||||
->click('#acl a.btn'); | |||||
}) | |||||
->click('@settings button[type=submit]') | |||||
->assertToast(Toast::TYPE_ERROR, "Form validation error") | |||||
->assertSeeIn('#acl + .invalid-feedback', "The specified email address is invalid.") | |||||
->with('@settings form', function ($browser) { | |||||
$browser->type('.row:nth-child(1) input', 'pass') | |||||
->click('.row:nth-child(2) input') | |||||
->click('.row:nth-child(3) input') | |||||
->click('#acl .input-group:last-child a.btn') | |||||
->type('#acl .input-group:first-child input', 'jack@kolab.org') | |||||
->click('#acl a.btn'); | |||||
}) | |||||
->click('@settings button[type=submit]') | |||||
->assertToast(Toast::TYPE_SUCCESS, "Room configuration updated successfully."); | |||||
$config = $room->getConfig(); | |||||
$this->assertSame('pass', $config['password']); | |||||
$this->assertSame(true, $config['locked']); | |||||
$this->assertSame(true, $config['nomedia']); | |||||
$this->assertSame(['jack@kolab.org, full'], $config['acl']); | |||||
// Test room deleting | |||||
$browser->assertSeeIn('button.button-delete', 'Delete room') | |||||
->click('button.button-delete') | |||||
->assertToast(Toast::TYPE_SUCCESS, "Room deleted successfully.") | |||||
->on(new RoomList()) | |||||
->whenAvailable('@table', function ($browser) { | |||||
$browser->assertElementsCount('tbody tr', 2); | |||||
}); | |||||
}); | |||||
} | |||||
/** | |||||
* Test acting as a non-controller user | |||||
* | |||||
* @group meet | |||||
*/ | |||||
public function testNonControllerRooms(): void | |||||
{ | |||||
$jack = $this->getTestUser('jack@kolab.org'); | |||||
$this->assignMeetEntitlement($jack); | |||||
$john = $this->getTestUser('john@kolab.org'); | |||||
$this->assignMeetEntitlement($john); | |||||
$room = Room::where('name', 'jack')->first(); | |||||
$room->session_id = null; | |||||
$room->save(); | |||||
$room->setConfig([ | |||||
'password' => 'pass', | |||||
'locked' => true, | |||||
'nomedia' => true, | |||||
'acl' => ['jack@kolab.org, full'] | |||||
]); | |||||
$this->browse(function (Browser $browser) use ($room) { | |||||
$browser->visit(new Home()) | |||||
->submitLogon('jack@kolab.org', 'simple123', true) | |||||
->on(new Dashboard()) | |||||
->click('@links a.link-chat') | |||||
->on(new RoomList()) | |||||
->assertMissing('button.room-new') | |||||
->assertMissing('button.button-delete') | |||||
->whenAvailable('@table', function ($browser) { | |||||
$browser->assertElementsCount('tbody tr', 1) | |||||
->with('tbody tr:nth-child(1)', function ($browser) { | |||||
$browser->assertSeeIn('td:nth-child(1) a', 'jack') | |||||
->assertSeeIn('td:nth-child(2) a', "Jack's room") | |||||
->assertVisible('td.buttons button.button-link') | |||||
->assertAttribute('td.buttons button.button-link', 'title', 'Enter the room'); | |||||
}) | |||||
->click('tbody tr:nth-child(1)'); | |||||
}) | |||||
->on(new RoomInfo()) | |||||
->assertSeeIn('.card-title', "Room: {$room->name}") | |||||
->assertVisible('@intro p') | |||||
->assertVisible("@intro a[href=\"/meet/{$room->name}\"]") | |||||
->assertElementsCount('@nav li', 1) | |||||
// Test room settings | |||||
->assertSeeIn('@nav li:last-child a', 'Settings') | |||||
->with('@settings form', function ($browser) { | |||||
$browser->assertSeeIn('.row:nth-child(1) label', 'Password') | |||||
->assertValue('.row:nth-child(1) input', 'pass') | |||||
->assertVisible('.row:nth-child(1) .form-text') | |||||
->assertSeeIn('.row:nth-child(2) label', 'Locked room') | |||||
->assertChecked('.row:nth-child(2) input') | |||||
->assertVisible('.row:nth-child(2) .form-text') | |||||
->assertSeeIn('.row:nth-child(3) label', 'Subscribers only') | |||||
->assertChecked('.row:nth-child(3) input') | |||||
->assertVisible('.row:nth-child(3) .form-text') | |||||
->assertSeeIn('.row:nth-child(4) label', 'Moderators') | |||||
->assertValue('#acl .input-group:last-child input', 'jack@kolab.org') | |||||
->assertVisible('.row:nth-child(4) .form-text') | |||||
->type('#acl .input-group:first-child input', 'joe@kolab.org') | |||||
->click('#acl a.btn') | |||||
->type('.row:nth-child(1) input', 'pass123') | |||||
->click('.row:nth-child(2) input') | |||||
->click('.row:nth-child(3) input'); | |||||
}) | |||||
->click('@settings button[type=submit]') | |||||
->assertToast(Toast::TYPE_SUCCESS, "Room configuration updated successfully."); | |||||
$config = $room->getConfig(); | |||||
$this->assertSame('pass123', $config['password']); | |||||
$this->assertSame(false, $config['locked']); | |||||
$this->assertSame(false, $config['nomedia']); | |||||
$this->assertSame(['joe@kolab.org, full', 'jack@kolab.org, full'], $config['acl']); | |||||
$browser->click("@intro a[href=\"/meet/{$room->name}\"]") | |||||
->on(new RoomPage('jack')) | |||||
// check that entering the room skips the logon form | |||||
->assertMissing('@toolbar') | |||||
->assertMissing('@menu') | |||||
->assertMissing('@session') | |||||
->assertMissing('@chat') | |||||
->assertMissing('@login-form') | |||||
->assertVisible('@setup-form') | |||||
->assertSeeIn('@setup-status-message', "The room is closed. It will be open for others after you join.") | |||||
->assertSeeIn('@setup-button', "JOIN") | |||||
->click('@setup-button') | |||||
->waitFor('@session') | |||||
->assertMissing('@setup-form') | |||||
->waitFor('a.meet-nickname svg.moderator'); | |||||
}); | |||||
} | |||||
} | } |