CakePHP
  • Documentation
    • Book
    • API
    • Videos
    • Logos & Trademarks
  • Business Solutions
  • Swag
  • Road Trip
  • Team
  • Community
    • Community
    • Team
    • Issues (Github)
    • YouTube Channel
    • Get Involved
    • Bakery
    • Featured Resources
    • Newsletter
    • Certification
    • My CakePHP
    • CakeFest
    • Facebook
    • Twitter
    • Help & Support
    • Forum
    • Stack Overflow
    • IRC
    • Slack
    • Paid Support
CakePHP

C CakePHP 3.7 Red Velvet API

  • Overview
  • Tree
  • Deprecated
  • Version:
    • 3.7
      • 3.7
      • 3.6
      • 3.5
      • 3.4
      • 3.3
      • 3.2
      • 3.1
      • 3.0
      • 2.10
      • 2.9
      • 2.8
      • 2.7
      • 2.6
      • 2.5
      • 2.4
      • 2.3
      • 2.2
      • 2.1
      • 2.0
      • 1.3
      • 1.2

Namespaces

  • Cake
    • Auth
      • Storage
    • Cache
      • Engine
    • Collection
      • Iterator
    • Command
    • Console
      • Exception
    • Controller
      • Component
      • Exception
    • Core
      • Configure
        • Engine
      • Exception
      • Retry
    • Database
      • Driver
      • Exception
      • Expression
      • Schema
      • Statement
      • Type
    • Datasource
      • Exception
    • Error
      • Middleware
    • Event
      • Decorator
    • Filesystem
    • Form
    • Http
      • Client
        • Adapter
        • Auth
      • Cookie
      • Exception
      • Middleware
      • Session
    • I18n
      • Formatter
      • Middleware
      • Parser
    • Log
      • Engine
    • Mailer
      • Exception
      • Transport
    • Network
      • Exception
    • ORM
      • Association
      • Behavior
        • Translate
      • Exception
      • Locator
      • Rule
    • Routing
      • Exception
      • Filter
      • Middleware
      • Route
    • Shell
      • Helper
      • Task
    • TestSuite
      • Fixture
      • Stub
    • Utility
      • Exception
    • Validation
    • View
      • Exception
      • Form
      • Helper
      • Widget
  • None

Classes

  • ConsoleIntegrationTestCase
  • IntegrationTestCase
  • LegacyCommandRunner
  • LegacyShellDispatcher
  • TestCase
  • TestEmailTransport
  • TestSuite

