Skip to content

Commit 56b7ca7

Browse files
committed
feat(e2e): add environment and TOTP utilities
- Add env.ts for GH_TEST_EMAIL, GH_TEST_PASSWORD, GH_TEST_TOTP_SECRET - Add totp.ts for generating TOTP codes for GitHub 2FA automation
1 parent 7db8c1e commit 56b7ca7

File tree

2 files changed

+89
-0
lines changed

2 files changed

+89
-0
lines changed

e2e/utils/env.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/**
2+
* Environment variable utilities for e2e tests
3+
*/
4+
5+
export interface E2EEnv {
6+
/** GitHub test account email */
7+
GH_TEST_EMAIL?: string
8+
/** GitHub test account password */
9+
GH_TEST_PASSWORD?: string
10+
/** GitHub test account TOTP secret for 2FA (base32 encoded) */
11+
GH_TEST_TOTP_SECRET?: string
12+
/** Whether running in CI */
13+
CI?: string
14+
}
15+
16+
/**
17+
* Get e2e environment variables
18+
*/
19+
export function getE2EEnv(): E2EEnv {
20+
return {
21+
GH_TEST_EMAIL: process.env.GH_TEST_EMAIL,
22+
GH_TEST_PASSWORD: process.env.GH_TEST_PASSWORD,
23+
GH_TEST_TOTP_SECRET: process.env.GH_TEST_TOTP_SECRET,
24+
CI: process.env.CI,
25+
}
26+
}
27+
28+
/**
29+
* Check if running in CI environment
30+
*/
31+
export function isCI(): boolean {
32+
return process.env.CI === 'true' || process.env.CI === '1'
33+
}
34+
35+
/**
36+
* Check if all required GitHub credentials are present
37+
*/
38+
export function hasRequiredCredentials(): boolean {
39+
const env = getE2EEnv()
40+
return !!(env.GH_TEST_EMAIL && env.GH_TEST_PASSWORD)
41+
}
42+
43+
/**
44+
* Log a skip message for tests that can't run without credentials
45+
*/
46+
export function logSkipReason(reason: string): void {
47+
console.log(`\n⏭️ Skipping e2e login flow tests: ${reason}\n`)
48+
console.log('To run these tests, set the following environment variables:')
49+
console.log(' - GH_TEST_EMAIL: Email for GitHub test account')
50+
console.log(' - GH_TEST_PASSWORD: Password for GitHub test account\n')
51+
}

e2e/utils/totp.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/**
2+
* TOTP (Time-based One-Time Password) generation for GitHub 2FA
3+
*/
4+
5+
import * as OTPAuth from 'otpauth'
6+
7+
/**
8+
* Generate a TOTP code from a base32-encoded secret
9+
*
10+
* @param secret - Base32-encoded TOTP secret (from GitHub 2FA setup)
11+
* @returns 6-digit TOTP code
12+
*/
13+
export function generateTOTP(secret: string): string {
14+
const totp = new OTPAuth.TOTP({
15+
issuer: 'GitHub',
16+
label: 'E2E Test',
17+
algorithm: 'SHA1',
18+
digits: 6,
19+
period: 30,
20+
secret: OTPAuth.Secret.fromBase32(secret.replace(/\s/g, '').toUpperCase()),
21+
})
22+
23+
return totp.generate()
24+
}
25+
26+
/**
27+
* Validate that a TOTP secret is properly formatted
28+
*/
29+
export function isValidTOTPSecret(secret: string): boolean {
30+
try {
31+
// Remove spaces and validate base32
32+
const cleaned = secret.replace(/\s/g, '').toUpperCase()
33+
OTPAuth.Secret.fromBase32(cleaned)
34+
return true
35+
} catch {
36+
return false
37+
}
38+
}

0 commit comments

Comments
 (0)