Symfony2: UnitTests for AJAX Controllers - php

I'm going to write some Symfony2 UnitTests (derived from Symfony\ Bundle\ FrameworkBundle\ Test\ WebTestCase) to test ajax controllers, similar to this How to get Ajax post request by symfony2 Controller.
My big problem is to get the parameters into the "request" bag of the request, not into the "parameter" bag. Similar to the upper example the method in the controller looks like this:
public function ajaxAction(Request $request)
{
$data = $request->request->get('data');
}
But if i do a var_dump of the $request, the paramaters i supply in the WebTestCase do not appear in $request->request, but in $request->parameter. Let's say this is the portion of code in my webtestcase:
....
$client = static::createClient();
$client->request('POST', '/ajax/blahblah', ... ?????);
I already tried supplying the parameter(s) directly within the url as
/ajax/blahblah?data=whocares
I tried specifying the parameter within an array
$client->request('POST', '/ajax/blahblah', array('data' => 'fruityloops'));
But nothing worked. Any chance to get this running?
Thanks in advance
Hennes

After you make the request, you need to get the response. Try this:
$client = static::createClient();
$client->request('POST', '/ajax/blahblah', array('data' => 'fruityloops'));
$response = $client->getResponse();
$this->assertEquals(200, $response->getStatusCode());
//convert to array
$data = json_decode($response->getContent(true), true);
var_dump($data);
$this->assertArrayHasKey('your_key', $data);

Related

Laravel HTTP Client - method chaining issue

I have been using the HTTP client in Laravel 8, as follows:
$http = Http::asForm()->post($url, $post_data);
$response = $http->body();
This works great. Now I want to include a file upload as part of this request, but the file is optional. I have tried to structure my request like this:
use Illuminate\Support\Facades\Http;
use Illuminate\Http\Request;
public function index(Request $request)
{
$url = 'my-url';
$post_data = $request->post();
$http = Http::asForm();
if ($request->hasFile('image')) {
$http->attach('image', $request->file('image'));
}
$http->post($url, $post_data);
$response = $http->body();
}
But this is not working. The error I am getting is: Method Illuminate\Http\Client\PendingRequest::body does not exist.
The post() method appears to be returning Illuminate\Http\Client\PendingRequest instead of Illuminate\Http\Client\Response.
Any ideas how to do this?
$response = $http->post($url, $post_data)->body();
// alternatively:
$pendingRequest = $http->post($url, $post_data);
$response = $pendingRequest->body();
In your second code sample, you don't assign the return of post() to a variable. But this return value (Illuminate\Http\Client\PendingRequest) is the object that defines the body() method. So either use a second variable (or reassign $http), or chain the post() and body() calls as shown above.

Accessing a URL stored in a variable from a controller

I am in a confusing situation
In my Laravel controller, I have a variable
public function storeName($key)
$store = new Store();
$storeName = $store->connectAPI($key);
This $storeName variable will actually give me a URL, which if accessed, will give me a JSON response.
If I die and dump $storeName variable it will print
http://store123.com?key=2093983892
But, what I actually want is to access this $storeName variable, by passing a GET request in my controller, so I can get a JSON response from this API call.
How can I access this URL in my controller?
From Guzzle docs
$client = new GuzzleHttp\Client();
$res = $client->request('GET', 'https://api.github.com/user', []);
if($res->getStatusCode())
{
// "200"
$json = $res->getBody();
}
I used json_decode inside a curl_init function to solve this issue.

Using value from previous test case in PHPUnit

