Compare commits

...

54 Commits

Author SHA1 Message Date
Lance Pioch abadcd2272 Fix not my stuff with php-cs-fixer 2022-10-29 18:16:18 -04:00
Lance Pioch da26f73735 Fix my stuff with php-cs-fixer 2022-10-29 18:16:01 -04:00
Lance Pioch 5ce5f2fea3
Merge branch '1.0-develop' into dusk 2022-10-29 18:13:28 -04:00
Lance Pioch 381c777834 Fix on local for now 2022-10-29 18:01:45 -04:00
Lance Pioch ff73db3829 Don't need this anymore 2022-10-29 03:58:59 -04:00
Lance Pioch bc6768fd76 Try this back in 2022-10-29 03:55:01 -04:00
Lance Pioch 780f6f3ed7 Whitelist these 2022-10-29 03:48:32 -04:00
Lance Pioch eb11ef5729 Revert 2022-10-29 03:48:15 -04:00
Lance Pioch ce0d6b9634 Better naming for artifacts 2022-10-29 03:24:05 -04:00
Lance Pioch aa0b93e16b Run cors middleware for testing routes 2022-10-29 03:17:23 -04:00
Lance Pioch 9592ba6cc4 Seriously 2022-10-29 03:07:51 -04:00
Lance Pioch 6b2ccf8dc2 Allow all for testing 2022-10-29 03:05:28 -04:00
Lance Pioch 664ef911e3 Use second instance of built in webserver 2022-10-29 02:55:58 -04:00
Lance Pioch eb139224e2 Run another instance 2022-10-29 02:55:38 -04:00
Lance Pioch 408ca6e994 Take out unnecessary tests 2022-10-29 02:55:18 -04:00
Lance Pioch e4b48c5b79 Try post requests 2022-10-29 02:36:24 -04:00
Lance Pioch 76af3dc5f5 Remove logging 2022-10-29 02:19:37 -04:00
Lance Pioch 5692dca579 This may make it much more confusing 2022-10-29 00:59:19 -04:00
Lance Pioch f112fec457 Does this make a difference? 2022-10-29 00:38:12 -04:00
Lance Pioch f25fe6ddd6 Try flagging it here 2022-10-28 23:28:43 -04:00
Lance Pioch 82d608dd87 Switch back to direct ip 2022-10-28 23:26:37 -04:00
Lance Pioch 9b09a67dc4 Try running this earlier 2022-10-28 23:20:14 -04:00
Lance Pioch f791aec7dc Try adding curl test 2022-10-28 23:09:59 -04:00
Lance Pioch 2865ca5aec Run composer after cache 2022-10-28 23:03:31 -04:00
Lance Pioch e7a0a2ea7e Cache these things yo 2022-10-28 22:57:41 -04:00
Lance Pioch d781a7f459 Try whitelisting all ips 2022-10-28 22:49:50 -04:00
Lance Pioch 9fbc35eb58 Revert "Try custom host"
This reverts commit a149e7001c.
2022-10-28 22:49:16 -04:00
Lance Pioch a149e7001c Try custom host 2022-10-28 17:06:46 -04:00
Lance Pioch ac5f8f80bc php-cs-fixer 2022-10-28 17:05:00 -04:00
Lance Pioch cd764b6d6f Fingers crossed 2022-10-28 15:40:37 -04:00
Lance Pioch f4312f5b21 Fix this step 2022-10-28 15:30:35 -04:00
Lance Pioch 93162ebfee Other testing 2022-10-28 15:27:52 -04:00
Lance Pioch d632fa97de Revert "Add temporary test logging"
This reverts commit 1d2a20d831.
2022-10-28 15:21:26 -04:00
Lance Pioch 1d2a20d831 Add temporary test logging 2022-10-28 15:14:26 -04:00
Lance Pioch 68b1f1ec27 Upload application logs too 2022-10-28 14:19:10 -04:00
Lance Pioch 56ae6c9765 Forcefully generate a new one 2022-10-28 14:18:46 -04:00
Lance Pioch edda6f80b0 Update these to the latest one 2022-10-28 13:43:08 -04:00
Lance Pioch b8f50e5162 Don't visit the same page twice 2022-10-28 13:20:59 -04:00
Lance Pioch 126c06a929 Update comments 2022-10-28 13:20:36 -04:00
Lance Pioch a45d054b48 Update comment 2022-10-28 13:16:47 -04:00
Lance Pioch 426c1cea66 Add comments 2022-10-28 13:16:09 -04:00
Lance Pioch f7ed8af52a Get the port out 2022-10-27 22:39:01 -04:00
Lance Pioch d59cf5294e Use domain from app url 2022-10-27 22:30:34 -04:00
Lance Pioch 060335043b Disable recaptcha 2022-10-27 22:19:21 -04:00
Lance Pioch 3a772cb2ca Build front end 2022-10-27 21:57:22 -04:00
Lance Pioch a502acab96 Add some variables 2022-10-27 21:52:17 -04:00
Lance Pioch 1810d6214d Copy this in from docs 2022-10-27 21:49:15 -04:00
Lance Pioch 8ee7652aad Add main tests 2022-10-27 21:46:37 -04:00
Lance Pioch cdf365ad8c Don't need this anymore 2022-10-27 21:46:28 -04:00
Lance Pioch 7db6665817 Make sure migrations aren't rolled back 2022-10-27 21:46:14 -04:00
Lance Pioch 553c4f6b09 Add testing routes 2022-10-27 21:45:51 -04:00
Lance Pioch 660c85aa97 Wip 2022-10-26 21:04:32 -04:00
Lance Pioch f38f8db445 Add base tests for dusk 2022-10-26 03:01:00 -04:00
Lance Pioch a7e2bd2866 Add dusk 2022-10-26 00:20:22 -04:00
18 changed files with 655 additions and 4 deletions

