diff --git a/src/.env.example b/src/.env.example index 178ba546..68e6519c 100644 --- a/src/.env.example +++ b/src/.env.example @@ -1,56 +1,57 @@ APP_NAME=Kolab APP_ENV=local APP_KEY= APP_DEBUG=true APP_URL=http://127.0.0.1:8000 +APP_DOMAIN=kolabnow.com LOG_CHANNEL=stack DB_CONNECTION=sqlite BROADCAST_DRIVER=log CACHE_DRIVER=file QUEUE_CONNECTION=sync SESSION_DRIVER=file SESSION_LIFETIME=120 LDAP_ADMIN_BIND_DN="cn=Directory Manager" LDAP_ADMIN_BIND_PW=Welcome2KolabSystems LDAP_DOMAIN_BASE_DN=ou=Domains,dc=mgmt,dc=com LDAP_HOSTED_BASE_DN=dc=hosted,dc=com LDAP_HOSTED_SEARCH_BIND_DN="uid=hosted-kolab-service,ou=Special Users,dc=mgmt,dc=com" LDAP_HOSTED_SEARCH_BIND_PW=Welcome2KolabSystems LDAP_HOSTNAME=127.0.0.1 LDAP_SEARCH_BIND_DN="uid=kolab-service,ou=Special Users,dc=mgmt,dc=com" LDAP_SEARCH_BIND_PW=Welcome2KolabSystems REDIS_HOST=127.0.0.1 REDIS_PASSWORD=null REDIS_PORT=6379 SWOOLE_HTTP_HOST=127.0.0.1 SWOOLE_HTTP_PORT=8000 MAIL_DRIVER=smtp MAIL_HOST=smtp.mailtrap.io MAIL_PORT=2525 MAIL_USERNAME=null MAIL_PASSWORD=null MAIL_ENCRYPTION=null MAIL_FROM_ADDRESS="noreply@example.com" Mail_FROM_NAME="Example.com" AWS_ACCESS_KEY_ID= AWS_SECRET_ACCESS_KEY= AWS_DEFAULT_REGION=us-east-1 AWS_BUCKET= PUSHER_APP_ID= PUSHER_APP_KEY= PUSHER_APP_SECRET= PUSHER_APP_CLUSTER=mt1 MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}" MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" JWT_SECRET= diff --git a/src/app/Http/Controllers/API/SignupController.php b/src/app/Http/Controllers/API/SignupController.php index 5eddb531..c910c974 100644 --- a/src/app/Http/Controllers/API/SignupController.php +++ b/src/app/Http/Controllers/API/SignupController.php @@ -1,257 +1,260 @@ all(), [ 'email' => 'required', 'name' => 'required', ] ); if ($v->fails()) { return response()->json(['status' => 'error', 'errors' => $v->errors()], 422); } // Validate user email (or phone) if ($error = $this->validatePhoneOrEmail($request->email, $is_phone)) { return response()->json(['status' => 'error', 'errors' => ['email' => __($error)]], 422); } // Generate the verification code $code = SignupCode::create([ 'data' => [ 'email' => $request->email, 'name' => $request->name, ] ]); // Send email/sms message if ($is_phone) { SignupVerificationSMS::dispatch($code); } else { SignupVerificationEmail::dispatch($code); } return response()->json(['status' => 'success', 'code' => $code->code]); } /** * Validation of the verification code. * * @param Illuminate\Http\Request HTTP request * * @return \Illuminate\Http\JsonResponse JSON response */ public function verify(Request $request) { // Validate the request args $v = Validator::make( $request->all(), [ 'code' => 'required', 'short_code' => 'required', ] ); if ($v->fails()) { return response()->json(['status' => 'error', 'errors' => $v->errors()], 422); } // Validate the verification code $code = SignupCode::find($request->code); if (empty($code) || $code->isExpired() || Str::upper($request->short_code) !== Str::upper($code->short_code) ) { $errors = ['short_code' => "The code is invalid or expired."]; return response()->json(['status' => 'error', 'errors' => $errors], 422); } // For signup last-step mode remember the code object, so we can delete it // with single SQL query (->delete()) instead of two (::destroy()) $this->code = $code; // Return user name and email/phone from the codes database on success return response()->json([ - 'status' => 'success', - 'email' => $code->data['email'], - 'name' => $code->data['name'], + 'status' => 'success', + 'email' => $code->data['email'], + 'name' => $code->data['name'], ]); } /** * Finishes the signup process by creating the user account. * * @param Illuminate\Http\Request HTTP request * * @return \Illuminate\Http\JsonResponse JSON response */ public function signup(Request $request) { // Validate input $v = Validator::make( $request->all(), [ - 'domain' => 'required|min:3', 'login' => 'required|min:2', - 'password' => 'required|min:3|confirmed', + 'password' => 'required|min:4|confirmed', ] ); if ($v->fails()) { return response()->json(['status' => 'error', 'errors' => $v->errors()], 422); } - $login = $request->login . '@' . $request->domain; + $login = $request->login . '@' . \config('app.domain'); // Validate login (email) if ($error = $this->validateEmail($login, true)) { return response()->json(['status' => 'error', 'errors' => ['login' => $error]], 422); } // Validate verification codes (again) $v = $this->verify($request); if ($v->status() !== 200) { return $v; } $code_data = $v->getData(); $user_name = $code_data->name; $user_email = $code_data->email; // We allow only ASCII, so we can safely lower-case the email address $login = Str::lower($login); $user = User::create( [ // TODO: Save the external email (or phone) 'name' => $user_name, 'email' => $login, 'password' => $request->password, ] ); // Remove the verification code $this->code->delete(); $token = auth()->login($user); return response()->json([ + 'status' => 'success', 'access_token' => $token, 'token_type' => 'bearer', 'expires_in' => Auth::guard()->factory()->getTTL() * 60, ]); } /** * Checks if the input string is a valid email address or a phone number * * @param string $email Email address or phone number * @param bool &$is_phone Will be set to True if the string is valid phone number * * @return string Error message label on validation error */ protected function validatePhoneOrEmail($input, &$is_phone = false) { $is_phone = false; return $this->validateEmail($input); // TODO: Phone number support /* if (strpos($input, '@')) { return $this->validateEmail($input); } $input = str_replace(array('-', ' '), '', $input); if (!preg_match('/^\+?[0-9]{9,12}$/', $input)) { return 'validation.noemailorphone'; } $is_phone = true; */ } /** * Email address validation * * @param string $email Email address * @param bool $signup Enables additional checks for signup mode * * @return string Error message label on validation error */ protected function validateEmail($email, $signup = false) { $v = Validator::make(['email' => $email], ['email' => 'required|email']); if ($v->fails()) { return 'validation.emailinvalid'; } list($local, $domain) = explode('@', $email); // don't allow @localhost and other no-fqdn if (strpos($domain, '.') === false) { return 'validation.emailinvalid'; } // Extended checks for an address that is supposed to become a login to Kolab if ($signup) { // Local part validation if (!preg_match('/^[A-Za-z0-9_.-]+$/', $local)) { return 'validation.emailinvalid'; } - // TODO: check if specified domain is allowed for signup + // Check if specified domain is allowed for signup + if ($domain != \config('app.domain')) { + return 'validation.emailinvalid'; + } // Check if the local part is not one of exceptions $exceptions = '/^(admin|administrator|sales|root)$/i'; if (preg_match($exceptions, $local)) { return 'validation.emailexists'; } // Check if user with specified login already exists // TODO: Aliases if (User::where('email', $email)->first()) { return 'validation.emailexists'; } } } } diff --git a/src/app/Providers/AppServiceProvider.php b/src/app/Providers/AppServiceProvider.php index 05fbaa94..d949d51f 100644 --- a/src/app/Providers/AppServiceProvider.php +++ b/src/app/Providers/AppServiceProvider.php @@ -1,42 +1,42 @@ sql, implode(', ', $query->bindings))); }); } } } diff --git a/src/config/app.php b/src/config/app.php index c9960cde..bd78501a 100644 --- a/src/config/app.php +++ b/src/config/app.php @@ -1,231 +1,238 @@ env('APP_NAME', 'Laravel'), /* |-------------------------------------------------------------------------- | Application Environment |-------------------------------------------------------------------------- | | This value determines the "environment" your application is currently | running in. This may determine how you prefer to configure various | services the application utilizes. Set this in your ".env" file. | */ 'env' => env('APP_ENV', 'production'), /* |-------------------------------------------------------------------------- | Application Debug Mode |-------------------------------------------------------------------------- | | When your application is in debug mode, detailed error messages with | stack traces will be shown on every error that occurs within your | application. If disabled, a simple generic error page is shown. | */ 'debug' => env('APP_DEBUG', false), /* |-------------------------------------------------------------------------- | Application URL |-------------------------------------------------------------------------- | | This URL is used by the console to properly generate URLs when using | the Artisan command line tool. You should set this to the root of | your application so that it is used when running Artisan tasks. - | */ 'url' => env('APP_URL', 'http://localhost'), 'asset_url' => env('ASSET_URL', null), + /* + |-------------------------------------------------------------------------- + | Application Domain + |-------------------------------------------------------------------------- + | + | System domain used for user signup (kolab identity) + */ + 'domain' => env('APP_DOMAIN', 'domain.tld'), + /* |-------------------------------------------------------------------------- | Application Timezone |-------------------------------------------------------------------------- | | Here you may specify the default timezone for your application, which | will be used by the PHP date and date-time functions. We have gone | ahead and set this to a sensible default for you out of the box. | */ 'timezone' => 'UTC', /* |-------------------------------------------------------------------------- | Application Locale Configuration |-------------------------------------------------------------------------- | | The application locale determines the default locale that will be used | by the translation service provider. You are free to set this value | to any of the locales which will be supported by the application. | */ 'locale' => 'en', /* |-------------------------------------------------------------------------- | Application Fallback Locale |-------------------------------------------------------------------------- | | The fallback locale determines the locale to use when the current one | is not available. You may change the value to correspond to any of | the language folders that are provided through your application. | */ 'fallback_locale' => 'en', /* |-------------------------------------------------------------------------- | Faker Locale |-------------------------------------------------------------------------- | | This locale will be used by the Faker PHP library when generating fake | data for your database seeds. For example, this will be used to get | localized telephone numbers, street address information and more. | */ 'faker_locale' => 'en_US', /* |-------------------------------------------------------------------------- | Encryption Key |-------------------------------------------------------------------------- | | This key is used by the Illuminate encrypter service and should be set | to a random, 32 character string, otherwise these encrypted strings | will not be safe. Please do this before deploying an application! | */ 'key' => env('APP_KEY'), 'cipher' => 'AES-256-CBC', /* |-------------------------------------------------------------------------- | Autoloaded Service Providers |-------------------------------------------------------------------------- | | The service providers listed here will be automatically loaded on the | request to your application. Feel free to add your own services to | this array to grant expanded functionality to your applications. | */ 'providers' => [ /* * Laravel Framework Service Providers... */ Illuminate\Auth\AuthServiceProvider::class, Illuminate\Broadcasting\BroadcastServiceProvider::class, Illuminate\Bus\BusServiceProvider::class, Illuminate\Cache\CacheServiceProvider::class, Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class, Illuminate\Cookie\CookieServiceProvider::class, Illuminate\Database\DatabaseServiceProvider::class, Illuminate\Encryption\EncryptionServiceProvider::class, Illuminate\Filesystem\FilesystemServiceProvider::class, Illuminate\Foundation\Providers\FoundationServiceProvider::class, Illuminate\Hashing\HashServiceProvider::class, Illuminate\Mail\MailServiceProvider::class, Illuminate\Notifications\NotificationServiceProvider::class, Illuminate\Pagination\PaginationServiceProvider::class, Illuminate\Pipeline\PipelineServiceProvider::class, Illuminate\Queue\QueueServiceProvider::class, Illuminate\Redis\RedisServiceProvider::class, Illuminate\Auth\Passwords\PasswordResetServiceProvider::class, Illuminate\Session\SessionServiceProvider::class, Illuminate\Translation\TranslationServiceProvider::class, Illuminate\Validation\ValidationServiceProvider::class, Illuminate\View\ViewServiceProvider::class, /* * Package Service Providers... */ /* * Application Service Providers... */ App\Providers\AppServiceProvider::class, App\Providers\AuthServiceProvider::class, // App\Providers\BroadcastServiceProvider::class, App\Providers\EventServiceProvider::class, App\Providers\RouteServiceProvider::class, ], /* |-------------------------------------------------------------------------- | Class Aliases |-------------------------------------------------------------------------- | | This array of class aliases will be registered when this application | is started. However, feel free to register as many as you wish as | the aliases are "lazy" loaded so they don't hinder performance. | */ 'aliases' => [ 'App' => Illuminate\Support\Facades\App::class, 'Arr' => Illuminate\Support\Arr::class, 'Artisan' => Illuminate\Support\Facades\Artisan::class, 'Auth' => Illuminate\Support\Facades\Auth::class, 'Blade' => Illuminate\Support\Facades\Blade::class, 'Broadcast' => Illuminate\Support\Facades\Broadcast::class, 'Bus' => Illuminate\Support\Facades\Bus::class, 'Cache' => Illuminate\Support\Facades\Cache::class, 'Config' => Illuminate\Support\Facades\Config::class, 'Cookie' => Illuminate\Support\Facades\Cookie::class, 'Crypt' => Illuminate\Support\Facades\Crypt::class, 'DB' => Illuminate\Support\Facades\DB::class, 'Eloquent' => Illuminate\Database\Eloquent\Model::class, 'Event' => Illuminate\Support\Facades\Event::class, 'File' => Illuminate\Support\Facades\File::class, 'Gate' => Illuminate\Support\Facades\Gate::class, 'Hash' => Illuminate\Support\Facades\Hash::class, 'Lang' => Illuminate\Support\Facades\Lang::class, 'Log' => Illuminate\Support\Facades\Log::class, 'Mail' => Illuminate\Support\Facades\Mail::class, 'Notification' => Illuminate\Support\Facades\Notification::class, 'Password' => Illuminate\Support\Facades\Password::class, 'Queue' => Illuminate\Support\Facades\Queue::class, 'Redirect' => Illuminate\Support\Facades\Redirect::class, 'Redis' => Illuminate\Support\Facades\Redis::class, 'Request' => Illuminate\Support\Facades\Request::class, 'Response' => Illuminate\Support\Facades\Response::class, 'Route' => Illuminate\Support\Facades\Route::class, 'Schema' => Illuminate\Support\Facades\Schema::class, 'Session' => Illuminate\Support\Facades\Session::class, 'Storage' => Illuminate\Support\Facades\Storage::class, 'Str' => Illuminate\Support\Str::class, 'URL' => Illuminate\Support\Facades\URL::class, 'Validator' => Illuminate\Support\Facades\Validator::class, 'View' => Illuminate\Support\Facades\View::class, ], - ]; diff --git a/src/phpunit.xml b/src/phpunit.xml index da4add30..447c94f0 100644 --- a/src/phpunit.xml +++ b/src/phpunit.xml @@ -1,33 +1,34 @@ ./tests/Unit ./tests/Feature ./app + diff --git a/src/resources/views/layouts/app.blade.php b/src/resources/views/layouts/app.blade.php index 6ec5f3fe..23908f25 100644 --- a/src/resources/views/layouts/app.blade.php +++ b/src/resources/views/layouts/app.blade.php @@ -1,22 +1,22 @@ {{ config('app.name') }} -- @yield('title') @laravelPWA
@yield('content')
- + diff --git a/src/resources/vue/components/Signup.vue b/src/resources/vue/components/Signup.vue index 5368dfc5..a390ec17 100644 --- a/src/resources/vue/components/Signup.vue +++ b/src/resources/vue/components/Signup.vue @@ -1,166 +1,158 @@ diff --git a/src/tests/Feature/Controller/SignupTest.php b/src/tests/Feature/Controller/SignupTest.php index 2d805f99..dae0a968 100644 --- a/src/tests/Feature/Controller/SignupTest.php +++ b/src/tests/Feature/Controller/SignupTest.php @@ -1,246 +1,387 @@ 'SignupControllerTest1@SignupControllerTest.com' - ] - ); + $user = User::firstOrCreate(['email' => 'SignupControllerTest1@' . \config('app.domain')]); } /** * {@inheritDoc} * * @return void */ public function tearDown(): void { - $user = User::firstOrCreate( - [ - 'email' => 'SignupControllerTest1@SignupControllerTest.com' - ] - ); - - $user->delete(); + User::where('email', 'SignupLogin@' . \config('app.domain')) + ->orWhere('email', 'SignupControllerTest1@' . \config('app.domain')) + ->delete(); parent::tearDown(); } + /** + * Test signup initialization with invalid input + * + * @return void + */ public function testSignupInitInvalidInput() { // Empty input data $data = []; $response = $this->post('/api/auth/signup/init', $data); $json = $response->json(); $response->assertStatus(422); $this->assertSame('error', $json['status']); $this->assertCount(2, $json['errors']); $this->assertArrayHasKey('email', $json['errors']); $this->assertArrayHasKey('name', $json['errors']); // Data with missing name $data = [ 'email' => 'UsersApiControllerTest1@UsersApiControllerTest.com', 'password' => 'simple123', 'password_confirmation' => 'simple123' ]; $response = $this->post('/api/auth/signup/init', $data); $json = $response->json(); $response->assertStatus(422); $this->assertSame('error', $json['status']); $this->assertCount(1, $json['errors']); $this->assertArrayHasKey('name', $json['errors']); // Data with invalid email (but not phone number) $data = [ 'email' => '@example.org', 'name' => 'Signup User', 'password' => 'simple123', 'password_confirmation' => 'simple123' ]; $response = $this->post('/api/auth/signup/init', $data); $json = $response->json(); $response->assertStatus(422); $this->assertSame('error', $json['status']); $this->assertCount(1, $json['errors']); $this->assertArrayHasKey('email', $json['errors']); // TODO: Test phone validation } + /** + * Test signup initialization with valid input + * + * @return array + */ public function testSignupInitValidInput() { $data = [ - 'email' => 'UsersApiControllerTest1@UsersApiControllerTest.com', + 'email' => 'testuser@external.com', 'name' => 'Signup User', 'password' => 'simple123', 'password_confirmation' => 'simple123' ]; $response = $this->post('/api/auth/signup/init', $data); $json = $response->json(); $response->assertStatus(200); $this->assertCount(2, $json); $this->assertSame('success', $json['status']); $this->assertNotEmpty($json['code']); - // TODO: Test verification email/sms + // TODO: Test verification email job/event return [ 'code' => $json['code'], 'email' => $data['email'], 'name' => $data['name'], ]; } /** + * Test signup code verification with invalid input + * * @depends testSignupInitValidInput + * @return void */ public function testSignupVerifyInvalidInput(array $result) { // Empty data $data = []; $response = $this->post('/api/auth/signup/verify', $data); $json = $response->json(); $response->assertStatus(422); - $this->assertCount(2, $json); $this->assertSame('error', $json['status']); + $this->assertCount(2, $json['errors']); $this->assertArrayHasKey('code', $json['errors']); $this->assertArrayHasKey('short_code', $json['errors']); // Data with existing code but missing short_code $data = [ 'code' => $result['code'], ]; $response = $this->post('/api/auth/signup/verify', $data); $json = $response->json(); $response->assertStatus(422); - $this->assertCount(2, $json); $this->assertSame('error', $json['status']); + $this->assertCount(1, $json['errors']); $this->assertArrayHasKey('short_code', $json['errors']); // Data with invalid short_code $data = [ 'code' => $result['code'], 'short_code' => 'XXXX', ]; $response = $this->post('/api/auth/signup/verify', $data); $json = $response->json(); $response->assertStatus(422); - $this->assertCount(2, $json); $this->assertSame('error', $json['status']); + $this->assertCount(1, $json['errors']); $this->assertArrayHasKey('short_code', $json['errors']); // TODO: Test expired code } /** + * Test signup code verification with valid input + * * @depends testSignupInitValidInput + * + * @return array */ public function testSignupVerifyValidInput(array $result) { $code = SignupCode::find($result['code']); $data = [ 'code' => $code->code, 'short_code' => $code->short_code, ]; $response = $this->post('/api/auth/signup/verify', $data); $json = $response->json(); $response->assertStatus(200); $this->assertCount(3, $json); $this->assertSame('success', $json['status']); $this->assertSame($result['email'], $json['email']); $this->assertSame($result['name'], $json['name']); + + return $result; + } + + /** + * Test last signup step with invalid input + * + * @depends testSignupVerifyValidInput + * @return void + */ + public function testSignupInvalidInput(array $result) + { + // Empty data + $data = []; + + $response = $this->post('/api/auth/signup', $data); + $json = $response->json(); + + $response->assertStatus(422); + $this->assertSame('error', $json['status']); + $this->assertCount(2, $json['errors']); + $this->assertArrayHasKey('login', $json['errors']); + $this->assertArrayHasKey('password', $json['errors']); + + // Passwords do not match + $data = [ + 'login' => 'test', + 'password' => 'test', + 'password_confirmation' => 'test2', + ]; + + $response = $this->post('/api/auth/signup', $data); + $json = $response->json(); + + $response->assertStatus(422); + $this->assertSame('error', $json['status']); + $this->assertCount(1, $json['errors']); + $this->assertArrayHasKey('password', $json['errors']); + + // Login too short + $data = [ + 'login' => '1', + 'password' => 'test', + 'password_confirmation' => 'test', + ]; + + $response = $this->post('/api/auth/signup', $data); + $json = $response->json(); + + $response->assertStatus(422); + $this->assertSame('error', $json['status']); + $this->assertCount(1, $json['errors']); + $this->assertArrayHasKey('login', $json['errors']); + + // Login invalid + $data = [ + 'login' => 'żżżżż', + 'password' => 'test', + 'password_confirmation' => 'test', + ]; + + $response = $this->post('/api/auth/signup', $data); + $json = $response->json(); + + $response->assertStatus(422); + $this->assertSame('error', $json['status']); + $this->assertCount(1, $json['errors']); + $this->assertArrayHasKey('login', $json['errors']); + + // Data with invalid short_code + $data = [ + 'login' => 'TestLogin', + 'password' => 'test', + 'password_confirmation' => 'test', + 'code' => $result['code'], + 'short_code' => 'XXXX', + ]; + + $response = $this->post('/api/auth/signup', $data); + $json = $response->json(); + + $response->assertStatus(422); + $this->assertSame('error', $json['status']); + $this->assertCount(1, $json['errors']); + $this->assertArrayHasKey('short_code', $json['errors']); } - public function testSignup() + /** + * Test last signup step with valid input (user creation) + * + * @depends testSignupVerifyValidInput + * @return void + */ + public function testSignupValidInput(array $result) { - // TODO + $identity = \strtolower('SignupLogin@') . \config('app.domain'); + + // Make sure the user does not exist (it may happen when executing + // tests again after failure) + User::where('email', $identity)->delete(); + + $code = SignupCode::find($result['code']); + $data = [ + 'login' => 'SignupLogin', + 'password' => 'test', + 'password_confirmation' => 'test', + 'code' => $code->code, + 'short_code' => $code->short_code, + ]; + + $response = $this->post('/api/auth/signup', $data); + $json = $response->json(); + + $response->assertStatus(200); + $this->assertCount(4, $json); + $this->assertSame('success', $json['status']); + $this->assertSame('bearer', $json['token_type']); + $this->assertTrue(!empty($json['expires_in']) && is_int($json['expires_in']) && $json['expires_in'] > 0); + $this->assertNotEmpty($json['access_token']); + + // Check if the code has been removed + $this->assertNull(SignupCode::where($result['code'])->first()); + + // Check if the user has been created + $user = User::where('email', $identity)->first(); + + $this->assertNotEmpty($user); + $this->assertSame($identity, $user->email); + $this->assertSame($result['name'], $user->name); +// $this->assertSame($result['email'], $user->settings->external_email); + + // TODO: Check if the access token works? } /** * List of email address validation cases for testValidateEmail() + * + * @return array Arguments for testValidateEmail() */ public function dataValidateEmail() { - $domain = 'example.org'; + // To access config from dataProvider method we have to refreshApplication() first + $this->refreshApplication(); + $domain = \config('app.domain'); return [ // general cases (invalid) ['', false, 'validation.emailinvalid'], ['example.org', false, 'validation.emailinvalid'], ['@example.org', false, 'validation.emailinvalid'], ['test@localhost', false, 'validation.emailinvalid'], // general cases (valid) ['test@domain.tld', false, null], ['&@example.org', false, null], // kolab identity cases ['admin@' . $domain, true, 'validation.emailexists'], ['administrator@' . $domain, true, 'validation.emailexists'], ['sales@' . $domain, true, 'validation.emailexists'], ['root@' . $domain, true, 'validation.emailexists'], ['&@' . $domain, true, 'validation.emailinvalid'], + ['testnonsystemdomain@invalid.tld', true, 'validation.emailinvalid'], // existing account - ['SignupControllerTest1@SignupControllerTest.com', true, 'validation.emailexists'], + ['SignupControllerTest1@' . $domain, true, 'validation.emailexists'], // valid for signup ['test.test@' . $domain, true, null], ['test_test@' . $domain, true, null], ['test-test@' . $domain, true, null], ]; } /** * Signup email validation. * * Note: Technicly these are mostly unit tests, but let's keep it here for now. * FIXME: Shall we do a http request for each case? * * @dataProvider dataValidateEmail */ public function testValidateEmail($email, $signup, $expected_result) { $method = new \ReflectionMethod('App\Http\Controllers\API\SignupController', 'validateEmail'); $method->setAccessible(true); $is_phone = false; $result = $method->invoke(new SignupController, $email, $signup); $this->assertSame($expected_result, $result); } }