PHPackages                             juampi92/test-seo - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Testing &amp; Quality](/categories/testing)
4. /
5. juampi92/test-seo

ActiveLibrary[Testing &amp; Quality](/categories/testing)

juampi92/test-seo
=================

Easy way to test your SEO

v1.9(1mo ago)26341.0k—8.1%5MITPHPPHP ^8.0.2CI passing

Since Aug 28Pushed 1mo ago1 watchersCompare

[ Source](https://github.com/juampi92/test-seo)[ Packagist](https://packagist.org/packages/juampi92/test-seo)[ Docs](https://github.com/juampi92/test-seo)[ RSS](/packages/juampi92-test-seo/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (9)Dependencies (12)Versions (12)Used By (0)

Test SEO
========

[](#test-seo)

[![Latest Version on Packagist](https://camo.githubusercontent.com/ab00719ca3f00bdf8918c58aa84d274a89a95bb6696d070682f86a810a20cb75/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6a75616d706939322f746573742d73656f2e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/juampi92/test-seo)[![GitHub Tests Action Status](https://camo.githubusercontent.com/58824bb24385565d46f837941fee01a5d7f75abcdc59487bc32c42c766fb939a/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6a75616d706939322f746573742d73656f2f72756e2d74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/juampi92/test-seo/actions?query=workflow%3Arun-tests+branch%3Amain)[![GitHub Code Style Action Status](https://camo.githubusercontent.com/0c2d09f004badcf7dc2c9ada25c84bb085e8aafe1c2540b727cbda7d95eeb16e/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6a75616d706939322f746573742d73656f2f70696e742e796d6c3f6272616e63683d6d61696e266c6162656c3d636f64652d7374796c65267374796c653d666c61742d737175617265)](https://github.com/juampi92/test-seo/actions?query=workflow%3A%22Fix+PHP+code+style+issues%22+branch%3Amain)[![Total Downloads](https://camo.githubusercontent.com/2107374a5c957d1aafe76dcea1b2d976b337b24283b0a644ce0f933e3b77c4f2/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6a75616d706939322f746573742d73656f2e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/juampi92/test-seo)

An easy-to-use package for testing SEO. The package allows you to extract SEO tags from a given HTML and verify that the SEO structure is correct.

- [Installation](#instalation)
- [Usage](#usage)
    - [PHPUnit](#phpunit)
    - [Laravel](#laravel)
    - [Pest](#pest)
- [API](#seo-data)
    - [SEO Data](#seo-data)
    - [Assertions](#sssertions)
- [Snapshot testing](#snapshots)

---

Installation
------------

[](#installation)

You can install the package via composer:

```
composer require juampi92/test-seo --dev
```

Usage
-----

[](#usage)

```
// Create TestSEO instance using the response:
$seo = new TestSEO($htmlResponse);

// Perform assertions:
$seo->assertTitleEndsWith(' - My Website');

// Assert the data yourself:
$this->assertEquals(
    'My title - My Website',
    $seo->data->title()
);
```

Look at the following examples using **PHPUnit**, **Laravel**, and **Pest**.

### PHPUnit

[](#phpunit)

```
public function testLandingPageSEO()
{
    // Arrange
    // ...

    // Act
    $response = $client->get('/')->send();

    // Assert
    $this->assertEquals(200, $response->getStatusCode());
    $html = json_decode($response->getBody(true), true);

    $seo = new TestSEO($html);

    // Assert
    $seo
        ->assertTitleEndsWith(' - My Website')
        ->assertCanonicalIs('https://www.mywebsite.com/');
}
```

### Laravel

[](#laravel)

```
public function test_landing_page_SEO()
{
    // Arrange
    // ...

    // Act
    $response = $this->get('/');

    // Assert
    $response->assertStatus(200);

    $seo = new TestSEO($response->getContent());

    $seo
        ->assertTitleEndsWith(' - My Website')
        ->assertCanonicalIs('https://www.mywebsite.com/');
}
```

### Pest

[](#pest)

```
test('landing page SEO tags', function () {
    // Arrange
    // ...

    // Act
    $response = get('/')->assertStatus(200);

    $seo = new TestSEO($response->getContent());

    // Assert
    expect($seo->data)
        ->title()->toEndWith(' - My Website')
        ->description()->toBe('This is my description')
        ->canonical()->not()->toBeNull()
        ->robots()->index()->toBeTrue()
        ->robots()->nofollow()->toBeTrue();
});
```

SEO Data
--------

[](#seo-data)

You can access the SEO Data yourself by accessing the public property `TestSEO->data`. Here are the available methods:

MethodReturnsDescription`title()``?string``{this}``description()``?string````image()``?Url` [🔍](https://github.com/spatie/url)```robots()``Robots` [🔍](https://github.com/juampi92/test-seo/blob/main/src/Tags/Robots.php)```canonical()``?Url` [🔍](https://github.com/spatie/url)```prev()``?Url` [🔍](https://github.com/spatie/url)```next()``?Url` [🔍](https://github.com/spatie/url)```openGraph()``TagCollection` [🔍](https://github.com/juampi92/test-seo/blob/main/src/Tags/TagCollection.php)```twitter()``TagCollection` [🔍](https://github.com/juampi92/test-seo/blob/main/src/Tags/TagCollection.php)```alternateHrefLang()``AlternateHrefLangCollection` [🔍](https://github.com/juampi92/test-seo/blob/main/src/Tags/AlternateHrefLangCollection.php)```images()``array`All images in the page. ```h1s()``array`All H1 in the page. `{this}``h2s()``array`All H2 in the page. `{this}``charset()``?string```The SEOData class is **Macroable**, so feel free to extend it yourself.

Assertions
----------

[](#assertions)

MethodNotes`assertCanonicalIs(string $expected)``assertCanonicalIsEmpty()``assertRobotsIsEmpty()``assertRobotsIsNoIndexNoFollow()`Checks that the robots are `noindex, nofollo` or `none``assertPaginationIsEmpty()``prev` and `next` are both missing.`assertAlternateHrefLangIsEmpty()``assertTitleIs(string $expected)``assertTitleContains(string $expected)``assertTitleEndsWith(string $expected)``assertDescriptionIs(string $expected)``assertThereIsOnlyOneH1()`Make sure there is only one H1 in the entire website.`assertAllImagesHaveAltText()`Make sure all images have an `alt="..."`Suggest your own!These assertions can help devs to follow the best SEO practices. Make a PR if you think some are missing!Snapshots
---------

[](#snapshots)

When it comes to SEO, a snapshot test is a great way to ensure nothing has been changed by accident.

Here is an example:

```
$seo = new TestSEO($response->getContent(), snapshotSerializer: null);

$json = json_encode($seo);
```

By default, the SEO tags are serialized using the `SimpleSerializer`. Make your own serializer by implementing the `SnapshotSerializer` interface:

```
$seo = new TestSEO($response->getContent(), new MyCustomSerializer());

$json = json_encode($seo);
```

### Pest Example

[](#pest-example)

```
use function Spatie\Snapshots\{assertMatchesSnapshot, assertMatchesJsonSnapshot};
use Juampi92\TestSEO\TestSEO;

test('landing page SEO', function () {
    $response = $this->get('/');

    $response->assertStatus(200);

    $seo = new TestSEO($response->getContent());

    assertMatchesJsonSnapshot(json_encode($seo));
});
```

**Note:** this example requires `spatie/pest-plugin-snapshots`.

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING](CONTRIBUTING.md) for details.

Credits
-------

[](#credits)

- [Juan Pablo Barreto](https://github.com/juampi92)
- [All Contributors](../../contributors)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

55

—

FairBetter than 98% of packages

Maintenance89

Actively maintained with recent releases

Popularity44

Moderate usage in the ecosystem

Community13

Small or concentrated contributor base

Maturity59

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 93.9% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~145 days

Recently: every ~276 days

Total

10

Last Release

55d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/1f8d31c9bb6d7862e21aac7af0f7b2615dc06485b4c30b19b8d9fdffaa42c712?d=identicon)[juampi92](/maintainers/juampi92)

---

Top Contributors

[![juampi92](https://avatars.githubusercontent.com/u/2080215?v=4)](https://github.com/juampi92 "juampi92 (46 commits)")[![canvural](https://avatars.githubusercontent.com/u/1574232?v=4)](https://github.com/canvural "canvural (2 commits)")[![bonsi](https://avatars.githubusercontent.com/u/1137656?v=4)](https://github.com/bonsi "bonsi (1 commits)")

---

Tags

php8phpunitseotestingphptestingphpunitseo

###  Code Quality

Static AnalysisPHPStan

Code StyleLaravel Pint

Type Coverage Yes

### Embed Badge

![Health badge](/badges/juampi92-test-seo/health.svg)

```
[![Health](https://phpackages.com/badges/juampi92-test-seo/health.svg)](https://phpackages.com/packages/juampi92-test-seo)
```

###  Alternatives

[brianium/paratest

Parallel testing for PHP

2.5k118.8M754](/packages/brianium-paratest)[blastcloud/guzzler

Supercharge your app or SDK with a testing library specifically for Guzzle.

272419.3k35](/packages/blastcloud-guzzler)[robiningelbrecht/phpunit-pretty-print

Prettify PHPUnit output

76460.0k15](/packages/robiningelbrecht-phpunit-pretty-print)[robiningelbrecht/phpunit-coverage-tools

PHPUnit coverage tools

1783.0k34](/packages/robiningelbrecht-phpunit-coverage-tools)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
