Skip to content

Commit 27401cd

Browse files
authored
Opt-in: Allow the URL host to be set from the sites home URL rather than WP_TESTS_DOMAIN (#614)
* Infer the https state from home_url instead of hard coding it * Opt-in approach to switching the URL host within testing * Add test for redirects * CHANGELOG * Condense into with_urls * Simplify * Rename to with_url * Testing CI * Fix merge conflict * Fixing another * Disable experimental
1 parent 3db21c5 commit 27401cd

File tree

5 files changed

+196
-20
lines changed

5 files changed

+196
-20
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
### Added
1313

14+
- ✨ Experimental feature ✨: Use the home URL as the base URL for testing rather
15+
than `WP_TESTS_DOMAIN`. This can be enabled by calling the
16+
`with_experimental_testing_url_host()` method of the installation manager or
17+
by setting the `MANTLE_EXPERIMENTAL_TESTING_USE_HOME_URL_HOST` environment
18+
variable.
19+
20+
Once enabled, the home URL will be used as the base URL for testing rather
21+
the hard-coded `WP_TESTS_DOMAIN`. It will also infer the HTTPS status from
22+
the home URL.
23+
- Added `with_option()`/`with_home_url()`/`with_site_url()` methods to the installation manager.
1424
- Add a `without_local_object_cache()` method to prevent the `object-cache.php` drop-in from being loaded locally.
1525
- Added a better `dump()` method to the response object when testing HTTP
1626
requests that will dump the request/response to the console.

src/mantle/testing/class-installation-manager.php

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,52 @@ public function with_active_plugins( array $plugins ): static {
188188
return $this->plugins( $plugins );
189189
}
190190

191+
/**
192+
* Define if the testing suite should use the experimental feature that will
193+
* use the site's home URL host as the HTTP host when making requests.
194+
*
195+
* Without enabling this feature, the HTTP host will be set to the value of
196+
* the WP_TESTS_DOMAIN constant and all relative URLs will be calculated from
197+
* that domain.
198+
*
199+
* In the next major release of Mantle, this feature will be enabled by default.
200+
*
201+
* @param bool $enable Whether to enable the experimental feature.
202+
*/
203+
public function with_experimental_testing_url_host( bool $enable = true ): static {
204+
return $this->before(
205+
fn () => putenv( 'MANTLE_EXPERIMENTAL_TESTING_USE_HOME_URL_HOST=' . ( $enable ? '1' : '0' ) ), // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.runtime_configuration_putenv
206+
);
207+
}
208+
209+
/**
210+
* Define a custom option to be set after the installation is loaded.
211+
*
212+
* @param string $option Option name.
213+
* @param mixed $value Option value.
214+
*/
215+
public function with_option( string $option, mixed $value ): static {
216+
return $this->loaded( fn () => update_option( $option, $value ) );
217+
}
218+
219+
/**
220+
* Define the site/home URLs to be set after the installation is loaded.
221+
*
222+
* @param string|null $home Home URL.
223+
* @param string|null $site Site URL.
224+
*/
225+
public function with_url( ?string $home = null, ?string $site = null ): static {
226+
if ( $home ) {
227+
$this->with_option( 'home', $home );
228+
}
229+
230+
if ( $site ) {
231+
$this->with_option( 'siteurl', $site );
232+
}
233+
234+
return $this;
235+
}
236+
191237
/**
192238
* Install the Mantle Testing Framework.
193239
*

src/mantle/testing/class-pending-testable-request.php

Lines changed: 68 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ class Pending_Testable_Request {
4949
/**
5050
* Indicates whether the request should be made over HTTPS.
5151
*/
52-
public bool $https = false;
52+
public ?bool $forced_https = null;
5353

5454
/**
5555
* The cookies for the request.
@@ -95,12 +95,15 @@ public function with_header( string $name, string $value ): static {
9595
}
9696

9797
/**
98-
* Define whether the request should be made over HTTPS.
98+
* Define whether the request should be forced to be made over HTTPS.
9999
*
100-
* @param bool $value Whether to use HTTPS.
100+
* This method will override the protocol of the URL passed when creating a
101+
* testable request.
102+
*
103+
* @param bool|null $value Whether to use HTTPS.
101104
*/
102-
public function with_https( bool $value ): static {
103-
$this->https = $value;
105+
public function with_https( ?bool $value ): static {
106+
$this->forced_https = $value;
104107

105108
return $this;
106109
}
@@ -235,11 +238,14 @@ public function call( string $method, mixed $uri, array $parameters = [], array
235238
$uri = $this->infer_url( $uri );
236239
}
237240

241+
$scheme = $this->get_default_url_scheme();
242+
$host = $this->get_default_url_host();
243+
238244
// Build a full URL from partial URIs.
239245
if ( '/' === $uri[0] ) {
240-
$url = 'https://' . WP_TESTS_DOMAIN . $uri;
246+
$url = "{$scheme}://{$host}{$uri}";
241247
} elseif ( false === strpos( $uri, '://' ) ) {
242-
$url = 'https://' . WP_TESTS_DOMAIN . '/' . $uri;
248+
$url = "{$scheme}://{$host}/{uri}";
243249
} else {
244250
$url = $uri;
245251
}
@@ -432,11 +438,8 @@ protected function reset_request_state(): void {
432438
}
433439
}
434440

435-
if ( $this->https ) {
436-
$_SERVER['HTTPS'] = 'on';
437-
} else {
438-
unset( $_SERVER['HTTPS'] );
439-
}
441+
// Clear the HTTPS flag which will be set as-needed by the call method.
442+
unset( $_SERVER['HTTPS'] );
440443

441444
// phpcs:enable
442445
}
@@ -453,8 +456,12 @@ protected function reset_request_state(): void {
453456
protected function set_server_state( $method, $url, $server, $data, array $cookies = [] ): void {
454457
// phpcs:disable WordPress.Security.NonceVerification
455458
$_SERVER['REQUEST_METHOD'] = strtoupper( $method );
456-
$_SERVER['SERVER_NAME'] = WP_TESTS_DOMAIN;
457459
$_SERVER['SERVER_PORT'] = '80';
460+
461+
$_SERVER['SERVER_NAME'] = $_SERVER['HTTP_HOST'] = $this->is_experimental_use_home_url_host_enabled()
462+
? wp_parse_url( home_url(), PHP_URL_HOST )
463+
: WP_TESTS_DOMAIN;
464+
458465
unset( $_SERVER['PATH_INFO'] );
459466

460467
$parts = wp_parse_url( $url );
@@ -469,9 +476,13 @@ protected function set_server_state( $method, $url, $server, $data, array $cooki
469476
$req = $url;
470477
}
471478

472-
$_SERVER['QUERY_STRING'] = $parts['query'] ?? '';
479+
// Set HTTPS if it is being forced or if the URL being requested is HTTPS.
480+
if ( $this->forced_https || ( isset( $parts['scheme'] ) && 'https' === $parts['scheme'] ) ) {
481+
$_SERVER['HTTPS'] = 'on';
482+
}
473483

474-
$_SERVER['REQUEST_URI'] = $req;
484+
$_SERVER['QUERY_STRING'] = $parts['query'] ?? '';
485+
$_SERVER['REQUEST_URI'] = $req;
475486

476487
$_POST = $data;
477488

@@ -539,6 +550,48 @@ protected function replace_rest_api(): void {
539550
add_action( 'parse_request', [ $this, 'serve_rest_api_request' ] );
540551
}
541552

553+
/**
554+
* Get the default URL scheme.
555+
*
556+
* If the request is being overridden to use HTTPS via {@see with_https()},
557+
* this will return 'https'. Otherwise, it will return the scheme of the home
558+
* URL of the WordPress installation.
559+
*/
560+
protected function get_default_url_scheme(): string {
561+
if ( $this->forced_https ) {
562+
return 'https';
563+
}
564+
565+
if ( ! $this->is_experimental_use_home_url_host_enabled() ) {
566+
return 'http';
567+
}
568+
569+
return wp_parse_url( home_url(), PHP_URL_SCHEME );
570+
}
571+
572+
/**
573+
* Get the default URL host.
574+
*
575+
* If the `MANTLE_EXPERIMENTAL_TESTING_USE_HOME_URL_HOST` environment variable
576+
* is set, this will return the host of the home URL. Otherwise, it will
577+
* return the host defined in the WordPress tests configuration.
578+
*
579+
* With the next major release of Mantle, we will be shifting to using the
580+
* home URL host by default.
581+
*/
582+
protected function get_default_url_host(): string {
583+
return $this->is_experimental_use_home_url_host_enabled()
584+
? wp_parse_url( home_url(), PHP_URL_HOST )
585+
: WP_TESTS_DOMAIN;
586+
}
587+
588+
/**
589+
* Check if the experimental testing URL host feature is enabled.
590+
*/
591+
protected function is_experimental_use_home_url_host_enabled(): bool {
592+
return Utils::env_bool( 'MANTLE_EXPERIMENTAL_TESTING_USE_HOME_URL_HOST', false );
593+
}
594+
542595
/**
543596
* Server the REST API request if applicable.
544597
*

src/mantle/testing/concerns/trait-makes-http-requests.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,9 +138,9 @@ public function with_header( string $name, string $value ): Pending_Testable_Req
138138
/**
139139
* Create a pending request with the HTTPS enabled/disabled.
140140
*
141-
* @param bool $value Whether to use HTTPS.
141+
* @param bool|null $value Whether to use HTTPS.
142142
*/
143-
public function with_https( bool $value = true ): Pending_Testable_Request {
143+
public function with_https( ?bool $value = true ): Pending_Testable_Request {
144144
return $this->create_pending_request()->with_https( $value );
145145
}
146146

tests/Testing/Concerns/MakesHttpRequestsTest.php

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Mantle\Http\Response;
77
use Mantle\Framework\Providers\Routing_Service_Provider;
88
use Mantle\Http\Request;
9+
use Mantle\Support\Str;
910
use Mantle\Testing\Concerns\Refresh_Database;
1011
use Mantle\Testing\Concerns\Reset_Server;
1112
use Mantle\Testing\Framework_Test_Case;
@@ -27,6 +28,8 @@ class MakesHttpRequestsTest extends Framework_Test_Case {
2728
protected function setUp(): void {
2829
parent::setUp();
2930

31+
putenv( 'MANTLE_EXPERIMENTAL_TESTING_USE_HOME_URL_HOST=' );
32+
3033
remove_all_actions( 'template_redirect' );
3134
}
3235

@@ -357,7 +360,9 @@ public function test_wp_is_rest_endpoint() {
357360
]
358361
);
359362

360-
$this->get( rest_url( '/mantle/v1/' . __FUNCTION__ ) );
363+
$this
364+
->get( rest_url( '/mantle/v1/' . __FUNCTION__ ) )
365+
->assertJsonPath( 'key', 'value here' );
361366

362367
$this->assertFalse( wp_is_rest_endpoint() );
363368
}
@@ -389,7 +394,13 @@ public function test_match_snapshot_rest() {
389394
] );
390395
}
391396

