arandutest

package
v0.46.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 6, 2026 License: MIT Imports: 7 Imported by: 0

Documentation

Overview

Package arandutest holds the helpers a test needs and an application must not use.

It is a browser (Client), the assertions worth having about what came back (Response), and the two pieces a test needs to say something about domain events (DrainOutbox, Collected).

This package is a bridge. It is removed in v1.0.0; import github.com/arandu-io/hesape/arandutest directly.

The helpers moved to github.com/arandu-io/hesape/arandutest -- the spelling is arandutest there too, because an import segment called "testing" shadows the standard library package every _test.go imports, and the precedent is net/http/httptest. What is left here is the old names pointing at them.

The death date above is what keeps this from being a second way to import one helper. Nothing here holds an implementation: the cookie jar, the CSRF token read off the last page, every comparison a Response makes and the pass the outbox drain runs are all hesape's. Where the name and the signature survived the move it is a Go alias, and where the design diverged it is an envelope that translates and nothing more.

Two hesape packages answer for it, and which one depends on the symbol:

hesape/arandutest  Client, Response, DrainOutbox, Collected
hesape/auth        the subject a test acts as

One name is a plain alias. The rest are envelopes, and the divergence each one absorbs is worth naming:

Collected    the alias. It has to satisfy framework/events.Publisher over
             framework/events.Stored, and both of those are hesape's own
             types under this module's names
Response     every assertion was renamed -- Status becomes AssertStatus, OK
             becomes AssertOk, See becomes AssertSee, DontSee becomes
             AssertDontSee, RedirectsTo becomes AssertRedirect, Body becomes
             GetContent. The envelope keeps the old names and forwards
Client       Get and Post answer the Response above, so the client that
             returns them is an envelope as well
ActingAs     hesape deleted the package-level form and put the subject under
             auth.WithSubject, which is the key a policy actually reads. The
             old signature is kept and now writes that key
Subject      the reader for the above; it is auth.SubjectFrom in hesape
DrainOutbox  a forward and not an alias, so the parameters keep the names
             this module spells them with. It carried an implementation for
             as long as framework/events.Outbox was a type of its own; that
             type is an alias now, so the two signatures name the same types
             and there is nothing left to translate

What hesape has and this bridge does not re-export

hesape/arandutest also has AssertDatabaseHas, AssertDatabaseMissing, AssertDatabaseCount, Match and Client.ActingAs. None of them ever existed under this import path, and adding them here would be a second place to learn the new API while the old one is being removed. Import hesape/arandutest for those.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ActingAs added in v0.18.0

func ActingAs(ctx context.Context, s security.Subject) context.Context

ActingAs is a context carrying a subject, for the code paths that take one directly rather than through a session.

A service, a job and a seeder are all called with a Subject. A test that wants to be somebody for one call does not need a browser, and building a session for it is machinery that proves nothing about what is being tested.

It does NOT put anybody in a session: a request made with Client after this is still anonymous, and it has to be, or the two ways of being somebody would disagree. A test that wants a client to be somebody uses hesape/arandutest.Client.ActingAs, which puts the subject on the outgoing request.

Deleted on the way to hesape: there is no package-level form there, and a subject goes under auth.WithSubject -- the key the edge middleware writes and every policy reads. This is one call to it and nothing else, so the name is the only thing left here that hesape does not spell the same way. The signature is untouched, because security.Subject is an alias for auth.Subject.

It used to hold a context key of its own that no policy, no repository and no middleware ever read, which authenticated nothing: a test written against it passed while proving the opposite of what it said. Naming that is worth a line because it is the reason to reach for auth.WithSubject and not for a key that looks equivalent.

func DrainOutbox

func DrainOutbox(t *testing.T, ctx context.Context, outbox *events.Outbox, publisher events.Publisher)

DrainOutbox publishes everything the outbox is holding, once.

It is the relay, executed inline instead of on a ticker:

arandutest.DrainOutbox(t, ctx, outbox, publisher)

A test that asserts on an event has to wait for it somehow, and the two alternatives are worse. Sleeping is flaky and slow. A synchronous publish path is a second implementation that will drift from the real one.

The parameters keep the names this module spells them with, so the call sites are untouched.

func Subject added in v0.18.0