86
.github/workflows/dusk.yml vendored Normal file
View File

@ -0,0 +1,86 @@
name: Dusk
on: [push]
jobs:
dusk-php:
runs-on: ubuntu-latest
env:
APP_URL: "http://127.0.0.1:8000"
APP_ENV: dusk
APP_CORS_ALLOWED_ORIGINS: "*"
DB_USERNAME: root
DB_PASSWORD: root
MAIL_MAILER: log
APP_KEY: "base64:8hOaU5CSjb45bxnFEToJwOsfhOpOvH/g4OWcoJPNyyE="
RECAPTCHA_ENABLED: false
steps:
- uses: actions/checkout@v3
- name: Prepare The Environment
run: cp .env.example .env
- name: Create Database
run: |
sudo systemctl start mysql
mysql --user="root" --password="root" -e "CREATE DATABASE \`panel\` character set UTF8mb4 collate utf8mb4_bin;"
- name: Get Cache Directory
id: composer-cache
run: |
echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- name: Cache Composer
uses: actions/cache@v3
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-8.1-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-composer-8.1-
- name: Install Composer Dependencies
run: composer install --no-interaction --no-progress --prefer-dist --optimize-autoloader
- name: Generate Application Key
run: php artisan key:generate --force --no-interaction
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 16
cache: "yarn"
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Build
run: yarn build:production
- name: Run Laravel Server
run: php artisan serve --no-reload &
- name: Run Laravel Server Pseudo Daemon
run: php artisan serve --no-reload &
- name: Upgrade Chrome Driver
run: php artisan dusk:chrome-driver --detect
- name: Start Chrome Driver
run: ./vendor/laravel/dusk/bin/chromedriver-linux &
- name: Run Dusk Tests
run: php artisan dusk
- name: Upload Screenshots
if: failure()
uses: actions/upload-artifact@v3
with:
name: browser-screenshots
path: tests/Browser/screenshots
- name: Upload Console Logs
if: failure()
uses: actions/upload-artifact@v3
with:
name: browser-console
path: tests/Browser/console
- name: Upload Application Logs
if: failure()
uses: actions/upload-artifact@v3
with:
name: storage-logs
path: storage/logs

View File

