diff --git a/api/config/main.php b/api/config/main.php index 79cad52..ca23f7a 100644 --- a/api/config/main.php +++ b/api/config/main.php @@ -13,7 +13,7 @@ return [ 'controllerNamespace' => 'api\controllers', 'components' => [ 'user' => [ - 'identityClass' => 'common\models\User', + 'identityClass' => 'common\models\Account', 'enableAutoLogin' => true, ], 'log' => [ @@ -28,6 +28,17 @@ return [ 'errorHandler' => [ 'errorAction' => 'site/error', ], + 'request' => [ + 'baseUrl' => '/api', + ], + 'urlManager' => [ + 'enablePrettyUrl' => true, + 'showScriptName' => false, + 'rules' => [], + ], + ], + 'modules' => [ + 'login' => 'api\modules\login\Module', ], 'params' => $params, ]; diff --git a/api/controllers/Controller.php b/api/controllers/Controller.php new file mode 100644 index 0000000..c139046 --- /dev/null +++ b/api/controllers/Controller.php @@ -0,0 +1,17 @@ +_user === null) { - $this->_user = User::findByUsername($this->username); + $this->_user = Account::findByEmail($this->username); } return $this->_user; diff --git a/api/models/PasswordResetRequestForm.php b/api/models/PasswordResetRequestForm.php index 2ef15ba..f691252 100644 --- a/api/models/PasswordResetRequestForm.php +++ b/api/models/PasswordResetRequestForm.php @@ -1,7 +1,7 @@ '\common\models\User', - 'filter' => ['status' => User::STATUS_ACTIVE], + 'filter' => ['status' => Account::STATUS_ACTIVE], 'message' => 'There is no user with such email.' ], ]; @@ -35,14 +35,14 @@ class PasswordResetRequestForm extends Model */ public function sendEmail() { - /* @var $user User */ - $user = User::findOne([ - 'status' => User::STATUS_ACTIVE, + /* @var $user Account */ + $user = Account::findOne([ + 'status' => Account::STATUS_ACTIVE, 'email' => $this->email, ]); if ($user) { - if (!User::isPasswordResetTokenValid($user->password_reset_token)) { + if (!Account::isPasswordResetTokenValid($user->password_reset_token)) { $user->generatePasswordResetToken(); } diff --git a/api/models/ResetPasswordForm.php b/api/models/ResetPasswordForm.php index a139867..a8ea443 100644 --- a/api/models/ResetPasswordForm.php +++ b/api/models/ResetPasswordForm.php @@ -1,7 +1,7 @@ _user = User::findByPasswordResetToken($token); + $this->_user = Account::findByPasswordResetToken($token); if (!$this->_user) { throw new InvalidParamException('Wrong password reset token.'); } diff --git a/api/models/SignupForm.php b/api/models/SignupForm.php index 94917eb..ab419e1 100644 --- a/api/models/SignupForm.php +++ b/api/models/SignupForm.php @@ -1,7 +1,7 @@ validate()) { - $user = new User(); - $user->username = $this->username; + $user = new Account(); $user->email = $this->email; $user->setPassword($this->password); $user->generateAuthKey(); diff --git a/api/modules/login/Module.php b/api/modules/login/Module.php new file mode 100644 index 0000000..dfbdc36 --- /dev/null +++ b/api/modules/login/Module.php @@ -0,0 +1,9 @@ + [ + 'class' => AccessControl::className(), + 'only' => ['login-info'], + 'rules' => [ + [ + 'actions' => ['login-info'], + 'allow' => true, + 'roles' => ['?'], + ], + ], + ], + ]); + } + + public function verbs() { + return [ + 'loginInfo' => ['post'], + ]; + } + + public function actionLoginInfo() { + $model = new AuthenticationForm(); + $model->load(Yii::$app->request->post()); + if (!$model->login()) { + return [ + 'success' => false, + 'errors' => $model->getErrors(), + ]; + } + + return [ + 'success' => true, + ]; + } + +} diff --git a/api/modules/login/controllers/DefaultController.php b/api/modules/login/controllers/DefaultController.php new file mode 100644 index 0000000..57bc9e3 --- /dev/null +++ b/api/modules/login/controllers/DefaultController.php @@ -0,0 +1,12 @@ + 'world']; + } + +} diff --git a/api/modules/login/models/.gitkeep b/api/modules/login/models/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/api/modules/login/models/AuthenticationForm.php b/api/modules/login/models/AuthenticationForm.php new file mode 100644 index 0000000..dd757f6 --- /dev/null +++ b/api/modules/login/models/AuthenticationForm.php @@ -0,0 +1,70 @@ + 'error.email_required'], + ['email', 'email', 'message' => 'error.email_invalid'], + ['email', 'validateEmail'], + + ['password', 'required', 'message' => 'error.password_required'], + ['password', 'validatePassword'], + + ['rememberMe', 'boolean'], + ]; + } + + public function validateEmail($attribute) { + if (!$this->hasErrors()) { + if ($this->getAccount() === NULL) { + $this->addError($attribute, 'error.email_not_exist'); + } + } + } + + public function validatePassword($attribute) { + if (!$this->hasErrors()) { + $account = $this->getAccount(); + if (!$account || !$account->validatePassword($this->password)) { + $this->addError($attribute, 'error.password_incorrect'); + } + } + } + + /** + * Logs in a user using the provided username and password. + * + * @return boolean whether the user is logged in successfully + */ + public function login() { + if (!$this->validate()) { + return false; + } + + return Yii::$app->user->login($this->getAccount(), $this->rememberMe ? 3600 * 24 * 30 : 0); + } + + /** + * @return Account|null + */ + protected function getAccount() { + if ($this->_user === NULL) { + $this->_user = Account::findByEmail($this->email); + } + + return $this->_user; + } + +} diff --git a/api/views/layouts/main.php b/api/views/layouts/main.php index 0afb7ed..a4da544 100644 --- a/api/views/layouts/main.php +++ b/api/views/layouts/main.php @@ -34,17 +34,17 @@ AppAsset::register($this); ], ]); $menuItems = [ - ['label' => 'Home', 'url' => ['/site/index']], - ['label' => 'About', 'url' => ['/site/about']], - ['label' => 'Contact', 'url' => ['/site/contact']], + ['label' => 'Home', 'url' => ['site/index']], + ['label' => 'About', 'url' => ['site/about']], + ['label' => 'Contact', 'url' => ['site/contact']], ]; if (Yii::$app->user->isGuest) { - $menuItems[] = ['label' => 'Signup', 'url' => ['/site/signup']]; - $menuItems[] = ['label' => 'Login', 'url' => ['/site/login']]; + $menuItems[] = ['label' => 'Signup', 'url' => ['site/signup']]; + $menuItems[] = ['label' => 'Login', 'url' => ['site/login']]; } else { $menuItems[] = [ 'label' => 'Logout (' . Yii::$app->user->identity->username . ')', - 'url' => ['/site/logout'], + 'url' => ['site/logout'], 'linkOptions' => ['data-method' => 'post'] ]; } diff --git a/api/views/site/login.php b/api/views/site/login.php index fe67ee0..60e411a 100644 --- a/api/views/site/login.php +++ b/api/views/site/login.php @@ -2,10 +2,10 @@ /* @var $this yii\web\View */ /* @var $form yii\bootstrap\ActiveForm */ -/* @var $model \common\models\LoginForm */ +/* @var $model \api\models\LoginForm */ -use yii\helpers\Html; use yii\bootstrap\ActiveForm; +use yii\helpers\Html; $this->title = 'Login'; $this->params['breadcrumbs'][] = $this->title; diff --git a/common/components/UserPass.php b/common/components/UserPass.php new file mode 100644 index 0000000..6c2a6d7 --- /dev/null +++ b/common/components/UserPass.php @@ -0,0 +1,15 @@ + 'yii\swiftmailer\Mailer', 'viewPath' => '@common/mail', ], + 'security' => [ + 'passwordHashStrategy' => 'password_hash', + ] ], ]; diff --git a/common/mail/passwordResetToken-html.php b/common/mail/passwordResetToken-html.php index f3daf49..451d21d 100644 --- a/common/mail/passwordResetToken-html.php +++ b/common/mail/passwordResetToken-html.php @@ -2,12 +2,12 @@ use yii\helpers\Html; /* @var $this yii\web\View */ -/* @var $user common\models\User */ +/* @var $user common\models\Account */ $resetLink = Yii::$app->urlManager->createAbsoluteUrl(['site/reset-password', 'token' => $user->password_reset_token]); ?>
-

