Repository navigation
Testing
package:wordpress_client/testing.dart provides a Dio adapter that serves canned responses, so code that uses the client can be tested without a live site or real network.
import 'package:dio/dio.dart';
import 'package:wordpress_client/testing.dart';
import 'package:wordpress_client/wordpress_client.dart';final adapter = MockWordpressAdapter();
final client = WordpressClient.fromDioInstance(
baseUrl: Uri.parse('https://example.com/wp-json/wp/v2'),
instance: Dio()..httpClientAdapter = adapter,
bootstrapper: (b) => b.build(), // add auth, retries, cache, ... as in production
);Routes match on HTTP method and path (a String is matched as a path suffix; pass a RegExp for patterns). The newest route wins.
adapter
..reply('GET', '/posts', MockResponse.paged(
[{'id': 1, 'title': {'rendered': 'Hello'}}],
total: 1,
totalPages: 1,
))
..reply('POST', '/posts', MockResponse.wpError(
statusCode: 403,
code: 'rest_cannot_create',
message: 'Sorry, you are not allowed to create posts.',
))
..reply('GET', '/pages', const MockResponse(statusCode: 200, body: []));MockResponse |
Result |
|---|---|
MockResponse(statusCode:, body:, headers:, delay:) |
Any response. body can be a map, list or string |
MockResponse.paged(items, total:, totalPages:, delay:) |
List with X-WP-Total and X-WP-TotalPages; delay simulates latency (handy for testing de-duplication and concurrency limits) |
MockResponse.wpError(statusCode:, code:, message:) |
A WordPress error body |
MockResponse.connectionError() |
A transport failure (NetworkFailure) |
MockResponse.timeout() |
A timeout (NetworkFailure(kind: timeout)) |
Dynamic and sequential answers:
adapter.on('GET', RegExp(r'/posts/\d+$'), (req) {
final id = int.parse(req.path.split('/').last);
return MockResponse(body: {'id': id, 'title': {'rendered': 'Post $id'}});
});
adapter.replySequence('GET', '/pages', [
MockResponse.timeout(), // first call fails
const MockResponse(body: []), // then succeeds (the last entry repeats)
]);MockWordpressAdapter(strict: true) throws a StateError for a request without a route; the default answers 404 rest_no_route.
await client.posts.create(CreatePostRequest(title: 'Hi'));
expect(adapter.callCount(method: 'POST', path: '/posts'), 1);
expect(adapter.lastRequest!.body.toString(), contains('Hi'));
expect(adapter.lastRequest!.headers['Authorization'], isNotNull); // when a default authorization is set
expect(adapter.requests.map((r) => r.uri.path), contains('/wp-json/wp/v2/posts'));
adapter.clearRequests();RecordedRequest has method, uri, path, headers, body (its type depends on the request: a map, a JSON string, form data).
final client = WordpressClient.fromDioInstance(
baseUrl: baseUrl,
instance: Dio()..httpClientAdapter = adapter,
bootstrapper: (b) => b
.withRetryPolicy(RetryPolicy(maxAttempts: 3, sleep: (_) async {})) // no real delay
.build(),
);
adapter.replySequence('GET', '/posts', [
MockResponse.wpError(statusCode: 503, code: 'unavailable'),
MockResponse.paged([], total: 0, totalPages: 0),
]);
final r = await client.posts.list(ListPostRequest());
expect(r.isSuccessful, isTrue);
expect(r.extra?[WordpressRequest.metaAttempts], 2);Inject the client (or a factory) into your repositories and pass this one in tests. Because the mock goes through the real pipeline, middlewares, caching, auth headers and typed failures behave as in production.
The repository's own integration tests run against WordPress in Docker. To run them locally (Docker with the compose plugin):
docker compose -f docker-compose.wordpress.yml up -d --wait
docker compose -f docker-compose.wordpress.yml run --rm setup # installs WordPress and the plugins
export WP_APP_PASSWORD=$(docker compose -f docker-compose.wordpress.yml run --rm -T setup \
wp user application-password create admin local --porcelain)
export WP_BASE_URL=http://localhost:8080/wp-json/wp/v2 WP_USERNAME=admin
dart test -t integration
docker compose -f docker-compose.wordpress.yml down -vThe site is set to the local environment type, so Application Passwords work over plain HTTP. WP_PLUGINS on the setup service picks the plugins to install (default: the JWT plugin and WPGraphQL). CI runs the same steps on every push.
Do this for your own app's tests too when the mock is not enough: point the client at the container and use the same variables.
Getting started
- Usage
- Bootstrap and Configuration
- Authorization
- Browser Sign-In
- WordPress.com and Jetpack
- Multisite
- Supported REST Methods
Requests and data
- Sending Requests
- Error Handling and Responses
- Fluent Queries
- Interfaces and Extensions
- Custom Post Types
- Model Generator
- Meta and ACF
- Concurrent Edits
- Batch Requests
- Embed and Fields
- Pagination and Finders
- Parallel Requests
- Streaming and Polling
- Pattern Directory Items
Behaviour
- Retries
- Caching
- Request De-duplication and Concurrency
- Middlewares
- Logging
- Offline Write Queue
- Events and Statistics
Other APIs
Extend and test
Reference