Appearance
Two-Factor Authentication (TOTP)
Many web applications require Two-Factor Authentication (2FA) or Multi-Factor Authentication (MFA) during login.
UI-licious includes a built-in totp plugin that calculates standard Time-based One-Time Passwords (TOTP) in real time during test runs. This lets automated tests seamlessly solve 2FA challenges for services like Google, GitHub, AWS, Salesforce, and enterprise SSO portals.
How It Works
- Get the secret key from the target application when setting up an authenticator app.
- Store the secret key securely in UI-licious project variables or test datasets.
- Load the
totpplugin and generate the current code withtotp.generateOTP(). - Fill and submit the verification code in your test.
Step 1: Obtain the Secret Key
When enabling Two-Factor Authentication on your application or test user account:
- Select Authenticator App (e.g. Google Authenticator or Microsoft Authenticator) as the verification method.
- When the setup screen displays a QR code, click "Can't scan it?", "Enter code manually", or similar link to view the secret key as plaintext.
- Copy the alphanumeric shared secret key (e.g.
JBSWY3DPEHPK3PXP). - Complete the initial registration on the service by entering a generated code once so the key is activated.
Store Keys Securely in Project Variables
Never hardcode production credentials or 2FA secret keys directly into your test scripts. Store your secret key in UI-licious Project Variables or a dataset file, and reference it in your tests as DATA.totp_secret.
Whitespaces and letter casing in secret keys are automatically normalized by the plugin.
Step 2: Generate and Fill the Code
To generate an OTP in your test:
js
// 1. Load the built-in totp plugin
let totp = TEST.loadPlugin("totp")
// 2. Generate the current 6-digit code using your secret key
let code = totp.generateOTP(DATA.totp_secret)
// 3. Fill the verification field and submit
I.fill("Verification code", code)
I.click("Verify")Step 3: Handle 2FA Prompts Conditionally
Many identity providers (such as Google, GitHub, or Okta) prompt for 2FA only when logging in from a new browser session or when risk checks trigger.
Use I.see$() to check whether the 2FA challenge appeared before attempting to generate and submit the code:
js
// Perform username and password login
I.fill("Email", DATA.user_email)
I.click("Next")
I.fill("Password", DATA.user_password)
I.click("Sign In")
// Handle 2FA challenge only if prompted
if (I.see$("Enter verification code")) {
let totp = TEST.loadPlugin("totp")
let code = totp.generateOTP(DATA.totp_secret)
I.fill("code", code)
I.click("Verify")
}
// Confirm successful login
I.see("Dashboard")Customizing OTP Options
By default, generateOTP() produces a 6-digit code with a 30-second time window using the SHA-1 hash algorithm (matching Google Authenticator and standard RFC 6238 implementations).
If your authentication provider requires custom parameters, pass an options object:
js
let totp = TEST.loadPlugin("totp")
let code = totp.generateOTP(DATA.totp_secret, {
digits: 8, // Length of the code: 6 or 8 (default: 6)
period: 60, // Time window in seconds (default: 30)
algorithm: "SHA-512" // Hash algorithm: "SHA-1" (default), "SHA-256", or "SHA-512"
})Built-in Expiration Protection
Standard TOTP codes refresh every 30 seconds. If a test generates a code right before the window expires, the target server might reject it by the time the browser submits the form.
The UI-licious totp plugin automatically prevents this:
- If fewer than 10 seconds remain before the current code expires, the plugin automatically pauses and waits for the next time window to start.
- It then returns a fresh code with a full validity period, eliminating test flakiness caused by token expiration races.
Complete Example
js
// Test: Login to Portal with Conditional 2FA
I.goTo("https://example.com/login")
// Step 1: Submit primary credentials
I.fill("Username", DATA.username)
I.fill("Password", DATA.password)
I.click("Log In")
// Step 2: Handle Two-Factor Authentication if prompted
if (I.see$("Two-step verification")) {
let totp = TEST.loadPlugin("totp")
let code = totp.generateOTP(DATA.totp_secret)
I.fill("Security code", code)
I.click("Submit")
}
// Step 3: Validate successful login
I.amAt("https://example.com/dashboard")
I.see("Welcome back")See Also
TOTP.generateOTP()— API reference for thetotpplugin.- Data-Driven Testing — How to manage sensitive credentials and secrets using test datasets.
- IP Whitelisting & reCAPTCHA — Managing bot detection and IP-based access in automated tests.