Test mode and end-to-end tests
Sign in to a development instance in automated tests with a fixed code, no mailbox and no phone.
Test mode and end-to-end tests
Email codes and texted codes make browser tests painful. Test mode gives development instances addresses and phone numbers that always accept one code:
| Code | 424242 |
any address with the tag +daywalker_test, like [email protected] |
|
| Phone | the reserved numbers +1 555 555 0100 to +1 555 555 0199 |
No email or text is sent to them. Everything else behaves as usual, including the attempt limits (5 wrong tries burn a code) and the per-address send limits. Real addresses and numbers are untouched.
Turn it on
Dashboard → Configure → Developers → Environments → Test mode on a development instance, or:
await backend().testMode.set(true); // PATCH /v1/instance/test_mode { "enabled": true }It is off by default. Don't leave it on for an instance real people use: anyone who knows the code can sign in to a test address. With it on, the components show "Development mode, test mode on" so it is never silent.
It never works on production
- Production instances can't turn it on (
403 test_mode_unavailable), and a stored flag is ignored. - On production, signing up with, or requesting a code for, a
+daywalker_testaddress fails with400 test_mode_unavailable, and a reserved phone number with400 test_phone_unavailable. The messages say it is for development instances. - With test mode off on a development instance, reserved phone numbers are refused too (there is nobody to text); test email addresses are ordinary addresses.
- Cloning configuration to production never copies it (the clone reports it under
skipped). - The platform's own dashboard instance never honors it.
- A test address is never proof of a company domain: organization domain auto-join and suggestions ignore it.
Writing a test
Helpers are in @daywalker/auth/server (and the browser entry point):
import { testEmail, testPhone, TEST_CODE } from "@daywalker/auth/server";
const email = testEmail("alice", { unique: true }); // [email protected]
const phone = testPhone(7); // +15555550107Playwright, passwordless sign-in with the components or hosted page:
test("signs in with a code", async ({ page }) => {
await page.goto("/sign-in");
await page.getByLabel("Email").fill(email);
await page.getByRole("button", { name: /email me a code/i }).click();
await page.getByLabel("Code").fill(TEST_CODE);
await page.getByRole("button", { name: /verify|continue/i }).click();
await expect(page).toHaveURL(/dashboard/);
});Sign-up with a password, then verification, password reset and the SMS second factor all take 424242 in the code field. To skip the UI for set-up, create the user from your test runner with the browser client or your backend and sign in through the page.
Tips:
- Use a unique address per run (
unique: true) so tests don't share accounts or hit the per-address send limit (5 per hour). - Clean up with
backend().users.delete(id); test users are ordinary users of the development instance. - Run your tests against the development instance's keys (
pk_test_…,sk_test_…), never production keys. - For session tokens in API tests, sign in once in
globalSetupand reuse the cookies. - For service-to-service tests use machine clients instead of a user.
Errors: test_mode_unavailable (400 on sign-up or sending a code, 403 when enabling), test_phone_unavailable (400).