Skip to content

Commit 99d1b30

Browse files
committed
fix: block network in phpunit so tests stop calling prod
1 parent 5db582a commit 99d1b30

3 files changed

Lines changed: 27 additions & 8 deletions

File tree

tests/bootstrap.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@
2323
define( 'ROXYAPI_ENCRYPTION_SALT', 'phpunit-test-encryption-salt-not-for-production-use' );
2424
}
2525

26+
// Unit tests must never reach the network. Core evaluates this AFTER the
27+
// pre_http_request filter, so a mocked request still short-circuits normally
28+
// while an unmocked one fails with the offending URL named in the WP_Error.
29+
if ( ! defined( 'WP_HTTP_BLOCK_EXTERNAL' ) ) {
30+
define( 'WP_HTTP_BLOCK_EXTERNAL', true );
31+
}
32+
2633
if ( ! file_exists( "{$_tests_dir}/includes/functions.php" ) ) {
2734
echo "Could not find {$_tests_dir}/includes/functions.php, have you run bin/install-wp-tests.sh ?" . PHP_EOL;
2835
exit( 1 );

tests/phpunit/Mock_Http_TestCase.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
*
55
* Subclasses populate $mock_responses keyed by substring match on the request URL.
66
* Any request whose URL contains a mocked substring short-circuits to the canned
7-
* response. Every other request falls through to the real HTTP API (should never
8-
* happen in CI).
7+
* response. Every other request is left for core to refuse: tests/bootstrap.php
8+
* defines WP_HTTP_BLOCK_EXTERNAL, which core evaluates after this filter, so an
9+
* unmocked URL fails with that URL named instead of reaching the network.
910
*
1011
* @package RoxyAPI
1112
*/

tests/phpunit/test-shortcode-registrar.php

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,18 @@
1313
use RoxyAPI\Plugin;
1414
use RoxyAPI\Shortcodes\Registrar;
1515

16-
class Test_Shortcode_Registrar extends \WP_UnitTestCase {
16+
class Test_Shortcode_Registrar extends Mock_Http_TestCase {
1717

1818
public function setUp(): void {
1919
parent::setUp();
20+
// test_hero_wins_on_tag_collision renders the hero for real, so the
21+
// response has to be canned. Without a key the client still reaches the
22+
// SaaS over the keyless free-tier path, which made this suite render a
23+
// live reading on every run.
24+
$this->mock_responses['astrology/horoscope/aries/daily'] = array(
25+
'sign' => 'aries',
26+
'overview' => 'A bold day ahead.',
27+
);
2028
// Re-running do_action('init') would double-register blocks and
2129
// bindings sources, which the test framework flags as
2230
// _doing_it_wrong. Instead, invoke the registrar's static methods
@@ -64,13 +72,16 @@ public function test_hero_wins_on_tag_collision(): void {
6472
$this->assertIsCallable( $callable );
6573

6674
// The hero closure has the Horoscope class baked in via `use ($class)`.
67-
// Render with a known sign and check the output contains the hero CSS
68-
// hook (`roxyapi-horoscope`), which the generic renderer never emits.
69-
// Even when the API call fails (no key configured here), the hero
70-
// returns the friendly placeholder string. The generic renderer would
71-
// emit a `<dl class="roxyapi-generic ...">` shell instead.
75+
// Render with a known sign against the canned response: the hero
76+
// template emits `roxy-horoscope-card`, which the generic renderer
77+
// never does. It emits a `<dl class="roxyapi-generic ...">` shell.
7278
$out = call_user_func( $callable, array( 'sign' => 'aries' ), '', $tag );
7379
$this->assertIsString( $out );
80+
$this->assertStringContainsString(
81+
'roxy-horoscope-card',
82+
$out,
83+
'The collided tag must resolve to the hero renderer.'
84+
);
7485
// Hero output must NOT contain the generic-renderer signature class.
7586
$this->assertStringNotContainsString( 'roxyapi-generic', $out );
7687
}

0 commit comments

Comments
 (0)