Hello username) ?>,

+

Hello email) ?>,

Follow the link below to reset your password:

diff --git a/common/mail/passwordResetToken-text.php b/common/mail/passwordResetToken-text.php index 244c0cb..936889d 100644 --- a/common/mail/passwordResetToken-text.php +++ b/common/mail/passwordResetToken-text.php @@ -1,11 +1,11 @@ urlManager->createAbsoluteUrl(['site/reset-password', 'token' => $user->password_reset_token]); ?> -Hello username ?>, +Hello email ?>, Follow the link below to reset your password: diff --git a/common/models/Account.php b/common/models/Account.php new file mode 100644 index 0000000..c7ed76a --- /dev/null +++ b/common/models/Account.php @@ -0,0 +1,208 @@ + $id]); + } + + /** + * @inheritdoc + */ + public static function findIdentityByAccessToken($token, $type = null) { + throw new NotSupportedException('"findIdentityByAccessToken" is not implemented.'); + } + + /** + * @param string $email + * @return static|null + */ + public static function findByEmail($email) { + return static::findOne(['email' => $email]); + } + + /** + * Finds user by password reset token + * + * @param string $token password reset token + * + * @return static|null + * + * TODO: этот метод нужно убрать из базовой модели + */ + public static function findByPasswordResetToken($token) { + if (!static::isPasswordResetTokenValid($token)) { + return null; + } + + return static::findOne([ + 'password_reset_token' => $token, + 'status' => self::STATUS_ACTIVE, + ]); + } + + /** + * Finds out if password reset token is valid + * + * @param string $token password reset token + * + * @return boolean + * + * TODO: этот метод нужно убрать из базовой модели + */ + public static function isPasswordResetTokenValid($token) { + if (empty($token)) { + return false; + } + + $timestamp = (int) substr($token, strrpos($token, '_') + 1); + $expire = Yii::$app->params['user.passwordResetTokenExpire']; + + return $timestamp + $expire >= time(); + } + + /** + * @inheritdoc + */ + public function getId() { + return $this->getPrimaryKey(); + } + + /** + * @inheritdoc + */ + public function getAuthKey() { + return $this->auth_key; + } + + /** + * @inheritdoc + */ + public function validateAuthKey($authKey) { + return $this->getAuthKey() === $authKey; + } + + /** + * Validates password + * + * @param string $password password to validate + * @param integer $passwordHashStrategy + * + * @return bool if password provided is valid for current user + * @throws InvalidConfigException + */ + public function validatePassword($password, $passwordHashStrategy = NULL) { + if ($passwordHashStrategy === NULL) { + $passwordHashStrategy = $this->password_hash_strategy; + } + + switch($passwordHashStrategy) { + case self::PASS_HASH_STRATEGY_OLD_ELY: + $hashedPass = UserPass::make($this->email, $password); + return $hashedPass === $this->password_hash; + + case self::PASS_HASH_STRATEGY_YII2: + return Yii::$app->security->validatePassword($password, $this->password_hash); + + default: + throw new InvalidConfigException('You must set valid password_hash_strategy before you can validate password'); + } + } + + /** + * @param string $password + * @throws InvalidConfigException + */ + public function setPassword($password) { + switch($this->password_hash_strategy) { + case self::PASS_HASH_STRATEGY_OLD_ELY: + $password = UserPass::make($this->email, $password); + break; + + case self::PASS_HASH_STRATEGY_YII2: + $password = Yii::$app->security->generatePasswordHash($password); + break; + + default: + throw new InvalidConfigException('You must specify password_hash_strategy before you can set password'); + } + + $this->password_hash = $password; + } + + /** + * Generates "remember me" authentication key + */ + public function generateAuthKey() { + $this->auth_key = Yii::$app->security->generateRandomString(); + } + + /** + * Generates new password reset token + * + * TODO: этот метод нужно отсюда убрать + */ + public function generatePasswordResetToken() { + $this->password_reset_token = Yii::$app->security->generateRandomString() . '_' . time(); + } + + /** + * Removes password reset token + * + * TODO: этот метод нужно отсюда убрать + */ + public function removePasswordResetToken() { + $this->password_reset_token = null; + } + +} diff --git a/common/models/User.php b/common/models/User.php deleted file mode 100644 index ce78fcd..0000000 --- a/common/models/User.php +++ /dev/null @@ -1,188 +0,0 @@ - self::STATUS_ACTIVE], - ['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_DELETED]], - ]; - } - - /** - * @inheritdoc - */ - public static function findIdentity($id) - { - return static::findOne(['id' => $id, 'status' => self::STATUS_ACTIVE]); - } - - /** - * @inheritdoc - */ - public static function findIdentityByAccessToken($token, $type = null) - { - throw new NotSupportedException('"findIdentityByAccessToken" is not implemented.'); - } - - /** - * Finds user by username - * - * @param string $username - * @return static|null - */ - public static function findByUsername($username) - { - return static::findOne(['username' => $username, 'status' => self::STATUS_ACTIVE]); - } - - /** - * Finds user by password reset token - * - * @param string $token password reset token - * @return static|null - */ - public static function findByPasswordResetToken($token) - { - if (!static::isPasswordResetTokenValid($token)) { - return null; - } - - return static::findOne([ - 'password_reset_token' => $token, - 'status' => self::STATUS_ACTIVE, - ]); - } - - /** - * Finds out if password reset token is valid - * - * @param string $token password reset token - * @return boolean - */ - public static function isPasswordResetTokenValid($token) - { - if (empty($token)) { - return false; - } - - $timestamp = (int) substr($token, strrpos($token, '_') + 1); - $expire = Yii::$app->params['user.passwordResetTokenExpire']; - return $timestamp + $expire >= time(); - } - - /** - * @inheritdoc - */ - public function getId() - { - return $this->getPrimaryKey(); - } - - /** - * @inheritdoc - */ - public function getAuthKey() - { - return $this->auth_key; - } - - /** - * @inheritdoc - */ - public function validateAuthKey($authKey) - { - return $this->getAuthKey() === $authKey; - } - - /** - * Validates password - * - * @param string $password password to validate - * @return boolean if password provided is valid for current user - */ - public function validatePassword($password) - { - return Yii::$app->security->validatePassword($password, $this->password_hash); - } - - /** - * Generates password hash from password and sets it to the model - * - * @param string $password - */ - public function setPassword($password) - { - $this->password_hash = Yii::$app->security->generatePasswordHash($password); - } - - /** - * Generates "remember me" authentication key - */ - public function generateAuthKey() - { - $this->auth_key = Yii::$app->security->generateRandomString(); - } - - /** - * Generates new password reset token - */ - public function generatePasswordResetToken() - { - $this->password_reset_token = Yii::$app->security->generateRandomString() . '_' . time(); - } - - /** - * Removes password reset token - */ - public function removePasswordResetToken() - { - $this->password_reset_token = null; - } -} diff --git a/composer.json b/composer.json index 22993b0..8fe35f8 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,8 @@ "php": ">=5.4.0", "yiisoft/yii2": ">=2.0.6", "yiisoft/yii2-bootstrap": "*", - "yiisoft/yii2-swiftmailer": "*" + "yiisoft/yii2-swiftmailer": "*", + "ramsey/uuid": "^3.1" }, "require-dev": { "yiisoft/yii2-codeception": "*", diff --git a/console/config/main.php b/console/config/main.php index 2c7d7d4..f6cdd06 100644 --- a/console/config/main.php +++ b/console/config/main.php @@ -21,5 +21,11 @@ return [ ], ], ], + 'controllerMap' => [ + 'migrate' => [ + 'class' => 'yii\console\controllers\MigrateController', + 'templateFile' => '@console/views/migration.php', + ], + ], 'params' => $params, ]; diff --git a/console/db/Migration.php b/console/db/Migration.php new file mode 100644 index 0000000..c2effcb --- /dev/null +++ b/console/db/Migration.php @@ -0,0 +1,21 @@ +db->driverName === 'mysql') { + // http://stackoverflow.com/questions/766809/whats-the-difference-between-utf8-general-ci-and-utf8-unicode-ci + $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE=' . $engine; + } + + return $tableOptions; + } + +} diff --git a/console/migrations/m130524_201442_init.php b/console/migrations/m130524_201442_init.php index 81a322a..68a7130 100644 --- a/console/migrations/m130524_201442_init.php +++ b/console/migrations/m130524_201442_init.php @@ -1,34 +1,26 @@ db->driverName === 'mysql') { - // http://stackoverflow.com/questions/766809/whats-the-difference-between-utf8-general-ci-and-utf8-unicode-ci - $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB'; - } +class m130524_201442_init extends Migration { - $this->createTable('{{%user}}', [ + public function up() { + $this->createTable('{{%accounts}}', [ 'id' => $this->primaryKey(), - 'username' => $this->string()->notNull()->unique(), - 'auth_key' => $this->string(32)->notNull(), - 'password_hash' => $this->string()->notNull(), - 'password_reset_token' => $this->string()->unique(), + 'uuid' => $this->string(36)->notNull(), 'email' => $this->string()->notNull()->unique(), - - 'status' => $this->smallInteger()->notNull()->defaultValue(10), + 'password_hash' => $this->string()->notNull(), + 'password_hash_strategy' => $this->smallInteger()->notNull(), + 'password_reset_token' => $this->string()->unique(), + 'status' => $this->smallInteger()->notNull()->defaultValue(0), + 'auth_key' => $this->string(32)->notNull(), 'created_at' => $this->integer()->notNull(), 'updated_at' => $this->integer()->notNull(), - ], $tableOptions); + ], $this->tableOptions); } - public function down() - { - $this->dropTable('{{%user}}'); + public function down() { + $this->dropTable('{{%accounts}}'); } + } diff --git a/console/views/migration.php b/console/views/migration.php new file mode 100644 index 0000000..4fc8b4a --- /dev/null +++ b/console/views/migration.php @@ -0,0 +1,19 @@ + + +use console\db\Migration; + +class extends Migration { + + public function safeUp() { + + } + + public function safeDown() { + + } + +} diff --git a/tests/codeception/api/_pages/LoginRoute.php b/tests/codeception/api/_pages/LoginRoute.php new file mode 100644 index 0000000..666dcaa --- /dev/null +++ b/tests/codeception/api/_pages/LoginRoute.php @@ -0,0 +1,21 @@ +actor->sendPOST($this->getUrl(), [ + 'email' => $email, + 'password' => $password, + ]); + } + +} diff --git a/tests/codeception/api/acceptance/LoginCept.php b/tests/codeception/api/acceptance/LoginCept.php index 21f3148..b117319 100644 --- a/tests/codeception/api/acceptance/LoginCept.php +++ b/tests/codeception/api/acceptance/LoginCept.php @@ -1,13 +1,13 @@ wantTo('ensure login page works'); -$loginPage = LoginPage::openBy($I); +$loginPage = LoginRoute::openBy($I); $I->amGoingTo('submit login form with no data'); $loginPage->login('', ''); diff --git a/tests/codeception/api/acceptance/SignupCest.php b/tests/codeception/api/acceptance/SignupCest.php index 96822f6..991a39a 100644 --- a/tests/codeception/api/acceptance/SignupCest.php +++ b/tests/codeception/api/acceptance/SignupCest.php @@ -3,7 +3,7 @@ namespace tests\codeception\api\acceptance; use tests\codeception\api\_pages\SignupPage; -use common\models\User; +use common\models\Account; class SignupCest { @@ -22,7 +22,7 @@ class SignupCest */ public function _after($event) { - User::deleteAll([ + Account::deleteAll([ 'email' => 'tester.email@example.com', 'username' => 'tester', ]); diff --git a/tests/codeception/api/functional.suite.yml b/tests/codeception/api/functional.suite.yml index 060efe1..b2bbce8 100644 --- a/tests/codeception/api/functional.suite.yml +++ b/tests/codeception/api/functional.suite.yml @@ -12,6 +12,7 @@ modules: - Filesystem - Yii2 - tests\codeception\common\_support\FixtureHelper + - REST config: Yii2: configFile: '../config/api/functional.php' diff --git a/tests/codeception/api/functional/LoginCept.php b/tests/codeception/api/functional/LoginCept.php index 79afe51..38be956 100644 --- a/tests/codeception/api/functional/LoginCept.php +++ b/tests/codeception/api/functional/LoginCept.php @@ -1,23 +1,33 @@ wantTo('ensure login page works'); -$loginPage = LoginPage::openBy($I); +$loginPage = LoginRoute::openBy($I); $I->amGoingTo('submit login form with no data'); $loginPage->login('', ''); $I->expectTo('see validations errors'); -$I->see('Username cannot be blank.', '.help-block'); -$I->see('Password cannot be blank.', '.help-block'); +$I->canSeeResponseContainsJson([ + 'success' => false, + 'errors' => [ + 'email' => [ + 'error.email_required', + ], + 'password' => [ + 'error.password_required', + ], + ], +]); +/* $I->amGoingTo('try to login with wrong credentials'); $I->expectTo('see validations errors'); -$loginPage->login('admin', 'wrong'); +$loginPage->login('', 'wrong'); $I->expectTo('see validations errors'); $I->see('Incorrect username or password.', '.help-block'); @@ -27,3 +37,4 @@ $I->expectTo('see that user is logged'); $I->seeLink('Logout (erau)'); $I->dontSeeLink('Login'); $I->dontSeeLink('Signup'); +*/ diff --git a/tests/codeception/api/functional/SignupCest.php b/tests/codeception/api/functional/SignupCest.php index 498c1ae..0e98e28 100644 --- a/tests/codeception/api/functional/SignupCest.php +++ b/tests/codeception/api/functional/SignupCest.php @@ -3,7 +3,7 @@ namespace tests\codeception\api\functional; use tests\codeception\api\_pages\SignupPage; -use common\models\User; +use common\models\Account; class SignupCest { @@ -22,7 +22,7 @@ class SignupCest */ public function _after($event) { - User::deleteAll([ + Account::deleteAll([ 'email' => 'tester.email@example.com', 'username' => 'tester', ]); diff --git a/tests/codeception/api/unit/fixtures/data/models/accounts.php b/tests/codeception/api/unit/fixtures/data/models/accounts.php new file mode 100644 index 0000000..b6e70ee --- /dev/null +++ b/tests/codeception/api/unit/fixtures/data/models/accounts.php @@ -0,0 +1,15 @@ + 1, + 'uuid' => 'df936908-b2e1-544d-96f8-2977ec213022', + 'password_hash' => '$2y$13$CXT0Rkle1EMJ/c1l5bylL.EylfmQ39O5JlHJVFpNn618OUS1HwaIi', # password_0 + 'password_hash_strategy' => 1, + 'password_reset_token' => NULL, + 'email' => 'admin@ely.by', + 'auth_key' => 'iwTNae9t34OmnK6l4vT4IeaTk-YWI2Rv', + 'status' => 10, + 'created_at' => 1451775316, + 'updated_at' => 1451775316, + ], +]; diff --git a/tests/codeception/api/unit/models/PasswordResetRequestFormTest.php b/tests/codeception/api/unit/models/PasswordResetRequestFormTest.php index 776f19b..dabdd9c 100644 --- a/tests/codeception/api/unit/models/PasswordResetRequestFormTest.php +++ b/tests/codeception/api/unit/models/PasswordResetRequestFormTest.php @@ -6,7 +6,7 @@ use Yii; use tests\codeception\api\unit\DbTestCase; use api\models\PasswordResetRequestForm; use tests\codeception\common\fixtures\UserFixture; -use common\models\User; +use common\models\Account; use Codeception\Specify; class PasswordResetRequestFormTest extends DbTestCase @@ -54,7 +54,7 @@ class PasswordResetRequestFormTest extends DbTestCase { $model = new PasswordResetRequestForm(); $model->email = $this->user[0]['email']; - $user = User::findOne(['password_reset_token' => $this->user[0]['password_reset_token']]); + $user = Account::findOne(['password_reset_token' => $this->user[0]['password_reset_token']]); expect('email sent', $model->sendEmail())->true(); expect('user has valid token', $user->password_reset_token)->notNull(); diff --git a/tests/codeception/api/unit/models/SignupFormTest.php b/tests/codeception/api/unit/models/SignupFormTest.php index e06a46c..86751dd 100644 --- a/tests/codeception/api/unit/models/SignupFormTest.php +++ b/tests/codeception/api/unit/models/SignupFormTest.php @@ -24,7 +24,6 @@ class SignupFormTest extends DbTestCase $this->assertInstanceOf('common\models\User', $user, 'user should be valid'); - expect('username should be correct', $user->username)->equals('some_username'); expect('email should be correct', $user->email)->equals('some_email@example.com'); expect('password should be correct', $user->validatePassword('some_password'))->true(); } diff --git a/tests/codeception/api/unit/modules/login/models/AuthenticationFormTest.php b/tests/codeception/api/unit/modules/login/models/AuthenticationFormTest.php new file mode 100644 index 0000000..a183ab2 --- /dev/null +++ b/tests/codeception/api/unit/modules/login/models/AuthenticationFormTest.php @@ -0,0 +1,124 @@ +user->logout(); + parent::tearDown(); + } + + public function testValidateEmail() { + $model = new AuthenticationForm(); + $this->specify('error.email_required expected if email is not set', function() use ($model) { + $model->validate(['email']); + expect($model->getErrors('email'))->equals(['error.email_required']); + }); + + $this->specify('error.email_invalid expected if email not correct', function() use ($model) { + $model->email = 'wrong-email-string'; + $model->validate(['email']); + expect($model->getErrors('email'))->equals(['error.email_invalid']); + + $model->email = 'wrong@email'; + $model->validate(['email']); + expect($model->getErrors('email'))->equals(['error.email_invalid']); + }); + + $this->specify('error.email_not_exist expected if email not exists in database', function() use ($model) { + $model->email = 'not-exist@user.com'; + $model->validate(['email']); + expect($model->getErrors('email'))->equals(['error.email_not_exist']); + }); + + $this->specify('no errors if email is correct and exists in database', function() use ($model) { + $model->email = 'admin@ely.by'; + $model->validate(['email']); + expect($model->getErrors('email'))->isEmpty(); + }); + } + + public function testValidatePassword() { + $model = new AuthenticationForm(); + $this->specify('error.password_required expected if password is not set', function() use ($model) { + $model->validate(['password']); + expect($model->getErrors('password'))->equals(['error.password_required']); + }); + + $this->specify('error.password_incorrect expected if password not correct for passed email', function() use ($model) { + $model->email = 'non-exist@valid.mail'; + $model->password = 'wrong-password'; + $model->validate(['password']); + expect('if email incorrect, the error should be displayed in any case,', $model->getErrors('password')) + ->equals(['error.password_incorrect']); + + $model->email = 'admin@ely.by'; + $model->password = 'wrong-password'; + $model->validate(['password']); + expect($model->getErrors('password'))->equals(['error.password_incorrect']); + }); + + $this->specify('no errors if email and password is correct and exists in database', function() use ($model) { + $model->email = 'admin@ely.by'; + $model->password = 'password_0'; + $model->validate(['password']); + expect($model->getErrors('password'))->isEmpty(); + }); + } + + public function testLoginNoUser() { + $model = new AuthenticationForm([ + 'email' => 'non-exist@valid.mail', + 'password' => 'not_existing_password', + ]); + + $this->specify('user should not be able to login, when there is no identity', function () use ($model) { + expect('model should not login user', $model->login())->false(); + expect('user should not be logged in', Yii::$app->user->isGuest)->true(); + }); + } + + public function testLoginWrongPassword() { + $model = new AuthenticationForm([ + 'email' => 'admin@ely.by', + 'password' => 'wrong_password', + ]); + + $this->specify('user should not be able to login with wrong password', function () use ($model) { + expect('model should not login user', $model->login())->false(); + expect('error message should be set', $model->errors)->hasKey('password'); + expect('user should not be logged in', Yii::$app->user->isGuest)->true(); + }); + } + + public function testLoginCorrect() { + $model = new AuthenticationForm([ + 'email' => 'admin@ely.by', + 'password' => 'password_0', + ]); + + $this->specify('user should be able to login with correct credentials', function () use ($model) { + expect('model should login user', $model->login())->true(); + expect('error message should not be set', $model->errors)->hasntKey('password'); + expect('user should be logged in', Yii::$app->user->isGuest)->false(); + }); + } + + public function fixtures() { + return [ + 'user' => [ + 'class' => AccountFixture::className(), + 'dataFile' => '@tests/codeception/api/unit/fixtures/data/models/accounts.php' + ], + ]; + } + +} diff --git a/tests/codeception/common/_pages/LoginPage.php b/tests/codeception/common/_pages/LoginPage.php deleted file mode 100644 index d97e266..0000000 --- a/tests/codeception/common/_pages/LoginPage.php +++ /dev/null @@ -1,25 +0,0 @@ -actor->fillField('input[name="LoginForm[username]"]', $username); - $this->actor->fillField('input[name="LoginForm[password]"]', $password); - $this->actor->click('login-button'); - } -} diff --git a/tests/codeception/common/_support/FixtureHelper.php b/tests/codeception/common/_support/FixtureHelper.php index c5ebcf1..2c87db1 100644 --- a/tests/codeception/common/_support/FixtureHelper.php +++ b/tests/codeception/common/_support/FixtureHelper.php @@ -63,10 +63,10 @@ class FixtureHelper extends Module public function fixtures() { return [ - 'user' => [ - 'class' => UserFixture::className(), - 'dataFile' => '@tests/codeception/common/fixtures/data/init_login.php', - ], + //'user' => [ + // 'class' => UserFixture::className(), + // 'dataFile' => '@tests/codeception/common/fixtures/data/init_login.php', + //], ]; } } diff --git a/tests/codeception/common/fixtures/AccountFixture.php b/tests/codeception/common/fixtures/AccountFixture.php new file mode 100644 index 0000000..0053ca8 --- /dev/null +++ b/tests/codeception/common/fixtures/AccountFixture.php @@ -0,0 +1,12 @@ + [ 'db' => [ - 'dsn' => 'mysql:host=localhost;dbname=yii2_advanced_tests', + 'dsn' => 'mysql:host=localhost;dbname=ely_accounts_test', ], 'mailer' => [ 'useFileTransport' => true,