Add tests for all of the account actions
This commit is contained in:
parent
be2c76c24a
commit
d9a09e92bd
9 changed files with 243 additions and 24 deletions
|
@ -2,7 +2,7 @@
|
||||||
<transition name="modal">
|
<transition name="modal">
|
||||||
<div class="modal-mask" v-show="show" v-on:click="close">
|
<div class="modal-mask" v-show="show" v-on:click="close">
|
||||||
<div class="modal-container" @click.stop>
|
<div class="modal-container" @click.stop>
|
||||||
<x-icon class="absolute pin-r pin-t m-2 text-grey cursor-pointer" aria-label="Close modal"
|
<x-icon class="absolute pin-r pin-t m-2 text-grey cursor-pointer" aria-label="Close modal" role="button"
|
||||||
v-on:click="close"
|
v-on:click="close"
|
||||||
/>
|
/>
|
||||||
<slot/>
|
<slot/>
|
||||||
|
|
|
@ -11,7 +11,9 @@
|
||||||
<div class="sm:m-4 md:ml-0">
|
<div class="sm:m-4 md:ml-0">
|
||||||
<update-email class="mb-4 sm:mb-8"/>
|
<update-email class="mb-4 sm:mb-8"/>
|
||||||
<div class="content-box text-center mb-4 sm:mb-0">
|
<div class="content-box text-center mb-4 sm:mb-0">
|
||||||
<button class="btn btn-green btn-sm" type="submit" v-on:click="openModal">Configure 2-Factor Authentication</button>
|
<button class="btn btn-green btn-sm" type="submit" id="grid-open-two-factor-modal"
|
||||||
|
v-on:click="openModal"
|
||||||
|
>Configure 2-Factor Authentication</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div id="configure-two-factor">
|
||||||
<div class="h-16 text-center" v-show="spinner">
|
<div class="h-16 text-center" v-show="spinner">
|
||||||
<span class="spinner spinner-xl text-blue"></span>
|
<span class="spinner spinner-xl text-blue"></span>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="response.enabled" v-show="!spinner">
|
<div id="container-disable-two-factor" v-if="response.enabled" v-show="!spinner">
|
||||||
<h2 class="font-medium text-grey-darkest">{{ $t('dashboard.account.two_factor.disable.title') }}</h2>
|
<h2 class="font-medium text-grey-darkest">{{ $t('dashboard.account.two_factor.disable.title') }}</h2>
|
||||||
<div class="mt-6">
|
<div class="mt-6">
|
||||||
<label class="input-label" for="grid-two-factor-token-disable">{{ $t('dashboard.account.two_factor.disable.field') }}</label>
|
<label class="input-label" for="grid-two-factor-token-disable">{{ $t('dashboard.account.two_factor.disable.field') }}</label>
|
||||||
|
@ -26,12 +26,12 @@
|
||||||
>{{ $t('strings.disable') }}</button>
|
>{{ $t('strings.disable') }}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else v-show="!spinner">
|
<div id="container-enable-two-factor" v-else v-show="!spinner">
|
||||||
<h2 class="font-medium text-grey-darkest">{{ $t('dashboard.account.two_factor.setup.title') }}</h2>
|
<h2 class="font-medium text-grey-darkest">{{ $t('dashboard.account.two_factor.setup.title') }}</h2>
|
||||||
<div class="flex mt-6">
|
<div class="flex mt-6">
|
||||||
<div class="flex-none w-full sm:w-1/2 text-center">
|
<div class="flex-none w-full sm:w-1/2 text-center">
|
||||||
<div class="h-48">
|
<div class="h-48">
|
||||||
<img :src="response.qr_image" alt="Two-factor qr image" class="h-48">
|
<img :src="response.qr_image" id="grid-qr-code" alt="Two-factor qr image" class="h-48">
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p class="text-xs text-grey-darker mb-2">{{ $t('dashboard.account.two_factor.setup.help') }}</p>
|
<p class="text-xs text-grey-darker mb-2">{{ $t('dashboard.account.two_factor.setup.help') }}</p>
|
||||||
|
|
|
@ -21,8 +21,21 @@ class AccountPage extends BasePage
|
||||||
{
|
{
|
||||||
return array_merge(parent::elements(), [
|
return array_merge(parent::elements(), [
|
||||||
'@email' => '#update-email-container #grid-email',
|
'@email' => '#update-email-container #grid-email',
|
||||||
'@password' => '#update-email-container #grid-password',
|
'@password' => '#update-email-container #grid-password[type="password"]',
|
||||||
'@submit' => '#update-email-container button[type="submit"]',
|
'@submit' => '#update-email-container button[type="submit"]',
|
||||||
|
|
||||||
|
'@current_password' => '#change-password-container #grid-password-current[type="password"]',
|
||||||
|
'@new_password' => '#change-password-container #grid-password-new[type="password"]',
|
||||||
|
'@confirm_password' => '#change-password-container #grid-password-new-confirm[type="password"]',
|
||||||
|
'@submit_password' => '#change-password-container button[type="submit"]',
|
||||||
|
|
||||||
|
'@2fa_button' => '#grid-open-two-factor-modal',
|
||||||
|
'@2fa_modal' => '.modal-mask #configure-two-factor',
|
||||||
|
'@2fa_token' => '#configure-two-factor #container-enable-two-factor #grid-two-factor-token[type="number"]',
|
||||||
|
'@2fa_token_disable' => '#configure-two-factor #container-disable-two-factor #grid-two-factor-token-disable',
|
||||||
|
'@2fa_enable' => '#configure-two-factor #container-enable-two-factor button[type="submit"]',
|
||||||
|
'@2fa_disable' => '#configure-two-factor #container-disable-two-factor button.btn-red[type="submit"]',
|
||||||
|
'@2fa_cancel' => '#configure-two-factor #container-disable-two-factor button.btn-secondary',
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,27 +2,11 @@
|
||||||
|
|
||||||
namespace Pterodactyl\Tests\Browser\Processes\Dashboard;
|
namespace Pterodactyl\Tests\Browser\Processes\Dashboard;
|
||||||
|
|
||||||
use Pterodactyl\Tests\Browser\BrowserTestCase;
|
|
||||||
use Pterodactyl\Tests\Browser\PterodactylBrowser;
|
use Pterodactyl\Tests\Browser\PterodactylBrowser;
|
||||||
use Pterodactyl\Tests\Browser\Pages\Dashboard\AccountPage;
|
use Pterodactyl\Tests\Browser\Pages\Dashboard\AccountPage;
|
||||||
|
|
||||||
class AccountEmailProcessTest extends BrowserTestCase
|
class AccountEmailProcessTest extends DashboardTestCase
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* @var \Pterodactyl\Models\User
|
|
||||||
*/
|
|
||||||
private $user;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Setup tests.
|
|
||||||
*/
|
|
||||||
protected function setUp()
|
|
||||||
{
|
|
||||||
parent::setUp();
|
|
||||||
|
|
||||||
$this->user = $this->user();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that an email address can be changed successfully.
|
* Test that an email address can be changed successfully.
|
||||||
*/
|
*/
|
||||||
|
@ -43,6 +27,23 @@ class AccountEmailProcessTest extends BrowserTestCase
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that the validation error message shows up when an invalid email is entered.
|
||||||
|
*/
|
||||||
|
public function testInvalidEmailShowsErrors()
|
||||||
|
{
|
||||||
|
$this->browse(function (PterodactylBrowser $browser) {
|
||||||
|
$browser->loginAs($this->user)
|
||||||
|
->visit(new AccountPage)
|
||||||
|
->assertMissing('@email ~ .input-help.error')
|
||||||
|
->type('@email', 'admin')
|
||||||
|
->assertVisible('@email ~ .input-help.error')
|
||||||
|
->assertSeeIn('@email ~ .input-help.error', 'The email field must be a valid email.')
|
||||||
|
->type('@email', 'admin@example.com')
|
||||||
|
->assertMissing('@email ~ .input-help.error');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that entering the wrong password for an account returns an error.
|
* Test that entering the wrong password for an account returns an error.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Pterodactyl\Tests\Browser\Processes\Dashboard;
|
||||||
|
|
||||||
|
use Pterodactyl\Tests\Browser\PterodactylBrowser;
|
||||||
|
use Pterodactyl\Tests\Browser\Pages\Dashboard\AccountPage;
|
||||||
|
|
||||||
|
class AccountPasswordProcessTest extends DashboardTestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Test that a user is able to change their password.
|
||||||
|
*/
|
||||||
|
public function testPasswordCanBeChanged()
|
||||||
|
{
|
||||||
|
$this->browse(function (PterodactylBrowser $browser) {
|
||||||
|
$browser->loginAs($this->user)
|
||||||
|
->visit(new AccountPage)
|
||||||
|
->type('@current_password', self::$userPassword)
|
||||||
|
->assertMissing('@new_password ~ .input-help.error')
|
||||||
|
->type('@new_password', 'test')
|
||||||
|
->assertSeeIn('@new_password ~ .input-help.error', 'The password field must be at least 8 characters.')
|
||||||
|
->type('@new_password', 'Test1234')
|
||||||
|
->assertMissing('@new_password ~ .input-help.error')
|
||||||
|
->assertMissing('@confirm_password ~ .input-help.error')
|
||||||
|
->type('@confirm_password', 'test')
|
||||||
|
->assertSeeIn('@confirm_password ~ .input-help.error', 'The password value is not valid.')
|
||||||
|
->type('@confirm_password', 'Test1234')
|
||||||
|
->assertMissing('@confirm_password ~ .input-help.error')
|
||||||
|
->click('@submit_password')
|
||||||
|
->waitFor('@@success')
|
||||||
|
->assertSeeIn('@@success', 'Your password has been updated.')
|
||||||
|
->assertInputValue('@current_password', '')
|
||||||
|
->assertInputValue('@new_password', '')
|
||||||
|
->assertInputValue('@confirm_password', '');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that invalid passwords result in the expected error message.
|
||||||
|
*/
|
||||||
|
public function testInvalidPassword()
|
||||||
|
{
|
||||||
|
$this->browse(function (PterodactylBrowser $browser) {
|
||||||
|
$browser->loginAs($this->user)
|
||||||
|
->visit(new AccountPage)
|
||||||
|
->type('@current_password', 'badpassword')
|
||||||
|
->type('@new_password', 'testtest')
|
||||||
|
->type('@confirm_password', 'testtest')
|
||||||
|
->click('@submit_password')
|
||||||
|
->waitFor('@@error')
|
||||||
|
->assertSeeIn('@@error', trans('validation.internal.invalid_password'))
|
||||||
|
->assertInputValue('@current_password', '');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
23
tests/Browser/Processes/Dashboard/DashboardTestCase.php
Normal file
23
tests/Browser/Processes/Dashboard/DashboardTestCase.php
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Pterodactyl\Tests\Browser\Processes\Dashboard;
|
||||||
|
|
||||||
|
use Pterodactyl\Tests\Browser\BrowserTestCase;
|
||||||
|
|
||||||
|
abstract class DashboardTestCase extends BrowserTestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var \Pterodactyl\Models\User
|
||||||
|
*/
|
||||||
|
protected $user;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup tests and provide a default user to calling functions.
|
||||||
|
*/
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->user = $this->user();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,111 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Pterodactyl\Tests\Browser\Processes\Dashboard;
|
||||||
|
|
||||||
|
use PragmaRX\Google2FA\Google2FA;
|
||||||
|
use Facebook\WebDriver\WebDriverKeys;
|
||||||
|
use Illuminate\Support\Facades\Crypt;
|
||||||
|
use Pterodactyl\Tests\Browser\PterodactylBrowser;
|
||||||
|
use Pterodactyl\Tests\Browser\Pages\Dashboard\AccountPage;
|
||||||
|
|
||||||
|
class TwoFactorAuthenticationProcessTest extends DashboardTestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Test that the modal can be opened and closed.
|
||||||
|
*/
|
||||||
|
public function testModalOpenAndClose()
|
||||||
|
{
|
||||||
|
$this->browse(function (PterodactylBrowser $browser) {
|
||||||
|
$browser->loginAs($this->user)
|
||||||
|
->visit(new AccountPage)
|
||||||
|
->assertMissing('.modal-mask')
|
||||||
|
->click('@2fa_button')
|
||||||
|
->waitFor('@2fa_modal')
|
||||||
|
->pause(500)// seems to fix fragile test
|
||||||
|
->clickPosition(100, 100)
|
||||||
|
->waitUntilMissing('@2fa_modal')
|
||||||
|
->click('@2fa_button')
|
||||||
|
->waitFor('@2fa_modal')
|
||||||
|
->click('svg[role="button"][aria-label="Close modal"]')
|
||||||
|
->waitUntilMissing('@2fa_modal')
|
||||||
|
->click('@2fa_button')
|
||||||
|
->waitFor('@2fa_modal')
|
||||||
|
->keys('', [WebDriverKeys::ESCAPE])
|
||||||
|
->waitUntilMissing('@2fa_modal');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that a user that does not have two-factor enabled can enable it on their account.
|
||||||
|
*/
|
||||||
|
public function testTwoFactorCanBeEnabled()
|
||||||
|
{
|
||||||
|
$this->browse(function (PterodactylBrowser $browser) {
|
||||||
|
$browser->loginAs($this->user)
|
||||||
|
->visit(new AccountPage)
|
||||||
|
->click('@2fa_button')
|
||||||
|
->waitForText(trans('dashboard/account.two_factor.setup.title'))
|
||||||
|
->assertFocused('@2fa_token')
|
||||||
|
->waitFor('#grid-qr-code')
|
||||||
|
->assertSee(trans('dashboard/account.two_factor.setup.help'));
|
||||||
|
|
||||||
|
// Grab information from the database so we can ensure the correct things are showing up.
|
||||||
|
// Also because we need to generate a code to send through and activate it with.
|
||||||
|
$updated = $this->user->fresh();
|
||||||
|
|
||||||
|
$secret = Crypt::decrypt($updated->totp_secret);
|
||||||
|
$code = (new Google2FA())->getCurrentOtp($secret);
|
||||||
|
|
||||||
|
$browser->assertSeeIn('code', $secret)
|
||||||
|
->assertVisible('@2fa_enable[disabled="disabled"]')
|
||||||
|
->assertMissing('@2fa_token ~ .input-help.error')
|
||||||
|
->type('@2fa_token', '12')
|
||||||
|
->assertSeeIn('@2fa_token ~ .input-help.error', 'The token length must be 6.')
|
||||||
|
->type('@2fa_token', $code)
|
||||||
|
->assertMissing('@2fa_token ~ .input-help.error')
|
||||||
|
->click('@2fa_enable')
|
||||||
|
->waitUntilMissing('@2fa_modal')
|
||||||
|
->assertSeeIn('@@success', trans('dashboard/account.two_factor.enabled'));
|
||||||
|
|
||||||
|
$this->assertDatabaseHas('users', ['id' => $this->user->id, 'use_totp' => 1]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that a user can disable two-factor authentication on thier account.
|
||||||
|
*/
|
||||||
|
public function testTwoFactorCanBeDisabled()
|
||||||
|
{
|
||||||
|
$secret = (new Google2FA)->generateSecretKey(16);
|
||||||
|
|
||||||
|
$this->user->update([
|
||||||
|
'use_totp' => true,
|
||||||
|
'totp_secret' => Crypt::encrypt($secret),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->browse(function (PterodactylBrowser $browser) use ($secret) {
|
||||||
|
$browser->loginAs($this->user)
|
||||||
|
->visit(new AccountPage)
|
||||||
|
->click('@2fa_button')
|
||||||
|
->waitForText(trans('dashboard/account.two_factor.disable.title'))
|
||||||
|
->click('@2fa_cancel')
|
||||||
|
->waitUntilMissing('@2fa_modal')
|
||||||
|
->click('@2fa_button')
|
||||||
|
->waitForText(trans('dashboard/account.two_factor.disable.title'))
|
||||||
|
->assertVisible('@2fa_disable[disabled="disabled"]')
|
||||||
|
->assertVisible('@2fa_cancel')
|
||||||
|
->assertFocused('@2fa_token_disable')
|
||||||
|
->assertMissing('@2fa_token_disable ~ .input-help.error')
|
||||||
|
->type('@2fa_token_disable', '12')
|
||||||
|
->assertSeeIn('@2fa_token_disable ~ .input-help.error', 'The token length must be 6.');
|
||||||
|
|
||||||
|
$token = (new Google2FA())->getCurrentOtp($secret);
|
||||||
|
|
||||||
|
$browser->type('@2fa_token_disable', $token)
|
||||||
|
->assertMissing('@2fa_token_disable ~ .input-help.error')
|
||||||
|
->click('@2fa_disable')
|
||||||
|
->waitUntilMissing('@2fa_modal')
|
||||||
|
->assertSeeIn('@@success', trans('dashboard/account.two_factor.disabled'));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,6 +8,20 @@ use PHPUnit\Framework\Assert as PHPUnit;
|
||||||
|
|
||||||
class PterodactylBrowser extends Browser
|
class PterodactylBrowser extends Browser
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Move the mouse to a specific location and then perform a left click action.
|
||||||
|
*
|
||||||
|
* @param int $x
|
||||||
|
* @param int $y
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function clickPosition(int $x, int $y)
|
||||||
|
{
|
||||||
|
$this->driver->getMouse()->mouseMove(null, $x, $y)->click();
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform a case insensitive search for a string in the body.
|
* Perform a case insensitive search for a string in the body.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in a new issue