Skip to content

Commit

Permalink
[2.x] Adds support for Pest (#866)
Browse files Browse the repository at this point in the history
* Adds full Pest support using the `--pest` option

* Removes non needed underscores

* Removes non needed underscores

* Adds missing examples

* Moves inertia pest tests to expectation API

* Moves tests to expectation API

* Fixes

* Uses `->skip` method

* Fix

* Removes extra semicolons

* Refactor

* Refactor

* Refactor

* CS

* CS

* Removes non needed underscores

* Wording

Co-authored-by: Nuno Maduro <[email protected]>
  • Loading branch information
lukeraymonddowning and nunomaduro authored Sep 8, 2021
1 parent 589a6f3 commit dd45c1a
Show file tree
Hide file tree
Showing 39 changed files with 1,262 additions and 35 deletions.
101 changes: 66 additions & 35 deletions src/Console/InstallCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class InstallCommand extends Command
*/
protected $signature = 'jetstream:install {stack : The development stack that should be installed}
{--teams : Indicates if team support should be installed}
{--pest : Indicates if Pest should be installed}
{--composer=global : Absolute path to the Composer binary which should be used to install packages}';

/**
Expand Down Expand Up @@ -70,11 +71,21 @@ public function handle()
}

// Tests...
copy(__DIR__.'/../../stubs/tests/AuthenticationTest.php', base_path('tests/Feature/AuthenticationTest.php'));
copy(__DIR__.'/../../stubs/tests/EmailVerificationTest.php', base_path('tests/Feature/EmailVerificationTest.php'));
copy(__DIR__.'/../../stubs/tests/PasswordConfirmationTest.php', base_path('tests/Feature/PasswordConfirmationTest.php'));
copy(__DIR__.'/../../stubs/tests/PasswordResetTest.php', base_path('tests/Feature/PasswordResetTest.php'));
copy(__DIR__.'/../../stubs/tests/RegistrationTest.php', base_path('tests/Feature/RegistrationTest.php'));
$stubs = $this->getTestStubsPath();

if ($this->option('pest')) {
$this->requireComposerPackages('pestphp/pest:^1.16', 'pestphp/pest-plugin-laravel:^1.1');

copy($stubs.'/Pest.php', base_path('tests/Pest.php'));
copy($stubs.'/ExampleTest.php', base_path('tests/Feature/ExampleTest.php'));
copy($stubs.'/ExampleUnitTest.php', base_path('tests/Unit/ExampleTest.php'));
}

copy($stubs.'/AuthenticationTest.php', base_path('tests/Feature/AuthenticationTest.php'));
copy($stubs.'/EmailVerificationTest.php', base_path('tests/Feature/EmailVerificationTest.php'));
copy($stubs.'/PasswordConfirmationTest.php', base_path('tests/Feature/PasswordConfirmationTest.php'));
copy($stubs.'/PasswordResetTest.php', base_path('tests/Feature/PasswordResetTest.php'));
copy($stubs.'/RegistrationTest.php', base_path('tests/Feature/RegistrationTest.php'));
}

/**
Expand Down Expand Up @@ -197,14 +208,16 @@ protected function installLivewireStack()
copy(__DIR__.'/../../stubs/livewire/resources/js/app.js', resource_path('js/app.js'));

// Tests...
copy(__DIR__.'/../../stubs/tests/livewire/ApiTokenPermissionsTest.php', base_path('tests/Feature/ApiTokenPermissionsTest.php'));
copy(__DIR__.'/../../stubs/tests/livewire/BrowserSessionsTest.php', base_path('tests/Feature/BrowserSessionsTest.php'));
copy(__DIR__.'/../../stubs/tests/livewire/CreateApiTokenTest.php', base_path('tests/Feature/CreateApiTokenTest.php'));
copy(__DIR__.'/../../stubs/tests/livewire/DeleteAccountTest.php', base_path('tests/Feature/DeleteAccountTest.php'));
copy(__DIR__.'/../../stubs/tests/livewire/DeleteApiTokenTest.php', base_path('tests/Feature/DeleteApiTokenTest.php'));
copy(__DIR__.'/../../stubs/tests/livewire/ProfileInformationTest.php', base_path('tests/Feature/ProfileInformationTest.php'));
copy(__DIR__.'/../../stubs/tests/livewire/TwoFactorAuthenticationSettingsTest.php', base_path('tests/Feature/TwoFactorAuthenticationSettingsTest.php'));
copy(__DIR__.'/../../stubs/tests/livewire/UpdatePasswordTest.php', base_path('tests/Feature/UpdatePasswordTest.php'));
$stubs = $this->getTestStubsPath();

copy($stubs.'/livewire/ApiTokenPermissionsTest.php', base_path('tests/Feature/ApiTokenPermissionsTest.php'));
copy($stubs.'/livewire/BrowserSessionsTest.php', base_path('tests/Feature/BrowserSessionsTest.php'));
copy($stubs.'/livewire/CreateApiTokenTest.php', base_path('tests/Feature/CreateApiTokenTest.php'));
copy($stubs.'/livewire/DeleteAccountTest.php', base_path('tests/Feature/DeleteAccountTest.php'));
copy($stubs.'/livewire/DeleteApiTokenTest.php', base_path('tests/Feature/DeleteApiTokenTest.php'));
copy($stubs.'/livewire/ProfileInformationTest.php', base_path('tests/Feature/ProfileInformationTest.php'));
copy($stubs.'/livewire/TwoFactorAuthenticationSettingsTest.php', base_path('tests/Feature/TwoFactorAuthenticationSettingsTest.php'));
copy($stubs.'/livewire/UpdatePasswordTest.php', base_path('tests/Feature/UpdatePasswordTest.php'));

// Teams...
if ($this->option('teams')) {
Expand All @@ -230,13 +243,15 @@ protected function installLivewireTeamStack()
(new Filesystem)->copyDirectory(__DIR__.'/../../stubs/livewire/resources/views/teams', resource_path('views/teams'));

// Tests...
copy(__DIR__.'/../../stubs/tests/livewire/CreateTeamTest.php', base_path('tests/Feature/CreateTeamTest.php'));
copy(__DIR__.'/../../stubs/tests/livewire/DeleteTeamTest.php', base_path('tests/Feature/DeleteTeamTest.php'));
copy(__DIR__.'/../../stubs/tests/livewire/InviteTeamMemberTest.php', base_path('tests/Feature/InviteTeamMemberTest.php'));
copy(__DIR__.'/../../stubs/tests/livewire/LeaveTeamTest.php', base_path('tests/Feature/LeaveTeamTest.php'));
copy(__DIR__.'/../../stubs/tests/livewire/RemoveTeamMemberTest.php', base_path('tests/Feature/RemoveTeamMemberTest.php'));
copy(__DIR__.'/../../stubs/tests/livewire/UpdateTeamMemberRoleTest.php', base_path('tests/Feature/UpdateTeamMemberRoleTest.php'));
copy(__DIR__.'/../../stubs/tests/livewire/UpdateTeamNameTest.php', base_path('tests/Feature/UpdateTeamNameTest.php'));
$stubs = $this->getTestStubsPath();

copy($stubs.'/livewire/CreateTeamTest.php', base_path('tests/Feature/CreateTeamTest.php'));
copy($stubs.'/livewire/DeleteTeamTest.php', base_path('tests/Feature/DeleteTeamTest.php'));
copy($stubs.'/livewire/InviteTeamMemberTest.php', base_path('tests/Feature/InviteTeamMemberTest.php'));
copy($stubs.'/livewire/LeaveTeamTest.php', base_path('tests/Feature/LeaveTeamTest.php'));
copy($stubs.'/livewire/RemoveTeamMemberTest.php', base_path('tests/Feature/RemoveTeamMemberTest.php'));
copy($stubs.'/livewire/UpdateTeamMemberRoleTest.php', base_path('tests/Feature/UpdateTeamMemberRoleTest.php'));
copy($stubs.'/livewire/UpdateTeamNameTest.php', base_path('tests/Feature/UpdateTeamNameTest.php'));

$this->ensureApplicationIsTeamCompatible();
}
Expand Down Expand Up @@ -373,14 +388,16 @@ protected function installInertiaStack()
// static::flushNodeModules();

// Tests...
copy(__DIR__.'/../../stubs/tests/inertia/ApiTokenPermissionsTest.php', base_path('tests/Feature/ApiTokenPermissionsTest.php'));
copy(__DIR__.'/../../stubs/tests/inertia/BrowserSessionsTest.php', base_path('tests/Feature/BrowserSessionsTest.php'));
copy(__DIR__.'/../../stubs/tests/inertia/CreateApiTokenTest.php', base_path('tests/Feature/CreateApiTokenTest.php'));
copy(__DIR__.'/../../stubs/tests/inertia/DeleteAccountTest.php', base_path('tests/Feature/DeleteAccountTest.php'));
copy(__DIR__.'/../../stubs/tests/inertia/DeleteApiTokenTest.php', base_path('tests/Feature/DeleteApiTokenTest.php'));
copy(__DIR__.'/../../stubs/tests/inertia/ProfileInformationTest.php', base_path('tests/Feature/ProfileInformationTest.php'));
copy(__DIR__.'/../../stubs/tests/inertia/TwoFactorAuthenticationSettingsTest.php', base_path('tests/Feature/TwoFactorAuthenticationSettingsTest.php'));
copy(__DIR__.'/../../stubs/tests/inertia/UpdatePasswordTest.php', base_path('tests/Feature/UpdatePasswordTest.php'));
$stubs = $this->getTestStubsPath();

copy($stubs.'/inertia/ApiTokenPermissionsTest.php', base_path('tests/Feature/ApiTokenPermissionsTest.php'));
copy($stubs.'/inertia/BrowserSessionsTest.php', base_path('tests/Feature/BrowserSessionsTest.php'));
copy($stubs.'/inertia/CreateApiTokenTest.php', base_path('tests/Feature/CreateApiTokenTest.php'));
copy($stubs.'/inertia/DeleteAccountTest.php', base_path('tests/Feature/DeleteAccountTest.php'));
copy($stubs.'/inertia/DeleteApiTokenTest.php', base_path('tests/Feature/DeleteApiTokenTest.php'));
copy($stubs.'/inertia/ProfileInformationTest.php', base_path('tests/Feature/ProfileInformationTest.php'));
copy($stubs.'/inertia/TwoFactorAuthenticationSettingsTest.php', base_path('tests/Feature/TwoFactorAuthenticationSettingsTest.php'));
copy($stubs.'/inertia/UpdatePasswordTest.php', base_path('tests/Feature/UpdatePasswordTest.php'));

// Teams...
if ($this->option('teams')) {
Expand All @@ -406,13 +423,15 @@ protected function installInertiaTeamStack()
(new Filesystem)->copyDirectory(__DIR__.'/../../stubs/inertia/resources/js/Pages/Teams', resource_path('js/Pages/Teams'));

// Tests...
copy(__DIR__.'/../../stubs/tests/inertia/CreateTeamTest.php', base_path('tests/Feature/CreateTeamTest.php'));
copy(__DIR__.'/../../stubs/tests/inertia/DeleteTeamTest.php', base_path('tests/Feature/DeleteTeamTest.php'));
copy(__DIR__.'/../../stubs/tests/inertia/InviteTeamMemberTest.php', base_path('tests/Feature/InviteTeamMemberTest.php'));
copy(__DIR__.'/../../stubs/tests/inertia/LeaveTeamTest.php', base_path('tests/Feature/LeaveTeamTest.php'));
copy(__DIR__.'/../../stubs/tests/inertia/RemoveTeamMemberTest.php', base_path('tests/Feature/RemoveTeamMemberTest.php'));
copy(__DIR__.'/../../stubs/tests/inertia/UpdateTeamMemberRoleTest.php', base_path('tests/Feature/UpdateTeamMemberRoleTest.php'));
copy(__DIR__.'/../../stubs/tests/inertia/UpdateTeamNameTest.php', base_path('tests/Feature/UpdateTeamNameTest.php'));
$stubs = $this->getTestStubsPath();

copy($stubs.'/inertia/CreateTeamTest.php', base_path('tests/Feature/CreateTeamTest.php'));
copy($stubs.'/inertia/DeleteTeamTest.php', base_path('tests/Feature/DeleteTeamTest.php'));
copy($stubs.'/inertia/InviteTeamMemberTest.php', base_path('tests/Feature/InviteTeamMemberTest.php'));
copy($stubs.'/inertia/LeaveTeamTest.php', base_path('tests/Feature/LeaveTeamTest.php'));
copy($stubs.'/inertia/RemoveTeamMemberTest.php', base_path('tests/Feature/RemoveTeamMemberTest.php'));
copy($stubs.'/inertia/UpdateTeamMemberRoleTest.php', base_path('tests/Feature/UpdateTeamMemberRoleTest.php'));
copy($stubs.'/inertia/UpdateTeamNameTest.php', base_path('tests/Feature/UpdateTeamNameTest.php'));

$this->ensureApplicationIsTeamCompatible();
}
Expand Down Expand Up @@ -512,6 +531,18 @@ protected function installMiddlewareAfter($after, $name, $group = 'web')
}
}

/**
* Returns the path to the correct test stubs.
*
* @return string
*/
protected function getTestStubsPath()
{
return $this->option('pest')
? __DIR__.'/../../stubs/pest-tests'
: __DIR__.'/../../stubs/tests';
}

/**
* Installs the given Composer Packages into the application.
*
Expand Down
33 changes: 33 additions & 0 deletions stubs/pest-tests/AuthenticationTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

use App\Models\User;
use App\Providers\RouteServiceProvider;

test('login screen can be rendered', function () {
$response = $this->get('/login');

$response->assertStatus(200);
});

test('users can authenticate using the login screen', function () {
$user = User::factory()->create();

$response = $this->post('/login', [
'email' => $user->email,
'password' => 'password',
]);

$this->assertAuthenticated();
$response->assertRedirect(RouteServiceProvider::HOME);
});

test('users can not authenticate with invalid_password', function () {
$user = User::factory()->create();

$this->post('/login', [
'email' => $user->email,
'password' => 'wrong-password',
]);

$this->assertGuest();
});
61 changes: 61 additions & 0 deletions stubs/pest-tests/EmailVerificationTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

use App\Models\User;
use App\Providers\RouteServiceProvider;
use Illuminate\Auth\Events\Verified;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\URL;
use Laravel\Fortify\Features;

test('email verification screen can be rendered', function () {
$user = User::factory()->withPersonalTeam()->create([
'email_verified_at' => null,
]);

$response = $this->actingAs($user)->get('/email/verify');

$response->assertStatus(200);
})->skip(function () {
return ! Features::enabled(Features::emailVerification());
}, 'Email verification not enabled.');

test('email can be verified', function () {
Event::fake();

$user = User::factory()->create([
'email_verified_at' => null,
]);

$verificationUrl = URL::temporarySignedRoute(
'verification.verify',
now()->addMinutes(60),
['id' => $user->id, 'hash' => sha1($user->email)]
);

$response = $this->actingAs($user)->get($verificationUrl);

Event::assertDispatched(Verified::class);

expect($user->fresh()->hasVerifiedEmail())->toBeTrue();
$response->assertRedirect(RouteServiceProvider::HOME.'?verified=1');
})->skip(function () {
return ! Features::enabled(Features::emailVerification());
}, 'Email verification not enabled.');

test('email can not verified with invalid hash', function () {
$user = User::factory()->create([
'email_verified_at' => null,
]);

$verificationUrl = URL::temporarySignedRoute(
'verification.verify',
now()->addMinutes(60),
['id' => $user->id, 'hash' => sha1('wrong-email')]
);

$this->actingAs($user)->get($verificationUrl);

expect($user->fresh()->hasVerifiedEmail())->toBeFalse();
})->skip(function () {
return ! Features::enabled(Features::emailVerification());
}, 'Email verification not enabled.');
7 changes: 7 additions & 0 deletions stubs/pest-tests/ExampleTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

test('example', function () {
$response = $this->get('/');

$response->assertStatus(200);
});
5 changes: 5 additions & 0 deletions stubs/pest-tests/ExampleUnitTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php

test('example', function () {
expect(true)->toBeTrue();
});
35 changes: 35 additions & 0 deletions stubs/pest-tests/PasswordConfirmationTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

use App\Models\User;
use Laravel\Jetstream\Features;

test('confirm password screen can be rendered', function () {
$user = Features::hasTeamFeatures()
? User::factory()->withPersonalTeam()->create()
: User::factory()->create();

$response = $this->actingAs($user)->get('/user/confirm-password');

$response->assertStatus(200);
});

test('password can be confirmed', function () {
$user = User::factory()->create();

$response = $this->actingAs($user)->post('/user/confirm-password', [
'password' => 'password',
]);

$response->assertRedirect();
$response->assertSessionHasNoErrors();
});

test('password is not confirmed with invalid password', function () {
$user = User::factory()->create();

$response = $this->actingAs($user)->post('/user/confirm-password', [
'password' => 'wrong-password',
]);

$response->assertSessionHasErrors();
});
73 changes: 73 additions & 0 deletions stubs/pest-tests/PasswordResetTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?php

use App\Models\User;
use Illuminate\Auth\Notifications\ResetPassword;
use Illuminate\Support\Facades\Notification;
use Laravel\Fortify\Features;

test('reset password link screen can be rendered', function () {
$response = $this->get('/forgot-password');

$response->assertStatus(200);
})->skip(function () {
return ! Features::enabled(Features::updatePasswords());
}, 'Password updates are not enabled.');

test('reset password link can be requested', function () {
Notification::fake();

$user = User::factory()->create();

$response = $this->post('/forgot-password', [
'email' => $user->email,
]);

Notification::assertSentTo($user, ResetPassword::class);
})->skip(function () {
return ! Features::enabled(Features::updatePasswords());
}, 'Password updates are not enabled.');

test('reset password screen can be rendered', function () {
Notification::fake();

$user = User::factory()->create();

$response = $this->post('/forgot-password', [
'email' => $user->email,
]);

Notification::assertSentTo($user, ResetPassword::class, function ($notification) {
$response = $this->get('/reset-password/'.$notification->token);

$response->assertStatus(200);

return true;
});
})->skip(function () {
return ! Features::enabled(Features::updatePasswords());
}, 'Password updates are not enabled.');

test('password can be reset with valid token', function () {
Notification::fake();

$user = User::factory()->create();

$response = $this->post('/forgot-password', [
'email' => $user->email,
]);

Notification::assertSentTo($user, ResetPassword::class, function ($notification) use ($user) {
$response = $this->post('/reset-password', [
'token' => $notification->token,
'email' => $user->email,
'password' => 'password',
'password_confirmation' => 'password',
]);

$response->assertSessionHasNoErrors();

return true;
});
})->skip(function () {
return ! Features::enabled(Features::updatePasswords());
}, 'Password updates are not enabled.');
Loading

0 comments on commit dd45c1a

Please sign in to comment.