Skip to content

Commit ce89ee4

Browse files
author
Aaron Gustavo Nieves
committed
Add moveForward() to navigate forward in history
Mirror of moveBack(): walks the BrowserKit history pointer forward N steps and replays the request with changeHistory = false, matching Symfony's native AbstractBrowser::forward(). Symfony exposes both back() and forward() with identical semantics, so InnerBrowser now offers the symmetric pair. This is purely additive (new public method) and is only usable now that moveBack() preserves the forward history entries instead of discarding them. Tests: testMoveForwardOneStep, testMoveForwardTwoSteps and testMoveForwardThrowsExceptionIfNumberOfStepsIsInvalid. The forward tests also assert that moveBack() kept the forward stack intact.
1 parent 1fa0951 commit ce89ee4

2 files changed

Lines changed: 84 additions & 0 deletions

File tree

src/Codeception/Lib/InnerBrowser.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2015,6 +2015,46 @@ public function moveBack(int $numberOfSteps = 1): void
20152015
);
20162016
}
20172017

2018+
/**
2019+
* Moves forward in history.
2020+
*
2021+
* @param int $numberOfSteps (default value 1)
2022+
*/
2023+
public function moveForward(int $numberOfSteps = 1): void
2024+
{
2025+
$request = null;
2026+
if (!is_int($numberOfSteps) || $numberOfSteps < 1) {
2027+
throw new InvalidArgumentException('numberOfSteps must be positive integer');
2028+
}
2029+
2030+
try {
2031+
$history = $this->getRunningClient()->getHistory();
2032+
for ($i = $numberOfSteps; $i > 0; --$i) {
2033+
$request = $history->forward();
2034+
}
2035+
} catch (LogicException $exception) {
2036+
throw new InvalidArgumentException(
2037+
sprintf(
2038+
'numberOfSteps is set to %d, but there are only %d forward steps in the history',
2039+
$numberOfSteps,
2040+
$numberOfSteps - $i
2041+
), $exception->getCode(), $exception);
2042+
}
2043+
2044+
// Replay the next request without appending to the history, so the
2045+
// browser history pointer moves forward (like a real Forward button)
2046+
// instead of pushing a new entry.
2047+
$this->_loadPage(
2048+
$request->getMethod(),
2049+
$request->getUri(),
2050+
$request->getParameters(),
2051+
$request->getFiles(),
2052+
$request->getServer(),
2053+
$request->getContent(),
2054+
false
2055+
);
2056+
}
2057+
20182058
protected function debugCookieJar(): void
20192059
{
20202060
$cookies = $this->client->getCookieJar()->all();

tests/unit/Codeception/Module/FrameworksTest.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,50 @@ public function testMoveBackThrowsExceptionIfNumberOfStepsIsInvalid()
100100
}
101101
}
102102

103+
public function testMoveForwardOneStep()
104+
{
105+
$this->module->amOnPage('/iframe');
106+
$this->module->amOnPage('/info');
107+
$this->module->amOnPage('/');
108+
$this->module->moveBack(2);
109+
$this->module->seeCurrentUrlEquals('/iframe');
110+
$this->module->moveForward();
111+
$this->module->seeCurrentUrlEquals('/info');
112+
$this->module->moveForward();
113+
$this->module->seeCurrentUrlEquals('/');
114+
}
115+
116+
public function testMoveForwardTwoSteps()
117+
{
118+
$this->module->amOnPage('/iframe');
119+
$this->module->amOnPage('/info');
120+
$this->module->amOnPage('/');
121+
$this->module->moveBack(2);
122+
$this->module->seeCurrentUrlEquals('/iframe');
123+
$this->module->moveForward(2);
124+
$this->module->seeCurrentUrlEquals('/');
125+
}
126+
127+
public function testMoveForwardThrowsExceptionIfNumberOfStepsIsInvalid()
128+
{
129+
$this->module->amOnPage('/iframe');
130+
$this->module->amOnPage('/');
131+
$this->module->moveBack();
132+
$this->module->seeCurrentUrlEquals('/iframe');
133+
134+
$invalidValues = [0, -5, 1.5, 'a', 3];
135+
foreach ($invalidValues as $invalidValue) {
136+
try {
137+
$this->module->moveForward($invalidValue);
138+
$this->fail('Expected to get exception here');
139+
} catch (InvalidArgumentException $exception) {
140+
codecept_debug('Exception: ' . $exception->getMessage());
141+
} catch (TypeError $error) {
142+
codecept_debug('Error: ' . $error->getMessage());
143+
}
144+
}
145+
}
146+
103147
public function testCreateSnapshotOnFail()
104148
{
105149
$container = Stub::make(ModuleContainer::class);

0 commit comments

Comments
 (0)