Cakephp testAction() is not sending a json payload to controller - cakephp

I am trying to test a controller function that accepts a json payload.
As per the documentation of testAction() this can be done via setting $options['data'] to the appropriate string. Its not working for me.
See the documentation quoted here: http://api20.cakephp.org/class/controller-test-case (Please scroll down the the testAction() section).
Here is my test case.
public function testCreate(){
//Some code here
$this->testAction('/shippingbatches/create', array('data' => '[3,6]', 'method' => 'post'));
//Some more code here
}
Here is my controller function
public function create(){
debug($this->request); //This debug shows me an empty array in $this->request->data
ob_flush();
$order_ids = json_decode($this->request->data);
//Some more code here
}
The first line of the controller function is showing me an empty array in $this->request->data. If the 'data' passed from the testAction() is an actual array it comes in nice & fine. But not when it is set to a string (unlike it says in the documentation).
Here is the output of the debug.
object(Mock_CakeRequest_ef4431a5) {
params => array(
'plugin' => null,
'controller' => 'shippingbatches',
'action' => 'create',
'named' => array(),
'pass' => array(),
'return' => (int) 1,
'bare' => (int) 1,
'requested' => (int) 1
)
data => array()
query => array(
'case' => 'Controller\ShippingBatchesController'
)
url => 'shippingbatches/create'
base => ''
webroot => '/'
here => '/shippingbatches/create'
}
Please help.
Gurpreet

When passing data like that, you must receive it using CakeRequest::input().
public function create() {
$json = $this->request->input('json_decode', true);
debug($json);
}
I should note that I discovered this by reading Cake's test cases for ControllerTestCase::testAction. Reading test cases can give you insight into how Cake's internals work and give you hints on writing tests.

Related

CakePHP/PHPUnit: Testing a redirect - Location header does not seem to be set correctly

When writing a cake php controller tests withing a mock object the Location header doesnt seem to be set. From looking at the code I know for a fact that redirect is being called with the correct value. What am I doing wrong here?
Login Code:
if (!$this->Auth->login()) {
...
echo "Redirect reached.\n";
$this->redirect('/users/login');
}
Test:
public function testLoginFailedRedirectsToLogin() {
$users = $this->generate('Users', array(
'components' => array('Session'=>array('setFlash'))));
$users->Session
->expects($this->once())
->method('setFlash');
$users->response
->expects($this->once())
->method('header')
->with('Location', '/users/login');
$data = array('Users' => array(
'username' => 'bad-user',
'password' => 'infinet',
'remember_me' => false,
));
$this->testAction('/users/login',
array('data' => $data, 'method' => 'post'));
var_dump($this->headers['Location']);
$this->assertEqual($this->headers['Location'], '/users/login');
}
Output:
Redirect reached.
string(74) "http://localhost/home/nishant/projects/atp/1/.build/tmp/27784/app/Console/"
...
1) LoginTest::testLoginFailedRedirectsToLogin
Failed asserting that two strings are equal.
--- Expected
+++ Actual
## ##
-'/users/login'
+'http://localhost/home/nishant/projects/atp/1/.build/tmp/27784/app/Console/
If I remove the assertEqual the redirect's expect fails as well.
Should be
return $this->redirect('/users/login');

CakePHP Pagination 'conditions' limited by $this->Session->read()

I'm trying to limit my pagination results by the $this->Session->read('Player.team_id')... so that the logged in user can only see his related team members.
PlayersController.php
public $paginate = array(
'conditions' => array(
'Player.team_id' => $this->Session->read('Player.0.Team.id')
),
'limit' => 20,
'order' => array('Player.fullname' => 'asc')
);
public function index() {
$this->Paginator->settings = $this->paginate;
$this->Player->recursive = 0;
$this->set('players', $this->Paginator->paginate());
}
This causes an error when viewing player/index
Error: syntax error, unexpected T_VARIABLE
File: /home/www/public_html/dev/app/Controller/PlayersController.php
Line: 21
If I hardcode the 'conditions' as below then it works fine and only retrieves the records I want
'conditions' => array('Player.team_id' => 1)
In the Player.php model login action it writes the Session Variable Team.id and Team.name.
I have used the $this->Session->read else where in my app (views and other models) and it works fine. It just doesn't seem to work with in the pagination component?
This is simply invalid PHP syntax, class members can only be initialized with constant values, that is values that can be evaluated at compile time (strings, numbers, booleans, arrays, etc...)
Assign the session value at runtime in the Controller::beforeFilter() callback (or even directly in the index() action in case appropriate) instead:
public $paginate = array(
'limit' => 20,
'order' => array('Player.fullname' => 'asc')
);
public function beforeFilter() {
parent::beforeFilter();
$this->paginate['conditions'] = array(
'Player.team_id' => $this->Session->read('Player.0.Team.id')
);
}
Also as pointed out in the comments, make sure that the session key you are accessing actually exists and holds the expected value!
See also http://www.php.net/manual/en/language.oop5.properties.php

2 Find statements in one function in CakePHP 2.1

Hi I'm currently working on a project and was wondering if it was possible to do two find functions in cakephp?
For example I am making a sports news website and I am grouping the news articles as top story, understory and headline.
What I want to do is retrive top stories so i can highlight these as the prominent story and then understory will be beneath as a lesser story and then headlines will be the least important.
This is what I have so far
function latestnews() {
$articles = $this->Article->find('all',
array('limit' =>3,
'order' =>
array('Article.date_created' => 'desc')));
if(isset($this->params['requested'])) {
return $articles;
}
$this->set('articles', $articles);
$articler = $this->Article->find('all',
array('Article.type' => 'topstory',
'Limit' => '1'
));
$this->set('articles', $articler);
}
however this doesn't seem to work, it doesn't limit the $articles function but instead echos all the data in the table.
in the view im doing a standard foreach statement to echo the data and I get thrown a undefined variable error.
Is what i am saying even possible or should I create different functions and then use them as elements?
Thanks for any input in advance!
You can bind the associationship with itself dynamically. Try this code:
function latestnews() {
$this->Article->bindModel(array('hasMany' => array('TopStory' => array('className' => 'Article',
'foreignKey' => false,
'conditions' => array('Article.type' => 'topstory')
),
'Highlight' .....
)));
$articles = $this->Article->find('all',
array('limit' =>3,
'order' => array('Article.date_created' => 'desc')));
if(isset($this->params['requested'])) {
return $articles;
}
$this->set('articles', $articles);
$articler = $this->Article->find('all',
array('Article.type' => 'topstory',
'Limit' => '1'
));
$this->set('articles', $articler);
}
Hope it will work for you.
#Arun Nope that didn't seem to work, I get this error, Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'Article.type' in 'where clause' also I've tried to put it in an element with its own function and I then get thrown this error...
Notice (8): Undefined variable: data [APP/View/Elements/Articles/topstories.ctp, line 5]
Warning (2): Invalid argument supplied for foreach() [APP/View/Elements/Articles/topstories.ctp, line 5]
Notice (8): Undefined property: View::$Paginator [CORE/Cake/View/View.php, line 806]
Fatal error: Call to a member function prev() on a non-object in /Applications/XAMPP/xamppfiles/htdocs/kickoff/app/View/Elements/Articles/topstories.ctp on line 21
The controller code is the following...
function topstories() {
$this->paginate = array(
'conditions' => array('Article.type' => 'topstory'),
'limit' => 2,
'order' => array(
'date_created' => 'asc'
)
);
$data = $this->paginate('Article');
$this->set(compact('data'));
}
I find this error confusing as if I don't put this in an element and in a view instead it works perfectly! however in an element not so perfect :S
any ideas as to why this is the case??
Instead of using two find methods in one function I instead chose to simply create different functions and use them as elements for example...
function premiershiptopstory() {
$pltopnews = $this->Article->find('all', array(
'conditions' => array('Article.league' => 'premiership',
'Article.type' => 'topstory')));
if(!empty($this->request->params['requested'])) {
return $pltopnews;}
$this->set('article', $pltopnews);
}
However in the view you must request the action otherwise you will get thrown an error, to request the action simply use this line of code...
<?php $pltopnews = $this->requestAction('/Articles/premiershiptopstory');
Hope this helps others!

mock cake request to stub out the data function

I have been searching all around the internet on how to mock cake requests. i want to stub out the data function to make $this->request->data('whatever') available in the controller. but something is going wrong with my test case
$Jobs = $this->generate('Tasks' , array(
'components' => array(
'RequestHandler' => array('isMobile','prefers','renderAs'))
));
// Mock CakeRequest
$request = $this->getMock('CakeRequest', array('_readInput'));
$Jobs->RequestHandler->request = $request;
$Jobs->RequestHandler->request->expects($this->any())
->method('data')->with('anything')->will($this->returnValue('test'));
$result = $this->testAction('/tasks/test/',
array('method' => 'get', 'return' => 'vars'));
whenever i call $this->request->data('anything') in the controller it returns null!
Please try to help me with this
From the PhpUnit documentation :
By default, all methods of the given class are replaced with a test double that just returns NULL unless a return value is configured using will($this->returnValue()), for instance.
When the second (optional) parameter is provided, only the methods whose names are in the array are replaced with a configurable test double. The behavior of the other methods is not changed.
So you need to either do this :
$Jobs = $this->generate('Tasks' , array(
'components' => array(
'RequestHandler' => array('isMobile','prefers','renderAs'))
));
// Mock CakeRequest
$request = $this->getMock('CakeRequest', array('_readInput'));
$Jobs->RequestHandler->request = $request;
$Jobs->RequestHandler->request->expects($this->any())
->method('_readInput')->with('anything')->will($this->returnValue('test'));
$result = $this->testAction('/tasks/test/',
array('method' => 'get', 'return' => 'vars'));
or this :
$Jobs = $this->generate('Tasks' , array(
'components' => array(
'RequestHandler' => array('isMobile','prefers','renderAs'))
));
// Mock CakeRequest
$request = $this->getMock('CakeRequest', array('data'));
$Jobs->RequestHandler->request = $request;
$Jobs->RequestHandler->request->expects($this->any())
->method('data')->with('anything')->will($this->returnValue('test'));
$result = $this->testAction('/tasks/test/',
array('method' => 'get', 'return' => 'vars'));
As I don't know cakePHP I can't tell you which is the right answer.
But according to this : http://api20.cakephp.org/view_source/controller-test-dispatcher
(line 232), you should try the former one.

How to pass parameters with testAction in CakePHP2.0

I want to test a function with this header:
public function includeNumComments($posts){
Where $post is an array of data.
I wonder how can i test the method passing it an array of posts.
I have tried things like this, but it doesn't work:
$result = $this->testAction("/comments/includeNumComments/", array('data' => $posts));
$result = $this->testAction("/comments/includeNumComments/", array($posts));
Thanks
Here's the correct case, it worked for me. Hope it helps:
public function testAddUser() {
$data = array(
'User' => array(
'id' => 12,
'username' => 'testname1',
'password' => 'Pass#123!',
'email' => 'test#example.com'
)
);
$result = $this->testAction(
'/users/add',
array('data' => $data, 'method' => 'post')
);
debug($result);
}
That's not really using testAction then, because you can't pass an array via HTTP. There'd be no way to do this via a form or link on a website.
You can just test it as a normal function:
$result = $this->CommentsController->includeNumComments($posts);

Resources