From 1e6c6e0a4fbb9f30f72cc1038467e51b18cd47dc Mon Sep 17 00:00:00 2001 From: Oleh Usik Date: Thu, 16 Apr 2020 13:59:13 +0300 Subject: [PATCH 1/6] Add GraphQL coverage for Reset password for MyAccount --- .../Resolver/RequestPasswordResetEmail.php | 88 +++++++ .../Model/Resolver/ResetPassword.php | 93 +++++++ .../CustomerGraphQl/etc/graphql/di.xml | 9 + .../CustomerGraphQl/etc/schema.graphqls | 8 + .../RequestPasswordResetEmailTest.php | 101 ++++++++ .../GraphQl/Customer/ResetPasswordTest.php | 236 ++++++++++++++++++ 6 files changed, 535 insertions(+) create mode 100644 app/code/Magento/CustomerGraphQl/Model/Resolver/RequestPasswordResetEmail.php create mode 100644 app/code/Magento/CustomerGraphQl/Model/Resolver/ResetPassword.php create mode 100644 dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/RequestPasswordResetEmailTest.php create mode 100644 dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/ResetPasswordTest.php diff --git a/app/code/Magento/CustomerGraphQl/Model/Resolver/RequestPasswordResetEmail.php b/app/code/Magento/CustomerGraphQl/Model/Resolver/RequestPasswordResetEmail.php new file mode 100644 index 0000000000000..c5b45f3ad5597 --- /dev/null +++ b/app/code/Magento/CustomerGraphQl/Model/Resolver/RequestPasswordResetEmail.php @@ -0,0 +1,88 @@ +customerAccountManagement = $customerAccountManagement; + $this->emailValidator = $emailValidator; + } + + /** + * Send password email request + * + * @param Field $field + * @param ContextInterface $context + * @param ResolveInfo $info + * @param array|null $value + * @param array|null $args + * + * @return bool|Value|mixed + * + * @throws GraphQlInputException + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function resolve( + Field $field, + $context, + ResolveInfo $info, + array $value = null, + array $args = null + ) { + if (empty($args['email'])) { + throw new GraphQlInputException(__('Email must be specified')); + } + + if (!$this->emailValidator->isValid($args['email'])) { + throw new GraphQlInputException(__('Email is invalid')); + } + + try { + return $this->customerAccountManagement->initiatePasswordReset( + $args['email'], + AccountManagement::EMAIL_RESET + ); + } catch (LocalizedException $e) { + throw new GraphQlInputException(__($e->getMessage()), $e); + } + } +} diff --git a/app/code/Magento/CustomerGraphQl/Model/Resolver/ResetPassword.php b/app/code/Magento/CustomerGraphQl/Model/Resolver/ResetPassword.php new file mode 100644 index 0000000000000..e07a7d101db44 --- /dev/null +++ b/app/code/Magento/CustomerGraphQl/Model/Resolver/ResetPassword.php @@ -0,0 +1,93 @@ +customerAccountManagement = $customerAccountManagement; + $this->emailValidator = $emailValidator; + } + + /** + * Reset old password and set new + * + * @param Field $field + * @param ContextInterface $context + * @param ResolveInfo $info + * @param array|null $value + * @param array|null $args + * + * @return bool|Value|mixed + * + * @throws GraphQlInputException + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function resolve( + Field $field, + $context, + ResolveInfo $info, + array $value = null, + array $args = null + ) { + if (empty($args['email'])) { + throw new GraphQlInputException(__('Email must be specified')); + } + + if (!$this->emailValidator->isValid($args['email'])) { + throw new GraphQlInputException(__('Email is invalid')); + } + + if (empty($args['resetPasswordToken'])) { + throw new GraphQlInputException(__('resetPasswordToken must be specified')); + } + + if (empty($args['newPassword'])) { + throw new GraphQlInputException(__('newPassword must be specified')); + } + + try { + return $this->customerAccountManagement->resetPassword( + $args['email'], + $args['resetPasswordToken'], + $args['newPassword'] + ); + } catch (LocalizedException $e) { + throw new GraphQlInputException(__($e->getMessage()), $e); + } + } +} diff --git a/app/code/Magento/CustomerGraphQl/etc/graphql/di.xml b/app/code/Magento/CustomerGraphQl/etc/graphql/di.xml index cb4ab0b7b27f4..1ba0e457430e0 100644 --- a/app/code/Magento/CustomerGraphQl/etc/graphql/di.xml +++ b/app/code/Magento/CustomerGraphQl/etc/graphql/di.xml @@ -20,4 +20,13 @@ + + + + customer/password/required_character_classes_number + customer/password/minimum_password_length + customer/password/autocomplete_on_storefront + + + diff --git a/app/code/Magento/CustomerGraphQl/etc/schema.graphqls b/app/code/Magento/CustomerGraphQl/etc/schema.graphqls index 9aa1fdaa841e4..b160747d686e1 100644 --- a/app/code/Magento/CustomerGraphQl/etc/schema.graphqls +++ b/app/code/Magento/CustomerGraphQl/etc/schema.graphqls @@ -1,6 +1,12 @@ # Copyright © Magento, Inc. All rights reserved. # See COPYING.txt for license details. +type StoreConfig @doc(description: "The type contains information about a store config") { + required_character_classes_number : String @doc(description: "Number of Required Character Classes") + minimum_password_length : String @doc(description: "Minimum Password Length") + autocomplete_on_storefront : Boolean @doc(description: "Enable Autocomplete on login or forgot password forms") +} + type Query { customer: Customer @resolver(class: "Magento\\CustomerGraphQl\\Model\\Resolver\\Customer") @doc(description: "The customer query returns information about a customer account") @cache(cacheable: false) isEmailAvailable ( @@ -17,6 +23,8 @@ type Mutation { createCustomerAddress(input: CustomerAddressInput!): CustomerAddress @resolver(class: "Magento\\CustomerGraphQl\\Model\\Resolver\\CreateCustomerAddress") @doc(description: "Create customer address") updateCustomerAddress(id: Int!, input: CustomerAddressInput): CustomerAddress @resolver(class: "Magento\\CustomerGraphQl\\Model\\Resolver\\UpdateCustomerAddress") @doc(description: "Update customer address") deleteCustomerAddress(id: Int!): Boolean @resolver(class: "Magento\\CustomerGraphQl\\Model\\Resolver\\DeleteCustomerAddress") @doc(description: "Delete customer address") + requestPasswordResetEmail(email: String!): Boolean @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\RequestPasswordResetEmail") @doc(description: "Request an email with reset password token for the registered customer identified by the provided email") + resetPassword(email: String!, resetPasswordToken: String!, newPassword: String!): Boolean @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\ResetPassword") @doc(description: "Reset customer password using reset password token received in the email after requesting it using requestPasswordResetEmail") } input CustomerAddressInput { diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/RequestPasswordResetEmailTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/RequestPasswordResetEmailTest.php new file mode 100644 index 0000000000000..7f1bd2c268b77 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/RequestPasswordResetEmailTest.php @@ -0,0 +1,101 @@ +graphQlMutation($query); + + self::assertArrayHasKey('requestPasswordResetEmail', $response); + self::assertTrue($response['requestPasswordResetEmail']); + } + + /** + * Check if customer account is not available + */ + public function testCustomerAccountWithEmailNotAvailable() + { + $query = + <<assertMessage('No such entity with email = customerNotAvalible@example.com, websiteId = 1'); + $this->graphQlMutation($query); + } + + /** + * Check if email value empty + */ + public function testEmailAvailableEmptyValue() + { + $query = <<assertMessage('Email must be specified'); + $this->graphQlMutation($query); + } + + /** + * Check if email is invalid + */ + public function testEmailAvailableInvalidValue() + { + $query = <<assertMessage('Email is invalid'); + $this->graphQlMutation($query); + } + + /** + * Check if email contain right type + */ + public function testEmailAvailableTypeValue() + { + $query = <<graphQlMutation($query); + } + + /** + * Checks Exception and ExceptionMessages + * + * @param $message + */ + private function assertMessage($message) + { + self::expectException(\Exception::class); + self::expectExceptionMessage("GraphQL response contains errors: {$message}"); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/ResetPasswordTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/ResetPasswordTest.php new file mode 100644 index 0000000000000..450ddc3f543e9 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/ResetPasswordTest.php @@ -0,0 +1,236 @@ +objectManager = Bootstrap::getObjectManager(); + $this->accountManagement = $this->objectManager->get(AccountManagementInterface::class); + $this->customerRegistry = $this->objectManager->get(CustomerRegistry::class); + parent::setUp(); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * + * @return void + * @throws NoSuchEntityException + * @throws Exception + * + * @throws LocalizedException + */ + public function testResetCustomerAccountPasswordSuccessfully(): void + { + $query = <<getCustomerEmail()}" + resetPasswordToken: "{$this->getResetPasswordToken()}" + newPassword: "{$this->getNewPassword()}" + ) +} +QUERY; + $response = $this->graphQlMutation($query); + self::assertArrayHasKey('resetPassword', $response); + self::assertTrue($response['resetPassword']); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * + * @throws NoSuchEntityException + * @throws Exception + * @throws LocalizedException + */ + public function testEmailAvailableEmptyValue() + { + $query = <<getResetPasswordToken()}" + newPassword: "{$this->getNewPassword()}" + ) +} +QUERY; + $this->assertMessage('Email must be specified'); + $this->graphQlMutation($query); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * + * @throws NoSuchEntityException + * @throws Exception + * @throws LocalizedException + */ + public function testEmailInvalidValue() + { + $query = <<getResetPasswordToken()}" + newPassword: "{$this->getNewPassword()}" + ) +} +QUERY; + $this->assertMessage('Email is invalid'); + $this->graphQlMutation($query); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * + * @throws NoSuchEntityException + * @throws Exception + * @throws LocalizedException + */ + public function testResetPasswordTokenEmptyValue() + { + $query = <<getCustomerEmail()}" + resetPasswordToken: "" + newPassword: "{$this->getNewPassword()}" + ) +} +QUERY; + $this->assertMessage('resetPasswordToken must be specified'); + $this->graphQlMutation($query); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * + * @throws NoSuchEntityException + * @throws Exception + * @throws LocalizedException + */ + public function testResetPasswordTokenMismatched() + { + $query = <<getCustomerEmail()}" + resetPasswordToken: "1234567890XYZ" + newPassword: "{$this->getNewPassword()}" + ) +} +QUERY; + $this->assertMessage('The password token is mismatched. Reset and try again.'); + $this->graphQlMutation($query); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * + * @throws NoSuchEntityException + * @throws Exception + * @throws LocalizedException + */ + public function testNewPasswordEmptyValue() + { + $query = <<getCustomerEmail()}" + resetPasswordToken: "{$this->getResetPasswordToken()}" + newPassword: "" + ) +} +QUERY; + $this->assertMessage('newPassword must be specified'); + $this->graphQlMutation($query); + } + + /** + * Assert messages + * + * @param $message + */ + private function assertMessage($message) + { + $expectedExceptionsMessage = "GraphQL response contains errors: {$message}"; + $this->expectException(ResponseContainsErrorsException::class); + $this->expectExceptionMessage($expectedExceptionsMessage); + } + + /** + * Get reset password token + * + * @return string + * + * @throws LocalizedException + * @throws NoSuchEntityException + */ + private function getResetPasswordToken() + { + $this->accountManagement->initiatePasswordReset( + $this->getCustomerEmail(), + AccountManagement::EMAIL_RESET, + 1 + ); + + $customerSecure = $this->customerRegistry->retrieveSecureData(1); + return $customerSecure->getRpToken(); + } + + /** + * Get customer email + * + * @return string + */ + private function getCustomerEmail() + { + return self::CUSTOMER_EMAIL; + } + + /** + * Get new password for customer account + * + * @return string + */ + private function getNewPassword() + { + return self::CUSTOMER_NEW_PASSWORD; + } +} From e56700063c30baa9cc70fdf6516770e7eb169a8f Mon Sep 17 00:00:00 2001 From: Oleh Usik Date: Tue, 28 Apr 2020 13:53:58 +0300 Subject: [PATCH 2/6] Added scenario for locked customer and fixed some minors issues --- .../Resolver/RequestPasswordResetEmail.php | 34 +++++++++++- .../Model/Resolver/ResetPassword.php | 39 +++++++++++-- .../RequestPasswordResetEmailTest.php | 55 +++++++++++-------- .../GraphQl/Customer/ResetPasswordTest.php | 53 ++++++++++++++---- 4 files changed, 140 insertions(+), 41 deletions(-) diff --git a/app/code/Magento/CustomerGraphQl/Model/Resolver/RequestPasswordResetEmail.php b/app/code/Magento/CustomerGraphQl/Model/Resolver/RequestPasswordResetEmail.php index c5b45f3ad5597..fdcc9f12eea60 100644 --- a/app/code/Magento/CustomerGraphQl/Model/Resolver/RequestPasswordResetEmail.php +++ b/app/code/Magento/CustomerGraphQl/Model/Resolver/RequestPasswordResetEmail.php @@ -8,7 +8,9 @@ namespace Magento\CustomerGraphQl\Model\Resolver; use Magento\Customer\Api\AccountManagementInterface; +use Magento\Customer\Api\CustomerRepositoryInterface; use Magento\Customer\Model\AccountManagement; +use Magento\Customer\Model\AuthenticationInterface; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\GraphQl\Config\Element\Field; use Magento\Framework\GraphQl\Exception\GraphQlInputException; @@ -23,6 +25,16 @@ */ class RequestPasswordResetEmail implements ResolverInterface { + /** + * @var AuthenticationInterface + */ + private $authentication; + + /** + * @var CustomerRepositoryInterface + */ + private $customerRepository; + /** * @var AccountManagementInterface */ @@ -36,13 +48,19 @@ class RequestPasswordResetEmail implements ResolverInterface /** * RequestPasswordResetEmail constructor. * - * @param AccountManagementInterface $customerAccountManagement - * @param EmailValidator $emailValidator + * @param AuthenticationInterface $authentication + * @param CustomerRepositoryInterface $customerRepository + * @param AccountManagementInterface $customerAccountManagement + * @param EmailValidator $emailValidator */ public function __construct( + AuthenticationInterface $authentication, + CustomerRepositoryInterface $customerRepository, AccountManagementInterface $customerAccountManagement, EmailValidator $emailValidator ) { + $this->authentication = $authentication; + $this->customerRepository = $customerRepository; $this->customerAccountManagement = $customerAccountManagement; $this->emailValidator = $emailValidator; } @@ -76,13 +94,23 @@ public function resolve( throw new GraphQlInputException(__('Email is invalid')); } + try { + $customer = $this->customerRepository->get($args['email']); + } catch (LocalizedException $e) { + throw new GraphQlInputException(__('Cannot reset customer password'), $e); + } + + if (true === $this->authentication->isLocked($customer->getId())) { + throw new GraphQlInputException(__("The current customer isn't authorized")); + } + try { return $this->customerAccountManagement->initiatePasswordReset( $args['email'], AccountManagement::EMAIL_RESET ); } catch (LocalizedException $e) { - throw new GraphQlInputException(__($e->getMessage()), $e); + throw new GraphQlInputException(__("Cannot reset customer password"), $e); } } } diff --git a/app/code/Magento/CustomerGraphQl/Model/Resolver/ResetPassword.php b/app/code/Magento/CustomerGraphQl/Model/Resolver/ResetPassword.php index e07a7d101db44..515b965952aed 100644 --- a/app/code/Magento/CustomerGraphQl/Model/Resolver/ResetPassword.php +++ b/app/code/Magento/CustomerGraphQl/Model/Resolver/ResetPassword.php @@ -8,6 +8,8 @@ namespace Magento\CustomerGraphQl\Model\Resolver; use Magento\Customer\Api\AccountManagementInterface; +use Magento\Customer\Api\CustomerRepositoryInterface; +use Magento\Customer\Model\AuthenticationInterface; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\GraphQl\Config\Element\Field; use Magento\Framework\GraphQl\Exception\GraphQlInputException; @@ -17,6 +19,9 @@ use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; use Magento\Framework\Validator\EmailAddress as EmailValidator; +/** + * Class Resolver for ResetPassword + */ class ResetPassword implements ResolverInterface { /** @@ -30,15 +35,31 @@ class ResetPassword implements ResolverInterface private $emailValidator; /** - * RequestPasswordResetEmail constructor. + * @var AuthenticationInterface + */ + private $authentication; + + /** + * @var CustomerRepositoryInterface + */ + private $customerRepository; + + /** + * ResetPassword constructor. * - * @param AccountManagementInterface $customerAccountManagement - * @param EmailValidator $emailValidator + * @param AuthenticationInterface $authentication + * @param CustomerRepositoryInterface $customerRepository + * @param AccountManagementInterface $customerAccountManagement + * @param EmailValidator $emailValidator */ public function __construct( + AuthenticationInterface $authentication, + CustomerRepositoryInterface $customerRepository, AccountManagementInterface $customerAccountManagement, EmailValidator $emailValidator ) { + $this->authentication = $authentication; + $this->customerRepository = $customerRepository; $this->customerAccountManagement = $customerAccountManagement; $this->emailValidator = $emailValidator; } @@ -80,6 +101,16 @@ public function resolve( throw new GraphQlInputException(__('newPassword must be specified')); } + try { + $customer = $this->customerRepository->get($args['email']); + } catch (LocalizedException $e) { + throw new GraphQlInputException(__('Cannot set customer password'), $e); + } + + if (true === $this->authentication->isLocked($customer->getId())) { + throw new GraphQlInputException(__("The current customer isn't authorized")); + } + try { return $this->customerAccountManagement->resetPassword( $args['email'], @@ -87,7 +118,7 @@ public function resolve( $args['newPassword'] ); } catch (LocalizedException $e) { - throw new GraphQlInputException(__($e->getMessage()), $e); + throw new GraphQlInputException(__('Cannot set customer password'), $e); } } } diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/RequestPasswordResetEmailTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/RequestPasswordResetEmailTest.php index 7f1bd2c268b77..f08badeb5732d 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/RequestPasswordResetEmailTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/RequestPasswordResetEmailTest.php @@ -7,10 +7,22 @@ namespace Magento\GraphQl\Customer; +use Magento\TestFramework\Helper\Bootstrap; use Magento\TestFramework\TestCase\GraphQlAbstract; class RequestPasswordResetEmailTest extends GraphQlAbstract { + /** + * @var LockCustomer + */ + private $lockCustomer; + + protected function setUp(): void + { + parent::setUp(); + + $this->lockCustomer = Bootstrap::getObjectManager()->get(LockCustomer::class); + } /** * @magentoApiDataFixture Magento/Customer/_files/customer.php */ @@ -30,6 +42,9 @@ public function testCustomerAccountWithEmailAvailable() /** * Check if customer account is not available + * + * @expectedException \Exception + * @expectedExceptionMessage Cannot reset customer password */ public function testCustomerAccountWithEmailNotAvailable() { @@ -39,12 +54,14 @@ public function testCustomerAccountWithEmailNotAvailable() requestPasswordResetEmail(email: "customerNotAvalible@example.com") } QUERY; - $this->assertMessage('No such entity with email = customerNotAvalible@example.com, websiteId = 1'); $this->graphQlMutation($query); } /** * Check if email value empty + * + * @expectedException \Exception + * @expectedExceptionMessage Email must be specified */ public function testEmailAvailableEmptyValue() { @@ -53,12 +70,14 @@ public function testEmailAvailableEmptyValue() requestPasswordResetEmail(email: "") } QUERY; - $this->assertMessage('Email must be specified'); $this->graphQlMutation($query); } /** * Check if email is invalid + * + * @expectedException \Exception + * @expectedExceptionMessage Email is invalid */ public function testEmailAvailableInvalidValue() { @@ -67,35 +86,27 @@ public function testEmailAvailableInvalidValue() requestPasswordResetEmail(email: "invalid-email") } QUERY; - $this->assertMessage('Email is invalid'); $this->graphQlMutation($query); } /** - * Check if email contain right type + * Check if email was sent for lock customer + * + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * + * @expectedException \Exception + * @expectedExceptionMessage The current customer isn't authorized */ - public function testEmailAvailableTypeValue() + public function testRequestPasswordResetEmailForLockCustomer() { - $query = <<lockCustomer->execute(1); + $query = + <<graphQlMutation($query); - } - /** - * Checks Exception and ExceptionMessages - * - * @param $message - */ - private function assertMessage($message) - { - self::expectException(\Exception::class); - self::expectExceptionMessage("GraphQL response contains errors: {$message}"); + $this->graphQlMutation($query); } } diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/ResetPasswordTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/ResetPasswordTest.php index 450ddc3f543e9..bf660ba8c94f2 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/ResetPasswordTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/ResetPasswordTest.php @@ -15,7 +15,6 @@ use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\ObjectManagerInterface; use Magento\TestFramework\Helper\Bootstrap; -use Magento\TestFramework\TestCase\GraphQl\ResponseContainsErrorsException; use Magento\TestFramework\TestCase\GraphQlAbstract; /** @@ -36,6 +35,11 @@ class ResetPasswordTest extends GraphQlAbstract /** @var CustomerRegistry */ private $customerRegistry; + /** + * @var LockCustomer + */ + private $lockCustomer; + /** * @inheritdoc */ @@ -44,6 +48,7 @@ protected function setUp() $this->objectManager = Bootstrap::getObjectManager(); $this->accountManagement = $this->objectManager->get(AccountManagementInterface::class); $this->customerRegistry = $this->objectManager->get(CustomerRegistry::class); + $this->lockCustomer = Bootstrap::getObjectManager()->get(LockCustomer::class); parent::setUp(); } @@ -75,6 +80,9 @@ public function testResetCustomerAccountPasswordSuccessfully(): void /** * @magentoApiDataFixture Magento/Customer/_files/customer.php * + * @expectedException \Exception + * @expectedExceptionMessage Email must be specified + * * @throws NoSuchEntityException * @throws Exception * @throws LocalizedException @@ -90,13 +98,15 @@ public function testEmailAvailableEmptyValue() ) } QUERY; - $this->assertMessage('Email must be specified'); $this->graphQlMutation($query); } /** * @magentoApiDataFixture Magento/Customer/_files/customer.php * + * @expectedException \Exception + * @expectedExceptionMessage Email is invalid + * * @throws NoSuchEntityException * @throws Exception * @throws LocalizedException @@ -112,13 +122,15 @@ public function testEmailInvalidValue() ) } QUERY; - $this->assertMessage('Email is invalid'); $this->graphQlMutation($query); } /** * @magentoApiDataFixture Magento/Customer/_files/customer.php * + * @expectedException \Exception + * @expectedExceptionMessage resetPasswordToken must be specified + * * @throws NoSuchEntityException * @throws Exception * @throws LocalizedException @@ -134,13 +146,15 @@ public function testResetPasswordTokenEmptyValue() ) } QUERY; - $this->assertMessage('resetPasswordToken must be specified'); $this->graphQlMutation($query); } /** * @magentoApiDataFixture Magento/Customer/_files/customer.php * + * @expectedException \Exception + * @expectedExceptionMessage Cannot set customer password + * * @throws NoSuchEntityException * @throws Exception * @throws LocalizedException @@ -156,13 +170,15 @@ public function testResetPasswordTokenMismatched() ) } QUERY; - $this->assertMessage('The password token is mismatched. Reset and try again.'); $this->graphQlMutation($query); } /** * @magentoApiDataFixture Magento/Customer/_files/customer.php * + * @expectedException \Exception + * @expectedExceptionMessage newPassword must be specified + * * @throws NoSuchEntityException * @throws Exception * @throws LocalizedException @@ -178,20 +194,33 @@ public function testNewPasswordEmptyValue() ) } QUERY; - $this->assertMessage('newPassword must be specified'); $this->graphQlMutation($query); } /** - * Assert messages + * Check password reset for lock customer + * + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * + * @expectedException \Exception + * @expectedExceptionMessage The current customer isn't authorized * - * @param $message + * @throws LocalizedException + * @throws NoSuchEntityException */ - private function assertMessage($message) + public function testPasswordResetForLockCustomer() { - $expectedExceptionsMessage = "GraphQL response contains errors: {$message}"; - $this->expectException(ResponseContainsErrorsException::class); - $this->expectExceptionMessage($expectedExceptionsMessage); + $this->lockCustomer->execute(1); + $query = <<getCustomerEmail()}" + resetPasswordToken: "{$this->getResetPasswordToken()}" + newPassword: "{$this->getNewPassword()}" + ) +} +QUERY; + $this->graphQlMutation($query); } /** From 14197522704a46d259d8675fdd00c56060189fa6 Mon Sep 17 00:00:00 2001 From: Oleh Usik Date: Wed, 29 Apr 2020 18:54:17 +0300 Subject: [PATCH 3/6] minor fix --- .../Model/Resolver/RequestPasswordResetEmail.php | 4 ++-- .../Magento/CustomerGraphQl/Model/Resolver/ResetPassword.php | 2 +- .../GraphQl/Customer/RequestPasswordResetEmailTest.php | 2 +- .../testsuite/Magento/GraphQl/Customer/ResetPasswordTest.php | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/CustomerGraphQl/Model/Resolver/RequestPasswordResetEmail.php b/app/code/Magento/CustomerGraphQl/Model/Resolver/RequestPasswordResetEmail.php index fdcc9f12eea60..df86dcc64a6cb 100644 --- a/app/code/Magento/CustomerGraphQl/Model/Resolver/RequestPasswordResetEmail.php +++ b/app/code/Magento/CustomerGraphQl/Model/Resolver/RequestPasswordResetEmail.php @@ -101,7 +101,7 @@ public function resolve( } if (true === $this->authentication->isLocked($customer->getId())) { - throw new GraphQlInputException(__("The current customer isn't authorized")); + throw new GraphQlInputException(__('The account is locked')); } try { @@ -110,7 +110,7 @@ public function resolve( AccountManagement::EMAIL_RESET ); } catch (LocalizedException $e) { - throw new GraphQlInputException(__("Cannot reset customer password"), $e); + throw new GraphQlInputException(__('Cannot reset customer password'), $e); } } } diff --git a/app/code/Magento/CustomerGraphQl/Model/Resolver/ResetPassword.php b/app/code/Magento/CustomerGraphQl/Model/Resolver/ResetPassword.php index 515b965952aed..95a6a3d51f845 100644 --- a/app/code/Magento/CustomerGraphQl/Model/Resolver/ResetPassword.php +++ b/app/code/Magento/CustomerGraphQl/Model/Resolver/ResetPassword.php @@ -108,7 +108,7 @@ public function resolve( } if (true === $this->authentication->isLocked($customer->getId())) { - throw new GraphQlInputException(__("The current customer isn't authorized")); + throw new GraphQlInputException(__('The account is locked')); } try { diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/RequestPasswordResetEmailTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/RequestPasswordResetEmailTest.php index f08badeb5732d..d877658ad73ce 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/RequestPasswordResetEmailTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/RequestPasswordResetEmailTest.php @@ -95,7 +95,7 @@ public function testEmailAvailableInvalidValue() * @magentoApiDataFixture Magento/Customer/_files/customer.php * * @expectedException \Exception - * @expectedExceptionMessage The current customer isn't authorized + * @expectedExceptionMessage The account is locked */ public function testRequestPasswordResetEmailForLockCustomer() { diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/ResetPasswordTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/ResetPasswordTest.php index bf660ba8c94f2..b7e95609fcf75 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/ResetPasswordTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/ResetPasswordTest.php @@ -203,7 +203,7 @@ public function testNewPasswordEmptyValue() * @magentoApiDataFixture Magento/Customer/_files/customer.php * * @expectedException \Exception - * @expectedExceptionMessage The current customer isn't authorized + * @expectedExceptionMessage The account is locked * * @throws LocalizedException * @throws NoSuchEntityException From 78200461a69f5292a39a9f5b0287f348b4e34a50 Mon Sep 17 00:00:00 2001 From: Oleh Usik Date: Wed, 29 Apr 2020 19:40:03 +0300 Subject: [PATCH 4/6] added test for checking type of autocomplete_on_storefront --- .../GraphQl/Customer/ResetPasswordTest.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/ResetPasswordTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/ResetPasswordTest.php index b7e95609fcf75..4d9e1d8bddfe9 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/ResetPasswordTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/ResetPasswordTest.php @@ -223,6 +223,25 @@ public function testPasswordResetForLockCustomer() $this->graphQlMutation($query); } + /** + * Check type of autocomplete_on_storefront storeConfig value + * + * @throws Exception + */ + public function testReturnTypeAutocompleteOnStorefrontConfig() + { + $query = <<graphQlQuery($query); + self::assertArrayHasKey('autocomplete_on_storefront', $response['storeConfig']); + self::assertInternalType('bool',$response['storeConfig']['autocomplete_on_storefront']); + } + /** * Get reset password token * From d363a5d74a758c5c53dd8e6809b767b7ec543acb Mon Sep 17 00:00:00 2001 From: Oleh Usik Date: Wed, 29 Apr 2020 22:33:03 +0300 Subject: [PATCH 5/6] Moved test for autocomplete_on_storefront to separate file --- .../GraphQl/Customer/ResetPasswordTest.php | 19 ---------- .../GraphQl/Customer/StoreConfigTest.php | 38 +++++++++++++++++++ 2 files changed, 38 insertions(+), 19 deletions(-) create mode 100644 dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/StoreConfigTest.php diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/ResetPasswordTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/ResetPasswordTest.php index 4d9e1d8bddfe9..b7e95609fcf75 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/ResetPasswordTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/ResetPasswordTest.php @@ -223,25 +223,6 @@ public function testPasswordResetForLockCustomer() $this->graphQlMutation($query); } - /** - * Check type of autocomplete_on_storefront storeConfig value - * - * @throws Exception - */ - public function testReturnTypeAutocompleteOnStorefrontConfig() - { - $query = <<graphQlQuery($query); - self::assertArrayHasKey('autocomplete_on_storefront', $response['storeConfig']); - self::assertInternalType('bool',$response['storeConfig']['autocomplete_on_storefront']); - } - /** * Get reset password token * diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/StoreConfigTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/StoreConfigTest.php new file mode 100644 index 0000000000000..473105c2c46be --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/StoreConfigTest.php @@ -0,0 +1,38 @@ +graphQlQuery($query); + self::assertArrayHasKey('autocomplete_on_storefront', $response['storeConfig']); + self::assertTrue($response['storeConfig']['autocomplete_on_storefront']); + } +} From 0b079a8611daf4f938199db5c19e9003cc4024f3 Mon Sep 17 00:00:00 2001 From: Oleh Usik Date: Fri, 8 May 2020 13:37:36 +0300 Subject: [PATCH 6/6] changed errors messages --- .../Model/Resolver/RequestPasswordResetEmail.php | 8 ++++---- .../CustomerGraphQl/Model/Resolver/ResetPassword.php | 8 ++++---- app/code/Magento/CustomerGraphQl/etc/schema.graphqls | 12 ++++++------ .../Customer/RequestPasswordResetEmailTest.php | 6 +++--- .../Magento/GraphQl/Customer/ResetPasswordTest.php | 6 +++--- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/app/code/Magento/CustomerGraphQl/Model/Resolver/RequestPasswordResetEmail.php b/app/code/Magento/CustomerGraphQl/Model/Resolver/RequestPasswordResetEmail.php index df86dcc64a6cb..d0985d6acaf19 100644 --- a/app/code/Magento/CustomerGraphQl/Model/Resolver/RequestPasswordResetEmail.php +++ b/app/code/Magento/CustomerGraphQl/Model/Resolver/RequestPasswordResetEmail.php @@ -87,17 +87,17 @@ public function resolve( array $args = null ) { if (empty($args['email'])) { - throw new GraphQlInputException(__('Email must be specified')); + throw new GraphQlInputException(__('You must specify an email address.')); } if (!$this->emailValidator->isValid($args['email'])) { - throw new GraphQlInputException(__('Email is invalid')); + throw new GraphQlInputException(__('The email address has an invalid format.')); } try { $customer = $this->customerRepository->get($args['email']); } catch (LocalizedException $e) { - throw new GraphQlInputException(__('Cannot reset customer password'), $e); + throw new GraphQlInputException(__('Cannot reset the customer\'s password'), $e); } if (true === $this->authentication->isLocked($customer->getId())) { @@ -110,7 +110,7 @@ public function resolve( AccountManagement::EMAIL_RESET ); } catch (LocalizedException $e) { - throw new GraphQlInputException(__('Cannot reset customer password'), $e); + throw new GraphQlInputException(__('Cannot reset the customer\'s password'), $e); } } } diff --git a/app/code/Magento/CustomerGraphQl/Model/Resolver/ResetPassword.php b/app/code/Magento/CustomerGraphQl/Model/Resolver/ResetPassword.php index 95a6a3d51f845..fa2ae669cc89d 100644 --- a/app/code/Magento/CustomerGraphQl/Model/Resolver/ResetPassword.php +++ b/app/code/Magento/CustomerGraphQl/Model/Resolver/ResetPassword.php @@ -86,11 +86,11 @@ public function resolve( array $args = null ) { if (empty($args['email'])) { - throw new GraphQlInputException(__('Email must be specified')); + throw new GraphQlInputException(__('You must specify an email address.')); } if (!$this->emailValidator->isValid($args['email'])) { - throw new GraphQlInputException(__('Email is invalid')); + throw new GraphQlInputException(__('The email address has an invalid format.')); } if (empty($args['resetPasswordToken'])) { @@ -104,7 +104,7 @@ public function resolve( try { $customer = $this->customerRepository->get($args['email']); } catch (LocalizedException $e) { - throw new GraphQlInputException(__('Cannot set customer password'), $e); + throw new GraphQlInputException(__('Cannot set the customer\'s password'), $e); } if (true === $this->authentication->isLocked($customer->getId())) { @@ -118,7 +118,7 @@ public function resolve( $args['newPassword'] ); } catch (LocalizedException $e) { - throw new GraphQlInputException(__('Cannot set customer password'), $e); + throw new GraphQlInputException(__('Cannot set the customer\'s password'), $e); } } } diff --git a/app/code/Magento/CustomerGraphQl/etc/schema.graphqls b/app/code/Magento/CustomerGraphQl/etc/schema.graphqls index b160747d686e1..3bf36d11e71fe 100644 --- a/app/code/Magento/CustomerGraphQl/etc/schema.graphqls +++ b/app/code/Magento/CustomerGraphQl/etc/schema.graphqls @@ -1,10 +1,10 @@ # Copyright © Magento, Inc. All rights reserved. # See COPYING.txt for license details. -type StoreConfig @doc(description: "The type contains information about a store config") { - required_character_classes_number : String @doc(description: "Number of Required Character Classes") - minimum_password_length : String @doc(description: "Minimum Password Length") - autocomplete_on_storefront : Boolean @doc(description: "Enable Autocomplete on login or forgot password forms") +type StoreConfig { + required_character_classes_number : String @doc(description: "The number of different character classes required in a password (lowercase, uppercase, digits, special characters).") + minimum_password_length : String @doc(description: "The minimum number of characters required for a valid password.") + autocomplete_on_storefront : Boolean @doc(description: "Enable autocomplete on login and forgot password forms") } type Query { @@ -23,8 +23,8 @@ type Mutation { createCustomerAddress(input: CustomerAddressInput!): CustomerAddress @resolver(class: "Magento\\CustomerGraphQl\\Model\\Resolver\\CreateCustomerAddress") @doc(description: "Create customer address") updateCustomerAddress(id: Int!, input: CustomerAddressInput): CustomerAddress @resolver(class: "Magento\\CustomerGraphQl\\Model\\Resolver\\UpdateCustomerAddress") @doc(description: "Update customer address") deleteCustomerAddress(id: Int!): Boolean @resolver(class: "Magento\\CustomerGraphQl\\Model\\Resolver\\DeleteCustomerAddress") @doc(description: "Delete customer address") - requestPasswordResetEmail(email: String!): Boolean @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\RequestPasswordResetEmail") @doc(description: "Request an email with reset password token for the registered customer identified by the provided email") - resetPassword(email: String!, resetPasswordToken: String!, newPassword: String!): Boolean @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\ResetPassword") @doc(description: "Reset customer password using reset password token received in the email after requesting it using requestPasswordResetEmail") + requestPasswordResetEmail(email: String!): Boolean @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\RequestPasswordResetEmail") @doc(description: "Request an email with a reset password token for the registered customer identified by the specified email.") + resetPassword(email: String!, resetPasswordToken: String!, newPassword: String!): Boolean @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\ResetPassword") @doc(description: "Reset a customer's password using the reset password token that the customer received in an email after requesting it using requestPasswordResetEmail.") } input CustomerAddressInput { diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/RequestPasswordResetEmailTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/RequestPasswordResetEmailTest.php index d877658ad73ce..9f30124fbb54a 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/RequestPasswordResetEmailTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/RequestPasswordResetEmailTest.php @@ -44,7 +44,7 @@ public function testCustomerAccountWithEmailAvailable() * Check if customer account is not available * * @expectedException \Exception - * @expectedExceptionMessage Cannot reset customer password + * @expectedExceptionMessage Cannot reset the customer's password */ public function testCustomerAccountWithEmailNotAvailable() { @@ -61,7 +61,7 @@ public function testCustomerAccountWithEmailNotAvailable() * Check if email value empty * * @expectedException \Exception - * @expectedExceptionMessage Email must be specified + * @expectedExceptionMessage You must specify an email address. */ public function testEmailAvailableEmptyValue() { @@ -77,7 +77,7 @@ public function testEmailAvailableEmptyValue() * Check if email is invalid * * @expectedException \Exception - * @expectedExceptionMessage Email is invalid + * @expectedExceptionMessage The email address has an invalid format. */ public function testEmailAvailableInvalidValue() { diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/ResetPasswordTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/ResetPasswordTest.php index b7e95609fcf75..ff9831abb590d 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/ResetPasswordTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/ResetPasswordTest.php @@ -81,7 +81,7 @@ public function testResetCustomerAccountPasswordSuccessfully(): void * @magentoApiDataFixture Magento/Customer/_files/customer.php * * @expectedException \Exception - * @expectedExceptionMessage Email must be specified + * @expectedExceptionMessage You must specify an email address. * * @throws NoSuchEntityException * @throws Exception @@ -105,7 +105,7 @@ public function testEmailAvailableEmptyValue() * @magentoApiDataFixture Magento/Customer/_files/customer.php * * @expectedException \Exception - * @expectedExceptionMessage Email is invalid + * @expectedExceptionMessage The email address has an invalid format. * * @throws NoSuchEntityException * @throws Exception @@ -153,7 +153,7 @@ public function testResetPasswordTokenEmptyValue() * @magentoApiDataFixture Magento/Customer/_files/customer.php * * @expectedException \Exception - * @expectedExceptionMessage Cannot set customer password + * @expectedExceptionMessage Cannot set the customer's password * * @throws NoSuchEntityException * @throws Exception