Compare commits
54 Commits
release/v1
...
dusk
Author | SHA1 | Date |
---|---|---|
Lance Pioch | abadcd2272 | |
Lance Pioch | da26f73735 | |
Lance Pioch | 5ce5f2fea3 | |
Lance Pioch | 381c777834 | |
Lance Pioch | ff73db3829 | |
Lance Pioch | bc6768fd76 | |
Lance Pioch | 780f6f3ed7 | |
Lance Pioch | eb11ef5729 | |
Lance Pioch | ce0d6b9634 | |
Lance Pioch | aa0b93e16b | |
Lance Pioch | 9592ba6cc4 | |
Lance Pioch | 6b2ccf8dc2 | |
Lance Pioch | 664ef911e3 | |
Lance Pioch | eb139224e2 | |
Lance Pioch | 408ca6e994 | |
Lance Pioch | e4b48c5b79 | |
Lance Pioch | 76af3dc5f5 | |
Lance Pioch | 5692dca579 | |
Lance Pioch | f112fec457 | |
Lance Pioch | f25fe6ddd6 | |
Lance Pioch | 82d608dd87 | |
Lance Pioch | 9b09a67dc4 | |
Lance Pioch | f791aec7dc | |
Lance Pioch | 2865ca5aec | |
Lance Pioch | e7a0a2ea7e | |
Lance Pioch | d781a7f459 | |
Lance Pioch | 9fbc35eb58 | |
Lance Pioch | a149e7001c | |
Lance Pioch | ac5f8f80bc | |
Lance Pioch | cd764b6d6f | |
Lance Pioch | f4312f5b21 | |
Lance Pioch | 93162ebfee | |
Lance Pioch | d632fa97de | |
Lance Pioch | 1d2a20d831 | |
Lance Pioch | 68b1f1ec27 | |
Lance Pioch | 56ae6c9765 | |
Lance Pioch | edda6f80b0 | |
Lance Pioch | b8f50e5162 | |
Lance Pioch | 126c06a929 | |
Lance Pioch | a45d054b48 | |
Lance Pioch | 426c1cea66 | |
Lance Pioch | f7ed8af52a | |
Lance Pioch | d59cf5294e | |
Lance Pioch | 060335043b | |
Lance Pioch | 3a772cb2ca | |
Lance Pioch | a502acab96 | |
Lance Pioch | 1810d6214d | |
Lance Pioch | 8ee7652aad | |
Lance Pioch | cdf365ad8c | |
Lance Pioch | 7db6665817 | |
Lance Pioch | 553c4f6b09 | |
Lance Pioch | 660c85aa97 | |
Lance Pioch | f38f8db445 | |
Lance Pioch | a7e2bd2866 |
|
@ -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
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 () => []);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Pterodactyl\Http\Controllers\Base;
|
||||
use Pterodactyl\Http\Middleware\RequireTwoFactorAuthentication;
|
||||
|
||||
|
|
|
@ -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');
|
||||
});
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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',
|
||||
];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
*
|
||||
!.gitignore
|
|
@ -0,0 +1,2 @@
|
|||
*
|
||||
!.gitignore
|
|
@ -0,0 +1,2 @@
|
|||
*
|
||||
!.gitignore
|
|
@ -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']);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue