Skip to content

Test Basics

Every readable end-to-end test has the same three-part shape, often called arrange, act, assert:

const { test, expect } = require("orbittest");
test("guest can open the pricing page", async (orbit) => {
// Arrange: get to the starting point
await orbit.open("https://example.com");
// Act: do what the user would do
await orbit.click("Pricing");
// Assert: check the outcome the user cares about
expect(await orbit.hasText("Choose your plan")).toBe(true);
});

The name matters as much as the body. “guest can open the pricing page” tells a teammate exactly what broke when it fails in CI. Names like “test 3” or “pricing-btn-check” force people to read the code to understand the failure, and most people will not.

Every test callback receives orbit, your handle to the browser. All actions are async, so you await every call. The methods you will use constantly:

MethodWhat it does
orbit.open(url)Navigate to a page.
orbit.click(target)Click a button, link, or any element by visible text or locator.
orbit.type(field, text)Type into an input found by label, placeholder, name, or accessible text.
orbit.hasText(text)Returns true if the page currently shows this text.
orbit.waitForText(text)Wait until text appears (with an optional timeout).
orbit.screenshot(path)Save a screenshot to a file.
orbit.title() / orbit.url()Read the current page title and URL.

A useful detail: click actions briefly show a small red dot at the exact coordinate before the click is sent. When you watch a run or look at trace screenshots, you can see precisely where OrbitTest clicked. Turn it off per action with { visualize: false } if it interferes with something.

Options go in an object between the name and the callback:

test("checkout", { retries: 1, timeout: 60000 }, async (orbit) => {
await orbit.open("https://example.com/checkout");
// ...
});

Use per-test options instead of raising global limits. If one report-generation flow legitimately takes 50 seconds, give that one test a 60-second budget; do not move the whole suite to 60 seconds and hide every future slowdown.

A test without a strong assertion is just a script: it proves the buttons are clickable, not that the feature works. Assert on things a user or the business would notice:

  • Meaningful text: “Order confirmed”, “Welcome back, Priya”, an error message you expect.
  • Navigation: expect(await orbit.url()).toContain("/dashboard").
  • Element state: a success banner exists, a spinner is gone.

And assert close to each significant action. If a test performs ten steps and only asserts at the end, a failure at step three surfaces as a confusing timeout at step ten. A small assertion after each meaningful step turns the same bug into a precise failure message.

await orbit.click("Save");
await orbit.waitForText("Saved"); // assert step worked...
await orbit.click("Publish");
await orbit.waitForText("Published"); // ...before moving on

OrbitTest gives every test a clean browser profile, so tests cannot share cookies or storage by accident. Keep your own logic just as independent: a test should never depend on another test having run first. Independent tests can run in parallel, retry safely, and be debugged alone with orbittest run tests/one-file.test.js.

When several tests need the same starting state, like a logged-in user, give them a shared helper or a saved session (Browser Storage) rather than ordering dependencies.

Yes, and OrbitTest prints your output even in the default quiet mode. It only hides its own internal logs unless you pass --verbose.

Long enough to cover one user goal, short enough to name honestly. If you cannot name the test without “and”, it is probably two tests.

Does expect support matchers like toContain?

Section titled “Does expect support matchers like toContain?”

Yes. toBe, toContain, and friends work the way you know from Jest-style assertions, and mobile tests add matchers like toHaveText (see Mobile Testing).

  • Lifecycle Hooks — beforeAll, beforeEach, afterEach, and afterAll: testInfo fields, global setup files, and using hooks without hiding test intent.
  • Locators — Target elements by visible text first, then by role, test ID, CSS, or XPath when needed, and which selectors to avoid.
  • Working with Elements — Clicking, typing, reading text with three text readers, waiting for state, and iterating collections with orbit.all().
  • Quick Start — Create a project with orbittest init, write and run a first browser test, and read the HTML report, in five short steps.