Traits

  • ConsoleIntegrationTestTrait
  • EmailAssertTrait
  • EmailTrait
  • IntegrationTestTrait
  • StringCompareTrait
   1: <?php
   2: /**
   3:  * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
   4:  * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
   5:  *
   6:  * Licensed under The MIT License
   7:  * For full copyright and license information, please see the LICENSE.txt
   8:  * Redistributions of files must retain the above copyright notice
   9:  *
  10:  * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  11:  * @since         3.7.0
  12:  * @license       https://opensource.org/licenses/mit-license.php MIT License
  13:  */
  14: namespace Cake\TestSuite;
  15: 
  16: use Cake\Core\Configure;
  17: use Cake\Database\Exception as DatabaseException;
  18: use Cake\Http\ServerRequest;
  19: use Cake\Http\Session;
  20: use Cake\Routing\Router;
  21: use Cake\TestSuite\Constraint\Response\BodyContains;
  22: use Cake\TestSuite\Constraint\Response\BodyEmpty;
  23: use Cake\TestSuite\Constraint\Response\BodyEquals;
  24: use Cake\TestSuite\Constraint\Response\BodyNotContains;
  25: use Cake\TestSuite\Constraint\Response\BodyNotEmpty;
  26: use Cake\TestSuite\Constraint\Response\BodyNotEquals;
  27: use Cake\TestSuite\Constraint\Response\BodyNotRegExp;
  28: use Cake\TestSuite\Constraint\Response\BodyRegExp;
  29: use Cake\TestSuite\Constraint\Response\ContentType;
  30: use Cake\TestSuite\Constraint\Response\CookieEncryptedEquals;
  31: use Cake\TestSuite\Constraint\Response\CookieEquals;
  32: use Cake\TestSuite\Constraint\Response\CookieNotSet;
  33: use Cake\TestSuite\Constraint\Response\CookieSet;
  34: use Cake\TestSuite\Constraint\Response\FileSent;
  35: use Cake\TestSuite\Constraint\Response\FileSentAs;
  36: use Cake\TestSuite\Constraint\Response\HeaderContains;
  37: use Cake\TestSuite\Constraint\Response\HeaderEquals;
  38: use Cake\TestSuite\Constraint\Response\HeaderNotContains;
  39: use Cake\TestSuite\Constraint\Response\HeaderNotSet;
  40: use Cake\TestSuite\Constraint\Response\HeaderSet;
  41: use Cake\TestSuite\Constraint\Response\StatusCode;
  42: use Cake\TestSuite\Constraint\Response\StatusError;
  43: use Cake\TestSuite\Constraint\Response\StatusFailure;
  44: use Cake\TestSuite\Constraint\Response\StatusOk;
  45: use Cake\TestSuite\Constraint\Response\StatusSuccess;
  46: use Cake\TestSuite\Constraint\Session\FlashParamEquals;
  47: use Cake\TestSuite\Constraint\Session\SessionEquals;
  48: use Cake\TestSuite\Constraint\View\LayoutFileEquals;
  49: use Cake\TestSuite\Constraint\View\TemplateFileEquals;
  50: use Cake\TestSuite\Stub\TestExceptionRenderer;
  51: use Cake\Utility\CookieCryptTrait;
  52: use Cake\Utility\Hash;
  53: use Cake\Utility\Security;
  54: use Cake\Utility\Text;
  55: use Cake\View\Helper\SecureFieldTokenTrait;
  56: use Exception;
  57: use LogicException;
  58: use PHPUnit\Exception as PhpunitException;
  59: 
  60: /**
  61:  * A trait intended to make integration tests of your controllers easier.
  62:  *
  63:  * This test class provides a number of helper methods and features
  64:  * that make dispatching requests and checking their responses simpler.
  65:  * It favours full integration tests over mock objects as you can test
  66:  * more of your code easily and avoid some of the maintenance pitfalls
  67:  * that mock objects create.
  68:  */
  69: trait IntegrationTestTrait
  70: {
  71:     use CookieCryptTrait;
  72:     use SecureFieldTokenTrait;
  73: 
  74:     /**
  75:      * Track whether or not tests are run against
  76:      * the PSR7 HTTP stack.
  77:      *
  78:      * @var bool
  79:      */
  80:     protected $_useHttpServer = false;
  81: 
  82:     /**
  83:      * The customized application class name.
  84:      *
  85:      * @var string|null
  86:      */
  87:     protected $_appClass;
  88: 
  89:     /**
  90:      * The customized application constructor arguments.
  91:      *
  92:      * @var array|null
  93:      */
  94:     protected $_appArgs;
  95: 
  96:     /**
  97:      * The data used to build the next request.
  98:      *
  99:      * @var array
 100:      */
 101:     protected $_request = [];
 102: 
 103:     /**
 104:      * The response for the most recent request.
 105:      *
 106:      * @var \Cake\Http\Response|null
 107:      */
 108:     protected $_response;
 109: 
 110:     /**
 111:      * The exception being thrown if the case.
 112:      *
 113:      * @var \Exception|null
 114:      */
 115:     protected $_exception;
 116: 
 117:     /**
 118:      * Session data to use in the next request.
 119:      *
 120:      * @var array
 121:      */
 122:     protected $_session = [];
 123: 
 124:     /**
 125:      * Cookie data to use in the next request.
 126:      *
 127:      * @var array
 128:      */
 129:     protected $_cookie = [];
 130: 
 131:     /**
 132:      * The controller used in the last request.
 133:      *
 134:      * @var \Cake\Controller\Controller|null
 135:      */
 136:     protected $_controller;
 137: 
 138:     /**
 139:      * The last rendered view
 140:      *
 141:      * @var string|null
 142:      */
 143:     protected $_viewName;
 144: 
 145:     /**
 146:      * The last rendered layout
 147:      *
 148:      * @var string|null
 149:      */
 150:     protected $_layoutName;
 151: 
 152:     /**
 153:      * The session instance from the last request
 154:      *
 155:      * @var \Cake\Http\Session|null
 156:      */
 157:     protected $_requestSession;
 158: 
 159:     /**
 160:      * Boolean flag for whether or not the request should have
 161:      * a SecurityComponent token added.
 162:      *
 163:      * @var bool
 164:      */
 165:     protected $_securityToken = false;
 166: 
 167:     /**
 168:      * Boolean flag for whether or not the request should have
 169:      * a CSRF token added.
 170:      *
 171:      * @var bool
 172:      */
 173:     protected $_csrfToken = false;
 174: 
 175:     /**
 176:      * Boolean flag for whether or not the request should re-store
 177:      * flash messages
 178:      *
 179:      * @var bool
 180:      */
 181:     protected $_retainFlashMessages = false;
 182: 
 183:     /**
 184:      * Stored flash messages before render
 185:      *
 186:      * @var null|array
 187:      */
 188:     protected $_flashMessages;
 189: 
 190:     /**
 191:      *
 192:      * @var null|string
 193:      */
 194:     protected $_cookieEncryptionKey;
 195: 
 196:     /**
 197:      * Auto-detect if the HTTP middleware stack should be used.
 198:      *
 199:      * @before
 200:      * @return void
 201:      */
 202:     public function setupServer()
 203:     {
 204:         $namespace = Configure::read('App.namespace');
 205:         $this->_useHttpServer = class_exists($namespace . '\Application');
 206:     }
 207: 
 208:     /**
 209:      * Clears the state used for requests.
 210:      *
 211:      * @after
 212:      * @return void
 213:      */
 214:     public function cleanup()
 215:     {
 216:         $this->_request = [];
 217:         $this->_session = [];
 218:         $this->_cookie = [];
 219:         $this->_response = null;
 220:         $this->_exception = null;
 221:         $this->_controller = null;
 222:         $this->_viewName = null;
 223:         $this->_layoutName = null;
 224:         $this->_requestSession = null;
 225:         $this->_appClass = null;
 226:         $this->_appArgs = null;
 227:         $this->_securityToken = false;
 228:         $this->_csrfToken = false;
 229:         $this->_retainFlashMessages = false;
 230:         $this->_useHttpServer = false;
 231:     }
 232: 
 233:     /**
 234:      * Toggle whether or not you want to use the HTTP Server stack.
 235:      *
 236:      * @param bool $enable Enable/disable the usage of the HTTP Stack.
 237:      * @return void
 238:      */
 239:     public function useHttpServer($enable)
 240:     {
 241:         $this->_useHttpServer = (bool)$enable;
 242:     }
 243: 
 244:     /**
 245:      * Configure the application class to use in integration tests.
 246:      *
 247:      * Combined with `useHttpServer()` to customize the class name and constructor arguments
 248:      * of your application class.
 249:      *
 250:      * @param string $class The application class name.
 251:      * @param array|null $constructorArgs The constructor arguments for your application class.
 252:      * @return void
 253:      */
 254:     public function configApplication($class, $constructorArgs)
 255:     {
 256:         $this->_appClass = $class;
 257:         $this->_appArgs = $constructorArgs;
 258:     }
 259: 
 260:     /**
 261:      * Calling this method will enable a SecurityComponent
 262:      * compatible token to be added to request data. This
 263:      * lets you easily test actions protected by SecurityComponent.
 264:      *
 265:      * @return void
 266:      */
 267:     public function enableSecurityToken()
 268:     {
 269:         $this->_securityToken = true;
 270:     }
 271: 
 272:     /**
 273:      * Calling this method will add a CSRF token to the request.
 274:      *
 275:      * Both the POST data and cookie will be populated when this option
 276:      * is enabled. The default parameter names will be used.
 277:      *
 278:      * @return void
 279:      */
 280:     public function enableCsrfToken()
 281:     {
 282:         $this->_csrfToken = true;
 283:     }
 284: 
 285:     /**
 286:      * Calling this method will re-store flash messages into the test session
 287:      * after being removed by the FlashHelper
 288:      *
 289:      * @return void
 290:      */
 291:     public function enableRetainFlashMessages()
 292:     {
 293:         $this->_retainFlashMessages = true;
 294:     }
 295: 
 296:     /**
 297:      * Configures the data for the *next* request.
 298:      *
 299:      * This data is cleared in the tearDown() method.
 300:      *
 301:      * You can call this method multiple times to append into
 302:      * the current state.
 303:      *
 304:      * @param array $data The request data to use.
 305:      * @return void
 306:      */
 307:     public function configRequest(array $data)
 308:     {
 309:         $this->_request = $data + $this->_request;
 310:     }
 311: 
 312:     /**
 313:      * Sets session data.
 314:      *
 315:      * This method lets you configure the session data
 316:      * you want to be used for requests that follow. The session
 317:      * state is reset in each tearDown().
 318:      *
 319:      * You can call this method multiple times to append into
 320:      * the current state.
 321:      *
 322:      * @param array $data The session data to use.
 323:      * @return void
 324:      */
 325:     public function session(array $data)
 326:     {
 327:         $this->_session = $data + $this->_session;
 328:     }
 329: 
 330:     /**
 331:      * Sets a request cookie for future requests.
 332:      *
 333:      * This method lets you configure the session data
 334:      * you want to be used for requests that follow. The session
 335:      * state is reset in each tearDown().
 336:      *
 337:      * You can call this method multiple times to append into
 338:      * the current state.
 339:      *
 340:      * @param string $name The cookie name to use.
 341:      * @param mixed $value The value of the cookie.
 342:      * @return void
 343:      */
 344:     public function cookie($name, $value)
 345:     {
 346:         $this->_cookie[$name] = $value;
 347:     }
 348: 
 349:     /**
 350:      * Returns the encryption key to be used.
 351:      *
 352:      * @return string
 353:      */
 354:     protected function _getCookieEncryptionKey()
 355:     {
 356:         if (isset($this->_cookieEncryptionKey)) {
 357:             return $this->_cookieEncryptionKey;
 358:         }
 359: 
 360:         return Security::getSalt();
 361:     }
 362: 
 363:     /**
 364:      * Sets a encrypted request cookie for future requests.
 365:      *
 366:      * The difference from cookie() is this encrypts the cookie
 367:      * value like the CookieComponent.
 368:      *
 369:      * @param string $name The cookie name to use.
 370:      * @param mixed $value The value of the cookie.
 371:      * @param string|bool $encrypt Encryption mode to use.
 372:      * @param string|null $key Encryption key used. Defaults
 373:      *   to Security.salt.
 374:      * @return void
 375:      * @see \Cake\Utility\CookieCryptTrait::_encrypt()
 376:      */
 377:     public function cookieEncrypted($name, $value, $encrypt = 'aes', $key = null)
 378:     {
 379:         $this->_cookieEncryptionKey = $key;
 380:         $this->_cookie[$name] = $this->_encrypt($value, $encrypt);
 381:     }
 382: 
 383:     /**
 384:      * Performs a GET request using the current request data.
 385:      *
 386:      * The response of the dispatched request will be stored as
 387:      * a property. You can use various assert methods to check the
 388:      * response.
 389:      *
 390:      * @param string|array $url The URL to request.
 391:      * @return void
 392:      * @throws \PHPUnit\Exception
 393:      */
 394:     public function get($url)
 395:     {
 396:         $this->_sendRequest($url, 'GET');
 397:     }
 398: 
 399:     /**
 400:      * Performs a POST request using the current request data.
 401:      *
 402:      * The response of the dispatched request will be stored as
 403:      * a property. You can use various assert methods to check the
 404:      * response.
 405:      *
 406:      * @param string|array $url The URL to request.
 407:      * @param string|array|null $data The data for the request.
 408:      * @return void
 409:      * @throws \PHPUnit\Exception
 410:      */
 411:     public function post($url, $data = [])
 412:     {
 413:         $this->_sendRequest($url, 'POST', $data);
 414:     }
 415: 
 416:     /**
 417:      * Performs a PATCH request using the current request data.
 418:      *
 419:      * The response of the dispatched request will be stored as
 420:      * a property. You can use various assert methods to check the
 421:      * response.
 422:      *
 423:      * @param string|array $url The URL to request.
 424:      * @param string|array|null $data The data for the request.
 425:      * @return void
 426:      * @throws \PHPUnit\Exception
 427:      */
 428:     public function patch($url, $data = [])
 429:     {
 430:         $this->_sendRequest($url, 'PATCH', $data);
 431:     }
 432: 
 433:     /**
 434:      * Performs a PUT request using the current request data.
 435:      *
 436:      * The response of the dispatched request will be stored as
 437:      * a property. You can use various assert methods to check the
 438:      * response.
 439:      *
 440:      * @param string|array $url The URL to request.
 441:      * @param string|array|null $data The data for the request.
 442:      * @return void
 443:      * @throws \PHPUnit\Exception
 444:      */
 445:     public function put($url, $data = [])
 446:     {
 447:         $this->_sendRequest($url, 'PUT', $data);
 448:     }
 449: 
 450:     /**
 451:      * Performs a DELETE request using the current request data.
 452:      *
 453:      * The response of the dispatched request will be stored as
 454:      * a property. You can use various assert methods to check the
 455:      * response.
 456:      *
 457:      * @param string|array $url The URL to request.
 458:      * @return void
 459:      * @throws \PHPUnit\Exception
 460:      */
 461:     public function delete($url)
 462:     {
 463:         $this->_sendRequest($url, 'DELETE');
 464:     }
 465: 
 466:     /**
 467:      * Performs a HEAD request using the current request data.
 468:      *
 469:      * The response of the dispatched request will be stored as
 470:      * a property. You can use various assert methods to check the
 471:      * response.
 472:      *
 473:      * @param string|array $url The URL to request.
 474:      * @return void
 475:      * @throws \PHPUnit\Exception
 476:      */
 477:     public function head($url)
 478:     {
 479:         $this->_sendRequest($url, 'HEAD');
 480:     }
 481: 
 482:     /**
 483:      * Performs an OPTIONS request using the current request data.
 484:      *
 485:      * The response of the dispatched request will be stored as
 486:      * a property. You can use various assert methods to check the
 487:      * response.
 488:      *
 489:      * @param string|array $url The URL to request.
 490:      * @return void
 491:      * @throws \PHPUnit\Exception
 492:      */
 493:     public function options($url)
 494:     {
 495:         $this->_sendRequest($url, 'OPTIONS');
 496:     }
 497: 
 498:     /**
 499:      * Creates and send the request into a Dispatcher instance.
 500:      *
 501:      * Receives and stores the response for future inspection.
 502:      *
 503:      * @param string|array $url The URL
 504:      * @param string $method The HTTP method
 505:      * @param string|array|null $data The request data.
 506:      * @return void
 507:      * @throws \PHPUnit\Exception
 508:      */
 509:     protected function _sendRequest($url, $method, $data = [])
 510:     {
 511:         $dispatcher = $this->_makeDispatcher();
 512:         $url = $dispatcher->resolveUrl($url);
 513: 
 514:         try {
 515:             $request = $this->_buildRequest($url, $method, $data);
 516:             $response = $dispatcher->execute($request);
 517:             $this->_requestSession = $request['session'];
 518:             if ($this->_retainFlashMessages && $this->_flashMessages) {
 519:                 $this->_requestSession->write('Flash', $this->_flashMessages);
 520:             }
 521:             $this->_response = $response;
 522:         } catch (PhpUnitException $e) {
 523:             throw $e;
 524:         } catch (DatabaseException $e) {
 525:             throw $e;
 526:         } catch (LogicException $e) {
 527:             throw $e;
 528:         } catch (Exception $e) {
 529:             $this->_exception = $e;
 530:             // Simulate the global exception handler being invoked.
 531:             $this->_handleError($e);
 532:         }
 533:     }
 534: 
 535:     /**
 536:      * Get the correct dispatcher instance.
 537:      *
 538:      * @return \Cake\TestSuite\MiddlewareDispatcher|\Cake\TestSuite\LegacyRequestDispatcher A dispatcher instance
 539:      */
 540:     protected function _makeDispatcher()
 541:     {
 542:         if ($this->_useHttpServer) {
 543:             return new MiddlewareDispatcher($this, $this->_appClass, $this->_appArgs);
 544:         }
 545: 
 546:         return new LegacyRequestDispatcher($this);
 547:     }
 548: 
 549:     /**
 550:      * Adds additional event spies to the controller/view event manager.
 551:      *
 552:      * @param \Cake\Event\Event $event A dispatcher event.
 553:      * @param \Cake\Controller\Controller|null $controller Controller instance.
 554:      * @return void
 555:      */
 556:     public function controllerSpy($event, $controller = null)
 557:     {
 558:         if (!$controller) {
 559:             /** @var \Cake\Controller\Controller $controller */
 560:             $controller = $event->getSubject();
 561:         }
 562:         $this->_controller = $controller;
 563:         $events = $controller->getEventManager();
 564:         $events->on('View.beforeRender', function ($event, $viewFile) use ($controller) {
 565:             if (!$this->_viewName) {
 566:                 $this->_viewName = $viewFile;
 567:             }
 568:             if ($this->_retainFlashMessages) {
 569:                 $this->_flashMessages = $controller->getRequest()->getSession()->read('Flash');
 570:             }
 571:         });
 572:         $events->on('View.beforeLayout', function ($event, $viewFile) {
 573:             $this->_layoutName = $viewFile;
 574:         });
 575:     }
 576: 
 577:     /**
 578:      * Attempts to render an error response for a given exception.
 579:      *
 580:      * This method will attempt to use the configured exception renderer.
 581:      * If that class does not exist, the built-in renderer will be used.
 582:      *
 583:      * @param \Exception $exception Exception to handle.
 584:      * @return void
 585:      * @throws \Exception
 586:      */
 587:     protected function _handleError($exception)
 588:     {
 589:         $class = Configure::read('Error.exceptionRenderer');
 590:         if (empty($class) || !class_exists($class)) {
 591:             $class = 'Cake\Error\ExceptionRenderer';
 592:         }
 593:         /** @var \Cake\Error\ExceptionRenderer $instance */
 594:         $instance = new $class($exception);
 595:         $this->_response = $instance->render();
 596:     }
 597: 
 598:     /**
 599:      * Creates a request object with the configured options and parameters.
 600:      *
 601:      * @param string|array $url The URL
 602:      * @param string $method The HTTP method
 603:      * @param string|array|null $data The request data.
 604:      * @return array The request context
 605:      */
 606:     protected function _buildRequest($url, $method, $data)
 607:     {
 608:         $sessionConfig = (array)Configure::read('Session') + [
 609:             'defaults' => 'php',
 610:         ];
 611:         $session = Session::create($sessionConfig);
 612:         $session->write($this->_session);
 613:         list($url, $query) = $this->_url($url);
 614:         $tokenUrl = $url;
 615: 
 616:         if ($query) {
 617:             $tokenUrl .= '?' . $query;
 618:         }
 619: 
 620:         parse_str($query, $queryData);
 621:         $props = [
 622:             'url' => $url,
 623:             'session' => $session,
 624:             'query' => $queryData,
 625:             'files' => [],
 626:         ];
 627:         if (is_string($data)) {
 628:             $props['input'] = $data;
 629:         }
 630:         if (!isset($props['input'])) {
 631:             $data = $this->_addTokens($tokenUrl, $data);
 632:             $props['post'] = $this->_castToString($data);
 633:         }
 634:         $props['cookies'] = $this->_cookie;
 635: 
 636:         $env = [
 637:             'REQUEST_METHOD' => $method,
 638:             'QUERY_STRING' => $query,
 639:             'REQUEST_URI' => $url,
 640:         ];
 641:         if (isset($this->_request['headers'])) {
 642:             foreach ($this->_request['headers'] as $k => $v) {
 643:                 $name = strtoupper(str_replace('-', '_', $k));
 644:                 if (!in_array($name, ['CONTENT_LENGTH', 'CONTENT_TYPE'])) {
 645:                     $name = 'HTTP_' . $name;
 646:                 }
 647:                 $env[$name] = $v;
 648:             }
 649:             unset($this->_request['headers']);
 650:         }
 651:         $props['environment'] = $env;
 652:         $props = Hash::merge($props, $this->_request);
 653: 
 654:         return $props;
 655:     }
 656: 
 657:     /**
 658:      * Add the CSRF and Security Component tokens if necessary.
 659:      *
 660:      * @param string $url The URL the form is being submitted on.
 661:      * @param array $data The request body data.
 662:      * @return array The request body with tokens added.
 663:      */
 664:     protected function _addTokens($url, $data)
 665:     {
 666:         if ($this->_securityToken === true) {
 667:             $keys = array_map(function ($field) {
 668:                 return preg_replace('/(\.\d+)+$/', '', $field);
 669:             }, array_keys(Hash::flatten($data)));
 670:             $tokenData = $this->_buildFieldToken($url, array_unique($keys));
 671:             $data['_Token'] = $tokenData;
 672:             $data['_Token']['debug'] = 'SecurityComponent debug data would be added here';
 673:         }
 674: 
 675:         if ($this->_csrfToken === true) {
 676:             if (!isset($this->_cookie['csrfToken'])) {
 677:                 $this->_cookie['csrfToken'] = Text::uuid();
 678:             }
 679:             if (!isset($data['_csrfToken'])) {
 680:                 $data['_csrfToken'] = $this->_cookie['csrfToken'];
 681:             }
 682:         }
 683: 
 684:         return $data;
 685:     }
 686: 
 687:     /**
 688:      * Recursively casts all data to string as that is how data would be POSTed in
 689:      * the real world
 690:      *
 691:      * @param array $data POST data
 692:      * @return array
 693:      */
 694:     protected function _castToString($data)
 695:     {
 696:         foreach ($data as $key => $value) {
 697:             if (is_scalar($value)) {
 698:                 $data[$key] = $value === false ? '0' : (string)$value;
 699: 
 700:                 continue;
 701:             }
 702: 
 703:             if (is_array($value)) {
 704:                 $looksLikeFile = isset($value['error'], $value['tmp_name'], $value['size']);
 705:                 if ($looksLikeFile) {
 706:                     continue;
 707:                 }
 708: 
 709:                 $data[$key] = $this->_castToString($value);
 710:             }
 711:         }
 712: 
 713:         return $data;
 714:     }
 715: 
 716:     /**
 717:      * Creates a valid request url and parameter array more like Request::_url()
 718:      *
 719:      * @param string|array $url The URL
 720:      * @return array Qualified URL and the query parameters
 721:      */
 722:     protected function _url($url)
 723:     {
 724:         // re-create URL in ServerRequest's context so
 725:         // query strings are encoded as expected
 726:         $request = new ServerRequest(['url' => $url]);
 727:         $url = $request->getRequestTarget();
 728: 
 729:         $query = '';
 730: 
 731:         $path = parse_url($url, PHP_URL_PATH);
 732:         if (strpos($url, '?') !== false) {
 733:             $query = parse_url($url, PHP_URL_QUERY);
 734:         }
 735: 
 736:         return [$path, $query];
 737:     }
 738: 
 739:     /**
 740:      * Get the response body as string
 741:      *
 742:      * @return string The response body.
 743:      */
 744:     protected function _getBodyAsString()
 745:     {
 746:         if (!$this->_response) {
 747:             $this->fail('No response set, cannot assert content.');
 748:         }
 749: 
 750:         return (string)$this->_response->getBody();
 751:     }
 752: 
 753:     /**
 754:      * Fetches a view variable by name.
 755:      *
 756:      * If the view variable does not exist, null will be returned.
 757:      *
 758:      * @param string $name The view variable to get.
 759:      * @return mixed The view variable if set.
 760:      */
 761:     public function viewVariable($name)
 762:     {
 763:         if (empty($this->_controller->viewVars)) {
 764:             $this->fail('There are no view variables, perhaps you need to run a request?');
 765:         }
 766:         if (isset($this->_controller->viewVars[$name])) {
 767:             return $this->_controller->viewVars[$name];
 768:         }
 769: 
 770:         return null;
 771:     }
 772: 
 773:     /**
 774:      * Asserts that the response status code is in the 2xx range.
 775:      *
 776:      * @param string $message Custom message for failure.
 777:      * @return void
 778:      */
 779:     public function assertResponseOk($message = null)
 780:     {
 781:         $verboseMessage = $this->extractVerboseMessage($message);
 782:         $this->assertThat(null, new StatusOk($this->_response), $verboseMessage);
 783:     }
 784: 
 785:     /**
 786:      * Asserts that the response status code is in the 2xx/3xx range.
 787:      *
 788:      * @param string $message Custom message for failure.
 789:      * @return void
 790:      */
 791:     public function assertResponseSuccess($message = null)
 792:     {
 793:         $verboseMessage = $this->extractVerboseMessage($message);
 794:         $this->assertThat(null, new StatusSuccess($this->_response), $verboseMessage);
 795:     }
 796: 
 797:     /**
 798:      * Asserts that the response status code is in the 4xx range.
 799:      *
 800:      * @param string $message Custom message for failure.
 801:      * @return void
 802:      */
 803:     public function assertResponseError($message = null)
 804:     {
 805:         $this->assertThat(null, new StatusError($this->_response), $message);
 806:     }
 807: 
 808:     /**
 809:      * Asserts that the response status code is in the 5xx range.
 810:      *
 811:      * @param string $message Custom message for failure.
 812:      * @return void
 813:      */
 814:     public function assertResponseFailure($message = null)
 815:     {
 816:         $this->assertThat(null, new StatusFailure($this->_response), $message);
 817:     }
 818: 
 819:     /**
 820:      * Asserts a specific response status code.
 821:      *
 822:      * @param int $code Status code to assert.
 823:      * @param string $message Custom message for failure.
 824:      * @return void
 825:      */
 826:     public function assertResponseCode($code, $message = null)
 827:     {
 828:         $this->assertThat($code, new StatusCode($this->_response), $message);
 829:     }
 830: 
 831:     /**
 832:      * Asserts that the Location header is correct.
 833:      *
 834:      * @param string|array|null $url The URL you expected the client to go to. This
 835:      *   can either be a string URL or an array compatible with Router::url(). Use null to
 836:      *   simply check for the existence of this header.
 837:      * @param string $message The failure message that will be appended to the generated message.
 838:      * @return void
 839:      */
 840:     public function assertRedirect($url = null, $message = '')
 841:     {
 842:         $verboseMessage = $this->extractVerboseMessage($message);
 843:         $this->assertThat(null, new HeaderSet($this->_response, 'Location'), $verboseMessage);
 844: 
 845:         if ($url) {
 846:             $this->assertThat(Router::url($url, ['_full' => true]), new HeaderEquals($this->_response, 'Location'), $verboseMessage);
 847:         }
 848:     }
 849: 
 850:     /**
 851:      * Asserts that the Location header contains a substring
 852:      *
 853:      * @param string $url The URL you expected the client to go to.
 854:      * @param string $message The failure message that will be appended to the generated message.
 855:      * @return void
 856:      */
 857:     public function assertRedirectContains($url, $message = '')
 858:     {
 859:         $verboseMessage = $this->extractVerboseMessage($message);
 860:         $this->assertThat(null, new HeaderSet($this->_response, 'Location'), $verboseMessage);
 861:         $this->assertThat($url, new HeaderContains($this->_response, 'Location'), $verboseMessage);
 862:     }
 863: 
 864:     /**
 865:      * Asserts that the Location header does not contain a substring
 866:      *
 867:      * @param string $url The URL you expected the client to go to.
 868:      * @param string $message The failure message that will be appended to the generated message.
 869:      * @return void
 870:      */
 871:     public function assertRedirectNotContains($url, $message = '')
 872:     {
 873:         $verboseMessage = $this->extractVerboseMessage($message);
 874:         $this->assertThat(null, new HeaderSet($this->_response, 'Location'), $verboseMessage);
 875:         $this->assertThat($url, new HeaderNotContains($this->_response, 'Location'), $verboseMessage);
 876:     }
 877: 
 878:     /**
 879:      * Asserts that the Location header is not set.
 880:      *
 881:      * @param string $message The failure message that will be appended to the generated message.
 882:      * @return void
 883:      */
 884:     public function assertNoRedirect($message = '')
 885:     {
 886:         $verboseMessage = $this->extractVerboseMessage($message);
 887:         $this->assertThat(null, new HeaderNotSet($this->_response, 'Location'), $verboseMessage);
 888:     }
 889: 
 890:     /**
 891:      * Asserts response headers
 892:      *
 893:      * @param string $header The header to check
 894:      * @param string $content The content to check for.
 895:      * @param string $message The failure message that will be appended to the generated message.
 896:      * @return void
 897:      */
 898:     public function assertHeader($header, $content, $message = '')
 899:     {
 900:         $verboseMessage = $this->extractVerboseMessage($message);
 901:         $this->assertThat(null, new HeaderSet($this->_response, $header), $verboseMessage);
 902:         $this->assertThat($content, new HeaderEquals($this->_response, $header), $verboseMessage);
 903:     }
 904: 
 905:     /**
 906:      * Asserts response header contains a string
 907:      *
 908:      * @param string $header The header to check
 909:      * @param string $content The content to check for.
 910:      * @param string $message The failure message that will be appended to the generated message.
 911:      * @return void
 912:      */
 913:     public function assertHeaderContains($header, $content, $message = '')
 914:     {
 915:         $verboseMessage = $this->extractVerboseMessage($message);
 916:         $this->assertThat(null, new HeaderSet($this->_response, $header), $verboseMessage);
 917:         $this->assertThat($content, new HeaderContains($this->_response, $header), $verboseMessage);
 918:     }
 919: 
 920:     /**
 921:      * Asserts response header does not contain a string
 922:      *
 923:      * @param string $header The header to check
 924:      * @param string $content The content to check for.
 925:      * @param string $message The failure message that will be appended to the generated message.
 926:      * @return void
 927:      */
 928:     public function assertHeaderNotContains($header, $content, $message = '')
 929:     {
 930:         $verboseMessage = $this->extractVerboseMessage($message);
 931:         $this->assertThat(null, new HeaderSet($this->_response, $header), $verboseMessage);
 932:         $this->assertThat($content, new HeaderNotContains($this->_response, $header), $verboseMessage);
 933:     }
 934: 
 935:     /**
 936:      * Asserts content type
 937:      *
 938:      * @param string $type The content-type to check for.
 939:      * @param string $message The failure message that will be appended to the generated message.
 940:      * @return void
 941:      */
 942:     public function assertContentType($type, $message = '')
 943:     {
 944:         $verboseMessage = $this->extractVerboseMessage($message);
 945:         $this->assertThat($type, new ContentType($this->_response), $verboseMessage);
 946:     }
 947: 
 948:     /**
 949:      * Asserts content in the response body equals.
 950:      *
 951:      * @param mixed $content The content to check for.
 952:      * @param string $message The failure message that will be appended to the generated message.
 953:      * @return void
 954:      */
 955:     public function assertResponseEquals($content, $message = '')
 956:     {
 957:         $verboseMessage = $this->extractVerboseMessage($message);
 958:         $this->assertThat($content, new BodyEquals($this->_response), $verboseMessage);
 959:     }
 960: 
 961:     /**
 962:      * Asserts content in the response body not equals.
 963:      *
 964:      * @param mixed $content The content to check for.
 965:      * @param string $message The failure message that will be appended to the generated message.
 966:      * @return void
 967:      */
 968:     public function assertResponseNotEquals($content, $message = '')
 969:     {
 970:         $verboseMessage = $this->extractVerboseMessage($message);
 971:         $this->assertThat($content, new BodyNotEquals($this->_response), $verboseMessage);
 972:     }
 973: 
 974:     /**
 975:      * Asserts content exists in the response body.
 976:      *
 977:      * @param string $content The content to check for.
 978:      * @param string $message The failure message that will be appended to the generated message.
 979:      * @param bool $ignoreCase A flag to check whether we should ignore case or not.
 980:      * @return void
 981:      */
 982:     public function assertResponseContains($content, $message = '', $ignoreCase = false)
 983:     {
 984:         $verboseMessage = $this->extractVerboseMessage($message);
 985:         $this->assertThat($content, new BodyContains($this->_response, $ignoreCase), $verboseMessage);
 986:     }
 987: 
 988:     /**
 989:      * Asserts content does not exist in the response body.
 990:      *
 991:      * @param string $content The content to check for.
 992:      * @param string $message The failure message that will be appended to the generated message.
 993:      * @param bool $ignoreCase A flag to check whether we should ignore case or not.
 994:      * @return void
 995:      */
 996:     public function assertResponseNotContains($content, $message = '', $ignoreCase = false)
 997:     {
 998:         $verboseMessage = $this->extractVerboseMessage($message);
 999:         $this->assertThat($content, new BodyNotContains($this->_response, $ignoreCase), $verboseMessage);
1000:     }
1001: 
1002:     /**
1003:      * Asserts that the response body matches a given regular expression.
1004:      *
1005:      * @param string $pattern The pattern to compare against.
1006:      * @param string $message The failure message that will be appended to the generated message.
1007:      * @return void
1008:      */
1009:     public function assertResponseRegExp($pattern, $message = '')
1010:     {
1011:         $verboseMessage = $this->extractVerboseMessage($message);
1012:         $this->assertThat($pattern, new BodyRegExp($this->_response), $verboseMessage);
1013:     }
1014: 
1015:     /**
1016:      * Asserts that the response body does not match a given regular expression.
1017:      *
1018:      * @param string $pattern The pattern to compare against.
1019:      * @param string $message The failure message that will be appended to the generated message.
1020:      * @return void
1021:      */
1022:     public function assertResponseNotRegExp($pattern, $message = '')
1023:     {
1024:         $verboseMessage = $this->extractVerboseMessage($message);
1025:         $this->assertThat($pattern, new BodyNotRegExp($this->_response), $verboseMessage);
1026:     }
1027: 
1028:     /**
1029:      * Assert response content is not empty.
1030:      *
1031:      * @param string $message The failure message that will be appended to the generated message.
1032:      * @return void
1033:      */
1034:     public function assertResponseNotEmpty($message = '')
1035:     {
1036:         $this->assertThat(null, new BodyNotEmpty($this->_response), $message);
1037:     }
1038: 
1039:     /**
1040:      * Assert response content is empty.
1041:      *
1042:      * @param string $message The failure message that will be appended to the generated message.
1043:      * @return void
1044:      */
1045:     public function assertResponseEmpty($message = '')
1046:     {
1047:         $this->assertThat(null, new BodyEmpty($this->_response), $message);
1048:     }
1049: 
1050:     /**
1051:      * Asserts that the search string was in the template name.
1052:      *
1053:      * @param string $content The content to check for.
1054:      * @param string $message The failure message that will be appended to the generated message.
1055:      * @return void
1056:      */
1057:     public function assertTemplate($content, $message = '')
1058:     {
1059:         $verboseMessage = $this->extractVerboseMessage($message);
1060:         $this->assertThat($content, new TemplateFileEquals($this->_viewName), $verboseMessage);
1061:     }
1062: 
1063:     /**
1064:      * Asserts that the search string was in the layout name.
1065:      *
1066:      * @param string $content The content to check for.
1067:      * @param string $message The failure message that will be appended to the generated message.
1068:      * @return void
1069:      */
1070:     public function assertLayout($content, $message = '')
1071:     {
1072:         $verboseMessage = $this->extractVerboseMessage($message);
1073:         $this->assertThat($content, new LayoutFileEquals($this->_layoutName), $verboseMessage);
1074:     }
1075: 
1076:     /**
1077:      * Asserts session contents
1078:      *
1079:      * @param string $expected The expected contents.
1080:      * @param string $path The session data path. Uses Hash::get() compatible notation
1081:      * @param string $message The failure message that will be appended to the generated message.
1082:      * @return void
1083:      */
1084:     public function assertSession($expected, $path, $message = '')
1085:     {
1086:         $verboseMessage = $this->extractVerboseMessage($message);
1087:         $this->assertThat($expected, new SessionEquals($this->_requestSession, $path), $verboseMessage);
1088:     }
1089: 
1090:     /**
1091:      * Asserts a flash message was set
1092:      *
1093:      * @param string $expected Expected message
1094:      * @param string $key Flash key
1095:      * @param string $message Assertion failure message
1096:      * @return void
1097:      */
1098:     public function assertFlashMessage($expected, $key = 'flash', $message = '')
1099:     {
1100:         $verboseMessage = $this->extractVerboseMessage($message);
1101:         $this->assertThat($expected, new FlashParamEquals($this->_requestSession, $key, 'message'), $verboseMessage);
1102:     }
1103: 
1104:     /**
1105:      * Asserts a flash message was set at a certain index
1106:      *
1107:      * @param int $at Flash index
1108:      * @param string $expected Expected message
1109:      * @param string $key Flash key
1110:      * @param string $message Assertion failure message
1111:      * @return void
1112:      */
1113:     public function assertFlashMessageAt($at, $expected, $key = 'flash', $message = '')
1114:     {
1115:         $verboseMessage = $this->extractVerboseMessage($message);
1116:         $this->assertThat($expected, new FlashParamEquals($this->_requestSession, $key, 'message', $at), $verboseMessage);
1117:     }
1118: 
1119:     /**
1120:      * Asserts a flash element was set
1121:      *
1122:      * @param string $expected Expected element name
1123:      * @param string $key Flash key
1124:      * @param string $message Assertion failure message
1125:      * @return void
1126:      */
1127:     public function assertFlashElement($expected, $key = 'flash', $message = '')
1128:     {
1129:         $verboseMessage = $this->extractVerboseMessage($message);
1130:         $this->assertThat($expected, new FlashParamEquals($this->_requestSession, $key, 'element'), $verboseMessage);
1131:     }
1132: 
1133:     /**
1134:      * Asserts a flash element was set at a certain index
1135:      *
1136:      * @param int $at Flash index
1137:      * @param string $expected Expected element name
1138:      * @param string $key Flash key
1139:      * @param string $message Assertion failure message
1140:      * @return void
1141:      */
1142:     public function assertFlashElementAt($at, $expected, $key = 'flash', $message = '')
1143:     {
1144:         $verboseMessage = $this->extractVerboseMessage($message);
1145:         $this->assertThat($expected, new FlashParamEquals($this->_requestSession, $key, 'element', $at), $verboseMessage);
1146:     }
1147: 
1148:     /**
1149:      * Asserts cookie values
1150:      *
1151:      * @param string $expected The expected contents.
1152:      * @param string $name The cookie name.
1153:      * @param string $message The failure message that will be appended to the generated message.
1154:      * @return void
1155:      */
1156:     public function assertCookie($expected, $name, $message = '')
1157:     {
1158:         $verboseMessage = $this->extractVerboseMessage($message);
1159:         $this->assertThat($name, new CookieSet($this->_response), $verboseMessage);
1160:         $this->assertThat($expected, new CookieEquals($this->_response, $name), $verboseMessage);
1161:     }
1162: 
1163:     /**
1164:      * Asserts a cookie has not been set in the response
1165:      *
1166:      * @param string $cookie The cookie name to check
1167:      * @param string $message The failure message that will be appended to the generated message.
1168:      * @return void
1169:      */
1170:     public function assertCookieNotSet($cookie, $message = '')
1171:     {
1172:         $verboseMessage = $this->extractVerboseMessage($message);
1173:         $this->assertThat($cookie, new CookieNotSet($this->_response), $verboseMessage);
1174:     }
1175: 
1176:     /**
1177:      * Disable the error handler middleware.
1178:      *
1179:      * By using this function, exceptions are no longer caught by the ErrorHandlerMiddleware
1180:      * and are instead re-thrown by the TestExceptionRenderer. This can be helpful
1181:      * when trying to diagnose/debug unexpected failures in test cases.
1182:      *
1183:      * @return void
1184:      */
1185:     public function disableErrorHandlerMiddleware()
1186:     {
1187:         Configure::write('Error.exceptionRenderer', TestExceptionRenderer::class);
1188:     }
1189: 
1190:     /**
1191:      * Asserts cookie values which are encrypted by the
1192:      * CookieComponent.
1193:      *
1194:      * The difference from assertCookie() is this decrypts the cookie
1195:      * value like the CookieComponent for this assertion.
1196:      *
1197:      * @param string $expected The expected contents.
1198:      * @param string $name The cookie name.
1199:      * @param string|bool $encrypt Encryption mode to use.
1200:      * @param string|null $key Encryption key used. Defaults
1201:      *   to Security.salt.
1202:      * @param string $message The failure message that will be appended to the generated message.
1203:      * @return void
1204:      * @see \Cake\Utility\CookieCryptTrait::_encrypt()
1205:      */
1206:     public function assertCookieEncrypted($expected, $name, $encrypt = 'aes', $key = null, $message = '')
1207:     {
1208:         $verboseMessage = $this->extractVerboseMessage($message);
1209:         $this->assertThat($name, new CookieSet($this->_response), $verboseMessage);
1210: 
1211:         $this->_cookieEncryptionKey = $key;
1212:         $this->assertThat($expected, new CookieEncryptedEquals($this->_response, $name, $encrypt, $this->_getCookieEncryptionKey()));
1213:     }
1214: 
1215:     /**
1216:      * Asserts that a file with the given name was sent in the response
1217:      *
1218:      * @param string $expected The absolute file path that should be sent in the response.
1219:      * @param string $message The failure message that will be appended to the generated message.
1220:      * @return void
1221:      */
1222:     public function assertFileResponse($expected, $message = '')
1223:     {
1224:         $verboseMessage = $this->extractVerboseMessage($message);
1225:         $this->assertThat(null, new FileSent($this->_response), $verboseMessage);
1226:         $this->assertThat($expected, new FileSentAs($this->_response), $verboseMessage);
1227:     }
1228: 
1229:     /**
1230:      * Inspect controller to extract possible causes of the failed assertion
1231:      *
1232:      * @param string $message Original message to use as a base
1233:      * @return null|string
1234:      */
1235:     protected function extractVerboseMessage($message = null)
1236:     {
1237:         if ($this->_exception instanceof \Exception) {
1238:             $message .= $this->extractExceptionMessage($this->_exception);
1239:         }
1240:         if ($this->_controller === null) {
1241:             return $message;
1242:         }
1243:         $error = Hash::get($this->_controller->viewVars, 'error');
1244:         if ($error instanceof \Exception) {
1245:             $message .= $this->extractExceptionMessage($this->viewVariable('error'));
1246:         }
1247: 
1248:         return $message;
1249:     }
1250: 
1251:     /**
1252:      * Extract verbose message for existing exception
1253:      *
1254:      * @param \Exception $exception Exception to extract
1255:      * @return string
1256:      */
1257:     protected function extractExceptionMessage(\Exception $exception)
1258:     {
1259:         return PHP_EOL .
1260:             sprintf('Possibly related to %s: "%s" ', get_class($exception), $exception->getMessage()) .
1261:             PHP_EOL .
1262:             $exception->getTraceAsString();
1263:     }
1264: }
1265: 
Follow @CakePHP
#IRC
OpenHub
Rackspace
  • Business Solutions
  • Showcase
  • Documentation
  • Book
  • API
  • Videos
  • Logos & Trademarks
  • Community
  • Team
  • Issues (Github)
  • YouTube Channel
  • Get Involved
  • Bakery
  • Featured Resources
  • Newsletter
  • Certification
  • My CakePHP
  • CakeFest
  • Facebook
  • Twitter
  • Help & Support
  • Forum
  • Stack Overflow
  • IRC
  • Slack
  • Paid Support

Generated using CakePHP API Docs