I am trying to assign a value to a variable inside the first testing function and then use it in other testing functions inside the class.
right now in my code the second function fails due to this error:
1) ApiAdTest::testApiAd_postedAdCreated
GuzzleHttp\Exception\ClientException: Client error: 404
and i dont know why. this is how the code looks like:
class ApiAdTest extends PHPUnit_Framework_TestCase
{
protected $adId;
private static $base_url = 'http://10.0.0.38/adserver/src/public/';
private static $path = 'api/ad/';
//start of expected flow
public function testApiAd_postAd()
{
$client = new Client(['base_uri' => self::$base_url]);
$response = $client->post(self::$path, ['form_params' => [
'name' => 'bellow content - guzzle testing'
]]);
$data = json_decode($response->getBody());
$this->adId = $data->id;
$code = $response->getStatusCode();
$this->assertEquals($code, 200);
}
public function testApiAd_postedAdCreated()
{
$client = new Client(['base_uri' => self::$base_url]);
$response = $client->get(self::$path.$this->adId);
$code = $response->getStatusCode();
$data = json_decode($response->getBody());
$this->assertEquals($code, 200);
$this->assertEquals($data->id, $this->adId);
$this->assertEquals($data->name, 'bellow content - guzzle testing');
}
in the phpunit doumintation https://phpunit.de/manual/current/en/fixtures.html i see i can define a
a variable inside the setUp method and then use it as i want but in my case i only know the value after the first post executes. any idea how can i use $this->adId in the second function??
Unit tests by definition should not rely on one another. You will end up with unstable and fragile tests which are then hard to debug the moment they start failing, since the cause is in another test case.
There is no guarantee in which order the tests execute in PHPUnit by default.
PHPUnit supports the #depends annotation to achieve what you want, the docs have the same warning though.

How do you pass Content-Type header when testing Silex REST service?

I'm testing a Silex REST service as explained here but also trying to automatically decode JSON data as is also explained in the manual but somehow it fails to create the $data parameter.
In my test I'm calling the service with:
$data = file_get_contents(__DIR__.'/resources/billing-info.json');
$client->request('POST', '/users/test_user/bills',array(), array(), array('Content-Type' => 'application/json'), $data);
and in the Controller I try to access the unmarshalled data as
$app->post('/users/{username}/bills', function(Request $request, $username) use($app) {
try {
$myData = $request->data;
.....
} catch (Exception $e){
return $app->json(array('error'=>$e->getMessage()),$e->getCode());
}
});
But the $data is non existent. What am I doing wrong?
You need to change Content-Type to CONTENT_TYPE. If you look at the source code for the Client class, you'll find that the $server argument needs to match the keys given by the $_SERVER superglobal. The content-type header is stored in the CONTENT_TYPE key.
$client->request('POST', '/users/test_user/bills',array(), array(), array('CONTENT_TYPE' => 'application/json'), $data);
Check out the Documentation on the Request-Object. I guess instead of $myData = $request->data; it must be:
$myData = $request->getContent();

Laravel - POST data is null when using external request

I'm new to laravel, and I'm trying to implement a simple rest api.
I have the controller implemented, and tested via unit testing.
My problem is with the POST request.
Via the tests Input:json has data, via an external rest client it returns null.
This is the code on the unit test
$newMenu = array(
'name'=>'Christmas Menu',
'description'=>'Christmas Menu',
'img_url'=>'http://www.example.com',
'type_id'=>1,
);
Request::setMethod('POST');
Input::$json = $newMenu;
$response = Controller::call('menu#index');
What am I doing wrong?
UPDATE:
This is realy driving me crazy
I've instanciated a new laravel project and just have this code:
Routes
Route::get('test', 'home#index');
Route::post('test', 'home#index');
Controller:
class Home_Controller extends Base_Controller {
public $restful = true;
public function get_index()
{
return Response::json(['test'=>'hello world']);
}
public function post_index()
{
return Response::json(['test'=>Input::all()]);
}
}
CURL call:
curl -H "Accept:application/json" -H"Content-type: application/json" -X POST -d '{"title":"world"}' http://localhost/laravel-post/public/test
response:
{"test":[]}
Can anyone point me to what is wrong.
This is really preventing me to use laravel, and I really liked the concept.
Because you are posting JSON as your HTTP body you don't get it with Input::all();
You should use:
$postInput = file_get_contents('php://input');
$data = json_decode($postInput, true);
$response = array('test' => $data);
return Response::json($response);
Also you can use
Route::any('test', 'home#index');
instead of
Route::get('test', 'home#index');
Route::post('test', 'home#index');
Remove header Content-type: application/json if you are sending it as key value pairs and not a json
If you use : Route::post('test', 'XYZController#test');
Send data format : Content-type : application/json
For example : {"data":"foo bar"}
And you can get the post (any others:get, put...etc) data with :
Input::get('data');
This is clearly written in here : http://laravel.com/docs/requests
. Correct Content-type is very important!
I am not sure your CURL call is correct. Maybe this can be helpful : How to POST JSON data with Curl from Terminal/Commandline to Test Spring REST?
I am using Input::get('data') and it works.
I was facing this problem, my response of post was always null. To solve that I put the body key in guzzle object, like this
$client = new Client([
'headers' => [
'Content-Type' => 'application/json',
'Authorization' => config('app.callisto_token'),
]
]);
$body = [
'firstResult'=> 0,
'data' => '05/05/2022'
];
$response = $client->post('http://'.$this->ip.'/IntegracaoERP'.'/status_pedido',
['body' => json_encode($body)]
);
Don't forget the json_encode in body key.
Hope this helps.

Categories