Skip to content

Commit 7669218

Browse files
committed
BREAKING: Refactor into more logical methods
Methods renamed to be more descriptive, and functionality broken up to be more modular. Public methods now handle HEAD requests and whether to follow redirects or not automatically.
1 parent ac1e816 commit 7669218

File tree

2 files changed

+139
-71
lines changed

2 files changed

+139
-71
lines changed

README.md

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ class RedirectsCest {
4747
4848
public function _before( AcceptanceTester $I ) {
4949
$this->I = $I;
50-
$this->I->followRedirects(false);
5150
}
5251
5352
/**
@@ -56,28 +55,43 @@ class RedirectsCest {
5655
* @example(old="content/abou/miss.php", new="about-us/top-third-mission")
5756
* @example(old="content/abou/exec.php", new="about-us/executive-team")
5857
* @example(old="content/abou/team.php", new="about-us/risk-management-specialists")
58+
*
5959
* @group redirects
6060
* @group redirectsabout
6161
*/
6262
public function redirectOldAboutUrlsToAboutUsPages( AcceptanceTester $I, Example $example ) {
63-
$this->redirectOldToNew( $example['old'], $example['new'] );
63+
$this->testIfOldRedirectsToNew($example['old'], $example['new']);
6464
}
6565
6666
/**
6767
* @example(old="content/myac/index.php", new="my-account")
6868
* @example(old="content/myac/stat.php", new="my-account/account-statements-explained")
6969
* @example(old="content/myac/depo.php", new="my-account/deposits-withdrawals")
7070
* @example(old="content/myac/wire.php", new="wire-instructions-r-j-obrien")
71+
*
7172
* @group redirects
7273
* @group redirectsmyaccount
7374
*/
7475
public function redirectOldMyAccountUrlsToNewMyAccountPages( AcceptanceTester $I, Example $example ) {
75-
$this->redirectOldToNew( $example['old'], $example['new'] );
76+
$this->testIfOldRedirectsToNew( $example['old'], $example['new'] );
7677
}
7778
78-
private function redirectOldToNew($old, $new) {
79-
$this->I->sendHEAD( $old );
80-
$this->I->seePermanentRedirectTo( $new );
79+
private function testIfOldRedirectsToNew($old, $new, $checkDestination = true) {
80+
$this->I->seePermanentRedirectBetween($old, $new);
81+
if ($checkDestinationExists) {
82+
$this->I->urlDoesNotRedirect($new);
83+
}
84+
85+
// Check old URL with trailing slash also redirects.
86+
if (
87+
'/' !== substr($old, -1) &&
88+
false === strpos( strrev($old), strrev('.php')) &&
89+
false === strpos( strrev($old), strrev('.pdf')) &&
90+
false === strpos( $old, '?')
91+
) {
92+
$old .= '/';
93+
$this->testIfOldRedirectsToNew($old, $new, $checkDestinationExists);
94+
}
8195
}
8296
}
8397
@@ -109,7 +123,7 @@ class ProtocolRedirectsCest
109123
public function forceHttp(Login $I)
110124
{
111125
$I->wantTo('check forced redirects to HTTP are working.');
112-
$I->seePermanentRedirectToHttpFor(ProfileCalendar::$URL);
126+
$I->seeHttpProtocolAlwaysUsedFor(ProfileCalendar::$URL);
113127
}
114128
115129
/**
@@ -118,8 +132,8 @@ class ProtocolRedirectsCest
118132
public function forceHttps(Login $I)
119133
{
120134
$I->wantTo('check forced redirects to HTTPS are working.');
121-
$I->seePermanentRedirectToHttpsFor(ProfileContactInformation::$URL);
122-
$I->seePermanentRedirectToHttpsFor(ProfileMyProducts::$URL);
135+
$I->seeHttpsProtocolAlwaysUsedFor(ProfileContactInformation::$URL);
136+
$I->seeHttpsProtocolAlwaysUsedFor(ProfileMyProducts::$URL);
123137
}
124138
}
125139
@@ -139,24 +153,38 @@ $I->followRedirects(false);
139153

140154
* `param bool` **`$followRedirects`**
141155

142-
Whether to follow automatic redirects or not. Default behaviour is true, so most times you'll want to pass in false for 301 redirects tests.
156+
Whether to follow automatic redirects or not. Default behaviour is true, so most times you'll want to pass in false for 301 redirects tests. Other methods in this package already call this as needed.
143157

144-
### seePermanentRedirectTo
158+
### seePermanentRedirectBetween
145159

146-
Checks for a `Location` response header and a `301` HTTP Status response code. Fails if either is missing, or `Location` header value does not match the `$url`.
160+
Check that a 301 HTTP Status is returned with the correct Location URL. Fails if either is missing, or `Location` header value does not match the `$url`. Automatically avoids following redirects.
147161

148162
```php
149-
$I->sendHEAD('company/financial-strength-and-security.cfm');
150-
$I->seePermanentRedirectTo('company/financial-security');
163+
$I->seePermanentRedirectBetween('company/financial-strength-and-security.cfm', 'company/financial-security');
151164
```
152165

166+
* `param` **`$oldUrl`**
167+
168+
Relative or absolute URL that should be redirected.
169+
* `param` **`$newUrl`**
170+
171+
Relative or absolute URL of redirect destination.
172+
173+
### urlDoesNotRedirect
174+
175+
Check that a 200 HTTP Status is returned and the URL has no redirects. Allows the possibility of following redirects.
176+
177+
```php
178+
$I->urlDoesNotRedirect('company/financial-security');
179+
```
180+
153181
* `param` **`$url`**
154182

155183
Absolute or relative (to REST config `url`) URL.
156184

157-
### seePermanentRedirectToHttpFor
185+
### seeHttpProtocolAlwaysUsedFor
158186

159-
Check that a 200 HTTP Status is returned with the URL as HTTP.
187+
Check that a 200 HTTP Status is eventually returned with the HTTP protocol. Follows redirects automatically.
160188

161189
```php
162190
$I->seePermanentRedirectToHttpFor('insecure-page');
@@ -168,7 +196,7 @@ $I->seePermanentRedirectToHttpFor('insecure-page');
168196

169197
### seePermanentRedirectToHttpsFor
170198

171-
Check that a 200 HTTP Status is returned with the URL as HTTPS.
199+
Check that a 200 HTTP Status is eventually returned with the HTTPS protocol. Follows redirects automatically.
172200

173201
```php
174202
$I->seePermanentRedirectToHttpsFor('contact-us');

src/Redirects.php

Lines changed: 94 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*
55
* @package gamajo\codeception-redirects
66
* @author Gary Jones
7-
* @copyright 2016 Gamajo Tech
7+
* @copyright 2016 Gamajo
88
* @license MIT
99
*/
1010

@@ -49,73 +49,135 @@ public function followRedirects($followRedirects = true)
4949
}
5050

5151
/**
52-
* Check that a 200 HTTP Status is returned with the correct Location URL.
52+
* Check if redirections are being followed or not.
5353
*
54-
* Should be HTTP.
54+
* @since 0.2.0
5555
*
56-
* @since 0.1.0
57-
*
58-
* @param string $url Relative or absolute URL of redirect destination.
56+
* @return bool True if redirects are being followed, false otherwise.
5957
*/
60-
public function seePermanentRedirectToHttpFor($url)
58+
protected function isFollowingRedirects()
6159
{
62-
$this->permanentRedirectForProtocol($url, self::PROTOCOL_HTTP);
60+
return $this->getModule('PhpBrowser')->client->isFollowingRedirects();
6361
}
6462

6563
/**
6664
* Check that a 301 HTTP Status is returned with the correct Location URL.
6765
*
68-
* @since 0.1.0
66+
* @since 0.2.0
6967
*
70-
* @param string $url Relative or absolute URL of redirect destination.
71-
* @param string $checkDestinationExists Optional. Whether to check if destination URL is 200 OK.
68+
* @param string $oldUrl Relative or absolute URL that should be redirected.
69+
* @param string $newUrl Relative or absolute URL of redirect destination.
7270
*/
73-
public function seePermanentRedirectTo($url, $checkDestinationExists = true )
71+
public function seePermanentRedirectBetween($oldUrl, $newUrl)
7472
{
75-
$followsRedirects = $this->getModule('PhpBrowser')->client->isFollowingRedirects();
73+
// We must follow all redirects, so save current situation, force follow redirects, and revert at the end.
74+
$followsRedirects = $this->isFollowingRedirects();
75+
$this->followRedirects(false);
7676

77-
/** @var Response $response */
78-
$response = $this->getModule('PhpBrowser')->client->getInternalResponse();
77+
$response = $this->sendHeadAndGetResponse($oldUrl);
7978
$responseCode = $response->getStatus();
8079
$locationHeader = $response->getHeader('Location', true);
8180

8281
// Check for 301 response code.
83-
$this->assertEquals(301, $responseCode);
82+
$this->assertEquals(301, $responseCode, 'Response code was not 301.');
8483

8584
// Check location header URL contains submitted URL.
86-
$this->assertContains($url, $locationHeader);
85+
$this->assertContains($newUrl, $locationHeader, 'Redirect destination not found in Location header.');
8786

88-
if ($checkDestinationExists && 'false' !== $checkDestinationExists) {
89-
$this->followRedirects( true );
90-
$this->urlExists( $url );
91-
$this->followRedirects( $followsRedirects );
92-
}
87+
$this->followRedirects($followsRedirects);
9388
}
9489

