ldc-crm/tests/Client/CrmClientV2QuestionTest.php

264 lines
11 KiB
PHP
Raw Normal View History

Version 3.0.0 This removes api authentification with token in favor of signature method. Refactorize code and clean up. It add more unit test plus code coverage in test/converage. - Added config.api.timestampTimeout - Added Helper::signRequest This calculates the request signature - Added more unit tests and extend code coverage. - Added rate limiter for web routes - Added RemoveSpaces Sanitizer on api requests - Added stress test suite - Changed AuthServiceProvider api-token to api-hmac - Changed CustomerSeeder to have at least of customer activated (for unit tests) - Changed used transation for saveing multiple models - Changed, in ServiceController generateApiToken to generateServicePassword - Changed, timestamp has to be send in request with a DateTime format, it also has to a UTC value - Composer added brianium/paratest - Composer update - Fixed case where removing single optin could be the wrong one (not for the good service) - Fixed customer delete - Fixed customer would not be resolved by brand. - Fixed Really check that request is json checking body content, preventing sending malformed requests - Remove ApiError::needAuth - Removed api_token - Removed ApiController::authenticate - Removed config.api.tokenTimeout - Removed Header check or usage because of HAProxy doing weird stuff - Removed lock files from gitignore - Removed memcached dependency - Removed unused questions resources api routes - Removed workspace file Migrations - Added unique index on services.bearer_token - Changed customer_id on customer_answer is nullable - Changed services.bearer_pwd length to 312 (the size of the token) - Dropped services.api_token and service.api_token_date
2021-12-19 15:57:24 +01:00
<?php
namespace Tests\Client;
use App\Models\CustomerAnswer;
use App\Models\Question as ModelsQuestion;
use LDC\LDCCRM\CrmApiV2;
use LDC\LDCCRM\Models\Answer;
use LDC\LDCCRM\Models\Question;
class CrmClientV2QuestionTest extends CrmClientTester
{
/**
* Get All Questions
*
* @return void
*/
public function testGetAllQuestions()
{
$questions = Question::all();
$this->assertIsArray($questions, 'Should have returned an array');
$this->assertNotEmpty($questions, 'Should have returned some questions');
collect($questions)->map(function ($question) {
$this->assertIsObject($question, 'Question should be an object ');
$this->assertTrue(\get_class($question) === Question::class, 'Question should be type ' . Question::class);
$this->assertIsArray($question->answers);
$this->assertNotEmpty($question->answers);
collect($question->answers)->map(function ($answer) {
$this->assertIsObject($answer, 'Answer should be an object ');
$this->assertTrue(\get_class($answer) === Answer::class, 'Question should be type ' . Answer::class);
});
});
}
/**
* Test customer is json serializable.
*
* @return void
*/
public function testJsonSerialize()
{
$questions = Question::all();
$this->assertIsArray($questions);
$this->assertTrue((bool)count($questions));
foreach ($questions as $question) {
$jsonDecoded = \json_decode(\json_encode($question), true);
$this->assertArrayHasKey('id', $jsonDecoded);
$this->assertEquals($question->id, $jsonDecoded['id']);
$this->assertArrayHasKey('question', $jsonDecoded);
$this->assertEquals($question->question, $jsonDecoded['question']);
$this->assertArrayHasKey('type', $jsonDecoded);
$this->assertEquals($question->type->value, $jsonDecoded['type']);
$this->assertArrayHasKey('answers', $jsonDecoded);
$this->assertIsArray($jsonDecoded['answers']);
foreach ($jsonDecoded['answers'] as $key => $answer) {
$this->assertArrayHasKey('id', $answer);
$this->assertArrayHasKey('answer', $answer);
$this->assertArrayHasKey($key, $question->answers);
$this->assertEquals($question->answers[$key]->id, $answer['id']);
$this->assertEquals($question->answers[$key]->answer, $answer['answer']);
}
}
}
/**
* Get all question with user answers
*
* @return void
*/
public function testGetAllQuestionsWithCustomerAnswers()
{
/** @var \App\Models\Question $answeredQuestion */
$answeredQuestion = ModelsQuestion::whereHas('brand', function ($q) {
$q->whereId(static::$brand->id);
})->firstOrFail();
// * Make sure a customer answer is set.
$firstAnswer = $answeredQuestion->answers->first();
$firstAnswer->load('question');
/** @var \App\Models\CustomerAnswer $custAnswer */
$custAnswer = CustomerAnswer::whereHas('customer', function ($q) {
$q->whereId(static::$customer->id);
})->whereHas('answer', function ($q) use ($firstAnswer) {
$q->whereId($firstAnswer->id);
})->firstOrNew();
$custAnswer->customer()->associate(static::$customer);
$custAnswer->answer()->associate($firstAnswer);
$custAnswer->saveOrFail();
$api = new CrmApiV2();
$customer = $api->getCustomerOrNew(static::$info->hashcode);
$questions = Question::allWithCustomerAnswers($customer);
$this->assertIsArray($questions, 'Should have returned an array');
$this->assertNotEmpty($questions, 'Should have returned some questions');
$hasCheckedCustomerAnswers = false;
collect($questions)->map(function ($question) use ($answeredQuestion, &$hasCheckedCustomerAnswers) {
$this->assertIsArray($question, 'Question should be an array');
$this->assertArrayHasKey('question', $question, 'Question should have a question key');
$this->assertIsObject($question['question'], 'Question should be an object');
$this->assertTrue(
\get_class($question['question']) === Question::class,
'Question should be type ' . Question::class
);
$this->assertIsArray($question['question']->answers);
$this->assertNotEmpty($question['question']->answers);
collect($question['question']->answers)->map(function ($answer) {
$this->assertIsObject($answer, 'Answer should be an object ');
$this->assertTrue(\get_class($answer) === Answer::class, 'Question should be type ' . Answer::class);
});
if ($answeredQuestion->id === $question['question']->id) {
$hasCheckedCustomerAnswers = true;
$this->assertArrayHasKey('customerAnswers', $question, 'Question should have customer answers');
$this->assertIsArray($question['customerAnswers'], 'Question should have customer answers');
collect($question['customerAnswers'])->map(function ($custAnswer) {
$this->assertIsObject($custAnswer, 'Customer answer should be an object ');
$this->assertTrue(
\get_class($custAnswer) === Answer::class,
'Customer answer should be type ' . Answer::class
);
});
}
});
$this->assertTrue(
$hasCheckedCustomerAnswers,
'Should have checked that response has at least on customer answer we have set on this test.'
);
}
/**
* Get all unanswered questions
*
* @return void
*/
public function testGetAllCustomerUnAnsweredQuestions()
{
/** @var \App\Models\Question $answeredQuestion */
$answeredQuestion = ModelsQuestion::whereHas('brand', function ($q) {
$q->whereId(static::$brand->id);
})->firstOrFail();
// * Make sure a customer answer is set.
$firstAnswer = $answeredQuestion->answers->first();
$firstAnswer->load('question');
/** @var \App\Models\CustomerAnswer $custAnswer */
$custAnswer = CustomerAnswer::whereHas('customer', function ($q) {
$q->whereId(static::$customer->id);
})->whereHas('answer', function ($q) use ($firstAnswer) {
$q->whereId($firstAnswer->id);
})->firstOrNew();
$custAnswer->customer()->associate(static::$customer);
$custAnswer->answer()->associate($firstAnswer);
$custAnswer->saveOrFail();
$api = new CrmApiV2();
$customer = $api->getCustomerOrNew(static::$info->hashcode);
$questions = Question::unansweredBy($customer);
$this->assertIsArray($questions, 'Should have returned an array');
$this->assertNotEmpty($questions, 'Should have returned some questions');
collect($questions)->map(function ($question) use ($answeredQuestion) {
$this->assertIsObject($question, 'Question should be an object');
$this->assertTrue(
\get_class($question) === Question::class,
'Question should be type ' . Question::class
);
$this->assertIsArray($question->answers);
$this->assertNotEmpty($question->answers);
collect($question->answers)->map(function ($answer) {
$this->assertIsObject($answer, 'Answer should be an object ');
$this->assertTrue(\get_class($answer) === Answer::class, 'Question should be type ' . Answer::class);
});
$this->assertFalse(
$answeredQuestion->id === $question->id,
'Questions should not have one we already answered'
);
});
}
/**
* Test submit answers.
*
* @return void
*/
public function testSubmitCustomerAnswer()
{
/** @var \App\Models\Question $answeredQuestion */
$answeredQuestion = ModelsQuestion::whereHas('brand', function ($q) {
$q->whereId(static::$brand->id);
})->inRandomOrder()->firstOrFail();
$api = new CrmApiV2();
$customer = $api->getCustomerOrNew(static::$info->hashcode);
$result = Answer::setQuestionAnswers(
$customer->hashcode,
$answeredQuestion->id,
[
$answeredQuestion->answers->get(0)->id,
$answeredQuestion->answers->get(1)->id,
]
);
$this->assertTrue($result);
$api = new CrmApiV2();
$customer = $api->getCustomerOrNew(static::$info->hashcode);
$questions = Question::unansweredBy($customer);
$this->assertIsArray($questions, 'Should have returned an array');
$this->assertNotEmpty($questions, 'Should have returned some questions');
collect($questions)->map(function ($question) use ($answeredQuestion) {
$this->assertIsObject($question, 'Question should be an object');
$this->assertTrue(
\get_class($question) === Question::class,
'Question should be type ' . Question::class
);
$this->assertIsArray($question->answers);
$this->assertNotEmpty($question->answers);
collect($question->answers)->map(function ($answer) {
$this->assertIsObject($answer, 'Answer should be an object ');
$this->assertTrue(\get_class($answer) === Answer::class, 'Question should be type ' . Answer::class);
});
$this->assertFalse(
$answeredQuestion->id === $question->id,
'Questions should not have one we already answered'
);
});
}
/**
* Test unansweredBy
*
* @return void
*/
public function testGetAllCustomerUnansweredQuestionsShouldNotContainFirst()
{
$unWantedQuestion = Question::all()[0];
$api = new CrmApiV2();
$customer = $api->getCustomerOrNew(static::$info->hashcode);
$questions = Question::unansweredBy($customer);
foreach ($questions as $question) {
$this->assertFalse($unWantedQuestion->id === $question->id);
}
}
/**
* test allWithCustomerAnswers
*
* @return void
*/
public function testGetAllQuestionsWithCustomerAnswersShouldHaveAnswers()
{
$api = new CrmApiV2();
$customer = $api->getCustomerOrNew(static::$info->hashcode);
$questions = Question::allWithCustomerAnswers($customer);
$this->assertNotEmpty($questions[0]['customerAnswers'], 'Should have customer answers');
}
}