Add tests for all of the account actions

This commit is contained in:
Dane Everitt 2018-07-15 15:58:24 -07:00
parent be2c76c24a
commit d9a09e92bd
No known key found for this signature in database
GPG key ID: EEA66103B3D71F53
9 changed files with 243 additions and 24 deletions

View file

@ -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/>

View file

@ -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>

View file

@ -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>

View file

@ -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',
]); ]);
} }
} }

View file

@ -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.
*/ */

View file

@ -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', '');
});
}
}

View 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();
}
}

View file

@ -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'));
});
}
}

View file

@ -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.
* *