Changeset View
Changeset View
Standalone View
Standalone View
src/tests/Browser/SignupTest.php
<?php | <?php | ||||
namespace Tests\Browser; | namespace Tests\Browser; | ||||
use App\Discount; | |||||
use App\Domain; | use App\Domain; | ||||
use App\SignupCode; | use App\SignupCode; | ||||
use App\User; | use App\User; | ||||
use Tests\Browser; | use Tests\Browser; | ||||
use Tests\Browser\Components\Menu; | use Tests\Browser\Components\Menu; | ||||
use Tests\Browser\Components\Toast; | use Tests\Browser\Components\Toast; | ||||
use Tests\Browser\Pages\Dashboard; | use Tests\Browser\Pages\Dashboard; | ||||
use Tests\Browser\Pages\Signup; | use Tests\Browser\Pages\Signup; | ||||
▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | public function testSignupCodeByLink(): void | ||||
// Test invalid code (valid format) | // Test invalid code (valid format) | ||||
$this->browse(function (Browser $browser) { | $this->browse(function (Browser $browser) { | ||||
$browser->visit('/signup/XXXXX-code'); | $browser->visit('/signup/XXXXX-code'); | ||||
// FIXME: User will not be able to continue anyway, so we should | // FIXME: User will not be able to continue anyway, so we should | ||||
// either display 1st step or 404 error page | // either display 1st step or 404 error page | ||||
$browser->waitFor('@step1') | $browser->waitFor('@step1') | ||||
->with(new Toast(Toast::TYPE_ERROR), function (Browser $browser) { | ->assertToast(Toast::TYPE_ERROR, 'Error', 'Form validation error'); | ||||
$browser->assertToastTitle('Error') | |||||
->assertToastMessage('Form validation error') | |||||
->closeToast(); | |||||
}); | |||||
}); | }); | ||||
// Test valid code | // Test valid code | ||||
$this->browse(function (Browser $browser) { | $this->browse(function (Browser $browser) { | ||||
$code = SignupCode::create([ | $code = SignupCode::create([ | ||||
'data' => [ | 'data' => [ | ||||
'email' => 'User@example.org', | 'email' => 'User@example.org', | ||||
'name' => 'User Name', | 'name' => 'User Name', | ||||
'plan' => 'individual', | 'plan' => 'individual', | ||||
'voucher' => '', | |||||
] | ] | ||||
]); | ]); | ||||
$browser->visit('/signup/' . $code->short_code . '-' . $code->code); | $browser->visit('/signup/' . $code->short_code . '-' . $code->code) | ||||
->waitFor('@step3') | |||||
$browser->waitFor('@step3'); | ->assertMissing('@step1') | ||||
$browser->assertMissing('@step1'); | ->assertMissing('@step2'); | ||||
$browser->assertMissing('@step2'); | |||||
// FIXME: Find a nice way to read javascript data without using hidden inputs | // FIXME: Find a nice way to read javascript data without using hidden inputs | ||||
$this->assertSame($code->code, $browser->value('@step2 #signup_code')); | $this->assertSame($code->code, $browser->value('@step2 #signup_code')); | ||||
// TODO: Test if the signup process can be completed | // TODO: Test if the signup process can be completed | ||||
}); | }); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 87 Lines • ▼ Show 20 Lines | public function testSignupStep1(): void | ||||
// Submit invalid email | // Submit invalid email | ||||
// We expect email input to have is-invalid class added, with .invalid-feedback element | // We expect email input to have is-invalid class added, with .invalid-feedback element | ||||
$browser->with('@step1', function ($step) use ($browser) { | $browser->with('@step1', function ($step) use ($browser) { | ||||
$step->type('#signup_name', 'Test User') | $step->type('#signup_name', 'Test User') | ||||
->type('#signup_email', '@test') | ->type('#signup_email', '@test') | ||||
->click('[type=submit]') | ->click('[type=submit]') | ||||
->waitFor('#signup_email.is-invalid') | ->waitFor('#signup_email.is-invalid') | ||||
->assertVisible('#signup_email + .invalid-feedback'); | ->assertVisible('#signup_email + .invalid-feedback') | ||||
->assertToast(Toast::TYPE_ERROR, 'Error', 'Form validation error'); | |||||
$browser->with(new Toast(Toast::TYPE_ERROR), function (Browser $browser) { | |||||
$browser->assertToastTitle('Error') | |||||
->assertToastMessage('Form validation error') | |||||
->closeToast(); | |||||
}); | |||||
}); | }); | ||||
// Submit valid data | // Submit valid data | ||||
// We expect error state on email input to be removed, and Step 2 form visible | // We expect error state on email input to be removed, and Step 2 form visible | ||||
$browser->with('@step1', function ($step) { | $browser->with('@step1', function ($step) { | ||||
$step->type('#signup_name', 'Test User'); | $step->type('#signup_name', 'Test User'); | ||||
$step->type('#signup_email', 'BrowserSignupTestUser1@kolab.org'); | $step->type('#signup_email', 'BrowserSignupTestUser1@kolab.org'); | ||||
$step->click('[type=submit]'); | $step->click('[type=submit]'); | ||||
▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | public function testSignupStep2(): void | ||||
// Submit invalid code | // Submit invalid code | ||||
// We expect code input to have is-invalid class added, with .invalid-feedback element | // We expect code input to have is-invalid class added, with .invalid-feedback element | ||||
$browser->with('@step2', function ($step) use ($browser) { | $browser->with('@step2', function ($step) use ($browser) { | ||||
$step->type('#signup_short_code', 'XXXXX'); | $step->type('#signup_short_code', 'XXXXX'); | ||||
$step->click('[type=submit]'); | $step->click('[type=submit]'); | ||||
$step->waitFor('#signup_short_code.is-invalid') | $step->waitFor('#signup_short_code.is-invalid') | ||||
->assertVisible('#signup_short_code + .invalid-feedback') | ->assertVisible('#signup_short_code + .invalid-feedback') | ||||
->assertFocused('#signup_short_code'); | ->assertFocused('#signup_short_code') | ||||
->assertToast(Toast::TYPE_ERROR, 'Error', 'Form validation error'); | |||||
$browser->with(new Toast(Toast::TYPE_ERROR), function (Browser $browser) { | |||||
$browser->assertToastTitle('Error') | |||||
->assertToastMessage('Form validation error') | |||||
->closeToast(); | |||||
}); | |||||
}); | }); | ||||
// Submit valid code | // Submit valid code | ||||
// We expect error state on code input to be removed, and Step 3 form visible | // We expect error state on code input to be removed, and Step 3 form visible | ||||
$browser->with('@step2', function ($step) { | $browser->with('@step2', function ($step) { | ||||
// Get the code and short_code from database | // Get the code and short_code from database | ||||
// FIXME: Find a nice way to read javascript data without using hidden inputs | // FIXME: Find a nice way to read javascript data without using hidden inputs | ||||
$code = $step->value('#signup_code'); | $code = $step->value('#signup_code'); | ||||
▲ Show 20 Lines • Show All 69 Lines • ▼ Show 20 Lines | public function testSignupStep3(): void | ||||
->type('#signup_login', '*') | ->type('#signup_login', '*') | ||||
->type('#signup_password', '12345678') | ->type('#signup_password', '12345678') | ||||
->type('#signup_confirm', '123456789') | ->type('#signup_confirm', '123456789') | ||||
->click('[type=submit]') | ->click('[type=submit]') | ||||
->waitFor('#signup_login.is-invalid') | ->waitFor('#signup_login.is-invalid') | ||||
->assertVisible('#signup_domain + .invalid-feedback') | ->assertVisible('#signup_domain + .invalid-feedback') | ||||
->assertVisible('#signup_password.is-invalid') | ->assertVisible('#signup_password.is-invalid') | ||||
->assertVisible('#signup_password + .invalid-feedback') | ->assertVisible('#signup_password + .invalid-feedback') | ||||
->assertFocused('#signup_login'); | ->assertFocused('#signup_login') | ||||
->assertToast(Toast::TYPE_ERROR, 'Error', 'Form validation error'); | |||||
$browser->with(new Toast(Toast::TYPE_ERROR), function (Browser $browser) { | |||||
$browser->assertToastTitle('Error') | |||||
->assertToastMessage('Form validation error') | |||||
->closeToast(); | |||||
}); | |||||
}); | }); | ||||
// Submit invalid data (valid login, invalid password) | // Submit invalid data (valid login, invalid password) | ||||
$browser->with('@step3', function ($step) use ($browser) { | $browser->with('@step3', function ($step) use ($browser) { | ||||
$step->type('#signup_login', 'SignupTestDusk') | $step->type('#signup_login', 'SignupTestDusk') | ||||
->click('[type=submit]') | ->click('[type=submit]') | ||||
->waitFor('#signup_password.is-invalid') | ->waitFor('#signup_password.is-invalid') | ||||
->assertVisible('#signup_password + .invalid-feedback') | ->assertVisible('#signup_password + .invalid-feedback') | ||||
->assertMissing('#signup_login.is-invalid') | ->assertMissing('#signup_login.is-invalid') | ||||
->assertMissing('#signup_domain + .invalid-feedback') | ->assertMissing('#signup_domain + .invalid-feedback') | ||||
->assertFocused('#signup_password'); | ->assertFocused('#signup_password') | ||||
->assertToast(Toast::TYPE_ERROR, 'Error', 'Form validation error'); | |||||
$browser->with(new Toast(Toast::TYPE_ERROR), function (Browser $browser) { | |||||
$browser->assertToastTitle('Error') | |||||
->assertToastMessage('Form validation error') | |||||
->closeToast(); | |||||
}); | |||||
}); | }); | ||||
// Submit valid data | // Submit valid data | ||||
$browser->with('@step3', function ($step) { | $browser->with('@step3', function ($step) { | ||||
$step->type('#signup_confirm', '12345678'); | $step->type('#signup_confirm', '12345678'); | ||||
$step->click('[type=submit]'); | $step->click('[type=submit]'); | ||||
}); | }); | ||||
▲ Show 20 Lines • Show All 62 Lines • ▼ Show 20 Lines | public function testSignupGroup(): void | ||||
->type('#signup_domain', 'test.com') | ->type('#signup_domain', 'test.com') | ||||
->type('#signup_password', '12345678') | ->type('#signup_password', '12345678') | ||||
->type('#signup_confirm', '123456789') | ->type('#signup_confirm', '123456789') | ||||
->click('[type=submit]') | ->click('[type=submit]') | ||||
->waitFor('#signup_login.is-invalid') | ->waitFor('#signup_login.is-invalid') | ||||
->assertVisible('#signup_domain + .invalid-feedback') | ->assertVisible('#signup_domain + .invalid-feedback') | ||||
->assertVisible('#signup_password.is-invalid') | ->assertVisible('#signup_password.is-invalid') | ||||
->assertVisible('#signup_password + .invalid-feedback') | ->assertVisible('#signup_password + .invalid-feedback') | ||||
->assertFocused('#signup_login'); | ->assertFocused('#signup_login') | ||||
->assertToast(Toast::TYPE_ERROR, 'Error', 'Form validation error'); | |||||
$browser->with(new Toast(Toast::TYPE_ERROR), function (Browser $browser) { | |||||
$browser->assertToastTitle('Error') | |||||
->assertToastMessage('Form validation error') | |||||
->closeToast(); | |||||
}); | |||||
}); | }); | ||||
// Submit invalid domain | // Submit invalid domain | ||||
$browser->with('@step3', function ($step) use ($browser) { | $browser->with('@step3', function ($step) use ($browser) { | ||||
$step->type('#signup_login', 'admin') | $step->type('#signup_login', 'admin') | ||||
->type('#signup_domain', 'aaa') | ->type('#signup_domain', 'aaa') | ||||
->type('#signup_password', '12345678') | ->type('#signup_password', '12345678') | ||||
->type('#signup_confirm', '12345678') | ->type('#signup_confirm', '12345678') | ||||
->click('[type=submit]') | ->click('[type=submit]') | ||||
->waitUntilMissing('#signup_login.is-invalid') | ->waitUntilMissing('#signup_login.is-invalid') | ||||
->assertVisible('#signup_domain.is-invalid + .invalid-feedback') | ->assertVisible('#signup_domain.is-invalid + .invalid-feedback') | ||||
->assertMissing('#signup_password.is-invalid') | ->assertMissing('#signup_password.is-invalid') | ||||
->assertMissing('#signup_password + .invalid-feedback') | ->assertMissing('#signup_password + .invalid-feedback') | ||||
->assertFocused('#signup_domain'); | ->assertFocused('#signup_domain') | ||||
->assertToast(Toast::TYPE_ERROR, 'Error', 'Form validation error'); | |||||
$browser->with(new Toast(Toast::TYPE_ERROR), function (Browser $browser) { | |||||
$browser->assertToastTitle('Error') | |||||
->assertToastMessage('Form validation error') | |||||
->closeToast(); | |||||
}); | |||||
}); | }); | ||||
// Submit invalid domain | // Submit invalid domain | ||||
$browser->with('@step3', function ($step) { | $browser->with('@step3', function ($step) { | ||||
$step->type('#signup_domain', 'user-domain-signup.com') | $step->type('#signup_domain', 'user-domain-signup.com') | ||||
->click('[type=submit]'); | ->click('[type=submit]'); | ||||
}); | }); | ||||
// At this point we should be auto-logged-in to dashboard | // At this point we should be auto-logged-in to dashboard | ||||
$browser->waitUntilMissing('@step3') | $browser->waitUntilMissing('@step3') | ||||
->waitUntilMissing('.app-loader') | ->waitUntilMissing('.app-loader') | ||||
->on(new Dashboard()) | ->on(new Dashboard()) | ||||
->assertUser('admin@user-domain-signup.com'); | ->assertUser('admin@user-domain-signup.com'); | ||||
$browser->click('a.link-logout'); | $browser->click('a.link-logout'); | ||||
}); | }); | ||||
} | } | ||||
/** | |||||
* Test signup with voucher | |||||
*/ | |||||
public function testSignupVoucherLink(): void | |||||
{ | |||||
$this->browse(function (Browser $browser) { | |||||
$browser->visit('/signup/voucher/TEST') | |||||
->onWithoutAssert(new Signup()) | |||||
->waitFor('@step0') | |||||
->click('.plan-individual button') | |||||
->whenAvailable('@step1', function (Browser $browser) { | |||||
$browser->type('#signup_name', 'Test User') | |||||
->type('#signup_email', 'BrowserSignupTestUser1@kolab.org') | |||||
->click('[type=submit]'); | |||||
}) | |||||
->whenAvailable('@step2', function (Browser $browser) { | |||||
// Get the code and short_code from database | |||||
// FIXME: Find a nice way to read javascript data without using hidden inputs | |||||
$code = $browser->value('#signup_code'); | |||||
$this->assertNotEmpty($code); | |||||
$code = SignupCode::find($code); | |||||
$browser->type('#signup_short_code', $code->short_code) | |||||
->click('[type=submit]'); | |||||
}) | |||||
->whenAvailable('@step3', function (Browser $browser) { | |||||
// Assert that the code is filled in the input | |||||
// Change it and test error handling | |||||
$browser->assertValue('#signup_voucher', 'TEST') | |||||
->type('#signup_voucher', 'TESTXX') | |||||
->type('#signup_login', 'signuptestdusk') | |||||
->type('#signup_password', '123456789') | |||||
->type('#signup_confirm', '123456789') | |||||
->click('[type=submit]') | |||||
->waitFor('#signup_voucher.is-invalid') | |||||
->assertVisible('#signup_voucher + .invalid-feedback') | |||||
->assertFocused('#signup_voucher') | |||||
->assertToast(Toast::TYPE_ERROR, 'Error', 'Form validation error') | |||||
// Submit the correct code | |||||
->type('#signup_voucher', 'TEST') | |||||
->click('[type=submit]'); | |||||
}) | |||||
->waitUntilMissing('@step3') | |||||
->waitUntilMissing('.app-loader') | |||||
->on(new Dashboard()) | |||||
->assertUser('signuptestdusk@' . \config('app.domain')) | |||||
// Logout the user | |||||
->click('a.link-logout'); | |||||
}); | |||||
$user = $this->getTestUser('signuptestdusk@' . \config('app.domain')); | |||||
$discount = Discount::where('code', 'TEST')->first(); | |||||
$this->assertSame($discount->id, $user->wallets()->first()->discount_id); | |||||
} | |||||
} | } |