Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
<env name="APP_MAINTENANCE_DRIVER" value="file"/>
<env name="BCRYPT_ROUNDS" value="4"/>
<env name="CACHE_STORE" value="array"/>
<env name="DB_DATABASE" value="testing"/>
<env name="DB_CONNECTION" value="sqlite"/>
<env name="DB_DATABASE" value=":memory:"/>
<env name="MAIL_MAILER" value="array"/>
<env name="PULSE_ENABLED" value="false"/>
<env name="QUEUE_CONNECTION" value="sync"/>
Expand Down
7 changes: 0 additions & 7 deletions tests/Feature/ExampleTest.php

This file was deleted.

139 changes: 139 additions & 0 deletions tests/Feature/RoutesTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
<?php

use Tests\Support\Wp;

/**
* Smoke coverage for every route in routes/web.php.
*
* Before this file the only feature test was `GET /` asserting 200, and it
* could not pass because no wp_* table existed in the test database.
*/
beforeEach(function () {
$this->author = Wp::user([
'user_login' => 'mayron',
'user_nicename' => 'mayron',
'display_name' => 'Autor Um',
'user_email' => 'autor@example.com',
]);

$this->post = Wp::post([
'post_author' => $this->author->ID,
'post_title' => 'Primeiro post',
'post_name' => 'primeiro-post',
'post_date' => '2026-07-15 12:00:00',
]);

Wp::categorise($this->post->ID, 'games');
Wp::categorise($this->post->ID, 'lancamentos', 'post_tag');
Wp::thumbnail($this->post->ID);
});

it('renders the home page', function () {
$this->get('/')
->assertOk()
->assertInertia(fn ($page) => $page
->component('Home')
->has('posts.data', 1)
->where('posts.data.0.title', 'Primeiro post')
);
});

it('excludes highlighted posts from the home listing', function () {
$highlighted = Wp::post(['post_title' => 'Em destaque', 'post_name' => 'em-destaque']);
Wp::categorise($highlighted->ID, 'destaques');

$this->get('/')
->assertOk()
->assertInertia(fn ($page) => $page
->has('posts.data', 1)
->has('highlightedPosts.data', 1)
->where('posts.data.0.title', 'Primeiro post')
->where('highlightedPosts.data.0.title', 'Em destaque')
);
});

it('renders a single post', function () {
$this->get('/2026/07/primeiro-post')
->assertOk()
->assertInertia(fn ($page) => $page
->component('PostContent')
->where('post.data.title', 'Primeiro post')
->where('post.data.slug', 'primeiro-post')
);
});

it('returns 404 for an unknown post slug', function () {
$this->get('/2026/07/nao-existe')->assertNotFound();
});

it('renders the category listing', function () {
$this->get('/category/games')
->assertOk()
->assertInertia(fn ($page) => $page
->component('CategoryPosts')
->has('posts.data', 1)
);
});

it('renders the tag listing', function () {
$this->get('/tag/lancamentos')
->assertOk()
->assertInertia(fn ($page) => $page
->component('TagPosts')
->has('posts.data', 1)
);
});

it('renders the author listing', function () {
$this->get('/author/mayron')
->assertOk()
->assertInertia(fn ($page) => $page
->component('AuthorPosts')
->has('posts.data', 1)
);
});

it('renders the year and month archive', function () {
$this->get('/2026/07')
->assertOk()
->assertInertia(fn ($page) => $page
->component('YearMonthPosts')
->has('posts.data', 1)
);
});

it('renders the privacy policy page', function () {
Wp::post([
'post_title' => 'Politica de Privacidade',
'post_name' => 'politica-de-privacidade',
'post_type' => 'page',
]);

$this->get('/politica-de-privacidade')
->assertOk()
->assertInertia(fn ($page) => $page
->component('PrivacyPolicy')
->where('page.data.title', 'Politica de Privacidade')
);
});

it('finds posts by search term', function () {
Wp::post(['post_title' => 'Outro assunto', 'post_name' => 'outro-assunto']);

$this->get('/?s=Primeiro')
->assertOk()
->assertInertia(fn ($page) => $page
->where('searchTerm', 'Primeiro')
->has('posts.data', 1)
->where('posts.data.0.title', 'Primeiro post')
);
});