@ -4,8 +4,8 @@ namespace Pterodactyl\Http\Controllers\Admin\Servers;
use Illuminate\Http\Request;
use Pterodactyl\Models\Server;
use Prologue\Alerts\AlertsMessageBag;
use Illuminate\Http\RedirectResponse;
use Prologue\Alerts\AlertsMessageBag;
use Pterodactyl\Models\ServerTransfer;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Services\Servers\TransferService;

View File

@ -90,6 +90,7 @@ class Kernel extends HttpKernel
'auth' => Authenticate::class,
'auth.basic' => AuthenticateWithBasicAuth::class,
'auth.session' => AuthenticateSession::class,
'cors' => HandleCors::class,
'guest' => RedirectIfAuthenticated::class,
'csrf' => VerifyCsrfToken::class,
'throttle' => ThrottleRequests::class,

View File

@ -2,9 +2,9 @@
namespace Pterodactyl\Models;
use Carbon\CarbonImmutable;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Carbon\CarbonImmutable;
use Illuminate\Support\Carbon;
use Illuminate\Validation\Rule;
use Illuminate\Container\Container;

View File

@ -32,6 +32,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
* @method static \Illuminate\Database\Eloquent\Builder|UserSSHKey whereUserId($value)
* @method static \Illuminate\Database\Query\Builder|UserSSHKey withTrashed()
* @method static \Illuminate\Database\Query\Builder|UserSSHKey withoutTrashed()
*
* @mixin \Eloquent
*
* @method static \Database\Factories\UserSSHKeyFactory factory(...$parameters)

View File

@ -62,6 +62,8 @@ class RouteServiceProvider extends ServiceProvider
->prefix('/api/remote')
->scopeBindings()
->group(base_path('routes/api-remote.php'));
$this->duskBoot();
});
}
@ -107,4 +109,25 @@ class RouteServiceProvider extends ServiceProvider
)->by($key);
});
}
// Laravel Dusk Browser Testing Route Helpers for the Daemon
private function duskBoot()
{
// Make sure we're only running in the Dusk testing environment
if (!app()->environment('dusk')) {
return;
}
// Simulate Node Ping
Route::get('/api/system', fn () => [
'version' => '1.7.0',
'kernel_version' => '5.4.0-126-generic',
'architecture' => 'amd64',
'os' => 'linux',
'cpu_count' => 2,
]);
// Simulate Successful Server Creation
Route::post('/api/servers', fn () => []);
}
}

View File

@ -58,6 +58,7 @@
"fakerphp/faker": "~1.20",
"friendsofphp/php-cs-fixer": "~3.11",
"itsgoingd/clockwork": "~5.1",
"laravel/dusk": "^7.1",
"mockery/mockery": "~1.5",
"nunomaduro/collision": "~6.3",
"php-mock/php-mock-phpunit": "~2.6",

