Skip to content

Testing

Rumen Damyanov edited this page Oct 28, 2025 · 2 revisions

Testing

Comprehensive testing guide for the PHP-SEO package, including unit tests, integration tests, and SEO validation testing.

Overview

Testing is crucial for ensuring your SEO implementation works correctly and consistently. This guide covers testing strategies, tools, and best practices for validating SEO functionality with the PHP-SEO package.

Current Test Status:

  • 413 tests passing (100% pass rate)
  • 📊 67.5% code coverage (improving towards 80%+ target)
  • 🧪 Pest PHP testing framework
  • ~24s full suite execution time

Testing Framework

The php-seo package uses Pest PHP as its testing framework, which provides an elegant, readable syntax for writing tests.

Installing Pest for Your Project

composer require pestphp/pest --dev
composer require pestphp/pest-plugin-laravel --dev  # For Laravel projects

# Initialize Pest
./vendor/bin/pest --init

Testing Strategies

Types of SEO Testing

  1. Unit Testing: Test individual components and methods
  2. Integration Testing: Test component interactions
  3. Functional Testing: Test complete SEO workflows
  4. Validation Testing: Verify SEO output correctness
  5. Performance Testing: Ensure acceptable performance
  6. Regression Testing: Prevent feature breakage

Unit Testing

Basic Test Setup with Pest

use Rumenx\PhpSeo\SeoManager;
use Rumenx\PhpSeo\Config\SeoConfig;

test('SeoManager can analyze basic content', function () {
    $config = new SeoConfig([
        'ai' => ['enabled' => false],
    ]);
    
    $seoManager = new SeoManager($config);
    $html = '<html><head><title>Test Page</title></head><body><h1>Hello World</h1></body></html>';
    
    $analysis = $seoManager->analyze($html);
    
    expect($analysis)->toBeArray()
        ->and($analysis['title'])->toBe('Test Page')
        ->and($analysis['headings']['h1'])->toHaveCount(1)
        ->and($analysis['headings']['h1'][0]['text'])->toBe('Hello World');
});

test('SeoManager generates meta tags', function () {
    $config = new SeoConfig();
    $seoManager = new SeoManager($config);
    
    $analysis = $seoManager->analyze('<html></html>', [
        'title' => 'Custom Title',
        'description' => 'Custom description',
    ]);
    
    $metaTags = $seoManager->renderMetaTags($analysis);
    
    expect($metaTags)->toContain('Custom Title')
        ->and($metaTags)->toContain('Custom description');
});

Meta Tags

test('generates title meta tag', function () {
    $seo = new SeoManager();
    $analysis = $seo->analyze('<html></html>', ['title' => 'Test Title']);
    
    $metaTags = $seo->renderMetaTags($analysis);
    
    expect($metaTags)->toContain('<title>Test Title</title>');
});

test('generates description meta tag', function () {
    $seo = new SeoManager();
    $analysis = $seo->analyze('<html></html>', [
        'description' => 'This is a test description'
    ]);
    
    $metaTags = $seo->renderMetaTags($analysis);
    
    expect($metaTags)->toContain('<meta name="description" content="This is a test description">');
});

test('generates Open Graph tags', function () {
    $seo = new SeoManager();
    $analysis = $seo->analyze('<html></html>', [
        'title' => 'OG Test',
        'description' => 'OG Description',
        'image' => 'https://example.com/image.jpg',
        'url' => 'https://example.com/page'
    ]);
    
    $metaTags = $seo->renderMetaTags($analysis);
    
    expect($metaTags)->toContain('<meta property="og:title" content="OG Test">')
        ->and($metaTags)->toContain('<meta property="og:description" content="OG Description">')
        ->and($metaTags)->toContain('<meta property="og:image" content="https://example.com/image.jpg">');
});

Structured Data

test('generates article schema', function () {
    $seo = new SeoManager();
    $content = '<article><h1>Article Title</h1><p>Article content</p></article>';
    
    $analysis = $seo->analyze($content, [
        'type' => 'article',
        'title' => 'Article Title',
        'author' => 'John Doe',
        'published_at' => '2024-01-01T10:00:00Z'
    ]);
    
    $structuredData = $seo->generateStructuredData($analysis);
    $schema = json_decode($structuredData, true);
    
    expect($schema['@type'])->toBe('Article')
        ->and($schema['headline'])->toBe('Article Title')
        ->and($schema['author']['name'])->toBe('John Doe');
});

