0

I am using CakePHP 2.9.7 and am trying to write a shell which is supposed to send mails with links (Router::url()) in them. The link will point to a page in my CakePHP application which will send another mail with another link. So we have one mail sent from the shell and one mail sent from within the application.

The documentation thaught me to set App.fullBaseUrl if I want to use routing in shells: https://book.cakephp.org/2.0/en/console-and-shells.html#routing-in-shells-cli. Since I wasn't sure if this includes the full base path, I just asked and learned that it indeed does. So I did set App.fullBaseUrl to something like http://example.com/my_app. The mail sent in the shell works like a charm now! However, some other links, e.g. the ones in mails sent from within the application are now broken because they point to http://example.com/my_app/my_app. I think it has something to do with me wanting the full URL for those links. Most other links work fine, because I don't ask for the full URL. However, if I pass along the 'full_base' => true option in the HtmlLinkHelper, the same issue occurs.

I found this: https://github.com/cakephp/cakephp/pull/1718 so I guessed this would solve my pain and I just set App.fullBaseUrl to http://example.com and App.base to /myapp. This works great in both usages. 'Yay' I thought and ran all the unit tests. They don't work anymore.

My unit tests make extensive use of $this->testAction() (in ControllerTests) and all the $this->testAction calls are now broken. For example: I have an index action in my CartController which can only be called through GET so we wrote a test to call it through POST. This worked until I set 'App.base'.

public function testIndexPost() {
    $this->testAction(
        array(
            'controller' => 'Cart',
            'action' => 'index',
        ),
        array(
            'method' => 'POST',
            'return' => 'vars',
        )
    );
}

Now I get an Error:

Failed asserting that exception of type "MissingActionException" matches expected exception "MethodNotAllowedException". Message was: "Action CartController::Cart() could not be found.".

Stack trace:

Action CartController::Cart() could not be found.
Test case: CartControllerTest(testIndexPost)

Stack trace:
F:\dev\xampp\htdocs\my_app\vendor\cakephp\cakephp\lib\Cake\Routing\Dispatcher.php : 193
F:\dev\xampp\htdocs\my_app\vendor\cakephp\cakephp\lib\Cake\Routing\Dispatcher.php : 167
F:\dev\xampp\htdocs\my_app\vendor\cakephp\cakephp\lib\Cake\TestSuite\ControllerTestCase.php : 287
ControllerTestCase::_testAction
F:\dev\xampp\htdocs\my_app\vendor\cakephp\cakephp\lib\Cake\TestSuite\ControllerTestCase.php : 199
F:\dev\xampp\htdocs\my_app\app\Test\Case\Controller\CartControllerTest.php : 83
F:\dev\xampp\htdocs\my_app\app\Test\Case\Controller\CartControllerTest.php : 83
CartControllerTest::testIndexPost
F:\dev\xampp\htdocs\my_app\vendor\phpunit\phpunit\PHPUnit\Framework\TestCase.php : 988
F:\dev\xampp\htdocs\my_app\vendor\phpunit\phpunit\PHPUnit\Framework\TestCase.php : 838
F:\dev\xampp\htdocs\my_app\vendor\phpunit\phpunit\PHPUnit\Framework\TestResult.php : 648
F:\dev\xampp\htdocs\my_app\vendor\phpunit\phpunit\PHPUnit\Framework\TestCase.php : 783
F:\dev\xampp\htdocs\my_app\vendor\cakephp\cakephp\lib\Cake\TestSuite\CakeTestCase.php : 82
F:\dev\xampp\htdocs\my_app\vendor\phpunit\phpunit\PHPUnit\Framework\TestSuite.php : 779
F:\dev\xampp\htdocs\my_app\vendor\phpunit\phpunit\PHPUnit\Framework\TestSuite.php : 749
F:\dev\xampp\htdocs\my_app\vendor\phpunit\phpunit\PHPUnit\TextUI\TestRunner.php : 350
F:\dev\xampp\htdocs\my_app\vendor\cakephp\cakephp\lib\Cake\TestSuite\CakeTestRunner.php : 62
F:\dev\xampp\htdocs\my_app\vendor\cakephp\cakephp\lib\Cake\TestSuite\CakeTestSuiteCommand.php : 98
F:\dev\xampp\htdocs\my_app\vendor\cakephp\cakephp\lib\Cake\TestSuite\CakeTestSuiteDispatcher.php : 259
F:\dev\xampp\htdocs\my_app\vendor\cakephp\cakephp\lib\Cake\TestSuite\CakeTestSuiteDispatcher.php : 96
F:\dev\xampp\htdocs\my_app\vendor\cakephp\cakephp\lib\Cake\TestSuite\CakeTestSuiteDispatcher.php : 113
F:\dev\xampp\htdocs\my_app\webroot\test.php : 104

I could of course set 'base' => false (which makes it work again) but that just doesn't feel right. I shouldn't have to change all my tests just because I set App.base in my application, right?

So whatever I do, I can't get this routing to work with all of CLI, web and unit-tests. One of them always gets messed up.

Am I doing something wrong?
Is there a better way to deal with these things?
Is this a bug?

Livia
  • 3
  • 3
  • Remove the expected exception assertion in order to retrieve the error stacktrace and add that your question, it's pretty hard to give any advice without knowing where exactly the error occours. Also where _exactly_ and how _exactly_ do you set these `App.*` options? – ndm Apr 11 '17 at 12:51
  • @ndm Thank you :) I edited the answer to contain the stack trace. When debugging ControllerTestCase::_testAction I can see that Line 236: ``$url = Router::url($url);`` returns "/my_app/Cart" but I think it should just return "/Cart". That is what it returns if ``App.base`` is not set. Maybe the Mock Object Generator gets confused by this? We set the `App.*` options in the core.php configuration. – Livia Apr 11 '17 at 13:45
  • If your app lives in the `my_app` subfolder, then the generated URL is correct in terms of that this is what `Router::url()` should generate. The problem seems to be that when passing the URL into the constructor of the request object, the possible base path isn't stripped from it, as it would when the request object generates the URL itself in `CakeRequest::_url()`, and then the wrong route is being matched. I'd suggest to report this as a bug, `ControllerTestCase::_testAction()` should maybe populate `$_SERVER['REQUEST_URI']` instead of passing the URL to the `CakeRequest` mock. – ndm Apr 11 '17 at 14:25
  • **https://github.com/cakephp/cakephp/pull/10517** – ndm Apr 13 '17 at 12:03
  • Thank you so much! I didn't get to look into it yet because I was busy with something else, but I planned to tackle this problem next week. – Livia Apr 13 '17 at 13:52

1 Answers1

0

The problem seems to be that in the request object the base path isn't stripped from the URL generated for your testAction() call.

In ControllerTestCase::_testAction(), when passing the URL into the constructor of the request object, the possible base path isn't stripped from it as it would when the request object generates the URL itself in CakeRequest::_url(), instead the URL is set as is, which then leads to the wrong route being matched.

I'd suggest to report this as a bug, ControllerTestCase::_testAction() should maybe populate $_SERVER['REQUEST_URI'] instead of passing the URL to the CakeRequest mock.

Until this is fixed, try modifying ControllerTestCase::_testAction() temporarily like this:

$_SERVER['REQUEST_URI'] = $url;
$request = $this->getMock('CakeRequest', array('_readInput'));

https://github.com/cakephp/.../blob/2.9.7/lib/Cake/TestSuite/ControllerTestCase.php#L251

ndm
  • 59,784
  • 9
  • 71
  • 110