370 lines
8.6 KiB
JavaScript
370 lines
8.6 KiB
JavaScript
/**
|
||
* 使用者資料管理流程端到端場景
|
||
*
|
||
* 此模組提供完整的使用者資料管理流程場景,組合多個 API 場景形成業務流程。
|
||
*
|
||
* 使用方式:
|
||
* import { getAndUpdateProfileFlow, emailVerificationFlow, phoneVerificationFlow, passwordChangeFlow } from './scenarios/e2e/user-profile-flow.js';
|
||
*/
|
||
|
||
import * as auth from '../apis/auth.js';
|
||
import * as user from '../apis/user.js';
|
||
import { sleep } from 'k6';
|
||
|
||
/**
|
||
* 取得並更新個人資料流程
|
||
* @param {Object} options - 配置選項
|
||
* @param {string} options.baseUrl - API 基礎 URL
|
||
* @param {string} options.accessToken - Access Token
|
||
* @param {Object} options.updateData - 要更新的資料
|
||
* @param {Object} options.customMetrics - 自定義指標對象(可選)
|
||
* @returns {Object} 流程結果
|
||
*/
|
||
export function getAndUpdateProfileFlow(options = {}) {
|
||
const {
|
||
baseUrl = __ENV.BASE_URL || 'https://localhost:8888',
|
||
accessToken,
|
||
updateData = {
|
||
nickname: `TestUser_${Date.now()}`,
|
||
preferred_language: 'zh-tw',
|
||
},
|
||
customMetrics = null,
|
||
} = options;
|
||
|
||
if (!accessToken) {
|
||
throw new Error('accessToken is required');
|
||
}
|
||
|
||
// 步驟 1: 取得使用者資訊
|
||
const getInfoResult = user.getUserInfo({
|
||
baseUrl,
|
||
accessToken,
|
||
customMetrics,
|
||
});
|
||
|
||
if (!getInfoResult.success) {
|
||
return {
|
||
success: false,
|
||
step: 'get_info',
|
||
error: 'Get user info failed',
|
||
getInfoResult,
|
||
};
|
||
}
|
||
|
||
// 短暫等待
|
||
sleep(1);
|
||
|
||
// 步驟 2: 更新使用者資訊
|
||
const updateInfoResult = user.updateUserInfo({
|
||
baseUrl,
|
||
accessToken,
|
||
updateData,
|
||
customMetrics,
|
||
});
|
||
|
||
if (!updateInfoResult.success) {
|
||
return {
|
||
success: false,
|
||
step: 'update_info',
|
||
error: 'Update user info failed',
|
||
getInfoResult,
|
||
updateInfoResult,
|
||
};
|
||
}
|
||
|
||
return {
|
||
success: true,
|
||
getInfoResult,
|
||
updateInfoResult,
|
||
originalData: getInfoResult.response,
|
||
updatedData: updateInfoResult.response,
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 完整 Email 驗證流程(請求 → 提交)
|
||
* @param {Object} options - 配置選項
|
||
* @param {string} options.baseUrl - API 基礎 URL
|
||
* @param {string} options.accessToken - Access Token
|
||
* @param {string} options.verifyCode - 驗證碼(在實際測試中可能需要從外部獲取)
|
||
* @returns {Object} 流程結果
|
||
*/
|
||
export function emailVerificationFlow(options = {}) {
|
||
const {
|
||
baseUrl = __ENV.BASE_URL || 'https://localhost:8888',
|
||
accessToken,
|
||
verifyCode,
|
||
} = options;
|
||
|
||
if (!accessToken) {
|
||
throw new Error('accessToken is required');
|
||
}
|
||
|
||
// 步驟 1: 請求 Email 驗證碼
|
||
const requestResult = user.requestVerificationCode({
|
||
baseUrl,
|
||
accessToken,
|
||
purpose: 'email_verification',
|
||
});
|
||
|
||
if (!requestResult.success) {
|
||
return {
|
||
success: false,
|
||
step: 'request',
|
||
error: 'Request email verification code failed',
|
||
requestResult,
|
||
};
|
||
}
|
||
|
||
// 短暫等待,模擬用戶收到驗證碼的時間
|
||
sleep(2);
|
||
|
||
// 步驟 2: 提交驗證碼
|
||
if (!verifyCode) {
|
||
return {
|
||
success: false,
|
||
step: 'submit',
|
||
error: 'verifyCode is required but not provided',
|
||
requestResult,
|
||
note: 'In real testing, verifyCode should be retrieved from external source (DB, email service, etc.)',
|
||
};
|
||
}
|
||
|
||
const submitResult = user.submitVerificationCode({
|
||
baseUrl,
|
||
accessToken,
|
||
purpose: 'email_verification',
|
||
verifyCode,
|
||
});
|
||
|
||
if (!submitResult.success) {
|
||
return {
|
||
success: false,
|
||
step: 'submit',
|
||
error: 'Submit email verification code failed',
|
||
requestResult,
|
||
submitResult,
|
||
};
|
||
}
|
||
|
||
return {
|
||
success: true,
|
||
requestResult,
|
||
submitResult,
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 完整手機驗證流程(請求 → 提交)
|
||
* @param {Object} options - 配置選項
|
||
* @param {string} options.baseUrl - API 基礎 URL
|
||
* @param {string} options.accessToken - Access Token
|
||
* @param {string} options.verifyCode - 驗證碼(在實際測試中可能需要從外部獲取)
|
||
* @returns {Object} 流程結果
|
||
*/
|
||
export function phoneVerificationFlow(options = {}) {
|
||
const {
|
||
baseUrl = __ENV.BASE_URL || 'https://localhost:8888',
|
||
accessToken,
|
||
verifyCode,
|
||
} = options;
|
||
|
||
if (!accessToken) {
|
||
throw new Error('accessToken is required');
|
||
}
|
||
|
||
// 步驟 1: 請求手機驗證碼
|
||
const requestResult = user.requestVerificationCode({
|
||
baseUrl,
|
||
accessToken,
|
||
purpose: 'phone_verification',
|
||
});
|
||
|
||
if (!requestResult.success) {
|
||
return {
|
||
success: false,
|
||
step: 'request',
|
||
error: 'Request phone verification code failed',
|
||
requestResult,
|
||
};
|
||
}
|
||
|
||
// 短暫等待,模擬用戶收到驗證碼的時間
|
||
sleep(2);
|
||
|
||
// 步驟 2: 提交驗證碼
|
||
if (!verifyCode) {
|
||
return {
|
||
success: false,
|
||
step: 'submit',
|
||
error: 'verifyCode is required but not provided',
|
||
requestResult,
|
||
note: 'In real testing, verifyCode should be retrieved from external source (DB, SMS service, etc.)',
|
||
};
|
||
}
|
||
|
||
const submitResult = user.submitVerificationCode({
|
||
baseUrl,
|
||
accessToken,
|
||
purpose: 'phone_verification',
|
||
verifyCode,
|
||
});
|
||
|
||
if (!submitResult.success) {
|
||
return {
|
||
success: false,
|
||
step: 'submit',
|
||
error: 'Submit phone verification code failed',
|
||
requestResult,
|
||
submitResult,
|
||
};
|
||
}
|
||
|
||
return {
|
||
success: true,
|
||
requestResult,
|
||
submitResult,
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 登入狀態下修改密碼流程
|
||
* @param {Object} options - 配置選項
|
||
* @param {string} options.baseUrl - API 基礎 URL
|
||
* @param {string} options.accessToken - Access Token
|
||
* @param {string} options.currentPassword - 當前密碼
|
||
* @param {string} options.newPassword - 新密碼
|
||
* @returns {Object} 流程結果
|
||
*/
|
||
export function passwordChangeFlow(options = {}) {
|
||
const {
|
||
baseUrl = __ENV.BASE_URL || 'https://localhost:8888',
|
||
accessToken,
|
||
currentPassword,
|
||
newPassword = 'NewPassword123!',
|
||
} = options;
|
||
|
||
if (!accessToken || !currentPassword) {
|
||
throw new Error('accessToken and currentPassword are required');
|
||
}
|
||
|
||
// 步驟 1: 修改密碼
|
||
const updatePasswordResult = user.updatePassword({
|
||
baseUrl,
|
||
accessToken,
|
||
currentPassword,
|
||
newPassword,
|
||
});
|
||
|
||
if (!updatePasswordResult.success) {
|
||
return {
|
||
success: false,
|
||
step: 'update_password',
|
||
error: 'Update password failed',
|
||
updatePasswordResult,
|
||
};
|
||
}
|
||
|
||
// 短暫等待
|
||
sleep(1);
|
||
|
||
// 步驟 2: 使用新密碼登入驗證(可選)
|
||
// 注意:這需要知道 loginId,可能需要從 getUserInfo 獲取
|
||
// 這裡僅作為示例,實際使用時可能需要調整
|
||
|
||
return {
|
||
success: true,
|
||
updatePasswordResult,
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 完整的使用者資料初始化流程(註冊 → 登入 → 取得資訊 → 更新資訊)
|
||
* @param {Object} options - 配置選項
|
||
* @param {string} options.baseUrl - API 基礎 URL
|
||
* @param {string} options.loginId - 登入 ID
|
||
* @param {string} options.password - 密碼
|
||
* @param {Object} options.updateData - 要更新的資料
|
||
* @param {Object} options.customMetrics - 自定義指標對象(可選)
|
||
* @returns {Object} 流程結果
|
||
*/
|
||
export function userProfileInitializationFlow(options = {}) {
|
||
const {
|
||
baseUrl = __ENV.BASE_URL || 'https://localhost:8888',
|
||
loginId = `test_${Date.now()}@example.com`,
|
||
password = 'Test123456!',
|
||
updateData = {
|
||
nickname: `TestUser_${Date.now()}`,
|
||
preferred_language: 'zh-tw',
|
||
currency: 'TWD',
|
||
},
|
||
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 getInfoResult = user.getUserInfo({
|
||
baseUrl,
|
||
accessToken: registerResult.tokens.accessToken,
|
||
customMetrics,
|
||
});
|
||
|
||
if (!getInfoResult.success) {
|
||
return {
|
||
success: false,
|
||
step: 'get_info',
|
||
error: 'Get user info failed',
|
||
registerResult,
|
||
getInfoResult,
|
||
};
|
||
}
|
||
|
||
sleep(1);
|
||
|
||
// 步驟 3: 更新使用者資訊
|
||
const updateInfoResult = user.updateUserInfo({
|
||
baseUrl,
|
||
accessToken: registerResult.tokens.accessToken,
|
||
updateData,
|
||
customMetrics,
|
||
});
|
||
|
||
if (!updateInfoResult.success) {
|
||
return {
|
||
success: false,
|
||
step: 'update_info',
|
||
error: 'Update user info failed',
|
||
registerResult,
|
||
getInfoResult,
|
||
updateInfoResult,
|
||
};
|
||
}
|
||
|
||
return {
|
||
success: true,
|
||
registerResult,
|
||
getInfoResult,
|
||
updateInfoResult,
|
||
tokens: registerResult.tokens,
|
||
};
|
||
}
|
||
|