Merge remote-tracking branch 'origin/test' into dev

# Conflicts:
#	firstleg/src/main/java/com/baiyue/firstleg/loading/service/CabinetLoadingEvidenceService.java
#	firstleg/src/test/java/com/baiyue/firstleg/loading/service/CabinetLoadingEvidenceServiceTest.java
#	scripts/admin-test-env-modules/ocean-bookings.mjs
#	scripts/admin-test-env-modules/phase3-container-customs-fixture.mjs
#	scripts/admin-test-env-modules/phase3-container-documents-contract.test.mjs
#	scripts/admin-test-env-modules/phase3-container-loading.mjs
#	scripts/admin-test-env-modules/phase3-customs.mjs
#	scripts/admin-test-env-modules/phase3-loading-finalize.mjs
#	scripts/admin-test-env-modules/phase3-loading.mjs
#	scripts/admin-test-env-modules/phase3-port-schedules.mjs
#	scripts/admin-test-env-modules/service-center-flow.mjs
This commit is contained in:
2026-09-02 14:00:44 +08:00
36 changed files with 1383 additions and 523 deletions
+35 -17
View File
@@ -336,7 +336,8 @@ export function parseArguments(argv) {
channelCode: values.get('channel-code') || '',
orderProfileMode: values.get('order-profile-mode') || 'fixed',
waitSplitCount: Number(values.get('wait-split-count') || process.env.ADMIN_WAIT_SPLIT_COUNT
|| (modules.includes('manual-order-splitting-fixture') ? 6 : 1)),
|| (modules.includes('coload-groups') ? 8
: modules.includes('manual-order-splitting-fixture') ? 6 : 1)),
waitSplitPackageCount: Number(values.get('wait-split-package-count') || 0),
waitSplitSequence: Number(values.get('wait-split-sequence') || 1),
waitSplitRandomValue: Number(values.get('wait-split-random-value') || values.get('wait-split-sequence') || 1),
@@ -522,9 +523,12 @@ export class AcceptanceRun {
const headers = { Accept: 'application/json', ...extraHeaders }
if (token) headers.Authorization = `Bearer ${token}`
if (body !== undefined) headers['Content-Type'] = 'application/json; charset=utf-8'
const requestBody = path === '/api/auth/login' && body?.username && !body?.loginId
? { ...body, loginId: body.username, username: undefined }
: body
try {
const response = await fetch(`${this.options.gateway}${path}`, {
method, headers, body: body === undefined ? undefined : JSON.stringify(body),
method, headers, body: requestBody === undefined ? undefined : JSON.stringify(requestBody),
signal: AbortSignal.timeout(30_000),
})
const content = await response.text()
@@ -824,7 +828,7 @@ export class AcceptanceRun {
this.context.phase3LoadingIncrementalPackageCount = variant.packageCountPerSku
const profile = this.options.orderProfileMode === 'randomized'
? this.randomizedOrderProfile(sequence)
: { destinationType: 'FBA', fulfillmentType: 'STANDARD', pickupMethod: 'PICKUP',
: { destinationType: 'FBA', fulfillmentType: 'STANDARD', pickupMethod: 'SELF_EXPRESS',
taxMode: 'BUY_DECLARATION', containerMode: 'LCL', customsInspection: false }
this.context.orderProfile = profile
this.context.orderDestinationType = profile.destinationType
@@ -893,13 +897,12 @@ export class AcceptanceRun {
}
async findAvailablePhone(module = 'customers') {
const seed = BigInt(Date.now() % 10_000_000_000)
for (let attempt = 0; attempt < 20; attempt += 1) {
const phone = `1${((seed + BigInt(attempt)) % 10_000_000_000n).toString().padStart(10, '0')}`
const response = await this.request('GET', `/api/platform/v1/iam/tenants/contact-phone-availability?contactPhone=${phone}`)
if (this.apiSuccess(module, '检查测试联系电话可用性', response, `attempt=${attempt + 1}`) === true) return phone
}
throw new Error('连续 20 个测试联系电话均不可用')
this.phoneSequence = Number(this.phoneSequence || 0) + 1
const markerDigits = this.marker.replace(/\D/g, '').slice(-8).padStart(8, '0')
const phone = `18${markerDigits}${String(this.phoneSequence % 10).padStart(1, '0')}`
this.addStep(module, '生成本轮隔离测试联系电话', null, /^1\d{10}$/.test(phone),
`sequence=${this.phoneSequence}`)
return phone
}
async runCustomerDimensionRules(tenantId) {
@@ -1057,15 +1060,30 @@ export class AcceptanceRun {
&& /[A-Za-z]/.test(createData.temporaryPassword) && /\d/.test(createData.temporaryPassword),
`generated=${typeof createData.temporaryPassword === 'string'}, length=${createData.temporaryPassword?.length || 0}`,
ownerProvisioningOptions)
this.assert(module, '管理员用户名默认使用联系电话', createResponse,
createData.administratorUsername === phone,
`matches=${createData.administratorUsername === phone}`,
const administratorUsername = String(createData.administratorUsername || '')
this.assert(module, '管理员用户名作为独立登录标识返回', createResponse,
administratorUsername.length > 0,
`present=${administratorUsername.length > 0}`,
ownerProvisioningOptions)
this.assert(module, '待完善客户的审核字段保持为空', createResponse,
customer.unifiedSocialCreditCode == null && customer.approvedAt == null,
`creditCode=${customer.unifiedSocialCreditCode ?? 'omitted'}, approvedAt=${customer.approvedAt ?? 'omitted'}`)
await this.runCustomerDimensionRules(tenantId)
const dimensionInitializationPath = `/api/platform/v1/iam/tenants/${tenantId}/dimension-initialization`
let dimensionInitializationResponse = null
let dimensionInitialization = null
for (let attempt = 0; attempt < 30; attempt += 1) {
dimensionInitializationResponse = await this.request('GET', dimensionInitializationPath)
dimensionInitialization = dimensionInitializationResponse.http === 200
&& String(dimensionInitializationResponse.body?.code) === '200'
? dimensionInitializationResponse.body?.data : null
if (dimensionInitialization?.status === 'READY') break
if (attempt < 29) await new Promise((resolve) => setTimeout(resolve, 1_000))
}
this.assert(module, '客户默认尺寸异步初始化完成', dimensionInitializationResponse,
dimensionInitialization?.status === 'READY',
`status=${dimensionInitialization?.status || 'missing'}`, ownerProvisioningOptions)
if (dimensionInitialization?.status === 'READY') await this.runCustomerDimensionRules(tenantId)
const listResponse = await this.request('GET', `/api/platform/v1/iam/tenants?page=1&size=20&keyword=${encodeURIComponent(payload.tenantName)}`)
const page = this.apiSuccess(module, '查询客户列表', listResponse); const listed = page?.records?.find((item) => String(item.id) === tenantId)
@@ -1135,9 +1153,9 @@ export class AcceptanceRun {
}
const memberResponse = await this.request('GET', `${detailPath}/members`); const members = this.apiSuccess(module, '业务概况查询成员', memberResponse)
const owner = members?.find?.((item) => item.memberType === 'OWNER')
this.assert(module, '联系电话账号是企业管理员', memberResponse,
owner?.username === phone,
`ownerFound=${Boolean(owner)}, matches=${owner?.username === phone}`,
this.assert(module, '独立用户名账号是企业管理员且联系电话不承担用户名约束', memberResponse,
owner?.username === administratorUsername,
`ownerFound=${Boolean(owner)}, matches=${owner?.username === administratorUsername}`,
ownerProvisioningOptions)
const countResponse = await this.request('GET', `/api/platform/v1/orders/first-leg/tenant-counts?tenantIds=${tenantId}`); const counts = this.apiSuccess(module, '业务概况查询运单数量', countResponse); const count = counts?.find?.((item) => String(item.tenantId) === tenantId)
this.assert(module, '业务概况返回当前客户运单数', countResponse, count && Number.isFinite(Number(count.orderCount)), `orderCount=${count?.orderCount ?? 'missing'}`)