Three lines
tests/Feature/BlogTest.php
Nothing is sent: no URL patterns, keys or JSON, and no config needed. Every call answers a valid model,
and
Attract::site('any-slug') is a faked site. It works the same in Pest.Answers
Give a method its answer by key,<accessor>.<method>:
Every kind of answer
Every kind of answer
A model, a wire array, a closure
fn (array $args, string $site) => …, an exception (thrown), or
Attract::sequence($first, $second) (each call takes the next). blogPosts.* answers a whole accessor. A key
that is no method throws, suggesting the closest one.Answers in turn: sequence()
Answers in turn: sequence()
Attract::sequence($page1, $page2) takes each answer as its own argument (not an array); each call takes
the next. One call past the end throws a LogicException: “The sequence for blogPosts.listBlogs ran
out.” Give one answer per call you expect.Errors, as the real SDK throws them
Errors, as the real SDK throws them
Attract::validationError([...]), notFound(), forbidden(), rateLimited(30),
unreachable(), siteError(500): the real exception classes, for the faked site and route.Factories
Factories
Every answer class has
::factory()->make([...]), makeMany(3) and raw() (the wire array),
filled with values the SDK’s own answer check accepts. Override by property name, with SDK values
(Carbon, a model, a Collection, an enum case) or as the API sends them: a date as an ISO 8601
string or now(), an enum as its string, a list as a plain array. A plain array for a nested model
or a list of them is filled in over that model’s own example, so only what you name changes.Walks, finds, jobs and request()
Walks, finds, jobs and request()
A
listBlogsAll() walk is answered through blogPosts.listBlogs, a findBlog() through
blogPosts.getBlog, request() through the key request. A job’s wait() needs the management
SDK, under the fake too.Your own values, nested
Fake one answer by key, override a nested field with a plain array, and assert the call:tests/Feature/MediaTest.php
results is a plain array filled in over MediaImage’s example, like any nested model,
so every field you don’t name is still valid.
Assertions
A failure lists what was called.
Scaffold an Action
- The Action
- Its test
- Options
app/Actions/Attract/GetBlog.php
Engine calls
Attract::fake() fakes the SDK’s methods, not the engine: an api() call under it throws, saying so.
For those, use Http::fake() with Sleep::fake() (the retry waits go through Laravel’s Sleep), and
a test key that keeps to a real key’s characters:
Sweeping a real site
Next: keeping keys secret
Where a key never shows up, and the one place it does.