diff --git a/tests/Unit/Transformers/TestFailurePromptTransformerTest.php b/tests/Unit/Transformers/TestFailurePromptTransformerTest.php
new file mode 100644
index 0000000..3f33519
--- /dev/null
+++ b/tests/Unit/Transformers/TestFailurePromptTransformerTest.php
@@ -0,0 +1,647 @@
+
+
+
+
+
+
+XML;
+}
+
+describe('TestFailurePromptTransformer', function () {
+ beforeEach(function () {
+ $this->transformer = new TestFailurePromptTransformer;
+ });
+
+ it('implements PromptTransformerInterface', function () {
+ expect($this->transformer)->toBeInstanceOf(PromptTransformerInterface::class);
+ });
+
+ describe('canHandle', function () {
+ it('handles check names containing "test"', function () {
+ expect($this->transformer->canHandle('test'))->toBeTrue();
+ expect($this->transformer->canHandle('Tests & Coverage'))->toBeTrue();
+ expect($this->transformer->canHandle('unit-test'))->toBeTrue();
+ });
+
+ it('handles check names containing "pest"', function () {
+ expect($this->transformer->canHandle('pest'))->toBeTrue();
+ expect($this->transformer->canHandle('Pest Syntax'))->toBeTrue();
+ });
+
+ it('handles check names containing "phpunit"', function () {
+ expect($this->transformer->canHandle('phpunit'))->toBeTrue();
+ expect($this->transformer->canHandle('PHPUnit Runner'))->toBeTrue();
+ });
+
+ it('rejects unrelated check names', function () {
+ expect($this->transformer->canHandle('security'))->toBeFalse();
+ expect($this->transformer->canHandle('syntax'))->toBeFalse();
+ expect($this->transformer->canHandle('coverage'))->toBeFalse();
+ });
+ });
+
+ describe('JUnit XML parsing', function () {
+ it('parses JUnit XML with failures', function () {
+ $xml = <<<'XML'
+
+
+
+
+
+
+XML;
+
+ $result = $this->transformer->transform($xml);
+
+ expect($result['prompt'])->toContain('Test Failures (1 total)')
+ ->and($result['prompt'])->toContain('it does something')
+ ->and($result['prompt'])->toContain('FAIL')
+ ->and($result['prompt'])->toContain('tests/Unit/FooTest.php:10')
+ ->and($result['prompt'])->toContain('Failed asserting that false is true.')
+ ->and($result['summary']['passed'])->toBeFalse()
+ ->and($result['summary']['failures'])->toBe(1)
+ ->and($result['summary']['errors'])->toBe(0)
+ ->and($result['summary']['tests'])->toBe(['it does something']);
+ });
+
+ it('parses JUnit XML with errors', function () {
+ $xml = <<<'XML'
+
+
+
+
+ Something exploded
+
+
+
+XML;
+
+ $result = $this->transformer->transform($xml);
+
+ expect($result['prompt'])->toContain('Test Failures (1 total)')
+ ->and($result['prompt'])->toContain('ERROR')
+ ->and($result['prompt'])->toContain('it throws')
+ ->and($result['summary']['failures'])->toBe(0)
+ ->and($result['summary']['errors'])->toBe(1);
+ });
+
+ it('parses JUnit XML with both failures and errors', function () {
+ $xml = <<<'XML'
+
+
+
+
+
+ Fatal error
+
+
+
+XML;
+
+ $result = $this->transformer->transform($xml);
+
+ expect($result['prompt'])->toContain('Test Failures (2 total)')
+ ->and($result['summary']['failures'])->toBe(1)
+ ->and($result['summary']['errors'])->toBe(1)
+ ->and($result['summary']['tests'])->toHaveCount(2);
+ });
+
+ it('returns all-passed for JUnit XML with no failures', function () {
+ $xml = <<<'XML'
+
+
+
+
+
+
+XML;
+
+ $result = $this->transformer->transform($xml);
+
+ expect($result['prompt'])->toBe('All tests passed.')
+ ->and($result['summary']['passed'])->toBeTrue()
+ ->and($result['summary']['failures'])->toBe(0);
+ });
+
+ it('handles testsuite root without testsuites wrapper', function () {
+ $xml = <<<'XML'
+
+
+
+
+XML;
+
+ $result = $this->transformer->transform($xml);
+
+ expect($result['prompt'])->toContain('Test Failures (1 total)')
+ ->and($result['summary']['failures'])->toBe(1);
+ });
+
+ it('handles nested test suites', function () {
+ $xml = <<<'XML'
+
+
+
+
+
+ Nested failure
+
+
+
+
+XML;
+
+ $result = $this->transformer->transform($xml);
+
+ expect($result['prompt'])->toContain('it fails nested')
+ ->and($result['summary']['failures'])->toBe(1);
+ });
+
+ it('falls back to Pest parsing for invalid XML', function () {
+ $invalidXml = '';
+
+ $result = $this->transformer->transform($invalidXml);
+
+ expect($result)->toHaveKeys(['prompt', 'summary']);
+ });
+
+ it('handles testcase with missing attributes', function () {
+ $xml = <<<'XML'
+
+
+
+
+ Some failure message
+
+
+
+XML;
+
+ $result = $this->transformer->transform($xml);
+
+ expect($result['prompt'])->toContain('Unknown')
+ ->and($result['prompt'])->toContain('Unknown file')
+ ->and($result['summary']['failures'])->toBe(1);
+ });
+
+ it('detects XML by testsuites tag without xml declaration', function () {
+ $xml = '';
+
+ $result = $this->transformer->transform($xml);
+
+ expect($result['prompt'])->toBe('All tests passed.');
+ });
+
+ it('handles failure with missing type attribute', function () {
+ $xml = <<<'XML'
+
+
+
+
+
+
+XML;
+
+ $result = $this->transformer->transform($xml);
+
+ expect($result['summary']['failures'])->toBe(1);
+ });
+
+ it('handles error with missing type attribute', function () {
+ $xml = <<<'XML'
+
+
+
+
+
+
+XML;
+
+ $result = $this->transformer->transform($xml);
+
+ expect($result['summary']['errors'])->toBe(1);
+ });
+ });
+
+ describe('Pest output parsing', function () {
+ it('parses Pest failures with cross mark', function () {
+ $output = <<<'OUTPUT'
+⨯ Tests\Unit\FooTest → it does something 0.5s
+ Expected true to be false.
+ at tests/Unit/FooTest.php:42
+
+Tests: 1 failed
+OUTPUT;
+
+ $result = $this->transformer->transform($output);
+
+ expect($result['prompt'])->toContain('Test Failures (1 total)')
+ ->and($result['prompt'])->toContain('it does something')
+ ->and($result['prompt'])->toContain('tests/Unit/FooTest.php')
+ ->and($result['summary']['passed'])->toBeFalse()
+ ->and($result['summary']['failures'])->toBe(1);
+ });
+
+ it('parses Pest failures with X mark', function () {
+ $output = <<