test('generates product schema', function () {
    $seo = new SeoManager();
    $analysis = $seo->analyze('<html></html>', [
        'type' => 'product',
        'name' => 'Test Product',
        'price' => 29.99,
        'currency' => 'USD'
    ]);
    
    $structuredData = $seo->generateStructuredData($analysis);
    $schema = json_decode($structuredData, true);
    
    expect($schema['@type'])->toBe('Product')
        ->and($schema['name'])->toBe('Test Product')
        ->and($schema['offers']['price'])->toBe(29.99);
});

Content Analysis

test('extracts headings from HTML', function () {
    $html = '
        <html>
            <body>
                <h1>Main Title</h1>
                <h2>Subtitle 1</h2>
                <h2>Subtitle 2</h2>
                <h3>Sub-subtitle</h3>
            </body>
        </html>
    ';
    
    $seo = new SeoManager();
    $analysis = $seo->analyze($html);
    
    expect($analysis['headings']['h1'])->toHaveCount(1)
        ->and($analysis['headings']['h2'])->toHaveCount(2)
        ->and($analysis['headings']['h3'])->toHaveCount(1)
        ->and($analysis['headings']['h1'][0]['text'])->toBe('Main Title');
});

test('analyzes images', function () {
    $html = '
        <html>
            <body>
                <img src="image1.jpg" alt="Image 1">
                <img src="image2.jpg" alt="">
                <img src="image3.jpg">
            </body>
        </html>
    ';
    
    $seo = new SeoManager();
    $analysis = $seo->analyze($html);
    
    expect($analysis['images'])->toHaveCount(3)
        ->and($analysis['images'][0]['alt'])->toBe('Image 1')
        ->and($analysis['images'][1]['alt'])->toBe('');
});

Running Tests

Run All Tests

# Run all tests
./vendor/bin/pest

# Run with coverage
./vendor/bin/pest --coverage

# Run with minimum coverage threshold
./vendor/bin/pest --coverage --min=70

Run Specific Tests

# Run specific test file
./vendor/bin/pest tests/Unit/SeoManagerTest.php

# Run tests matching a pattern
./vendor/bin/pest --filter="SeoManager"

# Run tests in a directory
./vendor/bin/pest tests/Unit/

# Run tests with specific group
./vendor/bin/pest --group=integration

Continuous Integration

Pest Configuration

// tests/Pest.php
<?php

uses(Tests\TestCase::class)->in('Feature');

/*
|--------------------------------------------------------------------------
| Expectations
|--------------------------------------------------------------------------
*/

expect()->extend('toBeOne', function () {
    return $this->toBe(1);
});

/*
|--------------------------------------------------------------------------
| Functions
|--------------------------------------------------------------------------
*/

function something()
{
    // ..
}

GitHub Actions Workflow

# .github/workflows/tests.yml
name: Tests

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        php-version: ['8.2', '8.3']
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Setup PHP
      uses: shivammathur/setup-php@v2
      with:
        php-version: ${{ matrix.php-version }}
        extensions: dom, curl, libxml, mbstring, zip
        coverage: xdebug
    
    - name: Install dependencies
      run: composer install --prefer-dist --no-progress
    
    - name: Run tests
      run: vendor/bin/pest --coverage --min=70
    
    - name: Upload coverage
      uses: codecov/codecov-action@v3
      with:
        files: ./coverage.xml

Test Coverage

The package currently achieves 67.5% code coverage with ongoing improvements. Coverage gaps are primarily in:

  • AI Provider HTTP methods (require extensive mocking)
  • Error handling edge cases
  • Framework-specific integrations

High Coverage Areas:

  • ✅ ContentAnalyzer: 100%
  • ✅ SeoConfig: 100%
  • ✅ MetaTagGenerator: 100%
  • ✅ PromptBuilder: 98.3%
  • ✅ ResponseValidator: 92%
  • ✅ ProviderFactory: 92%

Testing ensures your SEO implementation is reliable, maintainable, and performs well across different scenarios and environments.

Clone this wiki locally