Skip to content

Commit

Permalink
✅ Add routing integration tests (#422)
Browse files Browse the repository at this point in the history
Co-authored-by: QWp6t <[email protected]>
  • Loading branch information
retlehs and QWp6t authored Dec 21, 2024
1 parent 88096b5 commit 239ae07
Show file tree
Hide file tree
Showing 7 changed files with 204 additions and 5 deletions.
5 changes: 3 additions & 2 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
mariadb-client \
vim \
zip \
wget \
&& apt-get -y autoremove && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/*

# Install PHP extensions
Expand All @@ -36,9 +37,9 @@ RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
pdo \
pdo_mysql \
zip \
&& pecl install imagick-3.7.0 && docker-php-ext-enable imagick \
# && pecl install imagick-3.7.0 && docker-php-ext-enable imagick \ # https://github.com/Imagick/imagick/issues/689
&& pecl install -o -f redis && docker-php-ext-enable redis \
&& pecl install xdebug-3.3.1 && docker-php-ext-enable xdebug \
&& pecl install xdebug-3.4.0 && docker-php-ext-enable xdebug \
&& apt-get -y autoremove && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/*

# Install composer
Expand Down
4 changes: 3 additions & 1 deletion .devcontainer/config/web/default.conf
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
server {
listen 80 default;
listen [::]:80;
listen 8080 default_server;
listen [::]:8080 default_server;

# listen 443 ssl;
# listen [::]:443 ssl ipv6only=on;
Expand All @@ -11,7 +13,7 @@ server {
add_header X-Content-Type-Options "nosniff";
charset utf-8;

server_name web.local web;
server_name _;
root /roots/app/public;
index index.php index.html;

Expand Down
5 changes: 4 additions & 1 deletion .devcontainer/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ services:
build:
context: .
dockerfile: Dockerfile
image: roots/dev-8.3
image: roots/dev-8.4
extra_hosts:
- 'host.docker.internal:host-gateway'
environment:
Expand All @@ -29,6 +29,9 @@ services:
image: nginx:latest
ports:
- '${FORWARD_WEB_PORT:-8080}:80'

expose:
- '8080'
environment:
- NGINX_ENTRYPOINT_WORKER_PROCESSES_AUTOTUNE=1
volumes:
Expand Down
40 changes: 40 additions & 0 deletions .github/workflows/integration.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Integration

on: [push, pull_request, workflow_dispatch]

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Copy .env file
working-directory: .devcontainer
run: cp config/app/.env.example .env

- name: Start dev container and test
uses: devcontainers/[email protected]
with:
configFile: .devcontainer/devcontainer.json
runCmd: |
cd /roots/app
composer install
# ???
composer remove roots/acorn
composer require roots/acorn --no-interaction
composer require --dev nunomaduro/collision
composer require --dev spatie/laravel-ignition
# ???
while ! mysqladmin ping -h"database" --silent; do
sleep 1
done
wp core install --url=http://web:8080 --title=Acorn --admin_user=admin --admin_password=admin [email protected] --skip-email --allow-root
wp acorn optimize:clear
cd /roots/acorn
composer install
composer run-script test tests/Integration/Routing
- name: Verify routes
run: |
curl -s http://localhost:8080/test/ | grep "Howdy"
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,4 @@ jobs:
run: composer run-script lint

- name: Execute the Composer test script
run: composer run-script test
run: composer test -- --exclude-group=integration
81 changes: 81 additions & 0 deletions tests/Integration/Routing/RoutingTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<?php

namespace Roots\Acorn\Tests\Integration\Routing;

use GuzzleHttp\Client;

uses(RoutingTestCase::class)->group('integration');

expect()->extend('toHaveBodyClass', function (string $class) {
preg_match('/<body[^>]*class=["\']([^"\']*)["\']/', $this->value, $matches);
expect($matches)->toHaveCount(2, 'No body tag with class attribute found');
expect($matches[1])->toContain($class);

return $this;
});

it('handles the test route', function () {
$client = new Client([
'verify' => false,
]);

$response = $client->request('GET', 'http://web:8080/test/');
expect($response->getStatusCode())->toBe(200);
expect((string) $response->getBody())->toContain('Howdy');
});

it('does not intercept WordPress admin routes', function () {
$client = new Client([
'verify' => false,
'allow_redirects' => false,
]);

$response = $client->request('GET', 'http://web:8080/wp/wp-admin/');
expect($response->getStatusCode())->toBe(302);
expect($response->getHeader('Location')[0])->toContain('wp-login.php');
});

it('handles non-existent routes with 404', function () {
$client = new Client([
'verify' => false,
'http_errors' => false,
]);

$response = $client->request('GET', 'http://web:8080/non-existent-'.time());
expect($response->getStatusCode())->toBe(404);
expect((string) $response->getBody())->toContain('Page not found');
expect((string) $response->getBody())->toHaveBodyClass('error404');
});

it('handles default homepage', function () {
$client = new Client([
'verify' => false,
]);

$response = $client->request('GET', 'http://web:8080/');
expect($response->getStatusCode())->toBe(200);
expect((string) $response->getBody())->toHaveBodyClass('home');
});

it('handles WordPress REST API routes', function () {
$client = new Client([
'verify' => false,
]);

$response = $client->request('GET', 'http://web:8080/wp-json/');
expect($response->getStatusCode())->toBe(200);

$data = json_decode((string) $response->getBody(), true);
expect($data)->toHaveKey('name');
expect($data)->toHaveKey('url');
});

it('handles WordPress search route', function () {
$client = new Client([
'verify' => false,
]);

$response = $client->request('GET', 'http://web:8080/search/test/');
expect($response->getStatusCode())->toBe(200);
expect((string) $response->getBody())->toHaveBodyClass('search');
});
72 changes: 72 additions & 0 deletions tests/Integration/Routing/RoutingTestCase.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php

namespace Roots\Acorn\Tests\Integration\Routing;

use Illuminate\Foundation\Testing\Concerns\MakesHttpRequests;
use Mockery\Adapter\Phpunit\MockeryTestCase;
use Roots\Acorn\Tests\Test\Concerns\SupportsGlobalStubs;
use Roots\Acorn\Tests\Test\Concerns\SupportsScopedFixtures;

class RoutingTestCase extends MockeryTestCase
{
use MakesHttpRequests;
use SupportsGlobalStubs;
use SupportsScopedFixtures;

protected function setUp(): void
{
parent::setUp();
$this->clearStubs();

// Ensure routes directory exists
if (! is_dir('/roots/app/public/routes')) {
mkdir('/roots/app/public/routes', 0777, true);
}

// Create web.php routes file
$webRoutes = <<<'PHP'
<?php
use Illuminate\Support\Facades\Route;
Route::middleware(['web'])->group(function () {
Route::get('/test', fn() => 'Howdy')->name('test');
});
PHP;

file_put_contents('/roots/app/public/routes/web.php', $webRoutes);

// Ensure mu-plugins directory exists
if (! is_dir('/roots/app/public/content/mu-plugins')) {
mkdir('/roots/app/public/content/mu-plugins', 0777, true);
}

// Create or update the Acorn boot mu-plugin
$bootPlugin = <<<'PHP'
<?php
/*
Plugin Name: Acorn Boot
*/
use Roots\Acorn\Application;
use Roots\Acorn\Configuration\Exceptions;
use Roots\Acorn\Configuration\Middleware;
add_action('after_setup_theme', function () {
Application::configure()
->withMiddleware(function (Middleware $middleware) {
//
})
->withExceptions(function (Exceptions $exceptions) {
//
})
->withRouting(
web: '/roots/app/public/routes/web.php'
)
->boot();
}, 0);
PHP;

file_put_contents('/roots/app/public/content/mu-plugins/01-acorn-boot.php', $bootPlugin);
}
}

0 comments on commit 239ae07

Please sign in to comment.