sextile.testing

Driving a service the way a caller does, for a service’s own tests.

A service’s tests want to press keys and read the screen, which is what a reader does and what nothing else can stand in for: a handler returns a Page, but whether *3# reaches it, whether the field kept what was typed, and what 0 does from three pages in are all questions about the session rather than about any one page:

async with connect(app) as caller:
    await caller.press("*3#")
    await caller.press("ABC")
    assert "ABC" in caller.screen

connect opens the service and closes it again, so a lifespan that holds a database opens one for the test as it would for a call.

For testing a service, not the framework. The framework’s own tests drive Session directly, that being the thing they are testing.

class sextile.testing.Caller(session, sent=<factory>)[source]

Bases: object

A terminal at the other end of the line, driven a keypress at a time.

session

The session itself, for a test that needs something this does not offer.

sent

Everything the service has sent, in the order it was sent, greeting first. For a test about what went down the wire rather than about what is on the screen.

Parameters:
async press(pressed)[source]

Press one key, or several.

Parameters:

pressed (str | bytes) – What the terminal sends. A string is the characters a reader keys, “*3#” or “ABC”; bytes are for the codes no keyboard spells, such as b”x5f” for RETURN. Several keys at once are the same as one at a time: the session reads a byte at a time either way.

Return type:

None

property address: PageAddress

The page the reader is looking at.

property screen: str

What is on the screen, as rows of text.

The last whole frame the terminal was sent, which is not always the page the reader is on: a not-found or failed notice is shown over the page they were left on, so this reads the notice while address still names their page.

The characters only. Colour and the attribute codes that carry it are left out, a test about what a page says needing no knowledge of how an attribute cell is spelt.

sextile.testing.connect(application, *, start=None)[source]

Open the service, ring it up, and close it again afterwards.

Parameters:
  • application (Sextile) – The service to call, as its factory builds it.

  • start (str | PageAddress | None) – Where the call begins, for a test that would otherwise spend three keypresses getting there. The service’s own opening page by default, which is what a real caller sees.

Yields:

The caller, already shown the first frame.

async sextile.testing.fetch(app, target='1', *, neighbours=None)[source]

The page a service answers a number with, asserted to be present.

Sextile.fetch returns None where the service has no such page, which a test naming a page it has registered does not want to narrow at each call. This fetches and asserts, so the page comes back typed as a Page rather than a Page | None.

Parameters:
  • app (Sextile) – The service to ask, already started.

  • target (str | PageAddress) – The page number, defaulting to 1.

  • neighbours (Neighbours | None) – The pages either side of this one, where the test is about a sequence.

Return type:

Page

Returns:

The page at target.

sextile.testing.request_for(app, target='1', *, neighbours=None, session=None, history=())[source]

A request for a page on a service, for a test that has no session.

A handler and a layout both take the request they answer. A test that exercises one without ringing the service up builds the request here rather than by hand, so the service it belongs to is supplied in one place.

Parameters:
  • app (Sextile) – The service the page belongs to, reached as request.app.

  • target (str | PageAddress) – The page number the request is for, defaulting to 1.

  • neighbours (Neighbours | None) – The pages either side of this one, if the test is about a sequence.

  • session (State | None) – This caller’s own state, if the test reads or writes it.

  • history (tuple[PageAddress, ...]) – Where this caller has been, if the test is about that.

Return type:

PageRequest

sextile.testing.text_of(page, index=0)[source]

The characters a frame carries, its rows joined by newlines.

The usual way a test reads a built page back, and the one extraction a test module would otherwise write for itself. Given a Page, the frame at index; given a Frame already in hand – a drawing test working below the page – that frame, and index is not read.

Parameters:
  • page (Page | Frame) – The page whose frame to read, or a frame on its own.

  • index (int) – Which frame of a page, ignored when a frame is given.

Return type:

str

Returns:

The frame’s rows, each the full width, joined by newlines.