Browser Testing
phpspec includes a lightweight HTTP client for testing web endpoints. Make requests and assert on responses — no external dependencies needed.
Configuration
Add base_url to your config:
# phpspec.yaml base_url: http://localhost:8080
Quick example
describe('User API', function () { it('returns a user by id', function () { $response = get('/api/users/1'); expect($response)->toBeOk(); expect($response)->toHaveStatus(200); expect($response->json['name'])->toBe('Chuck Norris'); expect($response)->toHavePath('data.user.name', 'Chuck Norris'); }); it('creates a user', function () { $response = post('/api/users', json: ['name' => 'Chuck']); expect($response)->toHaveStatus(201); }); });
Making requests
| Function | Description |
|---|---|
visit(string $path) | GET request (alias for get()) |
get(string $path) | GET request |
post(string $path, ...) | POST request |
put(string $path, ...) | PUT request |
patch(string $path, ...) | PATCH request |
delete(string $path) | DELETE request |
Request options
| Key | Type | Description |
|---|---|---|
json | array | JSON-encoded body; sets Content-Type: application/json |
body | string | Raw request body |
headers | array | Additional HTTP headers |
Response object
| Property | Type | Description |
|---|---|---|
$response->status | int | HTTP status code |
$response->body | string | Raw response body |
$response->json | array | Body decoded as JSON (lazy) |
$response->headers | array | Response headers |
Response matchers
toBeOk()
Asserts the response status is 200.
expect($response)->toBeOk();
toBeBad()
Asserts the response status is 400.
toHaveStatus(int $code)
Asserts exact status code.
expect($response)->toHaveStatus(201); expect($response)->toHaveStatus(404);
toHavePath(string $path, mixed $expected)
Asserts a value at a dot-notation path in the JSON body.
expect($response)->toHavePath('data.user.name', 'Alice'); expect($response)->toHavePath('meta.total', 42);
toHaveHeader(string $name, ?string $value)
Asserts a header exists, optionally checking its value.
expect($response)->toHaveHeader('Content-Type'); expect($response)->toHaveHeader('Content-Type', 'application/json'); expect($response)->not()->toHaveHeader('X-Debug');
toRedirectTo(string $url)
Asserts a 3xx redirect with matching Location header.
expect($response)->toRedirectTo('/dashboard');
Using existing matchers
You don’t need special matchers for everything — use the ones you already know:
// Body expect($response->body)->toContain('hello'); expect($response->body)->toMatch('/id":\s*\d+/'); // JSON expect($response->json)->toHaveKey('name'); expect($response->json['items'])->toHaveCount(3); // Direct value access expect($response->json['name'])->toBe('Chuck Norris'); expect($response->status)->toBeGreaterThan(199);