9590
/**
96-
* Check that a 200 HTTP Status is returned with the correct Location URL.
91+
* Check that a 200 HTTP Status is returned and the URL has no redirects.
9792
*
98-
* Should be HTTPS.
93+
* @since 0.1.3
94+
* @since 0.2.0 Renamed method, made public.
95+
*
96+
* @param string $url Relative or absolute URL of redirect destination.
97+
*/
98+
public function urlDoesNotRedirect($url)
99+
{
100+
// We must follow all potential immediate redirects, so save current situation, force follow redirects, and revert at the end.
101+
$followsRedirects = $this->isFollowingRedirects();
102+
$this->followRedirects(true);
103+
104+
$response = $this->sendHeadAndGetResponse($url);
105+
$responseCode = $response->getStatus();
106+
$locationHeader = $response->getHeader('Location', true);
107+
108+
// Check for 200 response code.
109+
$this->assertEquals(200, $responseCode, 'Response code was not 200.');
110+
111+
// Check that destination URL does not try to redirect.
112+
// Somewhat redundant, as this should never appear with a 200 HTTP Status code anyway.
113+
$this->assertNull($locationHeader, 'Location header was found when it should not exist.');
114+
115+
$this->followRedirects($followsRedirects);
116+
}
117+
118+
/**
119+
* Use REST Module to send HEAD request and return the response.
120+
*
121+
* @since 0.2.0
122+
*
123+
* @param string $url
124+
*
125+
* @return null|Response
126+
*/
127+
protected function sendHeadAndGetResponse($url) {
128+
/** @var REST $rest */
129+
$rest = $this->getModule('REST');
130+
$rest->sendHEAD($url);
131+
132+
return $rest->client->getInternalResponse();
133+
}
134+
135+
/**
136+
* Check that a 200 HTTP Status is eventually returned with the HTTP protocol.
137+
*
138+
* Should be HTTP. The URL should be the same - only the protocol is different.
99139
*
100140
* @since 0.1.0
141+
* @since 0.2.0 Method renamed.
101142
*
102143
* @param string $url Relative or absolute URL of redirect destination.
103144
*/
104-
public function seePermanentRedirectToHttpsFor($url)
145+
public function seeHttpProtocolAlwaysUsedFor($url)
105146
{
106-
$this->permanentRedirectForProtocol($url, self::PROTOCOL_HTTPS);
147+
$this->checkUrlAndProtocolAreCorrect($url, self::PROTOCOL_HTTP);
107148
}
108149

109150
/**
110-
* Check that a 200 HTTP Status is returned with the correct Location URL.
151+
* Check that a 200 HTTP Status is eventually returned with the HTTPS protocol.
152+
*
153+
* Should be HTTPS. The URL should be the same - only the protocol is different.
111154
*
112155
* @since 0.1.0
156+
* @since 0.2.0 Method renamed.
157+
*
158+
* @param string $url Relative or absolute URL of redirect destination.
159+
*/
160+
public function seeHttpsProtocolAlwaysUsedFor($url)
161+
{
162+
$this->checkUrlAndProtocolAreCorrect($url, self::PROTOCOL_HTTPS);
163+
}
164+
165+
/**
166+
* For a given URL, check that a 200 HTTP Status is returned, the protocol matches given value,
167+
* and URL (except maybe protocol) has not changed.
168+
*
169+
* @since 0.1.0
170+
* @since 0.2.0 Method renamed.
113171
*
114172
* @param string $url Relative or absolute URL of redirect destination.
115173
* @param string $protocol Protocol: 'http' or 'https'.
116174
*/
117-
protected function permanentRedirectForProtocol($url, $protocol)
175+
protected function checkUrlAndProtocolAreCorrect($url, $protocol)
118176
{
177+
// We must follow all redirects, so save current situation, force follow redirects, and revert at the end.
178+
$followsRedirects = $this->isFollowingRedirects();
179+
$this->followRedirects(true);
180+
119181
$url = ltrim($url, '/');
120182

121183
/** @var REST $rest */
@@ -129,36 +191,14 @@ protected function permanentRedirectForProtocol($url, $protocol)
129191
$scheme = parse_url($responseUri, PHP_URL_SCHEME);
130192

131193
// Check for 200 response code.
132-
$this->assertEquals(200, $responseCode);
194+
$this->assertEquals(200, $responseCode, 'Response code was not 200.');
133195

134196
// Check that destination URL contains submitted URL part.
135-
$this->assertContains($url, $responseUri);
197+
$this->assertContains($url, $responseUri, 'Destination URL does not contain the original URL.');
136198

137199
// Check for submitted http/https value matches destination URL.
138-
$this->assertEquals($protocol, $scheme);
139-
}
140-
141-
/**
142-
* Check that a 200 HTTP Status is returned and the final URL has no more redirects.
143-
*
144-
* @since 0.1.3
145-
*
146-
* @param string $url Relative or absolute URL of redirect destination.
147-
* @param string $protocol Protocol: 'http' or 'https'.
148-
*/
149-
protected function urlExists($url)
150-
{
151-
$url = ltrim($url, '/');
200+
$this->assertEquals($protocol, $scheme, 'Protocol at destination URL does not match expected value.');
152201

153-
/** @var REST $rest */
154-
$rest = $this->getModule('REST');
155-
$rest->sendHEAD($url);
156-
$responseCode = $rest->client->getInternalResponse()->getStatus();
157-
$locationHeader = $rest->client->getInternalResponse()->getHeader('Location');
158-
159-
// Check for 200 response code.
160-
$this->assertEquals(200, $responseCode);
161-
// Check that destination URL does not try to redirect.
162-
$this->assertNull($locationHeader);
202+
$this->followRedirects($followsRedirects);
163203
}
164204
}

0 commit comments

Comments
 (0)