it('hides posts that are not published', function () {
Wp::post(['post_title' => 'Rascunho', 'post_name' => 'rascunho', 'post_status' => 'draft']);
Wp::post(['post_title' => 'Futuro', 'post_name' => 'futuro', 'post_date' => '2099-01-01 00:00:00']);

$this->get('/')
->assertOk()
->assertInertia(fn ($page) => $page->has('posts.data', 1));
});
11 changes: 11 additions & 0 deletions tests/Pest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,17 @@

pest()->extend(Tests\TestCase::class)
->use(Illuminate\Foundation\Testing\RefreshDatabase::class)
->beforeEach(function () {
// The app reads an existing WordPress database, so there are no
// migrations for wp_* tables. Build them per test instead.
Tests\Support\WordPressSchema::create();

// Rendering the root Blade view resolves @vite, which needs a built
// manifest. Stub it so the suite does not depend on `npm run build`.
$this->withoutVite();

cache()->flush();
})
->in('Feature');

/*
Expand Down
104 changes: 104 additions & 0 deletions tests/Support/WordPressSchema.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<?php

namespace Tests\Support;

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

/**
* Creates the WordPress tables this application reads.
*
* The app has no migrations for them — it points Eloquent models at an existing
* WordPress database — so without this the whole suite can only test code that
* never touches the database.
*
* Column types mirror WordPress core closely enough for the queries in
* App\Models and App\Services to behave as they do in production. Columns the
* application never reads are omitted on purpose, to keep the fixture readable.
*/
class WordPressSchema
{
/**
* @var list<string> Drop order matters only for readability; sqlite has no FKs here.
*/
private const TABLES = [
'wp_posts',
'wp_postmeta',
'wp_users',
'wp_usermeta',
'wp_terms',
'wp_term_taxonomy',
'wp_term_relationships',
];

public static function create(): void
{
self::drop();

Schema::create('wp_posts', function (Blueprint $table) {
$table->id('ID');
$table->unsignedBigInteger('post_author')->default(0);
$table->dateTime('post_date')->nullable();
$table->longText('post_content')->nullable();
$table->text('post_title')->nullable();
$table->text('post_excerpt')->nullable();
$table->string('post_status', 20)->default('publish');
$table->string('post_name', 200)->default('');
$table->string('post_type', 20)->default('post');
$table->string('guid', 255)->default('');
$table->integer('menu_order')->default(0);
$table->unsignedBigInteger('post_parent')->default(0);
});

Schema::create('wp_postmeta', function (Blueprint $table) {
$table->id('meta_id');
$table->unsignedBigInteger('post_id')->default(0);
$table->string('meta_key', 255)->nullable();
$table->longText('meta_value')->nullable();
});

Schema::create('wp_users', function (Blueprint $table) {
$table->id('ID');
$table->string('user_login', 60)->default('');
$table->string('user_pass', 255)->default('');
$table->string('user_nicename', 50)->default('');
$table->string('user_email', 100)->default('');
$table->string('display_name', 250)->default('');
});

Schema::create('wp_usermeta', function (Blueprint $table) {
$table->id('umeta_id');
$table->unsignedBigInteger('user_id')->default(0);
$table->string('meta_key', 255)->nullable();
$table->longText('meta_value')->nullable();
});

Schema::create('wp_terms', function (Blueprint $table) {
$table->id('term_id');
$table->string('name', 200)->default('');
$table->string('slug', 200)->default('');
});

Schema::create('wp_term_taxonomy', function (Blueprint $table) {
$table->id('term_taxonomy_id');
$table->unsignedBigInteger('term_id')->default(0);
$table->string('taxonomy', 32)->default('');
$table->longText('description')->nullable();
$table->unsignedBigInteger('parent')->default(0);
$table->bigInteger('count')->default(0);
});

Schema::create('wp_term_relationships', function (Blueprint $table) {
$table->unsignedBigInteger('object_id')->default(0);
$table->unsignedBigInteger('term_taxonomy_id')->default(0);
$table->integer('term_order')->default(0);
});
}

public static function drop(): void
{
foreach (self::TABLES as $table) {
Schema::dropIfExists($table);
}
}
}
Loading