diff --git a/_test/core/TestRequest.php b/_test/core/TestRequest.php index dad2060e5cafb7f05e4db672774462a1030fd862..18b78c6f6c9ce9a07fd4164e207c94f4b8393122 100644 --- a/_test/core/TestRequest.php +++ b/_test/core/TestRequest.php @@ -7,6 +7,8 @@ // output buffering $output_buffer = ''; +$currentTestRequest = null; + function ob_start_callback($buffer) { global $output_buffer; $output_buffer .= $buffer; @@ -25,6 +27,7 @@ class TestRequest { private $session = array(); private $get = array(); private $post = array(); + private $notifications = array(); public function getServer($key) { return $this->server[$key]; } public function getSession($key) { return $this->session[$key]; } @@ -45,6 +48,9 @@ class TestRequest { */ public function execute($uri='/doku.php') { global $INPUT; + global $currentTestRequest; + + $currentTestRequest = $this; // save old environment $server = $_SERVER; @@ -86,6 +92,9 @@ class TestRequest { $output_buffer, (function_exists('xdebug_get_headers') ? xdebug_get_headers() : headers_list()) // cli sapi doesn't do headers, prefer xdebug_get_headers() which works under cli ); + if ($this->notifications != null) { + $response->setNotifications($this->notifications); + } // reset environment $_SERVER = $server; @@ -95,6 +104,8 @@ class TestRequest { $_REQUEST = $request; $INPUT = $input; + $currentTestRequest = null; + return $response; } @@ -161,5 +172,10 @@ class TestRequest { return $this->execute($uri); } - + /** + * Add a notification to later store it in the test respone. + */ + public function addNotification(array $new) { + $this->notifications[] = $new; + } } diff --git a/_test/core/TestResponse.php b/_test/core/TestResponse.php index 7cc50ee4fcea61f05be97de1235d2b34e0ef68ae..459770f9d896468f8f803599bffdf68f8162b7ef 100644 --- a/_test/core/TestResponse.php +++ b/_test/core/TestResponse.php @@ -18,6 +18,11 @@ class TestResponse { */ private $pq = null; + /** + * @var notifications + */ + private $notifications = null; + /** * @param $content string * @param $headers array @@ -90,4 +95,18 @@ class TestResponse { if(is_null($this->pq)) $this->pq = phpQuery::newDocument($this->content); return $this->pq->find($selector); } + + /** + * @return array + */ + public function getNotifications() { + return $this->notifications; + } + + /** + * Set notifications + */ + public function setNotifications(array $new) { + $this->notifications = $new; + } } diff --git a/_test/data/pages/wiki/editandsavetest.txt b/_test/data/pages/wiki/editandsavetest.txt new file mode 100644 index 0000000000000000000000000000000000000000..f1e0655df1f26749d205ea3cec45f3c265c535ed --- /dev/null +++ b/_test/data/pages/wiki/editandsavetest.txt @@ -0,0 +1,16 @@ +This is a test page for testing the redirect happening on the ''edit and save'' workflow. +This page is required for the tests in **_tests/test/test/edit_and_save.test.php**. Do not edit this file. + +====== Headline1 ====== +Headline 1 content. + +====== Headline2 ====== +Headline 2a content. + +====== Headline2 ====== +Headline 2b content. + +====== Headline3 ====== +Headline 3 content. + +It is essential for the tests that there are two headlines with the title **Headline2**! diff --git a/_test/tests/test/edit_and_save.test.php b/_test/tests/test/edit_and_save.test.php new file mode 100644 index 0000000000000000000000000000000000000000..4d9518f2526f72668a3569132bda23edb26691d8 --- /dev/null +++ b/_test/tests/test/edit_and_save.test.php @@ -0,0 +1,185 @@ +<?php + +/** + * @group integration + */ +class EditAndSaveTest extends DokuWikiTest { + + /** + * Execute the following requests: + * - Section edit a page (headline 2, first occurrence) + * - Save a page + * - Redirect + * Check if the header id is transmitted and if the final redirect + * points to the correct header. + */ + function testEditSaveRedirect_Headline2_A() { + $request = new TestRequest(); + + $input = array( + 'id' => 'wiki:editandsavetest' + ); + + // Show page + $response = $request->post($input); + $content = $response->getContent(); + $this->assertTrue(!empty($content)); + + // If the test page has got the right content for our test it should have + // two headlines with the title "Headline2" + preg_match_all('#<h1[^>]*>Headline2</h1[^>]*>#', $content, $matches, PREG_SET_ORDER); + $this->assertEquals(2, count($matches)); + + // Get the header ids + $result = preg_match('/id="(.*)"/', $matches [0][0], $idA); + $this->assertEquals(1, $result); + $result = preg_match('/id="(.*)"/', $matches [1][0], $idB); + $this->assertEquals(1, $result); + $this->assertTrue($idA != $idB); + + // Search the section edit form/button for the second id + $pattern = '/<form class="button btn_secedit".*>.*'; + $pattern .= '<input type="hidden" name="hid" value="'; + $pattern .= $idA[1]; + $pattern .= '" \/>.*<\/form>/'; + $result = preg_match($pattern, $content, $formA); + $this->assertEquals(1, $result); + + // Extract all inputs from the form + $result = preg_match_all('/<input type="hidden" name="([^"]*)" value="([^"]*)" \/>/', $formA[0], $matches, PREG_SET_ORDER); + $input = array(); + foreach ($matches as $match) { + $input[$match[1]] = $match[2]; + } + $this->assertEquals($input['hid'], $idA[1]); + + // Post the input fields (= do a section edit) + $response = $request->post($input, '/doku.php'); + $content = $response->getContent(); + + // Our header id should have been sent back to us in the edit + // form as an hidden input field + $content = str_replace("\n", " ", $content); + $pattern = '/<form id="dw__editform"[^>]*>.*'; + $pattern .= '<input type="hidden" name="hid" value="'; + $pattern .= $idA[1]; + $pattern .= '" \/>.*<\/form>/'; + $result = preg_match($pattern, $content, $editForm); + $this->assertEquals(1, $result); + + // Extract all inputs from the edit form + $result = preg_match_all('/<input type="hidden" name="([^"]*)" value="([^"]*)" \/>/', $editForm[0], $matches, PREG_SET_ORDER); + $input = array(); + foreach ($matches as $match) { + $input[$match[1]] = $match[2]; + } + $this->assertEquals($input['hid'], $idA[1]); + $input['do'] = 'save'; + + // Post the input fields (= save page) + $response = $request->post($input, '/doku.php'); + + // The response should carry a notification that a redirect + // was executed to our header ID + $found = null; + $notifications = $response->getNotifications(); + foreach ($notifications as $notification) { + if ($notification['name'] == 'send_redirect') { + $found = &$notification; + } + } + $this->assertTrue($found !== null); + $hash = strpos($found['url'], '#'); + $headerID = substr($found['url'], $hash); + $this->assertEquals($headerID, '#'.$idA[1]); + } + + /** + * Execute the following requests: + * - Section edit a page (headline 2, second occurrence) + * - Save a page + * - Redirect + * Check if the header id is transmitted and if the final redirect + * points to the correct header. + */ + function testEditSaveRedirect_Headline2_B() { + $request = new TestRequest(); + + $input = array( + 'id' => 'wiki:editandsavetest' + ); + + // Show page + $response = $request->post($input); + $content = $response->getContent(); + $this->assertTrue(!empty($content)); + + // If the test page has got the right content for our test it should have + // two headlines with the title "Headline2" + preg_match_all('#<h1[^>]*>Headline2</h1[^>]*>#', $content, $matches, PREG_SET_ORDER); + $this->assertEquals(2, count($matches)); + + // Get the header ids + $result = preg_match('/id="(.*)"/', $matches [0][0], $idA); + $this->assertEquals(1, $result); + $result = preg_match('/id="(.*)"/', $matches [1][0], $idB); + $this->assertEquals(1, $result); + $this->assertTrue($idA != $idB); + + // Search the section edit form/button for the second id + $pattern = '/<form class="button btn_secedit".*>.*'; + $pattern .= '<input type="hidden" name="hid" value="'; + $pattern .= $idB[1]; + $pattern .= '" \/>.*<\/form>/'; + $result = preg_match($pattern, $content, $formB); + $this->assertEquals(1, $result); + + // Extract all inputs from the form + $result = preg_match_all('/<input type="hidden" name="([^"]*)" value="([^"]*)" \/>/', $formB[0], $matches, PREG_SET_ORDER); + $input = array(); + foreach ($matches as $match) { + $input[$match[1]] = $match[2]; + } + $this->assertEquals($input['hid'], $idB[1]); + + // Post the input fields (= do a section edit) + $response = $request->post($input, '/doku.php'); + $content = $response->getContent(); + + // Our header id should have been sent back to us in the edit + // form as an hidden input field + $content = str_replace("\n", " ", $content); + $pattern = '/<form id="dw__editform"[^>]*>.*'; + $pattern .= '<input type="hidden" name="hid" value="'; + $pattern .= $idB[1]; + $pattern .= '" \/>.*<\/form>/'; + $result = preg_match($pattern, $content, $editForm); + $this->assertEquals(1, $result); + + // Extract all inputs from the edit form + $result = preg_match_all('/<input type="hidden" name="([^"]*)" value="([^"]*)" \/>/', $editForm[0], $matches, PREG_SET_ORDER); + $input = array(); + foreach ($matches as $match) { + $input[$match[1]] = $match[2]; + } + $this->assertEquals($input['hid'], $idB[1]); + $input['do'] = 'save'; + + // Post the input fields (= save page) + $response = $request->post($input, '/doku.php'); + + // The response should carry a notification that a redirect + // was executed to our header ID + $found = null; + $notifications = $response->getNotifications(); + foreach ($notifications as $notification) { + if ($notification['name'] == 'send_redirect') { + $found = &$notification; + } + } + $this->assertTrue($found !== null); + $hash = strpos($found['url'], '#'); + $headerID = substr($found['url'], $hash); + $this->assertEquals($headerID, '#'.$idB[1]); + } +} diff --git a/inc/ActionRouter.php b/inc/ActionRouter.php index 22ff94c4ec9c29a1f44fe0e58af0f8f5840ebc3e..2c9832d26b8b3aea02f88077429d22fcc760aaf9 100644 --- a/inc/ActionRouter.php +++ b/inc/ActionRouter.php @@ -19,7 +19,7 @@ class ActionRouter { protected $action; /** @var ActionRouter */ - protected static $instance; + protected static $instance = NULL; /** @var int transition counter */ protected $transitions = 0; @@ -44,9 +44,14 @@ class ActionRouter { $this->disabled = array_map('trim', $this->disabled); $this->transitions = 0; - $ACT = act_clean($ACT); - $this->setupAction($ACT); - $ACT = $this->action->getActionName(); + if(defined('DOKU_UNITTEST') && (self::$instance !== null)) { + $ACT = act_clean($ACT); + $this->setupAction($ACT); + } else { + $ACT = act_clean($ACT); + $this->setupAction($ACT); + $ACT = $this->action->getActionName(); + } } /** diff --git a/inc/actions.php b/inc/actions.php index 22954ae7a227fed107b8845ce92ff96a07a36e9f..e31ef3c2eefb43ad80b1b7620792766b5324d52c 100644 --- a/inc/actions.php +++ b/inc/actions.php @@ -10,7 +10,12 @@ if(!defined('DOKU_INC')) die('meh.'); function act_dispatch(){ - $router = \dokuwiki\ActionRouter::getInstance(); // is this needed here or could we delegate it to tpl_content() later? + $reinit = false; + if(defined('DOKU_UNITTEST')) { + // For integration test running multiple requests we need a re-init here! + $reinit = true; + } + $router = \dokuwiki\ActionRouter::getInstance($reinit); // is this needed here or could we delegate it to tpl_content() later? $headers = array('Content-Type: text/html; charset=utf-8'); trigger_event('ACTION_HEADERS_SEND',$headers,'act_sendheaders'); diff --git a/inc/common.php b/inc/common.php index 9a1da79075cd016ad371dd276aac49e306306bd7..cd19ed911ef1d9ceead0870bd857f82dac652743 100644 --- a/inc/common.php +++ b/inc/common.php @@ -1924,7 +1924,16 @@ function send_redirect($url) { header('Location: '.$url); } - if(defined('DOKU_UNITTEST')) return; // no exits during unit tests + if(defined('DOKU_UNITTEST')) { + global $currentTestRequest; + if ($currentTestRequest != null) { + // Create a notification which later can we queried from the TestResponse by + // calling 'getNotifications()'. + $currentTestRequest->addNotification (array('name' => 'send_redirect', 'url' => $url)); + } + // no exits during unit tests + return; + } exit; }