How to get rid of error 422 laravel in a unit test? - testing

So I'm writing unit tests for a laravel 5.7 web app and when I test the login it gives me error 422(I know that it has something to do with invalid data, I just don't know how to fix it)
public function testRegularUserLogin_CreatedRegularUse_ReturnsStoreView()
{
$regularUser = factory( User::class)->create();
$response = $this->json('POST','/login',
[
'email' => $regularUser->email,
'password' => $regularUser->password,
'_token' => csrf_token()
]);
$response->assertStatus(200);
}
I've tried using the csrf token on the header
This is the output that test gives me

You should just mock authentication:
do something like this
public function getFakeClient()
{
$client = factory(App\User::class)->create();
$this->be($client);
Auth::shouldReceive('user')->andReturn($this->client);
Auth::shouldReceive('check')->andReturn(true);
return $this->client;
}
then
$user = $this->getFakeClient();
$user->shouldReceive('posts')->once()->andReturn(array('posts'));
as recommended by Taylor Otwell himself here.

Related

"Attempt to read property \"id\" on null", Create access token error with laravel passport, laravel 9, php 8.2.2

devs,
so I have been struggling with this problem for about 10 hours now, and I can't seem to find a solution online, worst is that I don't even know why it happens.
I am working on a project which uses PHP LARAVEL as the backend and I started writing the API for the flutter frontend to consume then I ran into this error while trying to test the API endpoint for registering and logging in.
The problem is the process fails with this error when I try to generate or create a token for the registered user or logged-in user.
Here a snapshot of my register function
public function store(Request $request)
{
$validated = Validator::make($request->all(),[
"email" => "required|email",
"password" => 'required',
"first_name"=> "required",
"last_name" => "required",
"phone_number" => 'required',
]);
if ($validated->fails()) {
return response()->json(['errors' => "Invalide credentials"], 403);
}
$user = User::create(
// [
// 'first_name' => $request->first_name,
// 'last_name'=> $request->last_name,
// 'email' => $request->email,
// 'password' => bcrypt($request->password),
// 'phone_number' => $request->phone_number,
// ]
$request->toArray()
);
Auth::guard('api')->check($user);
// $newUser = User::find($user->id);
$token = $user->createToken('authToken')->accessToken;
// return $token;
return response(['token' => $token, 'first_name'=>$user->first_name, 'email'=>$user->email ], 200);
}
The login and register functions all look the same at this point.
Error-causing code is :
$token = $user->createToken('authToken')->accessToken;
Please I am open to your suggestions, thanks.
I finally found a solution for this error and I believe it will help anyone out there with a similar problem.
The problem originates from the fact that your application is unable to asign a unique id to your client, remember your website or mobile app is a client to the backend with also(your mobile app or website) might have other users, so laravel passport will need to identify it with a unique id, below are some of the steps i used to fix this error.
First it originates because during the passport installation, i forgot to install
Blockquote
--uuids
If you have a similar error, follow the steps below to fix:
NOTE: You must have laravel passport installed already, if not, them follow the complete installtion guide Here
Step 1:
Install passport uuids
php artisan passport:install --uuids
Your result will look something like
After creating, the uuid for your application, you will have to include it in your .env file as such:
PASSPORT_PERSONAL_ACCESS_CLIENT_ID=986eb40c-0458-4b6e-bead-ea2fc4987033
PASSPORT_PERSONAL_ACCESS_CLIENT_SECRET=VXLdTpqWK9i3CBqFwZgje5fuerQ5Uf2lvwXJqBoP
And there you go, you can now try to do what you couldn't do before.

Mock API when performing a WebTestCase and do $client->submitform() in Symfony 5

I have a Test which submits a form. This form usually results in performing doing a external API call. I want to mock that because I'm not interested in the API but in the action.
Whenever I call submitForm the client is still making an external call, but I don't want that.
The test also fails because the api expects a api key which the test does not have.
class SubscriptionControllerTest extends WebTestCase
{
public function testSubscribe(): void
{
$client = static::createClient();
$userRepository = static::$container->get(UserRepository::class);
$testUser = $userRepository->findOneBy(['email' => UserFixtures::$testUser]);
$clientMock = $this->createMock(ApiClient::class);
//replace the api with the mock one
self::$container->set(ApiClient::class, $clientMock);
$client->loginUser($testUser);
$client->request('GET', '/subscription/new');
$client->submitForm('btn-submit', [
'subscribe[firstName]' => 'firstname',
'subscribe[lastName]' => 'lastname'
]);
$this->assertResponseStatusCodeSame(201);
}
}
What am I doing wrong here?
So the problem is described in this post:
https://stackoverflow.com/a/19951344/3679577
TL:DR
2 requests are being done in my test. A GET and a submitForm (POST). First one uses the proper Mock, second request rebuilds the kernel and the mocks are gone.
My solution was to just use 1 request by submitting the form with a POST request. Using the CSRF token manager to generate a csrf token:
public function testSubscribe(): void
{
$client = static::createClient();
$userRepository = static::$container->get(UserRepository::class);
$testUser = $userRepository->findOneBy(['email' => UserFixtures::$testUser]);
$csrfTokenGenerator = $client->getContainer()->get('security.csrf.token_manager');
$apiClient = $this->createMock(ApiClient::class);
$client->getContainer()->set(ApiClient::class, $apiClient);
$client->loginUser($testUser);
$client->request('POST', '/subscription/new', [
'subscribe' => [
"firstName" => 'firstname',
"lastName" => "lastname",
"_token" => $csrfTokenGenerator->getToken('subscribe')->getValue()
]
]);
$this->assertResponseRedirects('/subscription/thankyou');
}