140
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "80a0f1016b1ba9e0b31d6cfe0f27f8c1",
"content-hash": "9df3e017d39b7b7642cc1a958979894c",
"packages": [
{
"name": "aws/aws-crt-php",
@ -8725,6 +8725,79 @@
],
"time": "2022-10-19T21:46:50+00:00"
},
{
"name": "laravel/dusk",
"version": "v7.1.1",
"source": {
"type": "git",
"url": "https://github.com/laravel/dusk.git",
"reference": "c7aacfabdf0883ba9a76c23a0d08b63dea2d0de8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/dusk/zipball/c7aacfabdf0883ba9a76c23a0d08b63dea2d0de8",
"reference": "c7aacfabdf0883ba9a76c23a0d08b63dea2d0de8",
"shasum": ""
},
"require": {
"ext-json": "*",
"ext-zip": "*",
"illuminate/console": "^9.0",
"illuminate/support": "^9.0",
"nesbot/carbon": "^2.0",
"php": "^8.0",
"php-webdriver/webdriver": "^1.9.0",
"symfony/console": "^6.0",
"symfony/finder": "^6.0",
"symfony/process": "^6.0",
"vlucas/phpdotenv": "^5.2"
},
"require-dev": {
"mockery/mockery": "^1.4.2",
"orchestra/testbench": "^7.0",
"phpunit/phpunit": "^9.0"
},
"suggest": {
"ext-pcntl": "Used to gracefully terminate Dusk when tests are running."
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "7.x-dev"
},
"laravel": {
"providers": [
"Laravel\\Dusk\\DuskServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"Laravel\\Dusk\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylor@laravel.com"
}
],
"description": "Laravel Dusk provides simple end-to-end testing and browser automation.",
"keywords": [
"laravel",
"testing",
"webdriver"
],
"support": {
"issues": "https://github.com/laravel/dusk/issues",
"source": "https://github.com/laravel/dusk/tree/v7.1.1"
},
"time": "2022-09-29T09:38:10+00:00"
},
{
"name": "mockery/mockery",
"version": "1.5.1",
@ -9254,6 +9327,71 @@
],
"time": "2022-09-07T20:40:07+00:00"
},
{
"name": "php-webdriver/webdriver",
"version": "1.13.1",
"source": {
"type": "git",
"url": "https://github.com/php-webdriver/php-webdriver.git",
"reference": "6dfe5f814b796c1b5748850aa19f781b9274c36c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-webdriver/php-webdriver/zipball/6dfe5f814b796c1b5748850aa19f781b9274c36c",
"reference": "6dfe5f814b796c1b5748850aa19f781b9274c36c",
"shasum": ""
},
"require": {
"ext-curl": "*",
"ext-json": "*",
"ext-zip": "*",
"php": "^5.6 || ~7.0 || ^8.0",
"symfony/polyfill-mbstring": "^1.12",
"symfony/process": "^2.8 || ^3.1 || ^4.0 || ^5.0 || ^6.0"
},
"replace": {
"facebook/webdriver": "*"
},
"require-dev": {
"ondram/ci-detector": "^2.1 || ^3.5 || ^4.0",
"php-coveralls/php-coveralls": "^2.4",
"php-mock/php-mock-phpunit": "^1.1 || ^2.0",
"php-parallel-lint/php-parallel-lint": "^1.2",
"phpunit/phpunit": "^5.7 || ^7 || ^8 || ^9",
"squizlabs/php_codesniffer": "^3.5",
"symfony/var-dumper": "^3.3 || ^4.0 || ^5.0 || ^6.0"
},
"suggest": {
"ext-SimpleXML": "For Firefox profile creation"
},
"type": "library",
"autoload": {
"files": [
"lib/Exception/TimeoutException.php"
],
"psr-4": {
"Facebook\\WebDriver\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "A PHP client for Selenium WebDriver. Previously facebook/webdriver.",
"homepage": "https://github.com/php-webdriver/php-webdriver",
"keywords": [
"Chromedriver",
"geckodriver",
"php",
"selenium",
"webdriver"
],
"support": {
"issues": "https://github.com/php-webdriver/php-webdriver/issues",
"source": "https://github.com/php-webdriver/php-webdriver/tree/1.13.1"
},
"time": "2022-10-11T11:49:44+00:00"
},
{
"name": "phpdocumentor/reflection-common",
"version": "2.2.0",

View File

@ -18,7 +18,7 @@ return [
* You can enable CORS for 1 or multiple paths.
* Example: ['api/*']
*/
'paths' => ['/api/client', '/api/application', '/api/client/*', '/api/application/*'],
'paths' => ['/api/client', '/api/application', '/api/client/*', '/api/application/*', '/api/servers', '/api/system'],
/*
* Matches the request method. `['*']` allows all methods.

View File

@ -1,5 +1,6 @@
<?php
use Illuminate\Support\Facades\Route;
use Pterodactyl\Http\Controllers\Base;
use Pterodactyl\Http\Middleware\RequireTwoFactorAuthentication;

238
tests/Browser/MainTest.php Normal file
View File

@ -0,0 +1,238 @@
<?php
namespace Pterodactyl\Tests\Browser;
use Laravel\Dusk\Browser;
use Pterodactyl\Models\User;
use Pterodactyl\Models\Server;
use Pterodactyl\Tests\DuskTestCase;
use Illuminate\Support\Facades\Hash;
use Pterodactyl\Tests\Browser\Pages\Login;
use Pterodactyl\Tests\Traits\DatabaseMigrations;
class MainTest extends DuskTestCase
{
use DatabaseMigrations;
/**
* A Dusk test example.
*
* @return void
*/
public function testEverything()
{
$login = 'lance@pterodactyl.io';
$pass = 'password';
// Create Administrator
$user = User::factory()->create([
'email' => $login,
'password' => Hash::make($pass),
'root_admin' => true,
'name_first' => 'Lance',
'name_last' => 'Dactyl',
]);
// Seed initial eggs
$this->artisan('migrate --seed --force');
$this->browse(function (Browser $browser) use ($login, $pass) {
[$panelProtocol, $panelUrl] = explode('://', config('app.url'), 2);
$panelDomain = $panelUrl;
if (str_contains($panelUrl, ':')) {
[$panelDomain, $panelPort] = explode(':', $panelUrl, 2);
}
// Default to HTTP if not specified
$panelPort = intval($panelPort ?? 80);
// For CI, use next port
if ($panelPort !== 80) {
++$panelPort;
}
// Test Failed Login
$browser->visit('/auth/login');
$browser->type('username', $login);
$browser->type('password', 'incorrect');
$browser->click('button[type=submit]');
$browser->waitFor('div[role=alert]', 2);
$browser->assertSeeIn('div[role=alert]>span', 'ERROR');
// Test Successful Login
$browser->type('password', $pass);
$browser->visit(new Login())->loginToPanel($login, $pass);
$browser->assertPathIs('/');
// Test No Servers
$browser->assertMissing('section div>a');
// Click on Admin Dashboard /admin and see no redirect or not denied access
$browser->visit('/admin');
$browser->assertPathIs('/admin');
$browser->assertDontSee('Forbidden');
$browser->assertSee('Admin');
// Create new non administrator user and see success
$browser->visit('/admin/users/new');
$browser->type('email', 'matthew@example.com');
$browser->type('username', 'bird');
$browser->type('name_first', 'Matthew');
$browser->type('name_last', 'Dactyl');
$browser->type('password', 'mypasswordiscooler');
$browser->clickAndWaitForReload('input[type=submit]', 3);
$browser->assertPathIs('/admin/users/view/2');
// Try to create duplicate user and see failure
$browser->visit('/admin/users/new');
$browser->type('email', 'matthew@example.com');
$browser->type('username', 'bird');
$browser->type('name_first', 'First');
$browser->type('name_last', 'Last');
$browser->type('password', 'mypasswordiscool');
$browser->clickAndWaitForReload('input[type=submit]', 3);
$browser->assertSee('There was an error');
$browser->assertPathIs('/admin/users/new');
// Click on Locations in navigation and then click on Create New
$browser->visit('/admin/locations');
$browser->assertSee('Create New');
$browser->click('button[data-target="#newLocationModal"]');
$browser->waitFor('.modal-dialog', 3);
// Create New Location successfully
$browser->type('short', 'us');
$browser->type('long', 'Number one exporter of potassium');
$browser->clickAndWaitForReload('button[type=submit]');
$browser->assertPathIs('/admin/locations/view/1');
// Click on Nodes in navigation and then create a new Node successfully
$browser->visit('/admin/nodes/new');
$browser->type('name', 'noderize');
$browser->type('description', 'my server is the best');
$browser->select('location_id', '1');
$browser->type('fqdn', $panelDomain);
$browser->click('label[for=pSSLFalse]'); // radio http
$browser->type('memory', '1024');
$browser->type('memory_overallocate', '0');
$browser->type('disk', '1024');
$browser->type('disk_overallocate', '0');
$browser->type('daemonListen', $panelPort);
$browser->clickAndWaitForReload('button[type=submit]');
$browser->assertPathIs('/admin/nodes/view/1/allocation');
// Create 3 new dummy allocations successfully in the same Node
$browser->waitForText('Assign New Allocations');
$browser->type('select[name="allocation_ip"] + span.select2 input[type="search"]', '127.0.0.1');
$browser->type('select[name="allocation_ports[]"] + span.select2 input[type="search"]', '1234 ');
$browser->type('select[name="allocation_ports[]"] + span.select2 input[type="search"]', '2345 ');
$browser->type('select[name="allocation_ports[]"] + span.select2 input[type="search"]', '3456');
$browser->clickAndWaitForReload('button[type=submit]');
$browser->assertPathIs('/admin/nodes/view/1/allocation');
$browser->assertSeeIn('table', '1234');
$browser->assertSeeIn('table', '2345');
$browser->assertSeeIn('table', '3456');
// See that the heartbeat is green/success
$browser->visit('/admin/nodes');
$browser->waitFor('table .fa-heartbeat', 5);
// Create New Node successfully
$browser->visit('/admin/nodes/new');
$browser->type('name', 'antinode');
$browser->type('description', 'my server broke :(');
$browser->select('location_id', '1');
$browser->type('fqdn', $panelDomain);
$browser->click('label[for=pSSLFalse]'); // radio http
$browser->type('memory', '1024');
$browser->type('memory_overallocate', '0');
$browser->type('disk', '1024');
$browser->type('disk_overallocate', '0');
$browser->type('daemonListen', '9001');
$browser->clickAndWaitForReload('button[type=submit]');
$browser->assertPathIs('/admin/nodes/view/2/allocation');
// Go back to /admin/nodes and see the heartbeat is red/failing
$browser->visit('/admin/nodes');
$browser->waitFor('table .fa-heart-o', 5);
$servers = [
'names' => ['apple', 'banana', 'cherry'],
'owners' => ['Lance', 'Lance', 'Matthew'],
];
// Create 3 New Servers successfully
for ($i = 0; $i < 3; ++$i) {
// Click on Servers in navigation and then click on Create New
$browser->visit('/admin/servers/new');
$browser->type('name', $servers['names'][$i]);
$browser->click('select[name=owner_id] + .select2');
$browser->waitFor('script + .select2-container input[type=search]');
$browser->type('script + .select2-container input[type=search]', $servers['owners'][$i]);
$browser->waitForTextIn('.username', $servers['owners'][$i], 3);
$browser->click('.user-block');
$browser->type('description', 'Yay a server');
$browser->type('memory', '1024');
$browser->type('disk', '1024');
$browser->clickAndWaitForReload('input[type=submit]');
$browser->assertPathIs('/admin/servers/view/' . ($i + 1));
}
// Exit Admin Panel and see two servers
$browser->visit('/');
$browser->waitForText('SERVERS');
$browser->assertSee('apple');
$browser->assertSee('banana');
$browser->assertDontSee('cherry');
$browser->assertDontSee('There are no other servers to display.');
// Click the toggle and see the final one not owned by the admin
$browser->click('input[name=show_all_servers] + label');
$browser->waitForText('cherry');
$browser->assertSee('cherry');
$browser->assertDontSee('apple');
$browser->assertDontSee('banana');
// Switch back to the owned servers
$browser->click('input[name=show_all_servers] + label');
$browser->waitForText('banana');
/** @var Server $server */
$server = Server::query()->findOrFail(2);
$server->update(['status' => null]);
// Click on the middle server and then click on Users in the navigation
$browser->click("a[href='/server/$server->uuidShort']");
$browser->waitForText('banana');
$browser->click("a[href='/server/$server->uuidShort/users']");
$browser->waitForText("It looks like you don't have any subusers.");
// Click on New User and enter the same email as the non admin user (full permissions)
$browser->click('section button');
$browser->waitForText('Create new subuser');
$browser->click('input[type=checkbox]');
$browser->type('email', 'matthew@example.com');
$browser->assertDontSee('A valid email address must be provided.');
$browser->click('button[type=submit]');
$browser->waitFor('button[aria-label="Edit subuser"]');
$browser->assertSee('matthew@example.com');
// Click on logout and see redirect back to login screen
$browser->clickAndWaitForReload('#logo + div button');
$browser->assertPathIs('/auth/login');
// Login as the non admin user successfully
$browser->type('username', 'matthew@example.com');
$browser->type('password', 'mypasswordiscooler');
$browser->clickAndWaitForReload('button[type=submit]');
$browser->assertPathIs('/');
$browser->waitForText('127.0.0.1');
// See both owned server and unowned
$browser->assertDontSee('apple');
$browser->assertSee('banana');
$browser->assertSee('cherry');
});
}
}

View File

@ -0,0 +1,37 @@
<?php
namespace Pterodactyl\Tests\Browser\Pages;
use Laravel\Dusk\Page;
use Laravel\Dusk\Browser;
class Login extends Page
{
/**
* Get the URL for the page.
*
* @return string
*/
public function url()
{
return '/auth/login';
}
/**
* Assert that the browser is on the page.
*
* @return void
*/
public function assert(Browser $browser)
{
$browser->assertPathIs($this->url());
}
public function loginToPanel(Browser $browser, string $username, string $password)
{
$browser->type('username', $username);
$browser->type('password', $password);
$browser->clickAndWaitForReload('button[type=submit]', 2);
}
}

View File

@ -0,0 +1,20 @@
<?php
namespace Pterodactyl\Tests\Browser\Pages;
use Laravel\Dusk\Page as BasePage;
abstract class Page extends BasePage
{
/**
* Get the global element shortcuts for the site.
*
* @return array
*/
public static function siteElements()
{
return [
'@element' => '#selector',
];
}
}

2
tests/Browser/console/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*
!.gitignore

2
tests/Browser/screenshots/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*
!.gitignore

2
tests/Browser/source/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*
!.gitignore

74
tests/DuskTestCase.php Normal file
View File

@ -0,0 +1,74 @@
<?php
namespace Pterodactyl\Tests;
use Laravel\Dusk\TestCase as BaseTestCase;
use Facebook\WebDriver\Chrome\ChromeOptions;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\Remote\DesiredCapabilities;
abstract class DuskTestCase extends BaseTestCase
{
use CreatesApplication;
/**
* Prepare for Dusk test execution.
*
* @beforeClass
*
* @return void
*/
public static function prepare()
{
if (!static::runningInSail()) {
static::startChromeDriver();
}
}
/**
* Create the RemoteWebDriver instance.
*
* @return \Facebook\WebDriver\Remote\RemoteWebDriver
*/
protected function driver()
{
$options = (new ChromeOptions())->addArguments(collect([
$this->shouldStartMaximized() ? '--start-maximized' : '--window-size=1920,1080',
])->unless($this->hasHeadlessDisabled(), function ($items) {
return $items->merge([
'--disable-gpu',
'--headless',
]);
})->all());
return RemoteWebDriver::create(
$_ENV['DUSK_DRIVER_URL'] ?? 'http://localhost:9515',
DesiredCapabilities::chrome()->setCapability(
ChromeOptions::CAPABILITY,
$options
)
);
}
/**
* Determine whether the Dusk command has disabled headless mode.
*
* @return bool
*/
protected function hasHeadlessDisabled()
{
return isset($_SERVER['DUSK_HEADLESS_DISABLED']) ||
isset($_ENV['DUSK_HEADLESS_DISABLED']);
}
/**
* Determine if the browser window should start maximized.
*
* @return bool
*/
protected function shouldStartMaximized()
{
return isset($_SERVER['DUSK_START_MAXIMIZED']) ||
isset($_ENV['DUSK_START_MAXIMIZED']);
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace Pterodactyl\Tests\Traits;
use Illuminate\Contracts\Console\Kernel;
use Illuminate\Foundation\Testing\DatabaseMigrations as DM;
use Illuminate\Foundation\Testing\Traits\CanConfigureMigrationCommands;
trait DatabaseMigrations
{
use CanConfigureMigrationCommands;
use DM;
/**
* Define hooks to migrate the database before and after each test.
*
* @return void
*/
public function runDatabaseMigrations()
{
$this->artisan('migrate:fresh', $this->migrateFreshUsing());
$this->app[Kernel::class]->setArtisan(null);
}
}