Skip to content
Scalekit Docs
Talk to an Engineer Dashboard

Run end-to-end tests

Set up test users to run automated E2E tests for login and signup flows

Test users let you run Playwright, Cypress, and other E2E tests against signup and login flows without waiting for real OTP or magic-link emails. Scalekit accepts a static 6-digit code that you configure, so tests are fast, reliable, and inbox-free.

What doesn’t change: Test users only affects OTP email delivery. Everything else — organization creation, user creation, session creation, audit logs, webhooks, and post-login redirects — behaves the same as it does for a real user.

Enable the Magic Link & OTP auth method, with the delivery option set to Verification Code or Magic Link + Verification Code. Magic Link-only delivery is not supported. Magic link/OTP configuration

The test users allowlist is set per environment and accepts up to 5 emails. Configure it once — every signup and login test in that environment uses the same emails and static code.

  1. Go to Dashboard > Environment settings > Test users. Test users settings page

  2. Toggle Enable test users. Add up to 5 test emails — emails are stored lowercase and de-duplicated. Each entry must contain +sktest in the local part (before @); any domain works.

    EmailValid?Reason
    john+sktest@acmecorp.com+sktest present in the local part
    bob+sktest@anything.exampleAny domain works
    john@acmecorp.comMissing +sktest marker
    john+test@acmecorp.comMarker must be exactly +sktest
    sktest+john@acmecorp.comMust appear after +, not before @

    Test users allowlist with an email added

  3. Enter a Static confirmation code — exactly 6 digits. The default is 424242. Tests will enter this code at the OTP prompt.

  4. Click Save and reload the page to confirm the settings persisted.

Use this flow to verify that a new user can complete signup and end up as a member of an organization.

Point the test at Scalekit’s authorization endpoint with prompt=create so the browser lands directly on the hosted signup screen:

Authorization URL (signup)
<SCALEKIT_ENVIRONMENT_URL>/oauth/authorize?
response_type=code&
client_id=<SCALEKIT_CLIENT_ID>&
redirect_uri=<CALLBACK_URL>&
scope=openid+profile+email+offline_access&
state=<RANDOM_STATE>&
prompt=create

After OTP verification, Scalekit redirects to <CALLBACK_URL> with an authorization code. Assert on the callback URL in your test.

playwright/e2e/signup.spec.ts
import { test, expect } from '@playwright/test'
const AUTH_URL = process.env.SCALEKIT_TEST_AUTH_URL!
const TEST_USER_EMAIL = process.env.SCALEKIT_TEST_USER_EMAIL!
const TEST_USER_CODE = process.env.SCALEKIT_TEST_USER_CODE!
test('OTP signup with test user', async ({ page }) => {
await page.goto(AUTH_URL)
await page.fill('input[name="email"]', TEST_USER_EMAIL)
await page.getByRole('button', { name: 'Continue', exact: true }).click()
await page.locator('[data-scope="pin-input"][data-part="input"]').first().pressSequentially(TEST_USER_CODE)
await page.getByRole('button', { name: 'Continue', exact: true }).click()
// Replace with your app's post-login URL pattern
await expect(page).toHaveURL(/dashboard\.sampleapp\.com/)
})

Verify: After running the test, check:

  • A new organization exists with the test user as a member. Verify in Dashboard > Organizations > Newly created organization > Users. New organization and user created

  • Auth logs in Dashboard > Auth logs show two test-user events:

    • Verification email suppressed (test user)
    • OTP verification successful (test user)

    Auth logs for test users in signup flow

Use this flow to verify login for a user that already exists in an organization. The test user must be created before the test runs. Add them manually in Dashboard > Organizations > Newly created organization > Users > Create user, or create them programmatically with the Scalekit API or SDK:

Create test user in an organization
import { ScalekitClient } from '@scalekit-sdk/node'
const scalekit = new ScalekitClient(
process.env.SCALEKIT_ENVIRONMENT_URL!,
process.env.SCALEKIT_CLIENT_ID!,
process.env.SCALEKIT_CLIENT_SECRET!
)
const { user } = await scalekit.user.createUserAndMembership(orgId, {
email: 'john+sktest@acmecorp.com',
sendInvitationEmail: false,
})

Make sure the same email is also on the test users allowlist.

Point the test at Scalekit’s authorization endpoint with prompt=login so the browser lands directly on the hosted login screen:

Authorization URL (login)
<SCALEKIT_ENVIRONMENT_URL>/oauth/authorize?
response_type=code&
client_id=<SCALEKIT_CLIENT_ID>&
redirect_uri=<CALLBACK_URL>&
scope=openid+profile+email+offline_access&
state=<RANDOM_STATE>&
prompt=login

After OTP verification, Scalekit redirects to <CALLBACK_URL> with an authorization code. Assert on the callback URL in your test.

playwright/e2e/login.spec.ts
import { test, expect } from '@playwright/test'
const AUTH_URL = process.env.SCALEKIT_TEST_AUTH_URL!
const TEST_USER_EMAIL = process.env.SCALEKIT_TEST_USER_EMAIL!
const TEST_USER_CODE = process.env.SCALEKIT_TEST_USER_CODE!
test('OTP login with test user', async ({ page }) => {
await page.goto(AUTH_URL)
await page.fill('input[name="email"]', TEST_USER_EMAIL)
await page.getByRole('button', { name: 'Continue', exact: true }).click()
await page.locator('[data-scope="pin-input"][data-part="input"]').first().pressSequentially(TEST_USER_CODE)
await page.getByRole('button', { name: 'Continue', exact: true }).click()
// Replace with your app's post-login URL pattern
await expect(page).toHaveURL(/dashboard\.sampleapp\.com/)
})

Verify: After running the test, check:

  • Auth logs in Dashboard > Auth logs show two test-user events:

    • Verification email suppressed (test user)
    • OTP verification successful (test user)

    Auth log showing test-user events

Why am I still getting a real verification email?

All three conditions must be true for Test Users to apply:

  • Test Users feature is enabled in the environment.
  • The exact email is on the allowlist (case-insensitive match).
  • Magic Link & OTP auth method is enabled and the configuration is set to Verification Code or Magic Link + Verification Code.
Can I use a different code for each test run?

No, the static verification code is set per environment. For parallel isolation, add multiple +sktest addresses (up to 5) and assign a different one to each test run.

How do I keep Test Users out of production CI?

Never enable Test Users in your production environment. In CI, point to a dev or staging environment. Guard your test runner with an environment check — for example, require SCALEKIT_ENVIRONMENT_URL to contain .dev. or .staging. before running E2E tests.