How to unit test GraphQL responses on Lumen? - json

I'm trying to test an API I built with Lumen (PHP), but I'm stuck on unit test my GraphQL responses`.
This is what I have tried:
class MovieQueryTest extends Tests\GraphQLTestCase
{
use DatabaseMigrations;
public function testCanSearch()
{
Movie::create([
'name' => 'Fast & Furious 8',
'alias' => 'Fast and Furious 8',
'year' => 2016
]);
$response = $this->post('/graphql/v1', [
'query' => '{movies(search: "Fast & Furious"){data{name}}}'
]);
$response->seeJson([
'data' => [
'movies' => [
'data' => [
'name' => 'Fast & Furious 8'
]
]
]
]);
}
}
This is what I got:
PHPUnit 7.5.6 by Sebastian Bergmann and contributors.
F..... 6
/ 6 (100%)
Time: 690 ms, Memory: 24.00 MB
There was 1 failure:
1) MovieQueryTest::testCanSearch Unable to find JSON fragment
["data":{"movies":{"data":{"name":"Fast & Furious"}}}] within
[{"data":{"movies":{"data":[]}}}]. Failed asserting that false is
true.
The problem is that my data structure doesn't match the JSON's structure. While my data is inside an Array, the JSON's data is inside an Object and I can't figure out how to make it match:
["data":{"movies":{"data":{"name":"Fast & Furious 8"}}}]
[{"data":{"movies":{"data":[{"name":"Fast & Furious 8"}]}}}]
How can I make my data structure match the JSON's data structure or there is a better way to unit test GraphQL responses on Lumen?

You need to wrap 'name' => 'Fast & Furious 8' inside it's own array, for example:
The following:
$array = [
'data' => [
'movies' => [
'data' => [
['name' => 'Fast & Furious 8']
]
]
]
];
Should output:
{"data":{"movies":{"data":[{"name":"Fast & Furious 8"}]}}}

Related

Getting error while using GroupBy and Pagination in Eloquent

I'm trying to use eloquent to get me a grouped by response and at the same time give me a Pagination response (The one that gives me the link to the second page).
I'm trying to do this:
App\Eating::Where('student_id', 2)->orderBy('created_at', 'DESC')->groupBy(function ($row) {
return Carbon\Carbon::parse($row->created_at)->format('Y-m-d');
})->paginate(25);
But, I'm getting this error when running it in the Tinker:
PHP warning: strtolower() expects parameter 1 to be string, object given in D:\Folder\vendor\laravel\framework\src\Illuminate\Database\Grammar.php on line 58
without the groupBy, I'm getting the correct result:
>>> App\Eating::Where('student_id', 2)->orderBy('created_at', 'DESC')->paginate(25)->toArray();
=> [
"total" => 1,
"per_page" => 25,
"current_page" => 1,
"last_page" => 1,
"next_page_url" => null,
"prev_page_url" => null,
"from" => 1,
"to" => 3,
"data" => [
[
"id" => 5,
"status" => "Comeu Bem",
"created_at" => "2017-07-05 13:55:25",
"updated_at" => "2017-07-05 13:55:25",
],
],
]
BUT, when I remove the pagination, I do get the error but only because I added the get():
>>> App\Eating::Where('student_id', 2)->orderBy('created_at', 'DESC')->groupBy(function ($row) {
... return Carbon\Carbon::parse($row->created_at)->format('Y-m-d');
... })->get();
PHP warning: strtolower() expects parameter 1 to be string, object given in D:\Joao\git\F1Softwares\Code\Server\F1Softwares\vendor\laravel\framework\src\Illuminate\Database\Grammar.php on line 58
>>>
>>>
>>> App\Eating::Where('student_id', 2)->orderBy('created_at', 'DESC')->groupBy(function ($row) {
... return Carbon\Carbon::parse($row->created_at)->format('Y-m-d');
... });
=> Illuminate\Database\Eloquent\Builder {#855}
Any idea what I could be doing wrong? I do need to have the orderBy AND the pagination, to make it easier for the app to show the results(It is a RestFul call).
Thanks,
João
You must call the groupBy() method on a collection, but it seems this won't work with paginate(). You could try using the forPage() method on the collection:
App\Eating::where('student_id', 2)->orderBy('created_at', 'DESC')
->get()->groupBy(function ($eating) {
return $eating->created_at->format('Y-m-d');
})->forPage(1, 25);
Also, just a note, you don't need to use Carbon to parse the date, Eloquent does this for you.
Alternatively, you could try to manually create your paginator once you have the collection grouped using Illuminate\Pagination\LengthAwarePaginator.
$eatings = App\Eating::where('student_id', 2)->orderBy('created_at', 'DESC')
->get()->groupBy(function ($eating) {
return $eating->created_at->format('Y-m-d');
});
$paginatedEatings = new LengthAwarePaginator($eatings, $eatings->count(), 25);
return $paginatedEatings->toArray();

how to write mysql AND/OR in cakephp find() method [duplicate]

This question already has answers here:
cakephp OR condition
(4 answers)
Closed 6 years ago.
I wanted to find out a way to write the following code into cakephp find() method but the didn't find related resource on the cakebook.
my code is
SELECT * FROM Customers
WHERE
(Country='Germany' AND City='München')
OR (Country='Germany' AND CustomerName='München');
please share a way to write this accordingly in find() method. Thanks
You can do this using the OR key when using where:
$query = $this->Customers
->find()
->where([
'OR' => [
[
'City' => 'München',
'Country' => 'Germany'
],
[
'Country' => 'Germany',
'CustomerName' => 'München'
]
]
]);
This could be simplified to:
$query = $this->Customers
->find()
->where([
'Country' => 'Germany',
'OR' => [
['City' => 'München'],
['CustomerName' => 'München']
]
]);
See http://book.cakephp.org/3.0/en/orm/query-builder.html#advanced-conditions, I find using the andWhere and orWhere functions in combination so just stick to where!
Try
$query = $this->Customers->find(
'all',
[
'conditions' => [
'Country' => 'Germany',
'OR' => [
[
'City' => 'München',
],
[
'CustomerName' => 'München'
]
]
]
]
);
In the cookbook it says to wrap the or conditions in arrays if they are pertaining to the same field http://book.cakephp.org/2.0/en/models/retrieving-your-data.html#complex-find-conditions
If you want to paginate results you can try this:
public function yourFunctionName() {
$this->paginate['conditions']['and'][] = ['Country' => 'Germany'];
$this->paginate['conditions']['and']['or'][] = ['City' => 'München'];
$this->paginate['conditions']['and']['or'][] = ['CustomerName' => 'München'];
$customers = $this->paginate($this->Customers);
$this->set(compact('customers'));
$this->set('_serialize', ['customers']);
}

Routing in pretty url in yii2

I'm trying to use spanjeta/yii2-backup
For Project GM it works fine. here I'm not using prettyurl
For Projectamitopticals I'm getting 404 error.I'm using pretty url here.
I'm providing comparative codes below
GM - the routing -
[
'url' => Url::to(['/backup']),
'label' => 'Backup',
'icon' => 'glyphicon glyphicon-send',
'visible'=>Yii::$app->user->can('c_billing-person'),
],
Amitopticals - the routing
[
'url' => Url::to(['/backup']),
'label' => 'Backup',
'icon' => 'glyphicon glyphicon-download-alt',
],
Output screenshot in GM
Output screenshot of Amitopticals
Log of GM
Amitopticals Log
Please let me know how to resolve this.
I've sorted it out
Changed rules for pretty url -
Previous pretty url rule
'rules' => [
'<alias:>' => 'site/<alias>',
],
Corrected pretty url rule
'rules' => [
'<alias:\W+>' => 'site/<alias>',
],
Thanks everyone.

Yii2 kartik-datecontrol extension

I installed the above extension via composer and follow the documentation for every step; in my :
view : use kartik\datecontrol\DateControl;// <?=$form->field($model, 'dated')->widget(DateControl::classname(), [
'type'=>DateControl::FORMAT_DATE,
'ajaxConversion'=>false,
'options' => ['pluginOptions' => ['autoclose' => true ],'class'=>'col-xs-12 form-control input-sm']])?>
Web.php - Module configuration :
use \kartik\datecontrol\Module;
'datecontrol' => [
'class' => 'kartik\datecontrol\Module',
// format settings for displaying each date attribute (ICU format example)
'displaySettings' => [
Module::FORMAT_DATE => 'php:dd-m-Y',
Module::FORMAT_TIME => 'php:H:i:s',
Module::FORMAT_DATETIME => 'php:Y-m-d H:i:s',
],
// format settings for saving each date attribute (PHP format example)
'saveSettings' => [
Module::FORMAT_DATE => 'php:Y-m-d',
Module::FORMAT_TIME => 'php:H:i:s',
Module::FORMAT_DATETIME => 'php:Y-m-d H:i:s',
],
// set your display timezone
// 'displayTimezone' => 'Asia/Kolkata',
// set your timezone for date saved to db
// 'saveTimezone' => 'UTC',
// automatically use kartik\widgets for each of the above formats
'autoWidget' => true,
// default settings for each widget from kartik\widgets used when autoWidget is true
'autoWidgetSettings' => [
Module::FORMAT_DATE => ['type'=>2, 'pluginOptions'=>['autoclose'=>true]], // example
Module::FORMAT_DATETIME => [], // setup if needed
Module::FORMAT_TIME => [], // setup if needed
],
// custom widget settings that will be used to render the date input instead of kartik\widgets,
// this will be used when autoWidget is set to false at module or widget level.
'widgetSettings' => [
Module::FORMAT_DATE => [
'class' => 'yii\jui\DatePicker', // example
'options' => [
'dateFormat' => 'php:d-M-Y',
'options' => ['class'=>'form-control'],
]
]
]
// other settings
]
When I run the view I got the following error message :
{"name":"Invalid Configuration","message":"The class
'\kartik\date\DatePicker' was not found and is required for
DateControl 'date' format.\n\nPlease ensure you have installed one of
'yii2-widgets' OR 'yii2-widget-datepicker' extensions. To install, you
can run this console command from your application root:\n\nphp
composer.phar require kartik-v/yii2-widgets: \"#dev\"\n\n--- OR
---\n\nphp composer.phar require kartik-v/yii2-widget-datepicker: \"#dev\"","code":0,"type":"yii\base\InvalidConfigException","file":"C:\wamp\www\pub\vendor\kartik-v\yii2-krajee-base\Config.php","line":118,"stack-trace":["#0
C:\wamp\www\pub\vendor\kartik-v\yii2-krajee-base\Config.php(195):
kartik\base\Config::checkDependency('\\kartik\\date\\Da...',
Array, 'for DateControl...')","#1
C:\wamp\www\pub\vendor\kartik-v\yii2-datecontrol\DateControl.php(215):
kartik\base\Config::validateInputWidget('\\kartik\\date\\Da...',
'for DateControl...')","#2
C:\wamp\www\pub\vendor\kartik-v\yii2-datecontrol\DateControl.php(154):
kartik\datecontrol\DateControl->initConfig()","#3
C:\wamp\www\pub\vendor\yiisoft\yii2\base\Object.php(107):
kartik\datecontrol\DateControl->init()","#4 [internal function]:
yii\base\Object->__construct(Array)","#5
C:\wamp\www\pub\vendor\yiisoft\yii2\di\Container.php(372):
ReflectionClass->newInstanceArgs(Array)","#6
C:\wamp\www\pub\vendor\yiisoft\yii2\di\Container.php(151):
yii\di\Container->build('kartik\\datecont...', Array, Array)","#7
C:\wamp\www\pub\vendor\yiisoft\yii2\BaseYii.php(344):
yii\di\Container->get('kartik\\datecont...', Array, Array)","#8
C:\wamp\www\pub\vendor\yiisoft\yii2\base\Widget.php(97):
yii\BaseYii::createObject(Array)","#9
C:\wamp\www\pub\vendor\yiisoft\yii2\widgets\ActiveField.php(665):
yii\base\Widget::widget(Array)","#10
C:\wamp\www\pub\views\activite\schedules.php(49):
yii\widgets\ActiveField->widget('kartik\\datecont...',
Array)","#11
C:\wamp\www\pub\vendor\yiisoft\yii2\base\View.php(325):
require('C:\\wamp\\www\\pub...')","#12
C:\wamp\www\pub\vendor\yiisoft\yii2\base\View.php(247):
yii\base\View->renderPhpFile('C:\\wamp\\www\\pub...',
Array)","#13
C:\wamp\www\pub\vendor\yiisoft\yii2\base\View.php(149):
yii\base\View->renderFile('C:\\wamp\\www\\pub...', Array,
Object(app\controllers\ActiviteController))","#14
C:\wamp\www\pub\vendor\yiisoft\yii2\base\Controller.php(371):
yii\base\View->render('schedules', Array,
Object(app\controllers\ActiviteController))","#15
C:\wamp\www\pub\controllers\ActiviteController.php(407):
yii\base\Controller->render('schedules', Array)","#16 [internal
function]:
app\controllers\ActiviteController->actionAddsch('4')","#17
C:\wamp\www\pub\vendor\yiisoft\yii2\base\InlineAction.php(55):
call_user_func_array(Array, Array)","#18
C:\wamp\www\pub\vendor\yiisoft\yii2\base\Controller.php(151):
yii\base\InlineAction->runWithParams(Array)","#19
C:\wamp\www\pub\vendor\yiisoft\yii2\base\Module.php(455):
yii\base\Controller->runAction('addsch', Array)","#20
C:\wamp\www\pub\vendor\yiisoft\yii2\web\Application.php(84):
yii\base\Module->runAction('activite/addsch', Array)","#21
C:\wamp\www\pub\vendor\yiisoft\yii2\base\Application.php(375):
yii\web\Application->handleRequest(Object(yii\web\Request))","#22
C:\wamp\www\pub\web\index.php(12):
yii\base\Application->run()","#23 {main}"]}
Try installing the following widgets:
yii2-widget-datepicker
yii2-widget-datetimepicker
or better, install the kartik widgets using composer:
php composer.phar require kartik-v/yii2-widgets "*"
that will install the following widgets:
yii2-krajee-base
yii2-widget-activeform
yii2-widget-affix
yii2-widget-alert
yii2-widget-colorinput
yii2-widget-datepicker
yii2-widget-datetimepicker
yii2-widget-depdrop
yii2-widget-fileinput
yii2-widget-growl
yii2-widget-rangeinput
yii2-widget-rating
yii2-widget-select2
yii2-widget-sidenav
yii2-widget-spinner
yii2-widget-switchinput
yii2-widget-timepicker
yii2-widget-touchspin
yii2-widget-typeahead

How to parse this JSON object/string?

I am trying to parse the JSON written # http://a0.awsstatic.com/pricing/1/ec2/sles-od.min.js
Here is a quick snippet from above link:
{vers:0.01,config:{rate:"perhr",valueColumns:["vCPU","ECU","memoryGiB","storageGB","sles"],currencies:["USD"],regions:[{region:"us-east",instanceTypes:[{type:"generalCurrentGen",sizes:[{size:"t2.micro",vCPU:"1",ECU:"variable",
...
...
...
...
Please visit the aforementioned link to see the complete JSON.
As seen above, none of the keys of above JSON have Double Quotes around them.
This leads to malformed JSON string and my JSON parser is failing at it. I also tried putting this JSON in http://www.jsoneditoronline.org/ and it fails as well.
Now, this is the same link which is used by Amazon to display various prices of their EC2 instance. So I think I am missing something here. My Googling led me to believe that above thing is not JSON and is instead JSONP.. I don't understand what is that.
Could you help me understand how to parse this JSON. BTW, I am doing this work in perl using JSON Module.
Some background:
Amazon Web Services does not have an API to get Pricing info programmatically. Hence I am parsing these links which is what amazon is doing while displaying pricing information here. Besides, I am not from programming space and perl is all I know.
Like you said JSONP or "JSON with padding" can't be parsed by json parser because it is not json (it is a different format). But it is actually a json with the prefix (padding)
The padding is typically the name of a callback function that wraps json.
In this case, its default callback names 'callback' and we can do a bit hackiest way by using Regular Expression to capture json that is wrapped by 'callback()' like this
s/callback\((.*)\);$/$1/s;
Also, if you would like to use JSON library, you can enable allow_barekey which means you don't need those quotes around those keys.
Below is my working code. I use LWP::Simple to get the content for the given and Data::Dump to print the isolated data structure.
use strict;
use warnings;
use LWP::Simple;
use JSON;
my $jsonp = get("http://a0.awsstatic.com/pricing/1/ec2/sles-od.min.js")
or die "Couldn't get url";
( my $json = $jsonp ) =~ s/callback\((.*)\);$/$1/s; #grap the json from $jsonp and store in $json variable
my $hash = JSON->new->allow_barekey->decode ( $json );
use Data::Dump;
dd $hash;
Outputs:
{
config => {
currencies => ["USD"],
rate => "perhr",
regions => [
{
instanceTypes => [
{
sizes => [
{
ECU => "variable",
memoryGiB => 1,
size => "t2.micro",
storageGB => "ebsonly",
valueColumns => [{ name => "os", prices => { USD => 0.023 } }],
vCPU => 1,
},
{
ECU => "variable",
memoryGiB => 2,
size => "t2.small",
storageGB => "ebsonly",
valueColumns => [{ name => "os", prices => { USD => 0.056 } }],
vCPU => 1,
},
{
ECU => "variable",
memoryGiB => 4,
size => "t2.medium",
storageGB => "ebsonly",
valueColumns => [{ name => "os", prices => { USD => 0.152 } }],
vCPU => 2,
},
{
ECU => 3,
memoryGiB => 3.75,
size => "m3.medium",
storageGB => "1 x 4 SSD",
valueColumns => [{ name => "os", prices => { USD => "0.170" } }],
vCPU => 1,
},
....
As said in comments above, it is not JSON so it can't be parsed by JSON parser... But for an quick & (very)dirty work, you can try the JSON::DWIW module.
The next code:
use 5.014;
use warnings;
use WWW::Mechanize;
use Data::Dump;
use JSON::DWIW;
my $mech = WWW::Mechanize->new();
my $jsonstr = $mech->get('http://a0.awsstatic.com/pricing/1/ec2/sles-od.min.js')->content;
($jsonstr) = $jsonstr =~ /callback\((.*)\)/s;
my $json_obj = JSON::DWIW->new;
my $data = $json_obj->from_json( $jsonstr );
dd $data;
prints a structure what maybe is what you want, e.g.:
{
config => {
currencies => ["USD"],
rate => "perhr",
regions => [
{
instanceTypes => [
{
sizes => [
{
ECU => "variable",
memoryGiB => 1,
size => "t2.micro",
storageGB => "ebsonly",
valueColumns => [{ name => "os", prices => { USD => 0.023 } }],
vCPU => 1,
},
{