How to test function in laravel Unit testing

Using Unit Testing for the first time.
Ceated Test File by cmd:
php artisan module:make-test ProjectTest Projects
I can test by cmd:
./vendor/bin/phpunit
But I want to test my function, My function is like:
public function update(Request $request, $id)
{
$project = Project::find($id);
$project->project_name = request('project_name');
$project->save();
return response()->json([
'message' => "Project Updated Successfully",
'updatedId' => $project->id
], 200);
}
Can anyone please guide me on how to test this Controller in PHPUnit?
On PostMan testing the function like:
URL:(POST method) http://localhost:8000/api/updateProject/1
On Body
{
"project_name":"school",
}
How to use PHP Unit Testing in Laravel for the above Controller ?. Kindly explain to me with code Snippets.
You can test by using HTTP test . In order to test this you can make a request to defined route .
public function testUpdateProject()
{
$response = $this->json('POST', '/api/updateProject/project-id',$updatedData);
$response
->assertStatus(201)
->assertJson([
'field_that_return' = true
]);
}

Guzzle 6 is following redirects on local docker server, but not on production server

I am using Guzzle 6 Http Client to scrape web pages and analyze them from SEO perspective, however interesting thing is, that Guzzle does not follow redirects at all, when being used in production, but code is exatly the same. Here is the snippet I am using to request page and track redirects.
$onRedirect = function (RequestInterface $request, ResponseInterface $response, UriInterface $uri): void {
$this->totalRedirects++;
};
$response = $this->httpClient->request('GET', $url, [
'allow_redirects' => [
'max' => self::MAX_REDIRECTS,
'referer' => true,
'track_redirects' => true,
'on_redirect' => $onRedirect
],
'headers' => [
'User-Agent' => self::USER_AGENT
],
'http_errors' => true
]);
$redirectUrls = $response->getHeader('X-Guzzle-Redirect-History');
$redirectStatuses = $response->getHeader('X-Guzzle-Redirect-Status-History');
foreach ($redirectUrls as $key => $redirectUrl) {
$this->responses[] = new HttpResponse($redirectUrl, $redirectStatuses[$key]);
}
//Save last successful response
$this->responses[] = new HttpResponse($url, $response->getStatusCode());
My redirect middleware is not triggered at all, using this in production and it returns only "307", while in docker I get "307" and "200". This have been tested using samaritans page - (https://www.samaritans.org/)
Both Production and docker are using PHP 7.2 and Guzzle 6

Class 'KeenIO\Client\KeenIOClient' not found

I am including Keen in my product (code snippet below)
require INCLUDE_DIR . '/vendor/autoload.php'; // Autoloader for Composer (https://getcomposer.org/)
use KeenIO\Client\KeenIOClient;
class Statistics extends Model {
private $client;
public function __construct( $id = null ){
parent::__construct();
$this->client = KeenIOClient::factory([
'projectId' => KEEN_PROJECT_ID,
'writeKey' => KEEN_WRITE_KEY,
'readKey' => KEEN_READ_KEY
]);
}
...
but I continue to get an "Class 'KeenIO\Client\KeenIOClient' not found" error when the "KeenIOClient::factory" line runs. I was able to successfully install Keen.io through Composer - I feel it's something simple I'm missing - any ideas?
So I can't leave a comment, but I am wondering if there is maybe an issue with the include path? I was able to get this PHP snippet to work:
require 'vendor/autoload.php';
use KeenIO\Client\KeenIOClient;
$client = KeenIOClient::factory([
'projectId' => "53f3a8687d8cb95095000001",
'readKey' => "99a06e48fd7fb1279bc40995160eb0b61a9e0efaab8b651b029f0d895f77c0a804ba089282eff28bf8ad07f337422441d0542b7feaac9fea1e92fc153ee7efc51afad3276bda8d7754a338b349d540bfb402cba0dfdc82498c217054efd8abd0f47a0c0bc963bbdf0dc938c91b17d9f2"
]);
$count = $client->count('bitcoin-prices', [
'impressions' => [
'interval' => 'daily',
'timeframe' => 'this_30_days',
'group_by' => 'keen.timestamp'
]
]);
print_r($count);
That project id and read key are from the keen io open data sets (good to test with).