Skip to content

Commit 9ae09b3

Browse files
authored
Merge pull request #1 from solutionforest/claude/add-pest-tests-01CjFgGyDTQ6FWtYW4h7Mz3i
Add pest test cases for library
2 parents 5f38eee + 2ffe3a9 commit 9ae09b3

File tree

12 files changed

+1344
-0
lines changed

12 files changed

+1344
-0
lines changed

.github/workflows/tests.yml

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
name: Tests
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
- master
8+
tags:
9+
- 'v*'
10+
pull_request:
11+
branches:
12+
- main
13+
- master
14+
15+
jobs:
16+
test:
17+
runs-on: ${{ matrix.os }}
18+
19+
strategy:
20+
fail-fast: true
21+
matrix:
22+
os: [ubuntu-latest]
23+
php: [8.2, 8.3, 8.4]
24+
laravel: [11.*, 12.*]
25+
stability: [prefer-stable]
26+
include:
27+
- laravel: 11.*
28+
testbench: 9.*
29+
- laravel: 12.*
30+
testbench: 10.*
31+
32+
name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }}
33+
34+
steps:
35+
- name: Checkout code
36+
uses: actions/checkout@v4
37+
38+
- name: Setup PHP
39+
uses: shivammathur/setup-php@v2
40+
with:
41+
php-version: ${{ matrix.php }}
42+
extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv
43+
coverage: none
44+
45+
- name: Setup problem matchers
46+
run: |
47+
echo "::add-matcher::${{ runner.tool_cache }}/php.json"
48+
echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
49+
50+
- name: Install dependencies
51+
run: |
52+
composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update
53+
composer update --${{ matrix.stability }} --prefer-dist --no-interaction
54+
55+
- name: List installed dependencies
56+
run: composer show -D
57+
58+
- name: Execute tests
59+
run: vendor/bin/pest --ci

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,6 @@ Homestead.yaml
2121
Homestead.json
2222
/.vagrant
2323
.phpunit.result.cache
24+
.phpunit.cache/
2425
composer.lock
2526
/build/

composer.json

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,21 @@
1515
"illuminate/cache": "^11.0|^12.0",
1616
"ext-gd": "*"
1717
},
18+
"require-dev": {
19+
"orchestra/testbench": "^9.0|^10.0",
20+
"pestphp/pest": "^3.0",
21+
"pestphp/pest-plugin-laravel": "^3.0"
22+
},
1823
"autoload": {
1924
"psr-4": {
2025
"SolutionForest\\MathCaptcha\\": "src/"
2126
}
2227
},
28+
"autoload-dev": {
29+
"psr-4": {
30+
"SolutionForest\\MathCaptcha\\Tests\\": "tests/"
31+
}
32+
},
2333
"extra": {
2434
"laravel": {
2535
"providers": [
@@ -30,6 +40,15 @@
3040
}
3141
}
3242
},
43+
"scripts": {
44+
"test": "vendor/bin/pest",
45+
"test-coverage": "vendor/bin/pest --coverage"
46+
},
47+
"config": {
48+
"allow-plugins": {
49+
"pestphp/pest-plugin": true
50+
}
51+
},
3352
"minimum-stability": "dev",
3453
"prefer-stable": true
3554
}

phpunit.xml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
4+
bootstrap="vendor/autoload.php"
5+
colors="true"
6+
cacheDirectory=".phpunit.cache"
7+
>
8+
<testsuites>
9+
<testsuite name="Unit">
10+
<directory suffix="Test.php">./tests/Unit</directory>
11+
</testsuite>
12+
<testsuite name="Feature">
13+
<directory suffix="Test.php">./tests/Feature</directory>
14+
</testsuite>
15+
</testsuites>
16+
<source>
17+
<include>
18+
<directory suffix=".php">./src</directory>
19+
</include>
20+
</source>
21+
</phpunit>
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<?php
2+
3+
use SolutionForest\MathCaptcha\Contracts\CaptchaGenerator;
4+
use SolutionForest\MathCaptcha\MathCaptcha;
5+
6+
beforeEach(function () {
7+
$this->app->singleton(CaptchaGenerator::class, function ($app) {
8+
return new MathCaptcha([
9+
'cache_prefix' => 'test_controller',
10+
]);
11+
});
12+
});
13+
14+
describe('CaptchaController', function () {
15+
describe('generate()', function () {
16+
it('returns a JSON response', function () {
17+
$response = $this->get('/captcha');
18+
19+
$response->assertStatus(200)
20+
->assertHeader('Content-Type', 'application/json');
21+
});
22+
23+
it('returns response with token and image keys', function () {
24+
$response = $this->get('/captcha');
25+
26+
$response->assertStatus(200)
27+
->assertJsonStructure(['token', 'image']);
28+
});
29+
30+
it('returns a 32 character token', function () {
31+
$response = $this->get('/captcha');
32+
33+
$data = $response->json();
34+
35+
expect($data['token'])->toBeString()
36+
->toHaveLength(32);
37+
});
38+
39+
it('returns a valid base64 PNG image', function () {
40+
$response = $this->get('/captcha');
41+
42+
$data = $response->json();
43+
44+
expect($data['image'])->toBeString()
45+
->toStartWith('data:image/png;base64,');
46+
47+
// Verify we can decode it
48+
$base64Data = str_replace('data:image/png;base64,', '', $data['image']);
49+
$decodedImage = base64_decode($base64Data, true);
50+
51+
expect($decodedImage)->not->toBeFalse();
52+
});
53+
54+
it('stores the answer in cache', function () {
55+
$response = $this->get('/captcha');
56+
57+
$data = $response->json();
58+
$cacheKey = "test_controller:{$data['token']}";
59+
60+
expect(cache()->has($cacheKey))->toBeTrue();
61+
});
62+
63+
it('generates different tokens on each request', function () {
64+
$response1 = $this->get('/captcha');
65+
$response2 = $this->get('/captcha');
66+
$response3 = $this->get('/captcha');
67+
68+
$token1 = $response1->json('token');
69+
$token2 = $response2->json('token');
70+
$token3 = $response3->json('token');
71+
72+
expect($token1)->not->toBe($token2)
73+
->and($token2)->not->toBe($token3)
74+
->and($token1)->not->toBe($token3);
75+
});
76+
});
77+
78+
describe('route configuration', function () {
79+
it('responds on configured URI', function () {
80+
config(['math-captcha.route.uri' => '/custom-captcha']);
81+
82+
// Re-register routes with new config
83+
$this->app['router']->get('/custom-captcha', [\SolutionForest\MathCaptcha\Http\Controllers\CaptchaController::class, 'generate'])
84+
->name('custom.captcha.generate');
85+
86+
$response = $this->get('/custom-captcha');
87+
88+
$response->assertStatus(200)
89+
->assertJsonStructure(['token', 'image']);
90+
});
91+
92+
it('has named route', function () {
93+
expect(route('captcha.generate'))->toEndWith('/captcha');
94+
});
95+
});
96+
});

0 commit comments

Comments
 (0)