392-
public function test_https_request() {
397+
public function test_url_scheme_http_by_default() {
398+
$this->get( '/' )->assertOk();
399+
400+
$this->assertEmpty( $_SERVER['HTTPS'] ?? '' );
401+
}
402+
403+
public function test_url_scheme_https_opt_in() {
393404
$this->get( '/' )->assertOk();
394405

395406
$this->assertEmpty( $_SERVER['HTTPS'] ?? '' );
@@ -399,9 +410,54 @@ public function test_https_request() {
399410
$this->assertEquals( 'on', $_SERVER['HTTPS'] );
400411
}
401412

413+
public function test_url_scheme_https_by_home_url() {
414+
putenv( 'MANTLE_EXPERIMENTAL_TESTING_USE_HOME_URL_HOST=1' );
415+
416+
$home_url = get_option( 'home' );
417+
418+
$this->assertEquals( 'http://' . WP_TESTS_DOMAIN, $home_url );
419+
$this->assertEquals( 'http://' . WP_TESTS_DOMAIN, home_url() );
420+
421+
update_option( 'home', 'https://' . WP_TESTS_DOMAIN );
422+
423+
$this->assertEquals( 'https://' . WP_TESTS_DOMAIN, home_url() );
424+
425+
$this->get( '/' )->assertOk();
426+
427+
$this->assertEquals( 'on', $_SERVER['HTTPS'] ?? '' );
428+
}
429+
430+
#[Group( 'experimental' )]
431+
#[Group( 'experiment-testing-url-host' )]
432+
public function test_experimental_default_url_host() {
433+
$this->get( '/' )->assertOk();
434+
435+
$this->assertEquals( 'http://' . WP_TESTS_DOMAIN, home_url() );
436+
$this->assertEquals( WP_TESTS_DOMAIN, $_SERVER['HTTP_HOST'] );
437+
438+
$this->setup_experiment_testing_url_host();
439+
440+
$this->get( '/' )->assertOk();
441+
442+
$this->assertEquals( 'subdomain.' . WP_TESTS_DOMAIN, $_SERVER['HTTP_HOST'] );
443+
}
444+
445+
#[Group( 'experimental' )]
446+
#[Group( 'experiment-testing-url-host' )]
447+
public function test_experimental_redirect_to() {
448+
$this->setup_experiment_testing_url_host();
449+
450+
$this->app['router']->get(
451+
'/route-to-redirect/',
452+
fn () => redirect()->to( '/redirected/' ),
453+
);
454+
455+
$this->get( '/route-to-redirect/' )->assertRedirect( '/redirected/' );
456+
}
457+
402458
public function test_multiple_requests() {
403459
$methods = collect( get_class_methods( $this ) )
404-
->filter( fn ( $method ) => false === strpos( $method, '_snapshot_' ) )
460+
->filter( fn ( string $method ) => ! Str::contains( $method, [ 'experimental', '_snapshot_' ] ) && 0 === strpos( $method, 'test_' ) )
405461
->shuffle()
406462
->all();
407463

@@ -411,9 +467,20 @@ public function test_multiple_requests() {
411467
continue;
412468
}
413469

470+
$this->setUp();
471+
414472
$this->$method();
473+
474+
$this->tearDown();
415475
}
416476
}
477+
478+
protected function setup_experiment_testing_url_host() {
479+
putenv( 'MANTLE_EXPERIMENTAL_TESTING_USE_HOME_URL_HOST=1' );
480+
481+
update_option( 'home', 'https://subdomain.' . WP_TESTS_DOMAIN );
482+
$this->assertEquals( 'https://subdomain.' . WP_TESTS_DOMAIN, home_url() );
483+
}
417484
}
418485

419486
class JsonSerializableMixedResourcesStub implements JsonSerializable {

0 commit comments

Comments
 (0)