Skip to content

Commit 89ceac9

Browse files
authored
Merge pull request #3 from bnussbau/mock
test: add mock for easier testing
2 parents f8431b7 + b036e2d commit 89ceac9

File tree

5 files changed

+250
-0
lines changed

5 files changed

+250
-0
lines changed

README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,33 @@ echo "Generated image: $image";
122122

123123
This allows you to use BrowsershotLambda or any other Browsershot implementation that extends `Spatie\Browsershot\Browsershot`.
124124

125+
### Testing with Fake Mode
126+
127+
You can use the `fake()` method to prevent actual Browsershot and Imagick operations:
128+
129+
```php
130+
use Bnussbau\TrmnlPipeline\Model;
131+
use Bnussbau\TrmnlPipeline\TrmnlPipeline;
132+
use Bnussbau\TrmnlPipeline\Stages\BrowserStage;
133+
use Bnussbau\TrmnlPipeline\Stages\ImageStage;
134+
135+
// Enable fake mode for testing
136+
TrmnlPipeline::fake();
137+
138+
$html = '<html><body>Test Content</body></html>';
139+
140+
$result = (new TrmnlPipeline())
141+
->model(Model::OG)
142+
->pipe(new BrowserStage()->html($html))
143+
->pipe(new ImageStage())
144+
->process();
145+
146+
echo "Mock image generated: $result";
147+
148+
// Disable fake mode when done
149+
TrmnlPipeline::restore();
150+
```
151+
125152
## API Reference
126153

127154
### Pipeline

src/Stages/BrowserStage.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Bnussbau\TrmnlPipeline\Exceptions\ProcessingException;
88
use Bnussbau\TrmnlPipeline\Model;
99
use Bnussbau\TrmnlPipeline\StageInterface;
10+
use Bnussbau\TrmnlPipeline\TrmnlPipeline;
1011
use Spatie\Browsershot\Browsershot;
1112

1213
/**
@@ -125,6 +126,10 @@ public function __invoke(mixed $payload): string
125126
throw new ProcessingException('No HTML content provided for browser rendering. Use html() method to set HTML content.');
126127
}
127128

129+
if (TrmnlPipeline::isFake()) {
130+
return $this->createMockImage();
131+
}
132+
128133
try {
129134
// Create temporary file for output
130135
$tempFile = tempnam(sys_get_temp_dir(), 'browsershot_').'.png';
@@ -164,4 +169,28 @@ public function __invoke(mixed $payload): string
164169
);
165170
}
166171
}
172+
173+
/**
174+
* Create a mock image file for testing
175+
*/
176+
private function createMockImage(): string
177+
{
178+
$tempFile = tempnam(sys_get_temp_dir(), 'browsershot_fake_').'.png';
179+
180+
$image = imagecreate(800, 480);
181+
if ($image === false) {
182+
throw new ProcessingException('Failed to create mock image');
183+
}
184+
185+
$white = imagecolorallocate($image, 255, 255, 255);
186+
if ($white === false) {
187+
throw new ProcessingException('Failed to allocate color for mock image');
188+
}
189+
190+
imagefill($image, 0, 0, $white);
191+
imagepng($image, $tempFile);
192+
imagedestroy($image);
193+
194+
return $tempFile;
195+
}
167196
}

src/Stages/ImageStage.php

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Bnussbau\TrmnlPipeline\Exceptions\ProcessingException;
88
use Bnussbau\TrmnlPipeline\Model;
99
use Bnussbau\TrmnlPipeline\StageInterface;
10+
use Bnussbau\TrmnlPipeline\TrmnlPipeline;
1011
use Imagick;
1112
use ImagickException;
1213
use ImagickPixel;
@@ -202,6 +203,10 @@ public function __invoke(mixed $payload): string
202203
throw new ProcessingException('Invalid or missing image file: '.$imagePath);
203204
}
204205

206+
if (TrmnlPipeline::isFake()) {
207+
return $this->createMockProcessedImage($imagePath);
208+
}
209+
205210
try {
206211
$imagick = new Imagick($imagePath);
207212
$this->applyTransformations($imagick);
@@ -431,4 +436,40 @@ public function quantize(Imagick $imagick): void
431436
false
432437
);
433438
}
439+
440+
/**
441+
* Create a mock processed image file for testing
442+
*/
443+
private function createMockProcessedImage(string $inputPath): string
444+
{
445+
$outputPath = $this->outputPath ?? $this->generateOutputPath($inputPath);
446+
447+
// Create a simple image file based on the target format
448+
$format = $this->format ?? self::DEFAULT_FORMAT;
449+
$width = $this->width ?? self::DEFAULT_WIDTH;
450+
$height = $this->height ?? self::DEFAULT_HEIGHT;
451+
452+
$image = imagecreate($width, $height);
453+
if ($image === false) {
454+
throw new ProcessingException('Failed to create mock processed image');
455+
}
456+
457+
$white = imagecolorallocate($image, 255, 255, 255);
458+
if ($white === false) {
459+
throw new ProcessingException('Failed to allocate color for mock processed image');
460+
}
461+
462+
imagefill($image, 0, 0, $white);
463+
464+
// Save in the appropriate format
465+
match ($format) {
466+
'png' => imagepng($image, $outputPath),
467+
'bmp' => imagebmp($image, $outputPath),
468+
default => imagepng($image, $outputPath),
469+
};
470+
471+
imagedestroy($image);
472+
473+
return $outputPath;
474+
}
434475
}

