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:) |
List with X-WP-Total and X-WP-TotalPages
|
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.
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