func Subject(ctx context.Context) (security.Subject, bool)

Subject reads back what ActingAs put in, and reports whether there was one.

The second result is false when nothing put one there, which is a different fact from an anonymous reader: a public page has the Subject that security.Guest built.

Renamed on the way to hesape: it is auth.SubjectFrom there, and it is not in hesape/arandutest at all, because reading the subject out of a context is not a test-only question.

Types

type Client added in v0.18.0

type Client struct {
	// contains filtered or unexported fields
}

Client is a browser for a test: it keeps cookies and it does not follow redirects.

Not following them is deliberate. A test that asserts about a page after a redirect cannot tell a 200 from a 302 that happened to land somewhere with the same words on it, and "it redirected me to the sign-in screen" is the most common way a feature test passes while proving the opposite of what it says.

The jar, the CSRF token read off the last page, and the rule that a second Set-Cookie of a name replaces the first all live in hesape/arandutest.Client. This type holds nothing but that one.

It is declared here for one reason: Get and Post answer this package's Response, which keeps the assertion names hesape renamed. It becomes an alias the day Response does, and not before.

func NewClient added in v0.18.0

func NewClient(t *testing.T, h http.Handler) *Client

NewClient returns a client over a handler.

func (*Client) Get added in v0.18.0

func (c *Client) Get(path string) *Response

Get sends a GET.

func (*Client) Post added in v0.18.0

func (c *Client) Post(path string, form map[string]string) *Response

Post sends a form.

The CSRF token is read off the last page this client loaded and sent with the body, because that is what a browser does -- and a test that skips it is a test that proves the form works with protection disabled.

type Collected

type Collected = arandutest.Collected

Collected is a Publisher that keeps what it received, for a test to assert on.

Its Events field, its Publish and its Names are hesape's, reached through this name. Declaring the struct again here would compile and pass every assertion written against it, and it would be a second recorder to keep in step with the first.

type Response added in v0.18.0

type Response struct {
	// contains filtered or unexported fields
}

Response is what came back, with the assertions worth having.

Renamed on the way to hesape: every method below is spelled Assert* there, and Body is GetContent. Each one forwards to exactly one hesape method -- the comparison, the failure message and whether it stops the test are all decided by the code that runs there.

It is a declaration rather than an alias because of what an alias would carry: the new names, and only those. Every existing call of Status, OK, See, DontSee, RedirectsTo and Body would stop compiling on the day this type changed shape, which is the one thing a bridge exists to prevent. That is the condition, not a count of callers -- one call left anywhere is enough for it to hold, and it stops holding only when there are none.

func (*Response) Body added in v0.18.0

func (r *Response) Body() string

Body is what came back, for an assertion this package does not have.

Renamed on the way to hesape: it is Response.GetContent there.

func (*Response) DontSee added in v0.18.0

func (r *Response) DontSee(text string) *Response

DontSee fails when the text is in the body.

It is the half people skip, and the half that catches a leak: a draft in a public listing, an address in a page that should not name one, a button somebody without the permission can see.

Renamed on the way to hesape: it is Response.AssertDontSee there.

func (*Response) Header added in v0.18.0

func (r *Response) Header(name string) string

Header reads one response header.

func (*Response) OK added in v0.18.0

func (r *Response) OK() *Response

OK is Status(200).

Renamed on the way to hesape: it is Response.AssertOk there.

func (*Response) RedirectsTo added in v0.18.0

func (r *Response) RedirectsTo(want string) *Response

RedirectsTo fails unless the response sends the client to that address.

It reads HX-Redirect as well as Location, because a handler answering an HTMX request redirects with a header and a 204 -- and a test that only reads Location says "redirected to \"\"" for a response that is correct.

Renamed on the way to hesape: it is Response.AssertRedirect there.

func (*Response) See added in v0.18.0

func (r *Response) See(text string) *Response

See fails unless the text is in the body.

Renamed on the way to hesape: it is Response.AssertSee there.

func (*Response) Status added in v0.18.0

func (r *Response) Status(want int) *Response

Status fails unless the status is the one expected.

The body is printed on failure, because the answer to "why is this a 500" is in it and finding out otherwise means running the test again with a print.

Renamed on the way to hesape: it is Response.AssertStatus there.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL