Testing

Bridge mode

Test against injected providers when local stubs are not enough.

Use bridge mode when you need to prove that the app can talk to the real Nimiq Pay mini-app provider surface.

Do not make bridge mode your only CI signal. Local scenarios catch package and app regressions faster and do not depend on host availability.

Choose bridge for provider integration

Use bridge mode when one of these changed:

  • provider wait behavior
  • mini-app host integration
  • account reads around window.nimiq
  • signing calls made through the injected provider
  • remote Better Auth endpoint wiring

Do not use bridge mode for pure nonce, signature, QR-state, or profile parsing tests. Local mode covers those paths deterministically.

Run the package bridge script

Use the package script when testing this workspace.

terminal
pnpm --filter @onmax/better-auth-nimiq-pay-e2e test:e2e:bridge

Expected behavior:

output
NIMIQ_PAY_E2E_NETWORK=testnet
NIMIQ_PAY_E2E_MODE=bridge
NIMIQ_PAY_E2E_PROJECTS=e2e-direct-sign-in

The script builds package dependencies, waits for the injected provider, and runs the direct sign-in project.

Configure a bridge run explicitly

Use explicit environment variables in CI or one-off debugging so the test profile is visible in logs.

terminal
NIMIQ_PAY_E2E_NETWORK=testnet \
NIMIQ_PAY_E2E_MODE=bridge \
NIMIQ_PAY_E2E_PLAYGROUND_URL=http://127.0.0.1:3000 \
NIMIQ_PAY_E2E_NUXT_AUTH_BASE=http://127.0.0.1:3000/api/auth \
NIMIQ_PAY_E2E_PROJECTS=e2e-direct-sign-in \
pnpm --filter @onmax/better-auth-nimiq-pay-e2e test:e2e:bridge

Use NIMIQ_PAY_E2E_ENDPOINT_PREFIX when your direct auth endpoints are not under /nimiq. Use NIMIQ_PAY_E2E_QR_ENDPOINT_PREFIX when QR endpoints are not under /mobile-qr.

Write a bridge-focused test

Use a bridge profile and keep the test narrow. The bridge provider must resolve before the remote fetcher is useful.

test/e2e/bridge-auth.e2e.test.ts
import { describe, expect, it } from 'vitest'
import {
  defineE2EProfile,
  runSignInScenario,
} from '@onmax/better-auth-nimiq-pay-e2e'

describe('Nimiq Pay bridge auth', () => {
  it('signs in through the injected provider', async () => {
    const profile = defineE2EProfile({
      mode: 'bridge',
      network: 'testnet',
    })

    const result = await runSignInScenario({
      profile,
      bridgeProviderOptions: {
        timeoutMs: 10_000,
        intervalMs: 250,
      },
    })

    expect(result.ok, result.error).toBe(true)
    expect(result.mode).toBe('bridge')
    expect(result.network).toBe('testnet')
    expect(result.token).toBeTruthy()
  })
})

Expected behavior:

output
The test waits for window.nimiq.
The sign-in flow uses remote auth endpoints.
The returned token comes from the app, not the local token generator.

Diagnose provider timeouts

Bridge mode fails before auth calls when no provider appears.

test/e2e/provider-timeout.e2e.test.ts
import { expect, it } from 'vitest'
import {
  defineE2EProfile,
  runSignInScenario,
} from '@onmax/better-auth-nimiq-pay-e2e'

it('reports missing provider clearly', async () => {
  const result = await runSignInScenario({
    profile: defineE2EProfile({ mode: 'bridge', env: {} }),
    authBaseUrl: 'https://example.test/api/auth',
    fetcher: async () => {
      throw new Error('fetcher should not run before provider resolves')
    },
    bridgeProviderOptions: {
      source: () => null,
      timeoutMs: 20,
      intervalMs: 5,
    },
  })

  expect(result.ok).toBe(false)
  expect(result.error).toContain('window.nimiq provider')
})

If this fails in a real browser run, check that the app is loaded inside the Nimiq Pay host or simulator that injects window.nimiq.

Treat mainnet as an explicit manual run

Use mainnet only for manual bridge checks.

terminal
NIMIQ_PAY_E2E_NETWORK=mainnet \
NIMIQ_PAY_E2E_MODE=bridge \
NIMIQ_PAY_E2E_ALLOW_MAINNET=true \
NIMIQ_PAY_E2E_PROJECTS=e2e-direct-sign-in \
pnpm --filter @onmax/better-auth-nimiq-pay-e2e test:e2e:mainnet

Expected guardrails:

output
mainnet without NIMIQ_PAY_E2E_ALLOW_MAINNET=true is blocked
mainnet in CI is blocked
Copyright © 2026