{"id":25420035,"url":"https://github.com/chqthomas/approval-tests-php","last_synced_at":"2026-02-14T05:35:23.222Z","repository":{"id":277858729,"uuid":"933334499","full_name":"ChqThomas/approval-tests-php","owner":"ChqThomas","description":"A PHP assertion library for approval testing with PHPUnit","archived":false,"fork":false,"pushed_at":"2025-02-16T15:33:39.000Z","size":62,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-16T16:41:15.567Z","etag":null,"topics":["approval-testing","assertion-library","phpunit","snapshot-testing"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ChqThomas.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-02-15T17:54:22.000Z","updated_at":"2025-02-16T15:31:06.000Z","dependencies_parsed_at":"2025-02-16T16:53:47.735Z","dependency_job_id":null,"html_url":"https://github.com/ChqThomas/approval-tests-php","commit_stats":null,"previous_names":["chqthomas/approval-tests-php"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChqThomas%2Fapproval-tests-php","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChqThomas%2Fapproval-tests-php/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChqThomas%2Fapproval-tests-php/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChqThomas%2Fapproval-tests-php/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ChqThomas","download_url":"https://codeload.github.com/ChqThomas/approval-tests-php/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239181382,"owners_count":19595820,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["approval-testing","assertion-library","phpunit","snapshot-testing"],"created_at":"2025-02-16T19:22:39.156Z","updated_at":"2026-02-14T05:35:23.193Z","avatar_url":"https://github.com/ChqThomas.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PHP Approval Tests\n\nA PHP library for approval testing. This approach allows you to verify complex results by comparing them with approved versions, making it ideal for testing outputs that are difficult to assert traditionally (e.g., HTML, JSON, XML, or binary files).\n\n\u003e [!WARNING]  \n\u003e This library is still in development. It is not recommended for production use. Many features are still missing, and the API may change.\n\n## Table of Contents\n\n- [Installation](#installation)\n- [Basic Usage](#basic-usage)\n    - [Simple Test](#simple-test)\n    - [Structured Data Test](#structured-data-test)\n- [Specialized Verifications](#specialized-verifications)\n    - [HTML](#html)\n    - [JSON](#json)\n    - [XML](#xml)\n    - [CSV](#csv)\n    - [Binary Files](#binary-files)\n- [Advanced Features](#advanced-features)\n    - [Tests with Data Providers](#tests-with-data-providers)\n    - [Verify All Combinations](#verify-all-combinations)\n- [Configuration](#configuration)\n    - [PHPUnit Bootstrap Configuration](#phpunit-bootstrap-configuration)\n    - [Set a Custom Reporter](#set-a-custom-reporter)\n    - [Use a Custom Object Formatter](#use-a-custom-object-formatter)\n    - [Custom Namer](#custom-namer)\n    - [Auto-Approve Snapshots](#auto-approve-snapshots)\n- [Scrubbers](#scrubbers)\n    - [JSON Scrubbing](#json-scrubbing)\n        - [Ignore JSON Members](#ignore-json-members)\n        - [Scrub JSON Members](#scrub-json-members)\n    - [XML Scrubbing](#xml-scrubbing)\n    - [Regex Scrubbing](#regex-scrubbing)\n    - [Custom Scrubber](#custom-scrubber)\n- [Maintenance](#maintenance)\n    - [Cleanup Received Files](#cleanup-received-files)\n    - [Detect Orphaned Files](#detect-orphaned-files)\n- [Reporters](#reporters)\n    - [CLI Reporter](#cli-reporter)\n    - [Diff Reporter](#diff-reporter)\n    - [Composite Reporter](#composite-reporter)\n- [Symfony Integration](#symfony-integration)\n- [Best Practices](#best-practices)\n- [Contributing](#contributing)\n- [License](#license)\n\n## Installation\n\nInstall the library via Composer:\n\n```php\ncomposer require chqthomas/approval-tests\n```\n\n## Basic Usage\n\n### Simple Test\n\nVerify a simple string output:\n\n```php\nuse ChqThomas\\ApprovalTests\\Approvals;\n\npublic function testSimpleString(): void \n{\n    Approvals::verify(\"Hello World\");\n}\n```\n\nThe first time this runs, it generates a `.received.txt` file. Approve it by renaming it to `.approved.txt` or use auto-approval (see below).\n\n### Structured Data Test\n\nVerify complex data structures like arrays or objects:\n\n```php\npublic function testArray(): void \n{\n    $data = [\n        'name' =\u003e 'John Doe',\n        'age' =\u003e 30,\n        'roles' =\u003e ['admin', 'user']\n    ];\n    Approvals::verify($data);\n}\n```\n\n## Specialized Verifications\n\nThe library supports specific formats with dedicated methods:\n\n### HTML\n\nVerify HTML content with automatic formatting:\n\n```php\npublic function testHtml(): void \n{\n    $html = '\u003cdiv\u003eHello \u003cspan\u003eWorld\u003c/span\u003e\u003c/div\u003e';\n    Approvals::verifyHtml($html);\n}\n```\n\n### JSON\n\nVerify JSON with pretty-printing and scrubbing:\n\n```php\npublic function testJson(): void \n{\n    $json = '{\"name\":\"John\",\"age\":30}';\n    Approvals::verifyJson($json); // Automatically formatted\n}\n```\n\n### XML\n\nVerify XML with formatting:\n\n```php\npublic function testXml(): void \n{\n    $xml = '\u003c?xml version=\"1.0\"?\u003e\u003croot\u003e\u003cuser\u003eJohn\u003c/user\u003e\u003c/root\u003e';\n    Approvals::verifyXml($xml);\n}\n```\n\n### CSV\n\nVerify CSV content:\n\n```php\npublic function testCsv(): void \n{\n    $csv = \"name,age\\nJohn,30\\nJane,25\";\n    Approvals::verifyCsv($csv);\n}\n```\n\n### Binary Files\n\nVerify binary content (e.g., images):\n\n```php\npublic function testBinaryFile(): void \n{\n    Approvals::verifyBinaryFile('path/to/image.png', 'png');\n}\n```\n\n## Advanced Features\n\n### Tests with Data Providers\n\nUse PHPUnit data providers for parameterized tests:\n\n```php\n/**\n * @dataProvider provideTestData\n */\npublic function testWithDataProvider(array $data, string $expected): void \n{\n    $result = processData($data);\n    Approvals::verify($result);\n}\n\npublic static function provideTestData(): array\n{\n    return [\n        'case1' =\u003e [['input' =\u003e 1], 'output1'],\n        'case2' =\u003e [['input' =\u003e 2], 'output2'],\n    ];\n}\n```\n\n### Verify All Combinations\n\nTest all combinations of inputs:\n\n```php\npublic function testAllCombinations(): void \n{\n    $operations = ['+', '-', '*', '/'];\n    $numbers = [1, 2, 3];\n    \n    Approvals::verifyAllCombinations(\n        function($op, $a, $b) {\n            switch($op) {\n                case '+': return $a + $b;\n                case '-': return $a - $b;\n                case '*': return $a * $b;\n                case '/': return $b != 0 ? $a / $b : 'Division by zero';\n            }\n        },\n        [$operations, $numbers, $numbers]\n    );\n}\n```\n\n## Configuration\n\nCustomize the library’s behavior via the `Configuration` class:\n\n### PHPUnit Bootstrap Configuration\n\nCreate a `tests/bootstrap.php` file to configure the library globally for all your tests:\n\n```php\n\u003c?php\n\nrequire_once __DIR__ . '/../vendor/autoload.php';\n\nuse ChqThomas\\ApprovalTests\\Configuration;\nuse ChqThomas\\ApprovalTests\\Reporter\\DiffReporter;\nuse ChqThomas\\ApprovalTests\\Formatter\\SymfonyObjectFormatter;\n\n// Global configuration\nConfiguration::getInstance()\n    -\u003esetReporter(new DiffReporter())\n    -\u003esetObjectFormatter(new SymfonyObjectFormatter())\n    -\u003esetAutoApprove(false);\n\n// Configure default scrubbers for specific formats\nConfiguration::getInstance()\n    -\u003esetDefaultScrubber('json', JsonScrubber::create()\n        -\u003escrubMember('password', 'token')\n        -\u003eignoreMember('sensitive_data'))\n    -\u003esetDefaultScrubber('xml', XmlScrubber::create()\n        -\u003eaddScrubber(RegexScrubber::create([\n            '/\\d{4}-\\d{2}-\\d{2}/' =\u003e '[DATE]'\n        ])));\n```\n\nThen reference it in your phpunit.xml:\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n\u003cphpunit bootstrap=\"tests/bootstrap.php\"\u003e\n    \u003c!-- ... --\u003e\n\u003c/phpunit\u003e\n```\n\n### Set a Custom Reporter\n\nChange how differences are reported:\n\n```php\nuse ChqThomas\\ApprovalTests\\Configuration;\nuse ChqThomas\\ApprovalTests\\Reporter\\DiffReporter;\n\nConfiguration::getInstance()-\u003esetReporter(new DiffReporter());\n```\n\n### Use a Custom Object Formatter\n\nSwitch between default and Symfony formatters:\n\n```php\nuse ChqThomas\\ApprovalTests\\Formatter\\SymfonyObjectFormatter;\n\nConfiguration::getInstance()-\u003esetObjectFormatter(new SymfonyObjectFormatter());\n```\n\n*Note*: Requires `symfony/serializer` to be installed for `SymfonyObjectFormatter`.\n\n### Custom Namer\n\nSet a custom namer for file naming:\n\n```php\nuse ChqThomas\\ApprovalTests\\Namer\\EnvironmentAwareNamer;\n\nConfiguration::getInstance()-\u003esetNamerClass(EnvironmentAwareNamer::class);\n```\n\n### Auto-Approve Snapshots\n\nAutomatically approve new or changed snapshots:\n\n```php\nConfiguration::getInstance()-\u003esetAutoApprove(true);\n```\n\nOr use an environment variable:\n\n```php\nAPPROVE_SNAPSHOTS=true vendor/bin/phpunit\n```\n\n## Scrubbers\n\nScrubbers normalize content before comparison, handling dynamic data like dates or IDs.\n\n### JSON Scrubbing\n\nScrub sensitive or variable data:\n\n```php\npublic function testJsonScrubbing(): void \n{\n    $json = \u003c\u003c\u003cJSON\n{\n    \"user\": \"John\",\n    \"password\": \"secret123\",\n    \"timestamp\": \"2024-01-01T12:00:00\",\n    \"id\": \"550e8400-e29b-41d4-a716-446655440000\"\n}\nJSON;\n\n    // Default scrubbers automatically handle:\n    // - GUIDs (replaced with Guid_1, Guid_2, etc.)\n    // - Dates (replaced with DateTimeOffset_1, etc.)\n    Approvals::verifyJson($json);\n}\n```\n\n#### Ignore JSON Members\n\nRemove specific members:\n\n```php\npublic function testJsonIgnoreMember(): void \n{\n    $json = \u003c\u003c\u003cJSON\n{\n    \"user\": \"John\",\n    \"sensitive\": {\n        \"password\": \"secret123\",\n        \"token\": \"abc123\"\n    }\n}\nJSON;\n\n    Approvals::verifyJson($json, JsonScrubber::create()\n        -\u003eignoreMember('sensitive')); // Member will be removed\n}\n```\n\n#### Scrub JSON Members\n\nReplace members with a placeholder:\n\n```php\npublic function testJsonScrubMember(): void \n{\n    $json = \u003c\u003c\u003cJSON\n{\n    \"user\": \"John\",\n    \"password\": \"secret123\",\n    \"api_key\": \"xyz789\"\n}\nJSON;\n\n    Approvals::verifyJson($json, JsonScrubber::create()\n        -\u003escrubMember('password', 'api_key')); // Members will be replaced with \"[scrubbed]\"\n}\n```\n\n### XML Scrubbing\n\nCustom scrubbing for XML:\n\n```php\npublic function testXmlScrubbing(): void \n{\n    $xml = \u003c\u003c\u003cXML\n\u003c?xml version=\"1.0\"?\u003e\n\u003cuser\u003e\n    \u003cname\u003eJohn\u003c/name\u003e\n    \u003ccreated\u003e2024-01-01T12:00:00\u003c/created\u003e\n    \u003cid\u003e550e8400-e29b-41d4-a716-446655440000\u003c/id\u003e\n\u003c/user\u003e\nXML;\n\n    // Custom scrubber for XML\n    Approvals::verifyXml($xml, XmlScrubber::create()\n        -\u003eaddScrubber(fn($content) =\u003e preg_replace('/John/', '[NAME]', $content)));\n}\n```\n\n### Regex Scrubbing\n\nUse regular expressions for generic scrubbing:\n\n```php\npublic function testRegexScrubbing(): void \n{\n    $json = \u003c\u003c\u003cJSON\n{\n  \"nodes\": [\n    {\"id\": \"ABC123\", \"name\": \"Node1\"},\n    {\"id\": \"DEF456\", \"name\": \"Node2\"},\n    {\"id\": \"GHI789\", \"name\": \"Node3\"}\n  ]\n}\nJSON;\n\n    Approvals::verifyJson($json, JsonScrubber::create()\n        -\u003eaddScrubber(RegexScrubber::create(['/\"id\": \"([A-Z]{3}\\d{3})\"/' =\u003e '\"id\": \"MATCHED\"'])));\n}\n```\n\n### Custom Scrubber\n\nCreate a custom scrubber for any content:\n\n```php\nuse ChqThomas\\ApprovalTests\\Scrubber\\AbstractScrubber;\n\nclass MyScrubber extends AbstractScrubber\n{\n    public function scrub(string $content): string\n    {\n        // Apply base scrubbers first (GUIDs, dates)\n        $content = $this-\u003escrubGuids($content);\n        $content = $this-\u003escrubDates($content);\n        \n        // Add your custom rules\n        $content = preg_replace('/secret-\\d+/', '[SECRET]', $content);\n        \n        // Apply additional scrubbers\n        return $this-\u003eapplyAdditionalScrubbers($content);\n    }\n}\n\n// Usage\npublic function testWithCustomScrubber(): void \n{\n    $content = \"ID: secret-123\\nDate: 2024-01-01\";\n    \n    Approvals::verifyWithExtension(\n        $content,\n        \"txt\",\n        MyScrubber::create()\n            -\u003eaddScrubber(fn($text) =\u003e str_replace('ID:', 'Reference:', $text))\n    );\n}\n```\n\n## Maintenance\n\n### Cleanup Received Files\n\nRemove redundant `.received` files:\n\n```php\nuse ChqThomas\\ApprovalTests\\ApprovalMaintenance;\n\nApprovalMaintenance::cleanUpReceivedFiles(__DIR__ . '/tests/approvals');\n```\n\n### Detect Orphaned Files\n\nFind `.approved` files without associated tests:\n\n```php\n$orphanedFiles = ApprovalMaintenance::findOrphanedApprovedFiles(__DIR__ . '/tests');\n```\n\n## Reporters\n\nCustomize how differences are reported:\n\n### CLI Reporter\n\nDefault reporter for terminal output:\n\n```php\nuse ChqThomas\\ApprovalTests\\Reporter\\CliReporter;\n\nConfiguration::getInstance()-\u003esetReporter(new CliReporter());\n```\n\n### Diff Reporter\n\nShow differences using a diff format:\n\n```php\nuse ChqThomas\\ApprovalTests\\Reporter\\DiffReporter;\n\nConfiguration::getInstance()-\u003esetReporter(new DiffReporter());\n```\n\n### Composite Reporter\n\nCombine multiple reporters:\n\n```php\nuse ChqThomas\\ApprovalTests\\Reporter\\CompositeReporter;\n\n$reporter = new CompositeReporter([\n    new CliReporter(),\n    new DiffReporter()\n]);\nConfiguration::getInstance()-\u003esetReporter($reporter);\n```\n\n## Symfony Integration\n\nUse with Symfony’s DomCrawler for web testing:\n\n```php\nuse ChqThomas\\ApprovalTests\\Symfony\\ApprovalCrawlerAssertionsTrait;\n\nclass MyWebTest extends WebTestCase\n{\nuse ApprovalCrawlerAssertionsTrait;\n\n    public function testPageContent(): void\n    {\n        $client = static::createClient();\n        $client-\u003erequest('GET', '/');\n        self::verifySelectorHtml('#main-content');\n    }\n}\n```\n\n## Best Practices\n\n1. Store `.approved` files in version control.\n2. Use scrubbers for variable data (e.g., dates, IDs).\n3. Regularly clean up `.received` files.\n4. Check for orphaned `.approved` files.\n5. Use descriptive test names for clear file naming.\n\n## Contributing\n\nContributions are welcome! To contribute:\n1. Fork the project.\n2. Create a feature branch.\n3. Submit a pull request.\n\n## License\n\nMIT License","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchqthomas%2Fapproval-tests-php","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchqthomas%2Fapproval-tests-php","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchqthomas%2Fapproval-tests-php/lists"}