getCustomer()); $infos = $customer->infos; $logins = $customer->logins; $brands = $customer->brands; $optInHistory = $customer->optInHistory; $this->assertInstanceOf(Collection::class, $infos); $this->assertInstanceOf(Collection::class, $logins); $this->assertInstanceOf(Collection::class, $brands); $this->assertInstanceOf(Collection::class, $optInHistory); $this->assertInstanceOf(CustomerInfo::class, $customer->info($brands->first())); $this->assertInstanceOf(CustomerLogin::class, $customer->login($brands->first())); } /** * Test customer Authentification ok. * route: apiV2.customers.authenticate * * @return void */ public function testApiAuthenticateCustomerShouldWork(): void { extract($this->getCustomer(true)); $login->password = 'testPassword'; $login->saveOrFail(); $response = $this->callApiWithToken( $service, 'post', route('apiV2.customers.authenticate', []), [ 'email' => $customer->email, 'password' => 'testPassword' ] ); $json = $response->decodeResponseJson(); $this->assertApiResponseStatusIs($json, ApiStatus::OK); $this->assertNotEmpty($json->json('data')); $this->assertNotEmpty($json->json('data.firstname')); $this->assertNotEmpty($json->json('data.lastname')); $this->assertNotEmpty($json->json('data.birth_date')); $this->assertNotEmpty($json->json('data.address')); $this->assertNotEmpty($json->json('data.phone')); $this->assertNotEmpty($json->json('data.country')); $this->assertNotEmpty($json->json('data.city')); $this->assertNotEmpty($json->json('data.postcode')); $this->assertNotEmpty($json->json('data.hashcode')); } /** * Customer authentification should fail if the password is wrong. * route: apiV2.customers.authenticate * * @return void */ public function testApiAuthenticateCustomerShouldFailIfWrongPassword(): void { extract($this->getCustomer()); $response = $this->callApiWithToken( $service, 'post', route('apiV2.customers.authenticate', []), [ 'email' => $customer->email, 'password' => 'azdqdqdazd' ] ); $json = $response->decodeResponseJson(); $this->assertApiResponseStatusIs($json, ApiStatus::KO); $this->assertNotEmpty($json->json('data')); $this->assertNotEmpty($json->json('data.message')); $this->assertNotEmpty($json->json('data.code')); $this->assertEquals(ApiError::authFailed->value(), $json->json('data.code')); $this->assertEquals(ApiError::authFailed->label(), $json->json('data.message')); } /** * Customer authentification should fail if the email is wrong. * route: apiV2.customers.authenticate * * @return void */ public function testApiAuthenticateCustomerShouldFailIfWrongEmail(): void { extract($this->getCustomer()); $response = $this->callApiWithToken( $service, 'post', route('apiV2.customers.authenticate', []), [ 'email' => 'wrongemail@hotmail.fr', 'password' => 'azdqdqdazd' ] ); $json = $response->decodeResponseJson(); $this->assertApiResponseStatusIs($json, ApiStatus::KO); $this->assertNotEmpty($json->json('data')); $this->assertNotEmpty($json->json('data.message')); $this->assertNotEmpty($json->json('data.code')); $this->assertEquals(ApiError::authFailed->value(), $json->json('data.code')); $this->assertEquals(ApiError::authFailed->label(), $json->json('data.message')); } /** * Customer authentification should fail if the customer is not activated. * route: apiV2.customers.authenticate * * @return void */ public function testApiAuthenticateCustomerShouldFailIfCustomerNotActivated(): void { $login = CustomerLogin::query()->where('status', false)->firstOrFail(); /** @var \App\Models\Brand $brand */ $brand = $login->brand; /** @var \App\Models\Customer $customer */ $customer = $login->customer; /** @var \App\Models\Service $service */ $service = $brand->services()->firstOrFail(); $response = $this->callApiWithToken( $service, 'post', route('apiV2.customers.authenticate', []), [ 'email' => $customer->email, 'password' => 'testPassword' ] ); $json = $response->decodeResponseJson(); $this->assertApiResponseStatusIs($json, ApiStatus::KO); $this->assertNotEmpty($json->json('data')); $this->assertNotEmpty($json->json('data.message')); $this->assertNotEmpty($json->json('data.code')); $this->assertEquals(ApiError::customerNotActivated->value(), $json->json('data.code')); $this->assertEquals(ApiError::customerNotActivated->label(), $json->json('data.message')); } /** * Customer store ok. * route: apiV2.customers.store * * @return void */ public function testApiStoreCustomerOk(): void { extract($this->getCustomer()); // * Single optin should be deleted when creating new customer. $singleOptin = new SingleOptin(); $singleOptin->email = 'newcustomer@hotmail.fr'; $singleOptin->brand()->associate($brand); $singleOptin->saveOrFail(); $data = [ 'firstname' => 'Jean', 'lastname' => 'Bond', 'birth_date' => \date('1992-03-08'), 'address' => '10 rue des toto', 'email' => 'newcustomer@hotmail.fr', 'password' => '123.Mot.De.P4sse', 'phone' => '+33654821562', 'country' => Country::france->value(), 'city' => 'Connerré', 'postcode' => '72160', 'opt_in' => true ]; $response = $this->callApiWithToken($service, 'post', route('apiV2.customers.store'), $data); $json = $response->decodeResponseJson(); $this->assertApiResponseStatusIs($json, ApiStatus::OK); $this->assertNotEmpty($json->json('data.firstname')); $this->assertNotEmpty($json->json('data.lastname')); $this->assertNotEmpty($json->json('data.birth_date')); $this->assertNotEmpty($json->json('data.address')); $this->assertNotEmpty($json->json('data.phone')); $this->assertNotEmpty($json->json('data.country')); $this->assertNotEmpty($json->json('data.city')); $this->assertNotEmpty($json->json('data.postcode')); $this->assertNotEmpty($json->json('data.hashcode')); $this->assertEquals($data['firstname'], $json->json('data.firstname')); $this->assertEquals($data['lastname'], $json->json('data.lastname')); $this->assertEquals($data['birth_date'], $json->json('data.birth_date')); $this->assertEquals($data['address'], $json->json('data.address')); $this->assertEquals($data['phone'], $json->json('data.phone')); $this->assertEquals($data['country'], $json->json('data.country')); $this->assertEquals($data['city'], $json->json('data.city')); $this->assertEquals($data['postcode'], $json->json('data.postcode')); } /** * Customer store should fail if customer already exists. * route: apiV2.customers.store * * @return void */ public function testApiStoreCustomerShouldFailIfCustomerAlreadyExists(): void { extract($this->getCustomer()); $data = [ 'firstname' => 'Jean', 'lastname' => 'Bond', 'birth_date' => \date('1992-03-08'), 'address' => '10 rue des toto', 'email' => 'newcustomer@hotmail.fr', 'password' => '123.Mot.De.P4sse', 'phone' => '+33654821562', 'country' => Country::france->value(), 'city' => 'Connerré', 'postcode' => '72160', 'opt_in' => true ]; $this->createNewCustomer($data, $brand); $response = $this->callApiWithToken($service, 'post', route('apiV2.customers.store'), $data); $json = $response->decodeResponseJson(); $this->assertApiResponseStatusIs($json, ApiStatus::KO); $this->assertEquals(ApiError::customerExists->value(), $json->json('data.code')); $this->assertEquals(ApiError::customerExists->label(), $json->json('data.message')); } /** * Customer store validationFailures. * route: apiV2.customers.store * * @return void */ public function testApiStoreCustomerValidationFailures(): void { extract($this->getCustomer()); $data = [ 'firstname' => 'Jean', 'lastname' => 'Bond', 'birth_date' => \date('1992-03-08'), 'address' => '10 rue des toto', 'email' => 'newcustomer.failures@hotmail.fr', 'password' => '123.Mot.De.P4sse', 'phone' => '+33654821562', 'country' => Country::france->value(), 'city' => 'Connerré', 'postcode' => '72160', 'opt_in' => true ]; $sendData = $data; $sendData['password'] = 'password'; $response = $this->callApiWithToken($service, 'post', route('apiV2.customers.store'), $sendData); $json = $response->decodeResponseJson(); $this->assertApiResponseStatusIs($json, ApiStatus::KO); $this->assertEquals( ApiError::validationFailed->value(), $json->json('data.code'), 'Password strengh should be checked' ); $sendData = $data; $sendData['postcode'] = '12'; $response = $this->callApiWithToken($service, 'post', route('apiV2.customers.store'), $sendData); $json = $response->decodeResponseJson(); $this->assertApiResponseStatusIs($json, ApiStatus::KO); $this->assertEquals( ApiError::validationFailed->value(), $json->json('data.code'), 'Post code should be checked' ); $sendData = $data; $sendData['country'] = '12'; $response = $this->callApiWithToken($service, 'post', route('apiV2.customers.store'), $sendData); $json = $response->decodeResponseJson(); $this->assertApiResponseStatusIs($json, ApiStatus::KO); $this->assertEquals( ApiError::validationFailed->value(), $json->json('data.code'), 'Country code should be checked' ); $sendData = $data; $sendData['phone'] = '+49-89-636-48018'; $response = $this->callApiWithToken($service, 'post', route('apiV2.customers.store'), $sendData); $json = $response->decodeResponseJson(); $this->assertApiResponseStatusIs($json, ApiStatus::KO); $this->assertEquals( ApiError::validationFailed->value(), $json->json('data.code'), 'Country code should be checked' ); $sendData = $data; $sendData['email'] = 'toto@nonexistingfqdndomain.lol'; $response = $this->callApiWithToken($service, 'post', route('apiV2.customers.store'), $sendData); $json = $response->decodeResponseJson(); $this->assertApiResponseStatusIs($json, ApiStatus::KO); $this->assertEquals( ApiError::validationFailed->value(), $json->json('data.code'), 'Email code should be checked' ); } /** * Test activate customer ok. * route: apiV2.customers.activate * * @return void */ public function testActivateCustomerOk(): void { extract($this->getCustomer(false)); $login->status = false; $login->saveOrFail(); $response = $this->callApiWithToken($service, 'post', route( 'apiV2.customers.activate', ['serviceCustomer' => $info->hashcode] ), []); $json = $response->decodeResponseJson(); $this->assertApiResponseStatusIs($json, ApiStatus::OK); } /** * Test activate customer already activated. * route: apiV2.customers.activate * * @return void */ public function testActivateCustomerAlreadyActivated(): void { extract($this->getCustomer(true)); $login->status = true; $login->saveOrFail(); $response = $this->callApiWithToken($service, 'post', route( 'apiV2.customers.activate', ['serviceCustomer' => $info->hashcode] ), []); $json = $response->decodeResponseJson(); $this->assertApiResponseStatusIs($json, ApiStatus::KO); $this->assertEquals(ApiError::customerAlreadyActive->value(), $json->json('data.code')); $this->assertEquals(ApiError::customerAlreadyActive->label(), $json->json('data.message')); } /** * Test customer update ok. * route: apiV2.customers.update * * @return void */ public function testApiUpdateCustomerOk(): void { extract($this->getCustomer()); $data = [ 'firstname' => 'Jean2', 'lastname' => 'Bond2', 'birth_date' => \date('1992-03-09'), 'address' => '10 rue des toto', 'email' => 'newcustomertoupdate@hotmail.fr', 'password' => '123.Mot.De.P4sseNew', 'phone' => '+33654821563', 'country' => Country::luxembourg->value(), 'city' => 'Connerré2', 'postcode' => '72161', 'opt_in' => 0 ]; $newdata = [ 'firstname' => 'Jean3', 'lastname' => 'Bond3', 'birth_date' => \date('1992-03-07'), 'address' => '10 rue des toto3', 'email' => 'newcustomertoupdate3@hotmail.fr', 'password' => '123.Mot.De.P4sseNew3', 'phone' => '+33654821564', 'country' => Country::france->value(), 'city' => 'Connerré3', 'postcode' => '72163', 'opt_in' => 1 ]; $this->createNewCustomer($data, $brand); foreach ($data as $rowName => $row) { $response = $this->callApiWithToken($service, 'patch', route( 'apiV2.customers.update', ['serviceCustomer' => $info->hashcode] ), [$rowName => $newdata[$rowName]]); $json = $response->decodeResponseJson(); $this->assertApiResponseStatusIs($json, ApiStatus::OK); if ($rowName != 'password') { $this->assertNotNull($json->json('data.' . $rowName), "Failed asserting $rowName is not null"); $this->assertEquals( $newdata[$rowName], $json->json('data.' . $rowName), "Failed asserting $rowName is equal to $newdata[$rowName]" ); } else { $this->assertNull($json->json('data.' . $rowName), "Failed asserting $rowName is null"); $this->assertEquals( null, $json->json('data.' . $rowName), "Failed asserting $rowName is equal to null" ); } } //end foreach // Address2 does not exists in crm. $response = $this->callApiWithToken($service, 'patch', route( 'apiV2.customers.update', ['serviceCustomer' => $info->hashcode] ), ['address2' => 'anything']); $json = $response->decodeResponseJson(); $this->assertApiResponseStatusIs($json, ApiStatus::KO); $this->assertEquals(ApiError::validationFailed->value(), $json->json('data.code')); } /** * Test customer update should fail if no changes are provided. * route: apiV2.customers.update * * @return void */ public function testApiUpdateCustomerShouldFailWhenNothingChanges(): void { extract($this->getCustomer()); $data = [ 'firstname' => 'Jean2', 'lastname' => 'Bond2', 'birth_date' => \date('1992-03-09'), 'address' => '10 rue des toto', 'email' => 'anewcustomertoupdate@hotmail.fr', 'password' => '123.Mot.De.P4sseNew', 'phone' => '+33654821563', 'country' => Country::luxembourg->value(), 'city' => 'Connerré2', 'postcode' => '72161', 'opt_in' => 0 ]; $this->createNewCustomer($data, $brand); $response = $this->callApiWithToken($service, 'patch', route( 'apiV2.customers.update', ['serviceCustomer' => $info->hashcode] )); $json = $response->decodeResponseJson(); $this->assertApiResponseStatusIs($json, ApiStatus::KO); $this->assertEquals($json->json('data.code'), ApiError::validationFailed->value()); } /** * Test customer show ok. * route: apiV2.customers.show * * @return void */ public function testApiGetCustomerOk(): void { extract($this->getCustomer()); $response = $this->callApiWithToken($service, 'get', route( 'apiV2.customers.show', ['serviceCustomer' => $info->hashcode] )); $json = $response->decodeResponseJson(); $this->assertApiResponseStatusIs($json, ApiStatus::OK); $this->assertNotEmpty($json->json('data.firstname')); $this->assertNotEmpty($json->json('data.lastname')); $this->assertNotEmpty($json->json('data.birth_date')); $this->assertNotEmpty($json->json('data.address')); $this->assertNotEmpty($json->json('data.phone')); $this->assertNotEmpty($json->json('data.country')); $this->assertNotEmpty($json->json('data.city')); $this->assertNotEmpty($json->json('data.postcode')); $this->assertNotEmpty($json->json('data.hashcode')); } /** * Test customer show using email ok. * route: apiV2.customers.show * * @return void */ public function testApiGetCustomerByEmailOk(): void { extract($this->getCustomer()); $response = $this->callApiWithToken($service, 'get', route( 'apiV2.customers.show', ['serviceCustomer' => $customer->email] )); $json = $response->decodeResponseJson(); $this->assertApiResponseStatusIs($json, ApiStatus::OK); $this->assertNotEmpty($json->json('data.firstname')); $this->assertNotEmpty($json->json('data.lastname')); $this->assertNotEmpty($json->json('data.birth_date')); $this->assertNotEmpty($json->json('data.address')); $this->assertNotEmpty($json->json('data.phone')); $this->assertNotEmpty($json->json('data.country')); $this->assertNotEmpty($json->json('data.city')); $this->assertNotEmpty($json->json('data.postcode')); $this->assertNotEmpty($json->json('data.hashcode')); } /** * Test customer show not found. * route: apiV2.customers.show * * @return void */ public function testApiGetCustomerNotFound(): void { extract($this->getCustomer()); $csClassName = \array_slice(explode('\\', get_class($customer)), -1)[0]; $uuid = Str::uuid(); $response = $this->callApiWithToken($service, 'get', route( 'apiV2.customers.show', ['serviceCustomer' => $uuid] )); $json = $response->decodeResponseJson(); /** @var \App\Models\Customer */ $customer = Customer::whereHas('infos', function ($q) use ($uuid) { $q->where('hashcode', $uuid); })->first(); $this->assertApiResponseStatusIs($json, ApiStatus::KO); $this->assertEquals(ApiError::modelNotFound->value(), $json->json('data.code')); $this->assertEquals( sprintf(ApiError::modelNotFound->label(), $csClassName), $json->json('data.message') ); } /** * Test delete customer. * route: apiV2.customer.destroy * * @return void */ public function testApiDestroyCustomer(): void { extract($this->getCustomer()); $csClassName = \array_slice(explode('\\', get_class($customer)), -1)[0]; $service = $brand->services()->firstOrFail(); $response = $this->callApiWithToken($service, 'delete', route( 'apiV2.customers.destroy', ['serviceCustomer' => $info->hashcode] )); $json = $response->decodeResponseJson(); $this->assertApiResponseStatusIs($json, ApiStatus::OK); $this->assertEmpty($json->json('data')); $response = $this->callApiWithToken($service, 'get', route( 'apiV2.customers.show', ['serviceCustomer' => $info->hashcode] )); $json = $response->decodeResponseJson(); $this->assertApiResponseStatusIs($json, ApiStatus::KO); $this->assertEquals( sprintf(ApiError::modelNotFound->label(), $csClassName), $json->json('data.message'), 'Customer should have been deleted.' ); } /** * Test delete customer all of data. * route: apiV2.customer.destroy * * @return void */ public function testApiCompletelyDestroyCustomer(): void { $customer = Customer::whereHas('logins', null, '>', 1)->firstOrFail(); /** @var \Illuminate\Database\Eloquent\Collection $logins */ $logins = $customer->logins; /** @var \App\Models\CustomerLogin $keepLogin */ $keepLogin = $logins->pull(0); $logins->map(function (CustomerLogin $login) use ($customer) { CustomerInfo::whereHas('customer', function ($q) use ($customer) { $q->whereId($customer->id); })->whereHas('brand', function ($q) use ($login) { $q->whereId($login->brand->id); })->delete(); $login->delete(); }); $this->assertTrue( (bool) $customer->logins()->count(), 'This test assumes customer belongs to multiple brand.' ); $csClassName = \array_slice(explode('\\', get_class($customer)), -1)[0]; /** @var \App\Models\CustomerInfo $info */ $info = $customer->info($keepLogin->brand, Customer::FIRST_OR_FAIL); /** @var \App\Models\Service $service */ $service = $keepLogin->brand->services()->firstOrFail(); $response = $this->callApiWithToken($service, 'delete', route( 'apiV2.customers.destroy', ['serviceCustomer' => $info->hashcode] )); $json = $response->decodeResponseJson(); $this->assertApiResponseStatusIs($json, ApiStatus::OK); $this->assertEmpty($json->json('data')); $response = $this->callApiWithToken($service, 'get', route( 'apiV2.customers.show', ['serviceCustomer' => $info->hashcode] )); $json = $response->decodeResponseJson(); $this->assertApiResponseStatusIs($json, ApiStatus::KO); $this->assertEquals( sprintf(ApiError::modelNotFound->label(), $csClassName), $json->json('data.message'), 'Customer should have been deleted.' ); } /** * Make sute a customer exists and contains data. * * @param array $data * @param \App\Models\Brand $brand * @return void */ private function createNewCustomer(array $data, Brand $brand): void { $customer = Customer::whereEmail($data['email']) ->whereHas('brands', function ($q) use ($brand) { $q->where('brands.id', '=', $brand->id); })->firstOrNew(); $customer->fill($data); $saved = $customer->save(); // * Delete Single optin if exists. /** @var \App\Models\SingleOptin|null $singleOptin */ $singleOptin = SingleOptin::query()->where('email', $data['email']) ->whereHas('brand', function ($q) use ($brand) { $q->where('brands.id', '=', $brand->id); })->first(); if ($singleOptin) { $saved = $singleOptin->delete() && $saved; } /** @var \App\Models\CustomerInfo */ $customerInfo = $customer->info($brand, Customer::FIRST_OR_NEW); $customerInfo->fill($data); $customerInfo->brand()->associate($brand); $customerInfo->customer()->associate($customer); $saved = $customerInfo->save() && $saved; /** @var \App\Models\CustomerLogin */ $customerLogin = $customer->login($brand, Customer::FIRST_OR_NEW); $customerLogin->fill($data); $customerLogin->brand()->associate($brand); $customerLogin->customer()->associate($customer); $saved = $customerLogin->save() && $saved; $this->assertTrue($saved, 'A new customer should have been created.'); } }