Browse Source

Fix flash message retention

Merge retained flash messages with existing ones. This makes flash
message assertions work when there are multiple requests in a test
method.

Fixes #15268
Mark Story 5 years ago
parent
commit
0615bc6915

+ 10 - 5
src/TestSuite/IntegrationTestTrait.php

@@ -168,9 +168,9 @@ trait IntegrationTestTrait
     /**
      * Stored flash messages before render
      *
-     * @var array|null
+     * @var array
      */
-    protected $_flashMessages;
+    protected $_flashMessages = [];
 
     /**
      * @var string|null
@@ -205,6 +205,7 @@ trait IntegrationTestTrait
         $this->_securityToken = false;
         $this->_csrfToken = false;
         $this->_retainFlashMessages = false;
+        $this->_flashMessages = [];
     }
 
     /**
@@ -512,10 +513,14 @@ trait IntegrationTestTrait
         $this->_controller = $controller;
         $events = $controller->getEventManager();
         $flashCapture = function (EventInterface $event): void {
-            if ($this->_retainFlashMessages && empty($this->_flashMessages)) {
-                $controller = $event->getSubject();
-                $this->_flashMessages = $controller->getRequest()->getSession()->read('Flash');
+            if (!$this->_retainFlashMessages) {
+                return;
             }
+            $controller = $event->getSubject();
+            $this->_flashMessages = Hash::merge(
+                $this->_flashMessages,
+                $controller->getRequest()->getSession()->read('Flash')
+            );
         };
         $events->on('Controller.beforeRedirect', ['priority' => -100], $flashCapture);
         $events->on('Controller.beforeRender', ['priority' => -100], $flashCapture);

+ 21 - 1
tests/TestCase/TestSuite/IntegrationTestTraitTest.php

@@ -733,7 +733,7 @@ class IntegrationTestTraitTest extends TestCase
 
         $this->assertResponseCode(302);
 
-        $this->assertSession('An error message', 'Flash.flash.0.message');
+        $this->assertSession('A success message', 'Flash.flash.0.message');
     }
 
     /**
@@ -769,6 +769,26 @@ class IntegrationTestTraitTest extends TestCase
     }
 
     /**
+     * If multiple requests occur in the same test method
+     * flash messages should be retained.
+     *
+     * @return void
+     */
+    public function testFlashAssertionMultipleRequests()
+    {
+        $this->enableRetainFlashMessages();
+        $this->disableErrorHandlerMiddleware();
+
+        $this->get('/posts/index/with_flash');
+        $this->assertResponseCode(200);
+        $this->assertFlashMessage('An error message');
+
+        $this->get('/posts/someRedirect');
+        $this->assertResponseCode(302);
+        $this->assertFlashMessage('A success message');
+    }
+
+    /**
      * Test flash assertions stored with enableRememberFlashMessages() even if
      * the controller clears flash data in `beforeRender`
      *

+ 6 - 1
tests/test_app/TestApp/Application.php

@@ -22,6 +22,7 @@ use Cake\Core\ContainerInterface;
 use Cake\Error\Middleware\ErrorHandlerMiddleware;
 use Cake\Http\BaseApplication;
 use Cake\Http\MiddlewareQueue;
+use Cake\Routing\Exception\DuplicateNamedRouteException;
 use Cake\Routing\Middleware\RoutingMiddleware;
 use Cake\Routing\RouteBuilder;
 use stdClass;
@@ -86,7 +87,11 @@ class Application extends BaseApplication
             $routes->connect('/articles', ['controller' => 'Articles']);
             $routes->connect('/articles/:action/*', ['controller' => 'Articles']);
 
-            $routes->connect('/tests/:action/*', ['controller' => 'Tests'], ['_name' => 'testName']);
+            try {
+                $routes->connect('/tests/:action/*', ['controller' => 'Tests'], ['_name' => 'testName']);
+            } catch (DuplicateNamedRouteException $e) {
+                // do nothing. This happens when one test does multiple requests.
+            }
             $routes->fallbacks();
         });
         $routes->connect('/posts', ['controller' => 'Posts', 'action' => 'index']);

+ 1 - 1
tests/test_app/TestApp/Controller/PostsController.php

@@ -73,7 +73,7 @@ class PostsController extends AppController
      */
     public function someRedirect()
     {
-        $this->Flash->error('An error message');
+        $this->Flash->success('A success message');
 
         return $this->redirect('/somewhere');
     }