src/TrmnlPipeline.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ class TrmnlPipeline
1616

1717
private Pipeline $pipeline;
1818

19+
private static bool $isFake = false;
20+
1921
public function __construct()
2022
{
2123
$this->pipeline = new Pipeline;
@@ -73,4 +75,28 @@ public function process(): mixed
7375
);
7476
}
7577
}
78+
79+
/**
80+
* Enable fake mode for testing - prevents actual Browsershot and Imagick operations
81+
*/
82+
public static function fake(): void
83+
{
84+
self::$isFake = true;
85+
}
86+
87+
/**
88+
* Disable fake mode
89+
*/
90+
public static function restore(): void
91+
{
92+
self::$isFake = false;
93+
}
94+
95+
/**
96+
* Check if fake mode is enabled
97+
*/
98+
public static function isFake(): bool
99+
{
100+
return self::$isFake;
101+
}
76102
}

tests/FakeTest.php

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Bnussbau\TrmnlPipeline\Model;
6+
use Bnussbau\TrmnlPipeline\Stages\BrowserStage;
7+
use Bnussbau\TrmnlPipeline\Stages\ImageStage;
8+
use Bnussbau\TrmnlPipeline\TrmnlPipeline;
9+
10+
afterEach(function (): void {
11+
// Clean up after each test
12+
TrmnlPipeline::restore();
13+
});
14+
15+
it('can enable and disable fake mode', function (): void {
16+
expect(TrmnlPipeline::isFake())->toBeFalse();
17+
18+
TrmnlPipeline::fake();
19+
expect(TrmnlPipeline::isFake())->toBeTrue();
20+
21+
TrmnlPipeline::restore();
22+
expect(TrmnlPipeline::isFake())->toBeFalse();
23+
});
24+
25+
it('returns mock image path when browser stage is in fake mode', function (): void {
26+
TrmnlPipeline::fake();
27+
28+
$browserStage = new BrowserStage;
29+
$browserStage->html('<html><body>Test</body></html>');
30+
31+
$result = $browserStage(null);
32+
33+
expect($result)->toBeString();
34+
expect(file_exists($result))->toBeTrue();
35+
expect(str_contains($result, 'browsershot_fake_'))->toBeTrue();
36+
expect(str_ends_with($result, '.png'))->toBeTrue();
37+
});
38+
39+
it('returns mock processed image path when image stage is in fake mode', function (): void {
40+
TrmnlPipeline::fake();
41+
42+
// Create a temporary input image
43+
$inputImage = tempnam(sys_get_temp_dir(), 'test_input_').'.png';
44+
$image = imagecreate(10, 10);
45+
$white = imagecolorallocate($image, 255, 255, 255);
46+
imagefill($image, 0, 0, $white);
47+
imagepng($image, $inputImage);
48+
imagedestroy($image);
49+
50+
$imageStage = new ImageStage;
51+
$imageStage->format('png')->width(800)->height(480);
52+
53+
$result = $imageStage($inputImage);
54+
55+
expect($result)->toBeString();
56+
expect(file_exists($result))->toBeTrue();
57+
expect(str_contains($result, '_processed.png'))->toBeTrue();
58+
59+
// Clean up
60+
unlink($inputImage);
61+
unlink($result);
62+
});
63+
64+
it('processes full pipeline in fake mode', function (): void {
65+
TrmnlPipeline::fake();
66+
67+
$html = '<html><body>Test Content</body></html>';
68+
69+
$result = (new TrmnlPipeline)
70+
->model(Model::OG)
71+
->pipe((new BrowserStage)->html($html))
72+
->pipe(new ImageStage)
73+
->process();
74+
75+
expect($result)->toBeString();
76+
expect(file_exists($result))->toBeTrue();
77+
expect(str_contains((string) $result, '_processed.png'))->toBeTrue();
78+
79+
// Clean up
80+
unlink($result);
81+
});
82+
83+
it('respects image stage configuration in fake mode', function (): void {
84+
TrmnlPipeline::fake();
85+
86+
// Create a temporary input image
87+
$inputImage = tempnam(sys_get_temp_dir(), 'test_input_').'.png';
88+
$image = imagecreate(10, 10);
89+
$white = imagecolorallocate($image, 255, 255, 255);
90+
imagefill($image, 0, 0, $white);
91+
imagepng($image, $inputImage);
92+
imagedestroy($image);
93+
94+
$imageStage = new ImageStage;
95+
$imageStage
96+
->format('bmp')
97+
->width(400)
98+
->height(300)
99+
->outputPath('/tmp/custom_output.bmp');
100+
101+
$result = $imageStage($inputImage);
102+
103+
expect($result)->toBe('/tmp/custom_output.bmp');
104+
expect(file_exists($result))->toBeTrue();
105+
106+
// Clean up
107+
unlink($inputImage);
108+
unlink($result);
109+
});
110+
111+
it('still validates input in fake mode', function (): void {
112+
TrmnlPipeline::fake();
113+
114+
$browserStage = new BrowserStage;
115+
116+
expect(fn (): string => $browserStage(null))
117+
->toThrow(Exception::class, 'No HTML content provided for browser rendering');
118+
});
119+
120+
it('still validates file existence in fake mode', function (): void {
121+
TrmnlPipeline::fake();
122+
123+
$imageStage = new ImageStage;
124+
125+
expect(fn (): string => $imageStage('/nonexistent/file.png'))
126+
->toThrow(Exception::class, 'Invalid or missing image file');
127+
});

0 commit comments

Comments
 (0)