aspirecloud/tests/Feature/API/WpOrg/ThemeControllerTest.php
2025-10-25 13:15:51 -06:00

374 lines
14 KiB
PHP

<?php
declare(strict_types=1);
use App\Models\WpOrg\Author;
use App\Models\WpOrg\Theme;
use Carbon\CarbonImmutable;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
beforeEach(function () {
$author = Author::create([
'user_nicename' => 'tmeister',
'profile' => 'https://profiles.wp.org/tmeister',
'avatar' => 'https://avatars.wp.org/tmeister',
'display_name' => 'Tmeister',
'author' => 'Tmeister',
'author_url' => 'https://wp-themes.com/author/tmeister',
]);
Theme::factory()->create([
'ac_origin' => 'wp_org',
'active_installs' => 100,
'author_id' => $author->id,
'creation_time' => CarbonImmutable::parse('2011-11-11 11:11:11'),
'description' => 'My Theme',
'download_link' => 'https://downloads.wp/my-theme',
'downloaded' => 1000,
'external_repository_url' => 'https://test.com',
'homepage' => 'https://wordpress.org/themes/my-theme/',
'is_commercial' => false,
'is_community' => true,
'last_updated' => '2025-01-18T20:50:36+00:00',
'name' => 'My Theme',
'num_ratings' => 6,
'preview_url' => 'https://wp-themes.com/my-theme',
'rating' => 5,
'reviews_url' => 'https://wp-themes.com/my-theme/reviews',
'requires_php' => '5.6',
'screenshot_url' => 'https://wp-themes.com/my-theme/screenshot.png',
'slug' => 'my-theme',
'version' => '1.2.1',
])->addTagsBySlugs(['black', 'white', 'red', 'blue']);
});
it('returns 400 when slug is missing', function () {
$response = $this->get('/themes/info/1.2?action=theme_information');
$response
->assertStatus(400)
->assertJson(['error' => 'The slug field is required.']);
});
it('returns 404 when theme does not exist', function () {
$response = $this->get('/themes/info/1.2?action=theme_information&slug=non-existent-theme');
$response
->assertStatus(404)
->assertJson(['error' => 'Theme not found']);
});
it('returns theme_information (v1.1)', function () {
$response = $this->get('/themes/info/1.1?action=theme_information&slug=my-theme');
$response
->assertStatus(200)
->assertJson([
'author' => 'tmeister',
'download_link' => 'https://api.aspiredev.org/download/my-theme',
'downloaded' => 1000,
'homepage' => 'https://wordpress.org/themes/my-theme/',
'last_updated' => '2025-01-18',
'last_updated_time' => '2025-01-18 20:50:36',
'name' => 'My Theme',
'num_ratings' => 6,
'preview_url' => 'https://wp-themes.com/my-theme',
'rating' => 5,
'screenshot_url' => 'https://wp-themes.com/my-theme/screenshot.png',
'sections' => [],
'slug' => 'my-theme',
'tags' => [
'black' => 'black',
'blue' => 'blue',
'red' => 'red',
'white' => 'white',
],
'version' => '1.2.1',
]);
});
it('returns all fields in theme_information (v1.2)', function () {
$response = $this->get('/themes/info/1.2?action=theme_information&slug=my-theme');
$response
->assertStatus(200)
->assertJson([
'author' => [
'author' => 'Tmeister',
'author_url' => 'https://wp-themes.com/author/tmeister',
'avatar' => 'https://avatars.wp.org/tmeister',
'display_name' => 'Tmeister',
'profile' => 'https://profiles.wp.org/tmeister',
'user_nicename' => 'tmeister',
],
'creation_time' => '2011-11-11 11:11:11',
'download_link' => 'https://api.aspiredev.org/download/my-theme',
'downloaded' => 1000,
'external_repository_url' => 'https://test.com',
'homepage' => 'https://wordpress.org/themes/my-theme/',
'is_commercial' => false,
'is_community' => true,
'last_updated' => '2025-01-18',
'last_updated_time' => '2025-01-18 20:50:36',
'name' => 'My Theme',
'num_ratings' => 6,
'preview_url' => 'https://wp-themes.com/my-theme',
'rating' => 5,
'requires_php' => '5.6',
'reviews_url' => 'https://wp-themes.com/my-theme/reviews',
'screenshot_url' => 'https://wp-themes.com/my-theme/screenshot.png',
'sections' => [],
'slug' => 'my-theme',
'tags' => [
'black' => 'black',
'blue' => 'blue',
'red' => 'red',
'white' => 'white',
],
'version' => '1.2.1',
]);
});
it('returns theme query results (v1.1)', function () {
$this
->get('/themes/info/1.1?action=query_themes')
->assertStatus(200)
->assertJson([
'info' => ['page' => 1, 'pages' => 1, 'results' => 1],
'themes' => [
[
'author' => 'tmeister',
'description' => 'My Theme',
'homepage' => 'https://wordpress.org/themes/my-theme/',
'name' => 'My Theme',
'num_ratings' => 6,
'preview_url' => 'https://wp-themes.com/my-theme',
'rating' => 5,
'screenshot_url' => 'https://wp-themes.com/my-theme/screenshot.png',
'slug' => 'my-theme',
'version' => '1.2.1',
],
],
]);
});
it('returns theme query results (v1.2)', function () {
$this
->get('/themes/info/1.2?action=query_themes')
->assertStatus(200)
->assertJson([
'info' => ['page' => 1, 'pages' => 1, 'results' => 1],
'themes' => [
[
'author' => [
'author' => 'Tmeister',
'author_url' => 'https://wp-themes.com/author/tmeister',
'avatar' => 'https://avatars.wp.org/tmeister',
'display_name' => 'Tmeister',
'profile' => 'https://profiles.wp.org/tmeister',
'user_nicename' => 'tmeister',
],
'description' => 'My Theme',
'external_repository_url' => 'https://test.com',
'homepage' => 'https://wordpress.org/themes/my-theme/',
'is_commercial' => false,
'is_community' => true,
'name' => 'My Theme',
'num_ratings' => 6,
'preview_url' => 'https://wp-themes.com/my-theme',
'rating' => 5,
'requires_php' => '5.6',
'screenshot_url' => 'https://wp-themes.com/my-theme/screenshot.png',
'slug' => 'my-theme',
'version' => '1.2.1',
],
],
])
// GH-278: return all fields. these are not normally returned by default by .org
->assertJsonPath('themes.0.download_link', 'https://api.aspiredev.org/download/my-theme')
->assertJsonPath('themes.0.downloaded', 1000)
->assertJsonPath('themes.0.active_installs', 100)
->assertJsonPath('themes.0.tags.black', 'black');
});
it('returns theme query results for tags (v1.2)', function () {
$this
->get('/themes/info/1.2?action=query_themes&tag[]=black&tag[]=orange')
->assertStatus(200)
->assertJson([
'info' => ['page' => 1, 'pages' => 1, 'results' => 1],
'themes' => [
[
'author' => [
'author' => 'Tmeister',
'author_url' => 'https://wp-themes.com/author/tmeister',
'avatar' => 'https://avatars.wp.org/tmeister',
'display_name' => 'Tmeister',
'profile' => 'https://profiles.wp.org/tmeister',
'user_nicename' => 'tmeister',
],
'description' => 'My Theme',
'external_repository_url' => 'https://test.com',
'homepage' => 'https://wordpress.org/themes/my-theme/',
'is_commercial' => false,
'is_community' => true,
'name' => 'My Theme',
'num_ratings' => 6,
'preview_url' => 'https://wp-themes.com/my-theme',
'rating' => 5,
'requires_php' => '5.6',
'screenshot_url' => 'https://wp-themes.com/my-theme/screenshot.png',
'slug' => 'my-theme',
'version' => '1.2.1',
],
],
]);
$this
->get('/themes/info/1.2?action=query_themes&tag=orange')
->assertStatus(200)
->assertExactJson([
'info' => ['page' => 1, 'pages' => 0, 'results' => 0], // page 1 of 0 is a bit odd but it is correct
'themes' => [],
]);
});
it('returns theme query results for ac_tags (v1.2)', function () {
$this
->get('/themes/info/1.2?action=query_themes&ac_tag[]=black&ac_tag[]=blue')
->assertStatus(200)
->assertJson([
'info' => ['page' => 1, 'pages' => 1, 'results' => 1],
'themes' => [
[
'author' => [
'author' => 'Tmeister',
'author_url' => 'https://wp-themes.com/author/tmeister',
'avatar' => 'https://avatars.wp.org/tmeister',
'display_name' => 'Tmeister',
'profile' => 'https://profiles.wp.org/tmeister',
'user_nicename' => 'tmeister',
],
'description' => 'My Theme',
'external_repository_url' => 'https://test.com',
'homepage' => 'https://wordpress.org/themes/my-theme/',
'is_commercial' => false,
'is_community' => true,
'name' => 'My Theme',
'num_ratings' => 6,
'preview_url' => 'https://wp-themes.com/my-theme',
'rating' => 5,
'requires_php' => '5.6',
'screenshot_url' => 'https://wp-themes.com/my-theme/screenshot.png',
'slug' => 'my-theme',
'version' => '1.2.1',
],
],
]);
$this
->get('/themes/info/1.2?action=query_themes&tag=orange')
->assertStatus(200)
->assertExactJson([
'info' => ['page' => 1, 'pages' => 0, 'results' => 0], // page 1 of 0 is a bit odd but it is correct
'themes' => [],
]);
});
it('ANDs together ac_tags (v1.2)', function () {
$this
->get('/themes/info/1.2?action=query_themes&ac_tag[]=black&ac_tag[]=orange')
->assertStatus(200)
->assertJson([
'info' => ['page' => 1, 'pages' => 0, 'results' => 0],
'themes' => [],
]);
$this
->get('/themes/info/1.2?action=query_themes&tag=orange')
->assertStatus(200)
->assertExactJson([
'info' => ['page' => 1, 'pages' => 0, 'results' => 0], // page 1 of 0 is a bit odd but it is correct
'themes' => [],
]);
});
it('returns hot tags results (v1.1)', function () {
$this
->get('/themes/info/1.1?action=hot_tags')
->assertStatus(200)
->assertExactJson([
'black' => ['count' => 1, 'name' => 'black', 'slug' => 'black'],
'blue' => ['count' => 1, 'name' => 'blue', 'slug' => 'blue'],
'red' => ['count' => 1, 'name' => 'red', 'slug' => 'red'],
'white' => ['count' => 1, 'name' => 'white', 'slug' => 'white'],
]);
// TODO: test the actual hot tags sorting algorithm with multiple plugins
});
it('returns latest feature list when no wp version given (v1.2)', function () {
$this
->get('/themes/info/1.2?action=feature_list')
->assertStatus(200)
->assertExactJsonStructure(['Features', 'Layout', 'Subject'])
->assertJsonCount(26, 'Features')
->assertJsonCount(8, 'Layout')
->assertJsonCount(9, 'Subject');
});
it('returns feature list for wp version < 3.7.999 (v1.2)', function () {
$this
->get('/themes/info/1.2?action=feature_list&wp_version=3.7.998')
->assertStatus(200)
->assertExactJsonStructure(['Colors', 'Columns', 'Features', 'Subject', 'Width'])
->assertJsonCount(15, 'Colors')
->assertJsonCount(6, 'Columns')
->assertJsonCount(19, 'Features')
->assertJsonCount(3, 'Subject')
->assertJsonCount(2, 'Width');
});
it('returns latest feature list when no user-agent set (v1.1)', function () {
$this
->get('/themes/info/1.1?action=feature_list')
->assertStatus(200)
->assertExactJsonStructure(['Features', 'Layout', 'Subject'])
->assertJsonCount(26, 'Features')
->assertJsonCount(8, 'Layout')
->assertJsonCount(9, 'Subject');
});
// perverse, but something should test it
it('returns latest feature list in serialized object format (v1.0)', function () {
$body = $this
->get('/themes/info/1.0?action=feature_list')
->assertStatus(200)
->content();
$response = unserialize($body);
expect($response)->toBeObject();
expect($response)->toHaveProperty('Features');
expect($response)->toHaveProperty('Layout');
expect($response)->toHaveProperty('Subject');
expect($response->Features)->toBeArray()->toHaveCount(26);
expect($response->Layout)->toBeArray()->toHaveCount(8);
expect($response->Subject)->toBeArray()->toHaveCount(9);
});
it('returns feature list for wp version < 3.7.999 (v1.1)', function () {
$this
->withHeader('User-Agent', 'WordPress/3.7.998')
->get('/themes/info/1.1?action=feature_list')
->assertStatus(200)
->assertExactJsonStructure(['Colors', 'Columns', 'Features', 'Subject', 'Width'])
->assertJsonCount(15, 'Colors')
->assertJsonCount(6, 'Columns')
->assertJsonCount(19, 'Features')
->assertJsonCount(3, 'Subject')
->assertJsonCount(2, 'Width');
});
it('rejects invalid action with 404 not found', function () {
$response = $this->get('/themes/info/1.2?action=bogus')->assertNotFound();
});