243 lines
5.5 KiB
JavaScript
243 lines
5.5 KiB
JavaScript
|
|
/**
|
|||
|
|
* 認證流程端到端場景
|
|||
|
|
*
|
|||
|
|
* 此模組提供完整的認證流程場景,組合多個 API 場景形成業務流程。
|
|||
|
|
*
|
|||
|
|
* 使用方式:
|
|||
|
|
* import { registerAndLoginFlow, loginAndRefreshFlow, passwordResetFlow } from './scenarios/e2e/authentication-flow.js';
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
import * as auth from '../apis/auth.js';
|
|||
|
|
import { sleep } from 'k6';
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 註冊後立即登入流程
|
|||
|
|
* @param {Object} options - 配置選項
|
|||
|
|
* @param {string} options.baseUrl - API 基礎 URL
|
|||
|
|
* @param {string} options.loginId - 登入 ID
|
|||
|
|
* @param {string} options.password - 密碼
|
|||
|
|
* @param {Object} options.customMetrics - 自定義指標對象(可選)
|
|||
|
|
* @returns {Object} 流程結果
|
|||
|
|
*/
|
|||
|
|
export function registerAndLoginFlow(options = {}) {
|
|||
|
|
const {
|
|||
|
|
baseUrl = __ENV.BASE_URL || 'https://localhost:8888',
|
|||
|
|
loginId = `test_${Date.now()}@example.com`,
|
|||
|
|
password = 'Test123456!',
|
|||
|
|
customMetrics = null,
|
|||
|
|
} = options;
|
|||
|
|
|
|||
|
|
// 步驟 1: 註冊
|
|||
|
|
const registerResult = auth.registerWithCredentials({
|
|||
|
|
baseUrl,
|
|||
|
|
loginId,
|
|||
|
|
password,
|
|||
|
|
customMetrics,
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
if (!registerResult.success || !registerResult.tokens) {
|
|||
|
|
return {
|
|||
|
|
success: false,
|
|||
|
|
step: 'register',
|
|||
|
|
error: 'Registration failed',
|
|||
|
|
registerResult,
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 短暫等待,模擬真實用戶行為
|
|||
|
|
sleep(1);
|
|||
|
|
|
|||
|
|
// 步驟 2: 使用註冊的帳號登入
|
|||
|
|
const loginResult = auth.loginWithCredentials({
|
|||
|
|
baseUrl,
|
|||
|
|
loginId,
|
|||
|
|
password,
|
|||
|
|
customMetrics,
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
if (!loginResult.success || !loginResult.tokens) {
|
|||
|
|
return {
|
|||
|
|
success: false,
|
|||
|
|
step: 'login',
|
|||
|
|
error: 'Login failed after registration',
|
|||
|
|
registerResult,
|
|||
|
|
loginResult,
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
success: true,
|
|||
|
|
registerResult,
|
|||
|
|
loginResult,
|
|||
|
|
tokens: loginResult.tokens,
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 登入後刷新 Token 流程
|
|||
|
|
* @param {Object} options - 配置選項
|
|||
|
|
* @param {string} options.baseUrl - API 基礎 URL
|
|||
|
|
* @param {string} options.loginId - 登入 ID
|
|||
|
|
* @param {string} options.password - 密碼
|
|||
|
|
* @param {Object} options.customMetrics - 自定義指標對象(可選)
|
|||
|
|
* @returns {Object} 流程結果
|
|||
|
|
*/
|
|||
|
|
export function loginAndRefreshFlow(options = {}) {
|
|||
|
|
const {
|
|||
|
|
baseUrl = __ENV.BASE_URL || 'https://localhost:8888',
|
|||
|
|
loginId,
|
|||
|
|
password,
|
|||
|
|
customMetrics = null,
|
|||
|
|
} = options;
|
|||
|
|
|
|||
|
|
if (!loginId || !password) {
|
|||
|
|
throw new Error('loginId and password are required');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 步驟 1: 登入
|
|||
|
|
const loginResult = auth.loginWithCredentials({
|
|||
|
|
baseUrl,
|
|||
|
|
loginId,
|
|||
|
|
password,
|
|||
|
|
customMetrics,
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
if (!loginResult.success || !loginResult.tokens) {
|
|||
|
|
return {
|
|||
|
|
success: false,
|
|||
|
|
step: 'login',
|
|||
|
|
error: 'Login failed',
|
|||
|
|
loginResult,
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 短暫等待
|
|||
|
|
sleep(1);
|
|||
|
|
|
|||
|
|
// 步驟 2: 刷新 Token
|
|||
|
|
const refreshResult = auth.refreshToken({
|
|||
|
|
baseUrl,
|
|||
|
|
accessToken: loginResult.tokens.accessToken,
|
|||
|
|
refreshToken: loginResult.tokens.refreshToken,
|
|||
|
|
customMetrics,
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
if (!refreshResult.success || !refreshResult.tokens) {
|
|||
|
|
return {
|
|||
|
|
success: false,
|
|||
|
|
step: 'refresh',
|
|||
|
|
error: 'Token refresh failed',
|
|||
|
|
loginResult,
|
|||
|
|
refreshResult,
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
success: true,
|
|||
|
|
loginResult,
|
|||
|
|
refreshResult,
|
|||
|
|
tokens: refreshResult.tokens,
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 完整密碼重設流程(請求 → 驗證 → 重設)
|
|||
|
|
* @param {Object} options - 配置選項
|
|||
|
|
* @param {string} options.baseUrl - API 基礎 URL
|
|||
|
|
* @param {string} options.identifier - 使用者帳號(email 或 phone)
|
|||
|
|
* @param {string} options.accountType - 帳號類型(email/phone)
|
|||
|
|
* @param {string} options.verifyCode - 驗證碼(在實際測試中可能需要從外部獲取)
|
|||
|
|
* @param {string} options.newPassword - 新密碼
|
|||
|
|
* @returns {Object} 流程結果
|
|||
|
|
*/
|
|||
|
|
export function passwordResetFlow(options = {}) {
|
|||
|
|
const {
|
|||
|
|
baseUrl = __ENV.BASE_URL || 'https://localhost:8888',
|
|||
|
|
identifier,
|
|||
|
|
accountType = 'email',
|
|||
|
|
verifyCode,
|
|||
|
|
newPassword = 'NewPassword123!',
|
|||
|
|
} = options;
|
|||
|
|
|
|||
|
|
if (!identifier) {
|
|||
|
|
throw new Error('identifier is required');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 步驟 1: 請求密碼重設驗證碼
|
|||
|
|
const requestResult = auth.requestPasswordReset({
|
|||
|
|
baseUrl,
|
|||
|
|
identifier,
|
|||
|
|
accountType,
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
if (!requestResult.success) {
|
|||
|
|
return {
|
|||
|
|
success: false,
|
|||
|
|
step: 'request',
|
|||
|
|
error: 'Request password reset failed',
|
|||
|
|
requestResult,
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 短暫等待,模擬用戶收到驗證碼的時間
|
|||
|
|
sleep(2);
|
|||
|
|
|
|||
|
|
// 步驟 2: 驗證密碼重設驗證碼
|
|||
|
|
if (!verifyCode) {
|
|||
|
|
// 在實際測試中,驗證碼可能需要從外部獲取(如測試資料庫、郵件服務等)
|
|||
|
|
return {
|
|||
|
|
success: false,
|
|||
|
|
step: 'verify',
|
|||
|
|
error: 'verifyCode is required but not provided',
|
|||
|
|
requestResult,
|
|||
|
|
note: 'In real testing, verifyCode should be retrieved from external source (DB, email service, etc.)',
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const verifyResult = auth.verifyPasswordResetCode({
|
|||
|
|
baseUrl,
|
|||
|
|
identifier,
|
|||
|
|
verifyCode,
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
if (!verifyResult.success) {
|
|||
|
|
return {
|
|||
|
|
success: false,
|
|||
|
|
step: 'verify',
|
|||
|
|
error: 'Verify password reset code failed',
|
|||
|
|
requestResult,
|
|||
|
|
verifyResult,
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 短暫等待
|
|||
|
|
sleep(1);
|
|||
|
|
|
|||
|
|
// 步驟 3: 執行密碼重設
|
|||
|
|
const resetResult = auth.resetPassword({
|
|||
|
|
baseUrl,
|
|||
|
|
identifier,
|
|||
|
|
verifyCode,
|
|||
|
|
newPassword,
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
if (!resetResult.success) {
|
|||
|
|
return {
|
|||
|
|
success: false,
|
|||
|
|
step: 'reset',
|
|||
|
|
error: 'Reset password failed',
|
|||
|
|
requestResult,
|
|||
|
|
verifyResult,
|
|||
|
|
resetResult,
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
success: true,
|
|||
|
|
requestResult,
|
|||
|
|
verifyResult,
|
|||
|
|
resetResult,
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|