diff --git a/codeception.yml b/codeception.yml new file mode 100644 index 0000000..7f8b0b0 --- /dev/null +++ b/codeception.yml @@ -0,0 +1,30 @@ +actor: Tester +paths: + tests: tests + log: tests/_output + data: tests/_data + helpers: tests/_support +settings: + bootstrap: _bootstrap.php + colors: true + memory_limit: 1024M +modules: + config: + Yii2: + configFile: 'tests/_app/config/test.php' +coverage: + enabled: true + include: + - ../lib/User/AuthClient/* + - ../controllers/* + - ../events/* + - ../filters/* + - ../helpers/* + - ../models/* + - ../traits/* + - ../views/* + - ../widgets/* + - ../Bootstrap.php + - ../Module.php + - ../Mailer.php + - ../Finder.php diff --git a/composer.json b/composer.json index e620502..91b2e0d 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,10 @@ "fabpot/php-cs-fixer": "^1.12", "phpmd/phpmd": "^2.4", "dektrium/yii2-user": "^0.9.9", - "dektrium/yii2-rbac": "^0.3.0" + "dektrium/yii2-rbac": "^0.3.0", + "yiisoft/yii2-codeception": "^2.0.0", + "codeception/specify": "^0.4.3", + "codeception/verify": "^0.3.1" }, "autoload": { "psr-4": { diff --git a/composer.lock b/composer.lock index 5b4ca09..feffa91 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "15f47ee84555dd06400d7388b738aae6", - "content-hash": "7b85b85a725b61a678cfb1f7b17c6dc4", + "hash": "6a535aefcdf64b58d80efc0402124dbc", + "content-hash": "718049b93fe83097e6e146cfb7dc8ddc", "packages": [], "packages-dev": [ { @@ -290,6 +290,79 @@ ], "time": "2016-09-27 13:35:10" }, + { + "name": "codeception/specify", + "version": "0.4.5", + "source": { + "type": "git", + "url": "https://github.com/Codeception/Specify.git", + "reference": "5fb1d68a737f31155a0f7410cf47dea479b33415" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/Specify/zipball/5fb1d68a737f31155a0f7410cf47dea479b33415", + "reference": "5fb1d68a737f31155a0f7410cf47dea479b33415", + "shasum": "" + }, + "require": { + "myclabs/deep-copy": "~1.1", + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "Codeception\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "authors": [ + { + "name": "Michael Bodnarchuk", + "email": "davert.php@mailican.com" + } + ], + "description": "BDD code blocks for PHPUnit and Codeception", + "time": "2016-10-17 22:28:20" + }, + { + "name": "codeception/verify", + "version": "0.3.2", + "source": { + "type": "git", + "url": "https://github.com/Codeception/Verify.git", + "reference": "b06d706261d1fee0cc312bacc5c1b7c506e5213a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/Verify/zipball/b06d706261d1fee0cc312bacc5c1b7c506e5213a", + "reference": "b06d706261d1fee0cc312bacc5c1b7c506e5213a", + "shasum": "" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "autoload": { + "files": [ + "src/Codeception/function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Bodnarchuk", + "email": "davert.php@mailican.com" + } + ], + "description": "BDD assertion library for PHPUnit", + "time": "2016-08-29 22:49:25" + }, { "name": "dektrium/yii2-rbac", "version": "0.3.0", @@ -605,6 +678,48 @@ ], "time": "2016-11-17 09:07:14" }, + { + "name": "myclabs/deep-copy", + "version": "1.5.5", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "399c1f9781e222f6eb6cc238796f5200d1b7f108" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/399c1f9781e222f6eb6cc238796f5200d1b7f108", + "reference": "399c1f9781e222f6eb6cc238796f5200d1b7f108", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "doctrine/collections": "1.*", + "phpunit/phpunit": "~4.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "homepage": "https://github.com/myclabs/DeepCopy", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "time": "2016-10-31 17:19:45" + }, { "name": "pdepend/pdepend", "version": "2.3.2", @@ -893,12 +1008,12 @@ "source": { "type": "git", "url": "https://github.com/swiftmailer/swiftmailer.git", - "reference": "12a6329c24d08fb97bcf10128365757f845dc140" + "reference": "968cd5302dba8d60ddb64489069953fae2ff1a92" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/12a6329c24d08fb97bcf10128365757f845dc140", - "reference": "12a6329c24d08fb97bcf10128365757f845dc140", + "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/968cd5302dba8d60ddb64489069953fae2ff1a92", + "reference": "968cd5302dba8d60ddb64489069953fae2ff1a92", "shasum": "" }, "require": { @@ -938,7 +1053,7 @@ "mail", "mailer" ], - "time": "2016-11-24 01:01:52" + "time": "2016-12-06 13:58:36" }, { "name": "symfony/config", @@ -946,12 +1061,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "dc43722df24b1320e22a0a525a74fed0eba61552" + "reference": "c3539b8e8fbfbb44a1c5884473940ea0f1a08d0c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/dc43722df24b1320e22a0a525a74fed0eba61552", - "reference": "dc43722df24b1320e22a0a525a74fed0eba61552", + "url": "https://api.github.com/repos/symfony/config/zipball/c3539b8e8fbfbb44a1c5884473940ea0f1a08d0c", + "reference": "c3539b8e8fbfbb44a1c5884473940ea0f1a08d0c", "shasum": "" }, "require": { @@ -994,7 +1109,7 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2016-11-29 11:12:53" + "time": "2016-12-09 07:45:54" }, { "name": "symfony/console", @@ -1002,12 +1117,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "0eeddc19feb3bd91c443e676bd07c6ce5c30cfa3" + "reference": "3c2380fcde1e7311afdc20836f4db460f0550427" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/0eeddc19feb3bd91c443e676bd07c6ce5c30cfa3", - "reference": "0eeddc19feb3bd91c443e676bd07c6ce5c30cfa3", + "url": "https://api.github.com/repos/symfony/console/zipball/3c2380fcde1e7311afdc20836f4db460f0550427", + "reference": "3c2380fcde1e7311afdc20836f4db460f0550427", "shasum": "" }, "require": { @@ -1057,7 +1172,7 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2016-11-19 20:35:20" + "time": "2016-12-08 15:31:48" }, { "name": "symfony/debug", @@ -1122,12 +1237,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "3e613031d3e80beef18a015e544263a6dd58123f" + "reference": "7fff820a0b1ffc3dc16ee132168cc7e0e65ba5c2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/3e613031d3e80beef18a015e544263a6dd58123f", - "reference": "3e613031d3e80beef18a015e544263a6dd58123f", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/7fff820a0b1ffc3dc16ee132168cc7e0e65ba5c2", + "reference": "7fff820a0b1ffc3dc16ee132168cc7e0e65ba5c2", "shasum": "" }, "require": { @@ -1177,7 +1292,7 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2016-11-25 12:33:00" + "time": "2016-12-08 15:31:48" }, { "name": "symfony/event-dispatcher", @@ -1500,12 +1615,12 @@ "source": { "type": "git", "url": "https://github.com/yiisoft/yii2-framework.git", - "reference": "f8202bb4eda46c2cb4664fee24723e6bf48f07e5" + "reference": "39671fbb1308cc6feaa1c1091c6f4b8aca4f93f3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/yiisoft/yii2-framework/zipball/f8202bb4eda46c2cb4664fee24723e6bf48f07e5", - "reference": "f8202bb4eda46c2cb4664fee24723e6bf48f07e5", + "url": "https://api.github.com/repos/yiisoft/yii2-framework/zipball/39671fbb1308cc6feaa1c1091c6f4b8aca4f93f3", + "reference": "39671fbb1308cc6feaa1c1091c6f4b8aca4f93f3", "shasum": "" }, "require": { @@ -1586,7 +1701,7 @@ "framework", "yii2" ], - "time": "2016-12-03 06:25:39" + "time": "2016-12-10 18:26:22" }, { "name": "yiisoft/yii2-authclient", @@ -1687,6 +1802,52 @@ ], "time": "2016-08-09 21:17:28" }, + { + "name": "yiisoft/yii2-codeception", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/yiisoft/yii2-codeception.git", + "reference": "76fdd689b7ec49c3c57db6137ae5ea536fa8f16d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/yiisoft/yii2-codeception/zipball/76fdd689b7ec49c3c57db6137ae5ea536fa8f16d", + "reference": "76fdd689b7ec49c3c57db6137ae5ea536fa8f16d", + "shasum": "" + }, + "require": { + "yiisoft/yii2": ">=2.0.4" + }, + "type": "yii2-extension", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "yii\\codeception\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Mark Jebri", + "email": "mark.github@yandex.ru" + } + ], + "description": "The Codeception integration for the Yii framework", + "keywords": [ + "codeception", + "yii2" + ], + "abandoned": "codeception/codeception", + "time": "2016-10-20 13:07:49" + }, { "name": "yiisoft/yii2-composer", "version": "dev-master", diff --git a/tests/_app/config/console.php b/tests/_app/config/console.php new file mode 100644 index 0000000..11ddc2b --- /dev/null +++ b/tests/_app/config/console.php @@ -0,0 +1,15 @@ + 'yii2-test-console', + 'basePath' => dirname(__DIR__), + 'aliases' => [ + '@Da/User' => dirname(dirname(dirname(__DIR__))) . '/lib/User', + '@tests' => dirname(dirname(__DIR__)), + ], + 'components' => [ + 'log' => null, + 'cache' => null, + 'db' => require __DIR__ . '/db.php', + ], +]; diff --git a/tests/_app/config/db.php b/tests/_app/config/db.php new file mode 100644 index 0000000..07384e6 --- /dev/null +++ b/tests/_app/config/db.php @@ -0,0 +1,15 @@ + 'yii\db\Connection', + 'dsn' => 'mysql:host=localhost;dbname=test', + 'username' => 'root', + 'password' => '', + 'charset' => 'utf8', +]; + +if (file_exists(__DIR__ . '/db.local.php')) { + $db = array_merge($db, require(__DIR__ . '/db.local.php')); +} + +return $db; diff --git a/tests/_app/config/test.php b/tests/_app/config/test.php new file mode 100644 index 0000000..871f3dc --- /dev/null +++ b/tests/_app/config/test.php @@ -0,0 +1,34 @@ + 'yii2-user-tests', + 'basePath' => dirname(__DIR__), + 'language' => 'en-US', + 'aliases' => [ + '@Da/User' => dirname(dirname(dirname(__DIR__))) . '/lib/User', + '@tests' => dirname(dirname(__DIR__)), + '@vendor' => VENDOR_DIR, + '@bower' => VENDOR_DIR . '/bower-asset', + ], + 'bootstrap' => ['Da\User\Bootstrap'], + 'modules' => [ + 'user' => [ + 'class' => 'Da\User\Module', + 'administrators' => ['user'], + ], + ], + 'components' => [ + 'db' => require __DIR__ . '/db.php', + 'mailer' => [ + 'useFileTransport' => true, + ], + 'urlManager' => [ + 'showScriptName' => true, + ], + 'request' => [ + 'cookieValidationKey' => 'test', + 'enableCsrfValidation' => false, + ], + ], + 'params' => [], +]; diff --git a/tests/_app/controllers/SiteController.php b/tests/_app/controllers/SiteController.php new file mode 100644 index 0000000..913af9f --- /dev/null +++ b/tests/_app/controllers/SiteController.php @@ -0,0 +1,13 @@ +render('index'); + } +} diff --git a/tests/_app/views/layouts/main.php b/tests/_app/views/layouts/main.php new file mode 100644 index 0000000..24feb0a --- /dev/null +++ b/tests/_app/views/layouts/main.php @@ -0,0 +1,10 @@ +user->getIsGuest()) { + echo \yii\helpers\Html::a('Login', ['/user/security/login']); + echo \yii\helpers\Html::a('Registration', ['/user/registration/register']); +} else { + echo \yii\helpers\Html::a('Logout', ['/user/security/logout']); +} + +echo $content; diff --git a/tests/_app/views/site/index.php b/tests/_app/views/site/index.php new file mode 100644 index 0000000..c846c91 --- /dev/null +++ b/tests/_app/views/site/index.php @@ -0,0 +1 @@ +Index diff --git a/tests/_app/yii.php b/tests/_app/yii.php new file mode 100644 index 0000000..e4e322d --- /dev/null +++ b/tests/_app/yii.php @@ -0,0 +1,12 @@ +#!/usr/bin/env php +run(); +exit($exitCode); \ No newline at end of file diff --git a/tests/_bootstrap.php b/tests/_bootstrap.php new file mode 100644 index 0000000..033599b --- /dev/null +++ b/tests/_bootstrap.php @@ -0,0 +1,20 @@ + [ + 'user_id' => 1, + 'name' => 'John Doe', + ], +]; diff --git a/tests/_fixtures/data/token.php b/tests/_fixtures/data/token.php new file mode 100644 index 0000000..0842bf7 --- /dev/null +++ b/tests/_fixtures/data/token.php @@ -0,0 +1,32 @@ + [ + 'user_id' => 2, + 'code' => 'NO2aCmBIjFQX624xmAc3VBu7Th3NJoa6', + 'type' => Token::TYPE_CONFIRMATION, + 'created_at' => $time, + ], + 'expired_confirmation' => [ + 'user_id' => 3, + 'code' => 'qxYa315rqRgCOjYGk82GFHMEAV3T82AX', + 'type' => Token::TYPE_CONFIRMATION, + 'created_at' => $time - 86401, + ], + 'expired_recovery' => [ + 'user_id' => 5, + 'code' => 'a5839d0e73b9c525942c2f59e88c1aaf', + 'type' => Token::TYPE_RECOVERY, + 'created_at' => $time - 21601, + ], + 'recovery' => [ + 'user_id' => 6, + 'code' => '6f5d0dad53ef73e6ba6f01a441c0e602', + 'type' => Token::TYPE_RECOVERY, + 'created_at' => $time, + ], +]; diff --git a/tests/_fixtures/data/user.php b/tests/_fixtures/data/user.php new file mode 100644 index 0000000..6c9e98d --- /dev/null +++ b/tests/_fixtures/data/user.php @@ -0,0 +1,59 @@ + [ + 'username' => 'user', + 'email' => 'user@example.com', + 'password_hash' => '$2y$13$qY.ImaYBppt66qez6B31QO92jc5DYVRzo5NxM1ivItkW74WsSG6Ui', + 'auth_key' => '39HU0m5lpjWtqstFVGFjj6lFb7UZDeRq', + 'created_at' => $time, + 'updated_at' => $time, + 'confirmed_at' => $time, + ], + 'unconfirmed' => [ + 'username' => 'joe', + 'email' => 'joe@example.com', + 'password_hash' => '$2y$13$CIH1LSMPzU9xDCywt3QO8uovAu2axp8hwuXVa72oI.1G/USsGyMBS', + 'auth_key' => 'mhh1A6KfqQLmHP-MiWN0WB0M90Q2u5OE', + 'created_at' => $time, + 'updated_at' => $time, + ], + 'unconfirmed_with_expired_token' => [ + 'username' => 'john', + 'email' => 'john@example.com', + 'password_hash' => '$2y$13$qY.ImaYBppt66qez6B31QO92jc5DYVRzo5NxM1ivItkW74WsSG6Ui', + 'auth_key' => 'h6OS9csJbZEOW59ZILmJxU6bCiqVno9A', + 'created_at' => $time - 86401, + 'updated_at' => $time - 86401, + ], + 'blocked' => [ + 'username' => 'steven', + 'email' => 'steven@example.com', + 'password_hash' => '$2y$13$qY.ImaYBppt66qez6B31QO92jc5DYVRzo5NxM1ivItkW74WsSG6Ui', + 'auth_key' => 'TnXTrtLdj-YJBlG2A6jFHJreKgbsLYCa', + 'created_at' => $time, + 'updated_at' => $time, + 'blocked_at' => $time, + 'confirmed_at' => $time, + ], + 'user_with_expired_recovery_token' => [ + 'username' => 'andrew', + 'email' => 'andrew@example.com', + 'password_hash' => '$2y$13$qY.ImaYBppt66qez6B31QO92jc5DYVRzo5NxM1ivItkW74WsSG6Ui', + 'auth_key' => 'qxYa315rqRgCOjYGk82GFHMEAV3T82AX', + 'created_at' => $time - 21601, + 'updated_at' => $time - 21601, + 'confirmed_at' => $time - 21601, + ], + 'user_with_recovery_token' => [ + 'username' => 'alex', + 'email' => 'alex@example.com', + 'password_hash' => '$2y$13$qY.ImaYBppt66qez6B31QO92jc5DYVRzo5NxM1ivItkW74WsSG6Ui', + 'auth_key' => 'zQh1A65We0AmHPOMiWN0WB0M90Q24ziU', + 'created_at' => $time, + 'updated_at' => $time, + 'confirmed_at' => $time, + ], +]; diff --git a/tests/_output/.gitignore b/tests/_output/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/tests/_output/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/tests/_pages/AdminPage.php b/tests/_pages/AdminPage.php new file mode 100644 index 0000000..e6affae --- /dev/null +++ b/tests/_pages/AdminPage.php @@ -0,0 +1,16 @@ +actor->fillField('#user-username', $username); + $this->actor->fillField('#user-email', $email); + $this->actor->fillField('#user-password', $password); + $this->actor->click('Save'); + } +} diff --git a/tests/_pages/LoginPage.php b/tests/_pages/LoginPage.php new file mode 100644 index 0000000..1095d6a --- /dev/null +++ b/tests/_pages/LoginPage.php @@ -0,0 +1,27 @@ +actor->fillField('#login-form-login', $login); + $this->actor->fillField('#login-form-password', $password); + $this->actor->click('Sign in'); + } +} diff --git a/tests/_pages/RecoveryPage.php b/tests/_pages/RecoveryPage.php new file mode 100644 index 0000000..25a33de --- /dev/null +++ b/tests/_pages/RecoveryPage.php @@ -0,0 +1,25 @@ +actor->fillField('#recovery-form-email', $email); + $this->actor->click('Continue'); + } +} diff --git a/tests/_pages/RegistrationPage.php b/tests/_pages/RegistrationPage.php new file mode 100644 index 0000000..0387d7f --- /dev/null +++ b/tests/_pages/RegistrationPage.php @@ -0,0 +1,31 @@ +actor->fillField('#register-form-email', $email); + $this->actor->fillField('#register-form-username', $username); + if ($password !== null) { + $this->actor->fillField('#register-form-password', $password); + } + $this->actor->click('Sign up'); + } +} diff --git a/tests/_pages/ResendPage.php b/tests/_pages/ResendPage.php new file mode 100644 index 0000000..2753e1f --- /dev/null +++ b/tests/_pages/ResendPage.php @@ -0,0 +1,25 @@ +actor->fillField('#resend-form-email', $email); + $this->actor->click('Continue'); + } +} diff --git a/tests/_pages/SettingsPage.php b/tests/_pages/SettingsPage.php new file mode 100644 index 0000000..5d7cc28 --- /dev/null +++ b/tests/_pages/SettingsPage.php @@ -0,0 +1,31 @@ +actor->fillField('#settings-form-email', $email); + $this->actor->fillField('#settings-form-username', $username); + $this->actor->fillField('#settings-form-new_password', $password); + $this->actor->fillField('#settings-form-current_password', $currentPassword); + $this->actor->click('Save'); + } +} diff --git a/tests/_pages/UpdatePage.php b/tests/_pages/UpdatePage.php new file mode 100644 index 0000000..0819f82 --- /dev/null +++ b/tests/_pages/UpdatePage.php @@ -0,0 +1,29 @@ +actor->fillField('#user-username', $username); + $this->actor->fillField('#user-email', $email); + $this->actor->fillField('#user-password', $password); + $this->actor->click('Update'); + } +} diff --git a/tests/_support/FunctionalTester.php b/tests/_support/FunctionalTester.php new file mode 100644 index 0000000..7e888f8 --- /dev/null +++ b/tests/_support/FunctionalTester.php @@ -0,0 +1,26 @@ +wantTo('ensure that confirmation works'); +$I->haveFixtures(['token' => TokenFixture::className()]); + +$I->amGoingTo('check that error is showed when token expired'); +$token = $I->grabFixture('token', 'expired_confirmation'); +$I->amOnPage(Url::toRoute(['/user/registration/confirm', 'id' => $token->user_id, 'code' => $token->code])); +$I->see('The confirmation link is invalid or expired. Please try requesting a new one.'); + +$I->amGoingTo('check that user get confirmed'); +$token = $I->grabFixture('token', 'confirmation'); +$I->amOnPage(Url::toRoute(['/user/registration/confirm', 'id' => $token->user_id, 'code' => $token->code])); +$I->see('Thank you, registration is now complete.'); +$I->see('Logout'); diff --git a/tests/functional/CreateCept.php b/tests/functional/CreateCept.php new file mode 100644 index 0000000..ecbd37a --- /dev/null +++ b/tests/functional/CreateCept.php @@ -0,0 +1,32 @@ +wantTo('ensure that user creation works'); +$I->haveFixtures(['user' => UserFixture::className()]); + +$loginPage = LoginPage::openBy($I); +$user = $I->grabFixture('user', 'user'); +$loginPage->login($user->email, 'qwerty'); + +$page = CreatePage::openBy($I); + +$I->amGoingTo('try to create user with empty fields'); +$page->create('', '', ''); +$I->expectTo('see validations errors'); +$I->see('Username cannot be blank.'); +$I->see('Email cannot be blank.'); + +$page->create('foobar', 'foobar@example.com', 'foobar'); +$I->see('User has been created'); + +Yii::$app->user->logout(); +LoginPage::openBy($I)->login('foobar@example.com', 'foobar'); +$I->see('Logout'); diff --git a/tests/functional/LoginCept.php b/tests/functional/LoginCept.php new file mode 100644 index 0000000..db37073 --- /dev/null +++ b/tests/functional/LoginCept.php @@ -0,0 +1,41 @@ +wantTo('ensure that login works'); +$I->haveFixtures(['user' => UserFixture::className()]); + +$page = LoginPage::openBy($I); + +$I->amGoingTo('try to login with empty credentials'); +$page->login('', ''); +$I->expectTo('see validations errors'); +$I->see('Login cannot be blank.'); +$I->see('Password cannot be blank.'); + +$I->amGoingTo('try to login with unconfirmed account'); +$user = $I->grabFixture('user', 'unconfirmed'); +$page->login($user->email, 'qwerty'); +$I->see('You need to confirm your email address'); + +$I->amGoingTo('try to login with blocked account'); +$user = $I->grabFixture('user', 'blocked'); +$page->login($user->email, 'qwerty'); +$I->see('Your account has been blocked'); + +$I->amGoingTo('try to login with wrong credentials'); +$user = $I->grabFixture('user', 'user'); +$page->login($user->email, 'wrong'); +$I->expectTo('see validations errors'); +$I->see('Invalid login or password'); + +$I->amGoingTo('try to login with correct credentials'); +$page->login($user->email, 'qwerty'); +$I->dontSee('Login'); +$I->see('Logout'); diff --git a/tests/functional/RecoveryCept.php b/tests/functional/RecoveryCept.php new file mode 100644 index 0000000..26199ea --- /dev/null +++ b/tests/functional/RecoveryCept.php @@ -0,0 +1,56 @@ +wantTo('ensure that password recovery works'); +$I->haveFixtures(['user' => UserFixture::className(), 'token' => TokenFixture::className()]); + +$I->amGoingTo('try to request recovery token for unconfirmed account'); +$page = RecoveryPage::openBy($I); +$user = $I->grabFixture('user', 'unconfirmed'); +$page->recover($user->email); +$I->see('An email has been sent with instructions for resetting your password'); + +$I->amGoingTo('try to request recovery token'); +$page = RecoveryPage::openBy($I); +$user = $I->grabFixture('user', 'user'); +$page->recover($user->email); +$I->see('An email has been sent with instructions for resetting your password'); +$user = $I->grabRecord(User::className(), ['email' => $user->email]); +$token = $I->grabRecord(Token::className(), ['user_id' => $user->id, 'type' => Token::TYPE_RECOVERY]); +/** @var yii\swiftmailer\Message $message */ +$message = $I->grabLastSentEmail(); +$I->assertArrayHasKey($user->email, $message->getTo()); +$I->assertContains(Html::encode($token->getUrl()), utf8_encode(quoted_printable_decode($message->getSwiftMessage()->toString()))); + +$I->amGoingTo('reset password with invalid token'); +$user = $I->grabFixture('user', 'user_with_expired_recovery_token'); +$token = $I->grabRecord(Token::className(), ['user_id' => $user->id, 'type' => Token::TYPE_RECOVERY]); +$I->amOnPage(Url::toRoute(['/user/recovery/reset', 'id' => $user->id, 'code' => $token->code])); +$I->see('Recovery link is invalid or expired. Please try requesting a new one.'); + +$I->amGoingTo('reset password'); +$user = $I->grabFixture('user', 'user_with_recovery_token'); +$token = $I->grabRecord(Token::className(), ['user_id' => $user->id, 'type' => Token::TYPE_RECOVERY]); +$I->amOnPage(Url::toRoute(['/user/recovery/reset', 'id' => $user->id, 'code' => $token->code])); +$I->fillField('#recovery-form-password', 'newpass'); +$I->click('Finish'); +$I->see('Your password has been changed successfully.'); + +$page = LoginPage::openBy($I); +$page->login($user->email, 'qwerty'); +$I->see('Invalid login or password'); +$page->login($user->email, 'newpass'); +$I->dontSee('Invalid login or password'); diff --git a/tests/functional/RegistrationCest.php b/tests/functional/RegistrationCest.php new file mode 100644 index 0000000..6b6cba8 --- /dev/null +++ b/tests/functional/RegistrationCest.php @@ -0,0 +1,104 @@ +haveFixtures(['user' => UserFixture::className()]); + } + + public function _after(FunctionalTester $I) + { + \Yii::$container->set(Module::className(), [ + 'enableConfirmation' => true, + 'enableGeneratingPassword' => false, + ]); + } + + /** + * Tests registration with email, username and password without any confirmation. + * @param FunctionalTester $I + */ + public function testRegistration(FunctionalTester $I) + { + \Yii::$container->set(Module::className(), [ + 'enableConfirmation' => false, + 'enableGeneratingPassword' => false, + ]); + + $page = RegistrationPage::openBy($I); + + $I->amGoingTo('try to register with empty credentials'); + $page->register('', '', ''); + $I->see('Username cannot be blank'); + $I->see('Email cannot be blank'); + $I->see('Password cannot be blank'); + + $I->amGoingTo('try to register with already used email and username'); + $user = $I->grabFixture('user', 'user'); + + $page->register($user->email, $user->username, 'qwerty'); + $I->see(Html::encode('This username has already been taken')); + $I->see(Html::encode('This email address has already been taken')); + + $page->register('tester@example.com', 'tester', 'tester'); + $I->see('Your account has been created and a message with further instructions has been sent to your email'); + $user = $I->grabRecord(User::className(), ['email' => 'tester@example.com']); + $I->assertTrue($user->isConfirmed); + + $page = LoginPage::openBy($I); + $page->login('tester', 'tester'); + $I->see('Logout'); + } + + /** + * Tests registration when confirmation message is sent. + * @param FunctionalTester $I + */ + public function testRegistrationWithConfirmation(FunctionalTester $I) + { + \Yii::$container->set(Module::className(), [ + 'enableConfirmation' => true, + ]); + $page = RegistrationPage::openBy($I); + $page->register('tester@example.com', 'tester', 'tester'); + $I->see('Your account has been created and a message with further instructions has been sent to your email'); + $user = $I->grabRecord(User::className(), ['email' => 'tester@example.com']); + $token = $I->grabRecord(Token::className(), ['user_id' => $user->id, 'type' => Token::TYPE_CONFIRMATION]); + /** @var yii\swiftmailer\Message $message */ + $message = $I->grabLastSentEmail(); + $I->assertArrayHasKey($user->email, $message->getTo()); + $I->assertContains(Html::encode($token->getUrl()), utf8_encode(quoted_printable_decode($message->getSwiftMessage()->toString()))); + $I->assertFalse($user->isConfirmed); + } + + /** + * Tests registration when password is generated automatically and sent to user. + * @param FunctionalTester $I + */ + public function testRegistrationWithoutPassword(FunctionalTester $I) + { + \Yii::$container->set(Module::className(), [ + 'enableConfirmation' => false, + 'enableGeneratingPassword' => true, + ]); + $page = RegistrationPage::openBy($I); + $page->register('tester@example.com', 'tester'); + $I->see('Your account has been created and a message with further instructions has been sent to your email'); + $user = $I->grabRecord(User::className(), ['email' => 'tester@example.com']); + $I->assertEquals('tester', $user->username); + /** @var yii\swiftmailer\Message $message */ + $message = $I->grabLastSentEmail(); + $I->assertArrayHasKey($user->email, $message->getTo()); + $I->assertContains('We have generated a password for you', utf8_encode(quoted_printable_decode($message->getSwiftMessage()->toString()))); + } +} diff --git a/tests/functional/ResendCept.php b/tests/functional/ResendCept.php new file mode 100644 index 0000000..340e52f --- /dev/null +++ b/tests/functional/ResendCept.php @@ -0,0 +1,29 @@ +wantTo('ensure that resending of confirmation tokens works'); +$I->haveFixtures(['user' => UserFixture::className()]); + +$I->amGoingTo('try to resend token to non-existent user'); +$page = ResendPage::openBy($I); +$page->resend('foo@example.com'); +$I->see('A message has been sent to your email address. It contains a confirmation link that you must click to complete registration.'); + +$I->amGoingTo('try to resend token to already confirmed user'); +$page = ResendPage::openBy($I); +$user = $I->grabFixture('user', 'user'); +$page->resend($user->email); +$I->see('A message has been sent to your email address. It contains a confirmation link that you must click to complete registration.'); + +$I->amGoingTo('try to resend token to unconfirmed user'); +$page = ResendPage::openBy($I); +$user = $I->grabFixture('user', 'unconfirmed'); +$page->resend($user->email); +$I->see('A message has been sent to your email address. It contains a confirmation link that you must click to complete registration.'); diff --git a/tests/functional/SettingsCept.php b/tests/functional/SettingsCept.php new file mode 100644 index 0000000..4ecb6d8 --- /dev/null +++ b/tests/functional/SettingsCept.php @@ -0,0 +1,86 @@ +wantTo('ensure that account settings page work'); +$I->haveFixtures(['user' => UserFixture::className(), 'profile' => ProfileFixture::className()]); + +$page = LoginPage::openBy($I); +$user = $I->grabFixture('user', 'user'); +$page->login($user->username, 'qwerty'); + +$page = SettingsPage::openBy($I); + +$I->amGoingTo('check that current password is required and must be valid'); +$page->update($user->email, $user->username, 'wrong'); +$I->see('Current password is not valid'); + +$I->amGoingTo('check that email is changing properly'); +$page->update('new_user@example.com', $user->username, 'qwerty'); +$I->seeRecord(User::className(), ['email' => $user->email, 'unconfirmed_email' => 'new_user@example.com']); +$I->see('A confirmation message has been sent to your new email address'); +$user = $I->grabRecord(User::className(), ['id' => $user->id]); +$token = $I->grabRecord(Token::className(), ['user_id' => $user->id, 'type' => Token::TYPE_CONFIRM_NEW_EMAIL]); +/** @var yii\swiftmailer\Message $message */ +$message = $I->grabLastSentEmail(); +$I->assertArrayHasKey($user->unconfirmed_email, $message->getTo()); +$I->assertContains(Html::encode($token->getUrl()), utf8_encode(quoted_printable_decode($message->getSwiftMessage()->toString()))); + +Yii::$app->user->logout(); + +$I->amGoingTo('log in using new email address before clicking the confirmation link'); +$page = LoginPage::openBy($I); +$page->login('new_user@example.com', 'qwerty'); +$I->see('Invalid login or password'); + +$I->amGoingTo('log in using new email address after clicking the confirmation link'); +$user->attemptEmailChange($token->code); +$page->login('new_user@example.com', 'qwerty'); +$I->see('Logout'); +$I->seeRecord(User::className(), [ + 'id' => 1, + 'email' => 'new_user@example.com', + 'unconfirmed_email' => null, +]); + +$I->amGoingTo('reset email changing process'); +$page = SettingsPage::openBy($I); +$page->update('user@example.com', $user->username, 'qwerty'); +$I->see('A confirmation message has been sent to your new email address'); +$I->seeRecord(User::className(), [ + 'id' => 1, + 'email' => 'new_user@example.com', + 'unconfirmed_email' => 'user@example.com', +]); +$page->update('new_user@example.com', $user->username, 'qwerty'); +$I->see('Your account details have been updated'); +$I->seeRecord(User::className(), [ + 'id' => 1, + 'email' => 'new_user@example.com', + 'unconfirmed_email' => null, +]); +$I->amGoingTo('change username and password'); +$page->update('new_user@example.com', 'nickname', 'qwerty', '123654'); +$I->see('Your account details have been updated'); +$I->seeRecord(User::className(), [ + 'username' => 'nickname', + 'email' => 'new_user@example.com', +]); + +Yii::$app->user->logout(); + +$I->amGoingTo('login with new credentials'); +$page = LoginPage::openBy($I); +$page->login('nickname', '123654'); +$I->see('Logout'); diff --git a/tests/functional/UpdateCept.php b/tests/functional/UpdateCept.php new file mode 100644 index 0000000..086c78e --- /dev/null +++ b/tests/functional/UpdateCept.php @@ -0,0 +1,26 @@ +wantTo('ensure that user update works'); +$I->haveFixtures(['user' => UserFixture::className()]); + +$loginPage = LoginPage::openBy($I); +$user = $I->grabFixture('user', 'user'); +$loginPage->login($user->email, 'qwerty'); + +$page = UpdatePage::openBy($I, ['id' => $user->id]); + +$page->update('user', 'updated_user@example.com', 'new_pass'); +$I->see('Account details have been updated'); + +Yii::$app->user->logout(); +LoginPage::openBy($I)->login('updated_user@example.com', 'new_pass'); +$I->see('Logout'); diff --git a/tests/functional/_bootstrap.php b/tests/functional/_bootstrap.php new file mode 100644 index 0000000..b3d9bbc --- /dev/null +++ b/tests/functional/_bootstrap.php @@ -0,0 +1 @@ +