├── .gitignore ├── LICENSE ├── composer.json ├── readme.md └── src └── Codeception ├── Lib └── Connector │ └── Laravel5.php └── Module └── Laravel5.php /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2015 Jan-Henk Gerritsen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "janhenkgerritsen/codeception-laravel5", 3 | "description": "Laravel5 module for Codeception", 4 | "keywords": ["Codeception", "Laravel", "Laravel5"], 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Jan-Henk Gerritsen", 9 | "email": "j.h.gerritsen@movage.nl" 10 | } 11 | ], 12 | "require": { 13 | "php": ">=5.4.0", 14 | "codeception/codeception": "<2.0.11" 15 | }, 16 | "autoload": { 17 | "psr-0": { 18 | "Codeception": "src" 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Codeception Laravel 5 module 2 | 3 | ## This package is not maintained on this repository any longer since it is included in Codeception as of version 2.11. Please report issues there. 4 | 5 | This package provides a Laravel 5 module for [Codeception](https://github.com/Codeception/Codeception). 6 | It is based on the Laravel 4 module by Davert that is currently included with Codeception. 7 | 8 | ## Installation 9 | You can install this package through composer: 10 | 11 | composer require janhenkgerritsen/codeception-laravel5 12 | 13 | ## Usage 14 | You can use this module as any other Codeception module, by adding 'Laravel5' to the enabled modules in your Codeception suite configurations. 15 | 16 | ## Demo project 17 | A demo Laravel 5 project that uses this module can be found at . 18 | -------------------------------------------------------------------------------- /src/Codeception/Lib/Connector/Laravel5.php: -------------------------------------------------------------------------------- 1 | app = $app; 28 | $this->httpKernel = $this->app->make('Illuminate\Contracts\Http\Kernel'); 29 | $this->httpKernel->bootstrap(); 30 | $this->app->boot(); 31 | parent::__construct($this); 32 | } 33 | /** 34 | * Handle a request. 35 | * 36 | * @param DomRequest $request 37 | * @param int $type 38 | * @param bool $catch 39 | * @return Response 40 | */ 41 | public function handle(DomRequest $request, $type = self::MASTER_REQUEST, $catch = true) 42 | { 43 | $request = Request::createFromBase($request); 44 | $request->enableHttpMethodParameterOverride(); 45 | $this->app->bind('request', $request); 46 | return $this->httpKernel->handle($request); 47 | } 48 | /** 49 | * Terminates a request/response cycle. 50 | * 51 | * @param DomRequest $request A Request instance 52 | * @param Response $response A Response instance 53 | * 54 | * @api 55 | */ 56 | public function terminate(DomRequest $request, Response $response) 57 | { 58 | $this->httpKernel->terminate(Request::createFromBase($request), $response); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Codeception/Module/Laravel5.php: -------------------------------------------------------------------------------- 1 | 20 | * 21 | * ## Status 22 | * 23 | * * Maintainer: **Jan-Henk Gerritsen** 24 | * * Stability: **dev** 25 | * * Contact: janhenkgerritsen@gmail.com 26 | * 27 | * ## Config 28 | * 29 | * * cleanup: `boolean`, default `true` - all db queries will be run in transaction, which will be rolled back at the end of test. 30 | * * environment_file: `string`, default `.env` - The .env file to load for the tests. 31 | * * bootstrap: `string`, default `bootstrap/app.php` - Relative path to app.php config file. 32 | * * root: `string`, default `` - Root path of our application. 33 | * * packages: `string`, default `workbench` - Root path of application packages (if any). 34 | * 35 | * ## API 36 | * 37 | * * app - `Illuminate\Foundation\Application` instance 38 | * * client - `BrowserKit` client 39 | * 40 | */ 41 | class Laravel5 extends Framework implements ActiveRecord 42 | { 43 | 44 | /** 45 | * @var \Illuminate\Foundation\Application 46 | */ 47 | public $app; 48 | 49 | /** 50 | * @var array 51 | */ 52 | protected $config = []; 53 | 54 | /** 55 | * Constructor. 56 | * 57 | * @param $config 58 | */ 59 | public function __construct($config = null) 60 | { 61 | $this->config = array_merge( 62 | array( 63 | 'cleanup' => true, 64 | 'environment_file' => '.env', 65 | 'bootstrap' => 'bootstrap' . DIRECTORY_SEPARATOR . 'app.php', 66 | 'root' => '', 67 | 'packages' => 'workbench', 68 | ), 69 | (array) $config 70 | ); 71 | 72 | parent::__construct(); 73 | } 74 | 75 | /** 76 | * Initialize hook. 77 | */ 78 | public function _initialize() 79 | { 80 | $this->revertErrorHandler(); 81 | $this->initializeLaravel(); 82 | } 83 | 84 | /** 85 | * Before hook. 86 | * 87 | * @param \Codeception\TestCase $test 88 | * @throws ModuleConfig 89 | */ 90 | public function _before(\Codeception\TestCase $test) 91 | { 92 | $this->initializeLaravel(); 93 | 94 | if ($this->app['db'] && $this->config['cleanup']) { 95 | $this->app['db']->beginTransaction(); 96 | } 97 | } 98 | 99 | /** 100 | * After hook. 101 | * 102 | * @param \Codeception\TestCase $test 103 | */ 104 | public function _after(\Codeception\TestCase $test) 105 | { 106 | if ($this->app['db'] && $this->config['cleanup']) { 107 | $this->app['db']->rollback(); 108 | } 109 | 110 | if ($this->app['auth']) { 111 | $this->app['auth']->logout(); 112 | } 113 | 114 | if ($this->app['cache']) { 115 | $this->app['cache']->flush(); 116 | } 117 | 118 | if ($this->app['session']) { 119 | $this->app['session']->flush(); 120 | } 121 | 122 | // disconnect from DB to prevent "Too many connections" issue 123 | if ($this->app['db']) { 124 | $this->app['db']->disconnect(); 125 | } 126 | } 127 | 128 | /** 129 | * After step hook. 130 | * 131 | * @param \Codeception\Step $step 132 | */ 133 | public function _afterStep(\Codeception\Step $step) 134 | { 135 | \Illuminate\Support\Facades\Facade::clearResolvedInstances(); 136 | 137 | parent::_afterStep($step); 138 | } 139 | 140 | /** 141 | * Revert back to the Codeception error handler, 142 | * becauses Laravel registers it's own error handler. 143 | */ 144 | protected function revertErrorHandler() 145 | { 146 | $handler = new ErrorHandler(); 147 | set_error_handler(array($handler, 'errorHandler')); 148 | } 149 | 150 | /** 151 | * Initialize the Laravel framework. 152 | * 153 | * @throws ModuleConfig 154 | */ 155 | protected function initializeLaravel() 156 | { 157 | $this->app = $this->bootApplication(); 158 | $this->app->instance('request', new Request()); 159 | $this->client = new LaravelConnector($this->app); 160 | $this->client->followRedirects(true); 161 | } 162 | 163 | /** 164 | * Boot the Laravel application object. 165 | * 166 | * @return \Illuminate\Foundation\Application 167 | * @throws \Codeception\Exception\ModuleConfig 168 | */ 169 | protected function bootApplication() 170 | { 171 | $projectDir = explode($this->config['packages'], \Codeception\Configuration::projectDir())[0]; 172 | $projectDir .= $this->config['root']; 173 | require $projectDir . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php'; 174 | 175 | \Illuminate\Support\ClassLoader::register(); 176 | 177 | $bootstrapFile = $projectDir . $this->config['bootstrap']; 178 | 179 | if (! file_exists($bootstrapFile)) { 180 | throw new ModuleConfig( 181 | $this, "Laravel bootstrap file not found in $bootstrapFile.\nPlease provide a valid path to it using 'bootstrap' config param. " 182 | ); 183 | } 184 | 185 | $app = require $bootstrapFile; 186 | $app->loadEnvironmentFrom($this->config['environment_file']); 187 | 188 | return $app; 189 | } 190 | 191 | /** 192 | * Provides access the Laravel application object. 193 | * 194 | * @return \Illuminate\Foundation\Application 195 | */ 196 | public function getApplication() 197 | { 198 | return $this->app; 199 | } 200 | 201 | /** 202 | * Opens web page using route name and parameters. 203 | * 204 | * ```php 205 | * amOnRoute('posts.create'); 207 | * ?> 208 | * ``` 209 | * 210 | * @param $route 211 | * @param array $params 212 | */ 213 | public function amOnRoute($route, $params = []) 214 | { 215 | $domain = $this->app['routes']->getByName($route)->domain(); 216 | $absolute = ! is_null($domain); 217 | 218 | $url = $this->app['url']->route($route, $params, $absolute); 219 | $this->amOnPage($url); 220 | } 221 | 222 | /** 223 | * Opens web page by action name 224 | * 225 | * ```php 226 | * amOnAction('PostsController@index'); 228 | * ?> 229 | * ``` 230 | * 231 | * @param $action 232 | * @param array $params 233 | */ 234 | public function amOnAction($action, $params = []) 235 | { 236 | $namespacedAction = $this->actionWithNamespace($action); 237 | 238 | $domain = $this->app['routes']->getByAction($namespacedAction)->domain(); 239 | $absolute = ! is_null($domain); 240 | 241 | $url = $this->app['url']->action($action, $params, $absolute); 242 | $this->amOnPage($url); 243 | } 244 | 245 | /** 246 | * Normalize an action to full namespaced action. 247 | * 248 | * @param string $action 249 | * @return string 250 | */ 251 | protected function actionWithNamespace($action) 252 | { 253 | $rootNamespace = $this->getRootControllerNamespace(); 254 | 255 | if ($rootNamespace && ! (strpos($action, '\\') === 0)) { 256 | return $rootNamespace . '\\' . $action; 257 | } else { 258 | return trim($action, '\\'); 259 | } 260 | } 261 | 262 | /** 263 | * Get the root controller namespace for the application. 264 | * 265 | * @return string 266 | */ 267 | protected function getRootControllerNamespace() 268 | { 269 | $urlGenerator = $this->app['url']; 270 | $reflection = new \ReflectionClass($urlGenerator); 271 | 272 | $property = $reflection->getProperty('rootNamespace'); 273 | $property->setAccessible(true); 274 | 275 | return $property->getValue($urlGenerator); 276 | } 277 | 278 | /** 279 | * Checks that current url matches route 280 | * 281 | * ```php 282 | * seeCurrentRouteIs('posts.index'); 284 | * ?> 285 | * ``` 286 | * @param $route 287 | * @param array $params 288 | */ 289 | public function seeCurrentRouteIs($route, $params = array()) 290 | { 291 | $this->seeCurrentUrlEquals($this->app['url']->route($route, $params, false)); 292 | } 293 | 294 | /** 295 | * Checks that current url matches action 296 | * 297 | * ```php 298 | * seeCurrentActionIs('PostsController@index'); 300 | * ?> 301 | * ``` 302 | * 303 | * @param $action 304 | * @param array $params 305 | */ 306 | public function seeCurrentActionIs($action, $params = array()) 307 | { 308 | $this->seeCurrentUrlEquals($this->app['url']->action($action, $params, false)); 309 | } 310 | 311 | /** 312 | * Assert that the session has a given list of values. 313 | * 314 | * @param string|array $key 315 | * @param mixed $value 316 | * @return void 317 | */ 318 | public function seeInSession($key, $value = null) 319 | { 320 | if (is_array($key)) { 321 | $this->seeSessionHasValues($key); 322 | return; 323 | } 324 | 325 | if (is_null($value)) { 326 | $this->assertTrue($this->app['session']->has($key)); 327 | } else { 328 | $this->assertEquals($value, $this->app['session']->get($key)); 329 | } 330 | } 331 | 332 | /** 333 | * Assert that the session has a given list of values. 334 | * 335 | * @param array $bindings 336 | * @return void 337 | */ 338 | public function seeSessionHasValues(array $bindings) 339 | { 340 | foreach ($bindings as $key => $value) { 341 | if (is_int($key)) { 342 | $this->seeInSession($value); 343 | } else { 344 | $this->seeInSession($key, $value); 345 | } 346 | } 347 | } 348 | 349 | /** 350 | * Assert that the form errors are bound to the View. 351 | * 352 | * @return bool 353 | */ 354 | public function seeFormHasErrors() 355 | { 356 | $viewErrorBag = $this->app->make('view')->shared('errors'); 357 | $this->assertTrue(count($viewErrorBag) > 0); 358 | } 359 | 360 | /** 361 | * Assert that specific form error messages are set in the view. 362 | * 363 | * Useful for validation messages and generally messages array 364 | * e.g. 365 | * return `Redirect::to('register')->withErrors($validator);` 366 | * 367 | * Example of Usage 368 | * 369 | * ``` php 370 | * seeFormErrorMessages(array('username'=>'Invalid Username')); 372 | * ?> 373 | * ``` 374 | * @param array $bindings 375 | */ 376 | public function seeFormErrorMessages(array $bindings) 377 | { 378 | foreach ($bindings as $key => $value) { 379 | $this->seeFormErrorMessage($key, $value); 380 | } 381 | } 382 | 383 | /** 384 | * Assert that specific form error message is set in the view. 385 | * 386 | * Useful for validation messages and generally messages array 387 | * e.g. 388 | * return `Redirect::to('register')->withErrors($validator);` 389 | * 390 | * Example of Usage 391 | * 392 | * ``` php 393 | * seeFormErrorMessage('username', 'Invalid Username'); 395 | * ?> 396 | * ``` 397 | * @param string $key 398 | * @param string $errorMessage 399 | */ 400 | public function seeFormErrorMessage($key, $errorMessage) 401 | { 402 | $viewErrorBag = $this->app['view']->shared('errors'); 403 | 404 | $this->assertEquals($errorMessage, $viewErrorBag->first($key)); 405 | } 406 | 407 | /** 408 | * Set the currently logged in user for the application. 409 | * Takes either an object that implements the User interface or 410 | * an array of credentials. 411 | * 412 | * @param \Illuminate\Contracts\Auth\User|array $user 413 | * @param string $driver 414 | * @return void 415 | */ 416 | public function amLoggedAs($user, $driver = null) 417 | { 418 | if ($user instanceof Authenticatable) { 419 | $this->app['auth']->driver($driver)->setUser($user); 420 | } else { 421 | $this->app['auth']->driver($driver)->attempt($user); 422 | } 423 | } 424 | 425 | /** 426 | * Logs user out 427 | */ 428 | public function logout() 429 | { 430 | $this->app['auth']->logout(); 431 | } 432 | 433 | /** 434 | * Checks that user is authenticated 435 | */ 436 | public function seeAuthentication() 437 | { 438 | $this->assertTrue($this->app['auth']->check(), 'User is not logged in'); 439 | } 440 | 441 | /** 442 | * Check that user is not authenticated 443 | */ 444 | public function dontSeeAuthentication() 445 | { 446 | $this->assertFalse($this->app['auth']->check(), 'User is logged in'); 447 | } 448 | 449 | /** 450 | * Return an instance of a class from the IoC Container. 451 | * (http://laravel.com/docs/ioc) 452 | * 453 | * Example 454 | * ``` php 455 | * grabService('foo'); 464 | * 465 | * // Will return an instance of FooBar, also works for singletons. 466 | * ?> 467 | * ``` 468 | * 469 | * @param string $class 470 | * @return mixed 471 | */ 472 | public function grabService($class) 473 | { 474 | return $this->app[$class]; 475 | } 476 | 477 | /** 478 | * Inserts record into the database. 479 | * 480 | * ``` php 481 | * haveRecord('users', array('name' => 'Davert')); 483 | * ?> 484 | * ``` 485 | * 486 | * @param $model 487 | * @param array $attributes 488 | * @return mixed 489 | */ 490 | public function haveRecord($model, $attributes = array()) 491 | { 492 | $id = $this->app['db']->table($model)->insertGetId($attributes); 493 | if (!$id) { 494 | $this->fail("Couldn't insert record into table $model"); 495 | } 496 | return $id; 497 | } 498 | 499 | /** 500 | * Checks that record exists in database. 501 | * 502 | * ``` php 503 | * $I->seeRecord('users', array('name' => 'davert')); 504 | * ``` 505 | * 506 | * @param $model 507 | * @param array $attributes 508 | */ 509 | public function seeRecord($model, $attributes = array()) 510 | { 511 | $record = $this->findRecord($model, $attributes); 512 | if (!$record) { 513 | $this->fail("Couldn't find $model with " . json_encode($attributes)); 514 | } 515 | $this->debugSection($model, json_encode($record)); 516 | } 517 | 518 | /** 519 | * Checks that record does not exist in database. 520 | * 521 | * ``` php 522 | * dontSeeRecord('users', array('name' => 'davert')); 524 | * ?> 525 | * ``` 526 | * 527 | * @param $model 528 | * @param array $attributes 529 | */ 530 | public function dontSeeRecord($model, $attributes = array()) 531 | { 532 | $record = $this->findRecord($model, $attributes); 533 | $this->debugSection($model, json_encode($record)); 534 | if ($record) { 535 | $this->fail("Unexpectedly managed to find $model with " . json_encode($attributes)); 536 | } 537 | } 538 | 539 | /** 540 | * Retrieves record from database 541 | * 542 | * ``` php 543 | * grabRecord('users', array('name' => 'davert')); 545 | * ?> 546 | * ``` 547 | * 548 | * @param $model 549 | * @param array $attributes 550 | * @return mixed 551 | */ 552 | public function grabRecord($model, $attributes = array()) 553 | { 554 | return $this->findRecord($model, $attributes); 555 | } 556 | 557 | /** 558 | * @param $model 559 | * @param array $attributes 560 | * @return mixed 561 | */ 562 | protected function findRecord($model, $attributes = array()) 563 | { 564 | $query = $this->app['db']->table($model); 565 | foreach ($attributes as $key => $value) { 566 | $query->where($key, $value); 567 | } 568 | return $query->first(); 569 | } 570 | 571 | } 572 | --------------------------------------------------------------------------------