Automated tests in jenkins object instantiation errors Using Laravel phpunit - php

I am running automated tests in jenkins on an aws linux server using nginx and php7.3. When the tests are run I am getting the following errors
1) Tests\Feature\admin\EventManagementTest::test_admin_can_edit_event_and_view_in_event_list
Error: Call to a member function path() on null
/var/lib/jenkins/workspace/answers-integration/tests/Feature/admin/EventManagementTest.php:134
2) Tests\Feature\admin\EventManagementTest::test_admin_can_soft_delete_event_and_does_not_appear_on_event_list
Error: Call to a member function path() on null
/var/lib/jenkins/workspace/answers-integration/tests/Feature/admin/EventManagementTest.php:190
Function path() is located in my Event model
On my local environment, everything works fine. Every test passes
Objects are not being instantiated and I have no ideas as to why
The following code is where it's failing to instantiate the object with an eloquent query
$event = Event::with('event_categories', 'event_topics')->find(1);
This happens to the majority of my tests. Below is the full test code
namespace Tests\Feature\admin;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Support\Facades\DB;
use Tests\TestCase;
use \App\Event;
class EventManagementTest extends TestCase
{
use WithFaker, DatabaseMigrations;
public function setUp(): void
{
parent::setUp();
$this->seed();
}
public function test_admin_can_create_event_and_view_in_event_list()
{
//login as admin
$admin = $this->signInAsAdmin();
$attributes = [
'event_name' => $this->faker->name,
'event_description' => $this->faker->paragraph,
'event_start_date_time' => $this->faker->date('Y-m-d H:i:s'),
'event_end_date_time' => $this->faker->date('Y-m-d H:i:s'),
'organisation_name' => $this->faker->company,
'location' => $this->faker->address,
'contact_name' => $this->faker->name,
'contact_phone' => $this->faker->phoneNumber,
'contact_email' => $this->faker->email,
'contact_link' => $this->faker->url,
'venue' => $this->faker->address,
'event_categories' => [1,2],
'event_topics' => [2,3]
];
//create new event
$this->post('/admin/events', $attributes);
//retrieve event from database
$event = Event::with('event_categories', 'event_topics')->find(1);
//ensure the event data is in the database
$this->assertDatabaseHas('events', ['event_name' => $attributes['event_name'], 'event_description' => $attributes['event_description']]);
//ensure the data is in the pivot tables for categories
foreach ($event->event_categories AS $event_category){
$this->assertDatabaseHas('content_category_event', [
'event_id' => $event_category->pivot->event_id,
'content_category_id' => $event_category->pivot->content_category_id
]);
}
//ensure the data is in the pivot tables for tags
foreach ($event->event_topics AS $event_topics){
$this->assertDatabaseHas('content_tag_event', [
'event_id' => $event_topics->pivot->event_id,
'content_tag_id' => $event_topics->pivot->content_tag_id
]);
}
//make sure the title appears on the group list
$this->get('/admin/events')->assertSee($attributes['event_name']);
}
public function test_admin_can_edit_event_and_view_in_event_list()
{
//login as admin
$admin = $this->signInAsAdmin();
$attributes = [
'event_name' => $this->faker->name,
'event_description' => $this->faker->paragraph,
'event_start_date_time' => $this->faker->date('Y-m-d H:i:s'),
'event_end_date_time' => $this->faker->date('Y-m-d H:i:s'),
'organisation_name' => $this->faker->company,
'location' => $this->faker->address,
'contact_name' => $this->faker->name,
'contact_phone' => $this->faker->phoneNumber,
'contact_email' => $this->faker->email,
'contact_link' => $this->faker->url,
'venue' => $this->faker->address,
'event_categories' => [1,2],
'event_topics' => [2,3]
];
//create new event
$this->post('/admin/events', $attributes);
//retrieve event from database
$event = Event::with('event_categories', 'event_topics')->find(1);
$attributes_edit = [
'event_name' => $this->faker->name,
'event_description' => $this->faker->paragraph,
'event_start_date_time' => $this->faker->date('Y-m-d H:i:s'),
'event_end_date_time' => $this->faker->date('Y-m-d H:i:s'),
'organisation_name' => $this->faker->company,
'location' => $this->faker->address,
'contact_name' => $this->faker->name,
'contact_phone' => $this->faker->phoneNumber,
'contact_email' => $this->faker->email,
'contact_link' => $this->faker->url,
'venue' => $this->faker->address,
'event_categories' => [3,2],
'event_topics' => [2,1]
];
//update event
$this->put($event->path(), $attributes_edit);
//retrieve event from database
$event = Event::with('event_categories', 'event_topics')->find(1);
//ensure the event data is in the database
$this->assertDatabaseHas('events', [
'event_name' => $attributes_edit['event_name'],
'location' => $attributes_edit['location']
]);
//ensure the data is in the pivot tables for categories
foreach ($event->event_categories AS $event_category){
$this->assertDatabaseHas('content_category_event', [
'event_id' => $event_category->pivot->event_id,
'content_category_id' => $event_category->pivot->content_category_id
]);
}
//ensure the data is in the pivot tables for tags
foreach ($event->event_topics AS $event_topics){
$this->assertDatabaseHas('content_tag_event', [
'event_id' => $event_topics->pivot->event_id,
'content_tag_id' => $event_topics->pivot->content_tag_id
]);
}
//make sure the title appears on the group list
$this->get('/admin/events')->assertSee($attributes_edit['event_name']);
}
public function test_admin_can_soft_delete_event_and_does_not_appear_on_event_list()
{
//login as admin
$admin = $this->signInAsAdmin();
$attributes = [
'event_name' => $this->faker->name,
'event_description' => $this->faker->paragraph,
'event_start_date_time' => $this->faker->date('Y-m-d H:i:s'),
'event_end_date_time' => $this->faker->date('Y-m-d H:i:s'),
'organisation_name' => $this->faker->company,
'location' => $this->faker->address,
'contact_name' => $this->faker->name,
'contact_phone' => $this->faker->phoneNumber,
'contact_email' => $this->faker->email,
'contact_link' => $this->faker->url,
'venue' => $this->faker->address,
'event_categories' => [1,2],
'event_topics' => [2,3]
];
//create new event
$this->post('/admin/events', $attributes);
$event = Event::with('event_categories', 'event_topics')->find(1);
$this->delete($event->path());
//check the record has been soft deleted
$this->assertSoftDeleted('events', ['event_name' => $attributes['event_name']]);
//make sure the event name does not appear in event list
$this->get('/admin/users')->assertDontSee($attributes['event_name']);
}
}
EDIT
A further update doing a dd($this->post('/admin/events', $attributes)) I get the following error:
exception: Illuminate\Session\TokenMismatchException^ {#3806
#message: "CSRF token mismatch."
#code: 0
#file: "./vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php"
#line: 83
trace: {
How can a token be passed during a test?
Any help would be greatly appreciated
Regards
Danny

I found the solution to this problem from the following post
TokenMismatchException in Laravel's auth form

Related

How to return metric totals in GA4 using the PHP client library?

When using php-data-analytics, if I call getTotals() on the runReport() response, I get a "RepeatedField" object:
$params = [
"property" => "properties/{$property_id}",
"dateRanges" => [
new DateRange([
'start_date' => '7daysAgo',
'end_date' => 'yesterday',
]),
new DateRange([
'start_date' => '14daysAgo',
'end_date' => '8daysAgo',
])
],
"dimensions" => [
new Dimension([ 'name' => 'nthDay' ])
],
"metrics" => [
new Metric([ 'name' => 'activeUsers' ])
],
"orderBys" => [
new OrderBy([
'desc' => false,
'dimension' => new OrderBy\DimensionOrderBy([
"dimension_name" => 'nthDay',
"order_type" => OrderBy\DimensionOrderBy\OrderType::NUMERIC
])
])
],
"keepEmptyRows" => true
];
$report = $client->runReport($params);
$totals = $report->getTotals();
$totals is returned as the following object:
Google\Protobuf\Internal\RepeatedField Object
(
[container:Google\Protobuf\Internal\RepeatedField:private] => Array
(
)
[type:Google\Protobuf\Internal\RepeatedField:private] => 11
[klass:Google\Protobuf\Internal\RepeatedField:private] => Google\Analytics\Data\V1beta\Row
[legacy_klass:Google\Protobuf\Internal\RepeatedField:private] => Google\Analytics\Data\V1beta\Row
)
How do I use the GA4 PHP client library to return the totals for each of my metrics? According to the official documentation, this should return a Row object?
The RepeatedField result returned from calling Google\Analytics\Data\V1beta\RunReportResponse::getTotals() can be iterated.
You must request a metric aggregation when you run the report to retrieve totals.
use Google\Analytics\Data\V1beta\BetaAnalyticsDataClient;
use Google\Analytics\Data\V1beta\DateRange;
use Google\Analytics\Data\V1beta\Dimension;
use Google\Analytics\Data\V1beta\Metric;
use Google\Analytics\Data\V1beta\MetricAggregation;
use Google\Analytics\Data\V1beta\OrderBy;
use Google\Analytics\Data\V1beta\OrderBy\DimensionOrderBy;
use Google\Analytics\Data\V1beta\OrderBy\DimensionOrderBy\OrderType;
$property_id = '314116996';
$client = new BetaAnalyticsDataClient();
$params = [
'property' => "properties/{$property_id}",
'dateRanges' => [
new DateRange([
'start_date' => '7daysAgo',
'end_date' => 'yesterday',
]),
new DateRange([
'start_date' => '14daysAgo',
'end_date' => '8daysAgo',
]),
],
'dimensions' => [
new Dimension(['name' => 'nthDay']),
],
'metrics' => [
new Metric(['name' => 'activeUsers']),
],
'orderBys' => [
new OrderBy([
'desc' => false,
'dimension' => new DimensionOrderBy([
'dimension_name' => 'nthDay',
'order_type' => OrderType::NUMERIC,
]),
]),
],
'keepEmptyRows' => true,
'metricAggregations' => [
MetricAggregation::TOTAL,
],
];
$response = $client->runReport($params);
$totals = $response->getTotals();
foreach ($totals as $row) {
foreach ($row->getMetricValues() as $metricValue) {
echo 'Metric Value: '.$metricValue->getValue().PHP_EOL;
}
}
There's a GA4 Dimensions & Metrics Explorer, which can be used to build requests.
When having a request which yields results, it's not so difficult to port it to PHP then.
Dimension name nthDay may actually be ga:nthDay (at least for UA).

Laravel: Factory Fake Car Data

I created a new factory in Laravel called "CarFactory.php" and I want to use https://github.com/pelmered/fake-car.
This is the fake data that I will insert into my database using Tinker:
return [
'name' => $this->faker->vehicleBrand(),
'founded' => $this->faker->biasedNumberBetween(1998,2017, 'sqrt'),
'description' => $this->faker->paragraph()
];
In the Laravel usage code, I'm not sure where to put this (e.g. Car Model, CarFactory):
$faker->addProvider(new \Faker\Provider\Fakecar($faker));
$v = $faker->vehicleArray();
return [
'vehicle_type' => 'car',
'vin' => $faker->vin,
'registration_no' => $faker->vehicleRegistration,
'type' => $faker->vehicleType,
'fuel' => $faker->vehicleFuelType,
'brand' => $v['brand'],
'model' => $v['model'],
'year' => $faker->biasedNumberBetween(1998,2017, 'sqrt'),
];
Help is needed to know how to set this up.

Laravel: Edit value only if it appears in the request?

in my app the user can update the info of stripe connected account, however I ONLY want to actullay update the value of the fields that appear in the request payload, I could do this with a simple if check but the way I update the stripe array method makes this issue more complicated .
Is there any syntax sugar or trick to make this easier.
How my update method looks;
public function editConnectedAccount(Request $request)
{
$account = Account::retrieve($request->connectedAccountId);
Account::update(
$request->connectedAccountId,
[
'type' => 'custom',
'country' => 'ES',
'email' => $request->userEmail,
'business_type' => 'individual',
'tos_acceptance' => [ 'date' => Carbon::now()->timestamp, 'ip' => '83.46.154.71' ],
'individual' =>
[
'dob' => [ 'day' => $request->userDOBday, 'month' => $request->userDOBmonth, 'year' => $request->userDOByear ],
'first_name' => $request->userName,
'email' => $request->userEmail,
'phone' => $request->userPhone,
'last_name' => $request->userSurname,
//'ssn_last_4' => 7871,
'address' => [ 'city' => $request->userBusinessCity, 'line1' => $request->userBusinessAddress, 'postal_code' => $request->userBusinessZipCode, 'state' => $request->userBusinessCity ]
],
'business_profile' =>
[
'mcc' => 5812, //got it
'description' => '',
//'url' => 'https://www.youtube.com/?hl=es&gl=ES', //got it
],
'capabilities' => [
'card_payments' => ['requested' => true],
'transfers' => ['requested' => true],
],
]
);
return response()->json([
'account' => $account,
], 200);
Consider using a Form Request where you preform validation. This will neaten up your controller for a start and also make validation (never trust user input!) reusable.
Assuming validation is successful, calling $request->validated() from inside your controller method will return only the fields present and validated. You can then use either fill($request->validated()) or update($request->validated()).

How to make PayPalCheckout return value by post method?

I am using PayPalCheckoutSdk library following the examples, I have the following:
<?php
require __DIR__ . '/PayPalCheckout/vendor/autoload.php';
use PayPalCheckoutSdk\Core\PayPalHttpClient;
use PayPalCheckoutSdk\Core\SandboxEnvironment;
$clientId = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
$clientSecret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
$environment = new SandboxEnvironment($clientId, $clientSecret);
$client = new PayPalHttpClient($environment);
$invoiceNumber = uniqid();
$items = array();
$items[0] = [
'name' => 'HTML5',
'description' => 'Video streaming service',
'type' => 'SERVICE',
'sku' => 'sku03',
'unit_amount' =>
[
'currency_code' => 'USD',
'value' => '90.00',
],
'quantity' => '1',
'category' => 'DIGITAL_GOODS',
];
$new_item = [
'name' => 'CSS3',
'description' => 'Video streaming service',
'type' => 'SERVICE',
'sku' => 'sku02',
'unit_amount' =>
[
'currency_code' => 'USD',
'value' => '45.00',
],
'quantity' => '2',
'category' => 'DIGITAL_GOODS',
];
array_push($items , $new_item);
use PayPalCheckoutSdk\Orders\OrdersCreateRequest;
$request = new OrdersCreateRequest();
$request->prefer('return=representation');
$request->body = [
'intent' => 'CAPTURE',
'application_context' => [
'brand_name' => 'COMPANY',
'locale' => 'us-US',
'user_action' => 'PAY_NOW',
"cancel_url" => "http://localhost/PayPal/cancel.php",
"return_url" => "http://localhost/PayPal/return.php",
'landing_page' => 'BILLING',
],
'purchase_units' => [0 => [
'reference_id' => $invoiceNumber,
'amount' => [
'currency_code' => 'USD',
'value' => '160.00',
'breakdown' => [
'item_total' => [
'currency_code' => 'USD',
'value' => '180.00',
],
'shipping_discount' => [
'currency_code' => 'USD',
'value' => '20.00',
],
],
],
'items' =>
$items,
]],
];
try {
$response= $client->execute($request);
if ($response->statusCode == 201){
for ($i = 0; $i < count($response->result->links); ++$i){
$link = $response->result->links[$i];
if ($link->rel =='approve') {
header("location: $link->href");
}
}
} else {
exit(1);
}
} catch (HttpException $ex) {
echo $ex->statusCode;
print_r($ex->getMessage());
}
?>
I am receiving the data by get method print_r($_REQUEST);:
Array ( [token] => 3JX899952R0552721 [PayerID] => J95XSJRX4WXVS
And, that information is processed in the file return.php which has the following code: https://ideone.com/ncVjIt
I would like to be able to receive the information but by post method, what configurations should I make so that the data is sent by post and not by get?
As explained in comments, you can't change the redirect method back from PayPal. It will always be a GET string appended to your return_url.
However, the ideal and recommended solution is to not use any redirects. At all. Instead, use the PayPal-Checkout-SDK you have to make two routes on your server, one for 'Create Order' and one for 'Capture Order', documented here, that return only JSON data (no HTML or text). The latter one should (on success) store the payment details in your database before it does the return (particularly purchase_units[0].payments.captures[0].id, the PayPal transaction ID)
Pair these two JSON-only routes with the following approval flow that does not use any redirects, and instead keeps your site loaded in the background (lightboxed) at all times during payment approval: https://developer.paypal.com/demo/checkout/#/pattern/server

Add custom RBAC rule to PhpManager in Yii 2.0

I want to add a custom rule to PhpManager RBAC in Yii 2.0.
Here is the custom rule (#app/rbac/OwnerRule.php):
<?php
namespace app\rbac;
use yii\rbac\Rule;
/**
* Checks if userID matches user passed via params
*/
class OwnerRule extends Rule
{
public $name = 'isOwner';
public function execute($user, $item, $params)
{
$access = false;
if(isset($params['id'])){
// My custom logic used to set $access
}
return $access;
}
}
Here is the RBAC hierarchy file (#app/data/rbac.php)
<?php
use yii\rbac\Item;
return [
'manageThing0' => ['type' => Item::TYPE_OPERATION, 'description' => '...', 'bizRule' => NULL, 'data' => NULL],
'manageThing1' => ['type' => Item::TYPE_OPERATION, 'description' => '...', 'bizRule' => NULL, 'data' => NULL],
'manageThing2' => ['type' => Item::TYPE_OPERATION, 'description' => '...', 'bizRule' => NULL, 'data' => NULL],
// AND THE ROLES
'guest' => [
'type' => Item::TYPE_ROLE,
'description' => 'Guest',
'bizRule' => NULL,
'data' => NULL
],
'user' => [
'type' => Item::TYPE_ROLE,
'description' => 'User',
'children' => [
'guest',
'manageThing0', // User can edit thing0
],
'bizRule' => 'return !Yii::$app->user->isGuest;',
'data' => NULL
],
'moderator' => [
'type' => Item::TYPE_ROLE,
'description' => 'Moderator',
'children' => [
'user', // Can manage all that user can
'manageThing1', // and also thing1
],
'bizRule' => NULL,
'data' => NULL
],
'admin' => [
'type' => Item::TYPE_ROLE,
'description' => 'Admin',
'children' => [
'moderator', // can do all the stuff that moderator can
'manageThing2', // and also manage thing2
],
'bizRule' => NULL,
'data' => NULL
],
];
How do I use my custom rule in the hierarchy file?
See these links hope you will find what you are looking for,
http://www.yiiframework.com/doc-2.0/guide-security-authorization.html
http://yii2-user.dmeroff.ru/docs/custom-access-control
RBAC for basic yii2 template

Categories