优化
This commit is contained in:
@@ -530,14 +530,11 @@ 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
|
||||
const maxAttempts = ['GET', 'HEAD'].includes(String(method).toUpperCase()) ? 3 : 1
|
||||
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
||||
try {
|
||||
const response = await fetch(`${this.options.gateway}${path}`, {
|
||||
method, headers, body: requestBody === undefined ? undefined : JSON.stringify(requestBody),
|
||||
method, headers, body: body === undefined ? undefined : JSON.stringify(body),
|
||||
signal: AbortSignal.timeout(30_000),
|
||||
})
|
||||
const content = await response.text()
|
||||
@@ -913,8 +910,8 @@ export class AcceptanceRun {
|
||||
|
||||
async findAvailablePhone(module = 'customers') {
|
||||
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')}`
|
||||
const markerDigits = this.marker.replace(/\D/g, '').slice(-7).padStart(7, '0')
|
||||
const phone = `18${markerDigits}${String(this.phoneSequence % 100).padStart(2, '0')}`
|
||||
this.addStep(module, '生成本轮隔离测试联系电话', null, /^1\d{10}$/.test(phone),
|
||||
`sequence=${this.phoneSequence}`)
|
||||
return phone
|
||||
|
||||
@@ -244,7 +244,7 @@ async function createSecondCustomer(context) {
|
||||
const fixture = context.context?.merchantQualificationFixture
|
||||
if (!fixture?.tenantId || !fixture?.username || !fixture?.password || fixture.marker !== context.marker) return null
|
||||
const loginResponse = await context.request('POST', '/api/auth/login',
|
||||
{ username: fixture.username, password: fixture.password }, '')
|
||||
{ loginId: fixture.username, password: fixture.password }, '')
|
||||
const login = context.apiSuccess(MODULE, '第二隔离客户登录', loginResponse, diagnostic(loginResponse), OPTIONS)
|
||||
return { customerId: id(fixture.tenantId), token: login?.accessToken }
|
||||
} finally {
|
||||
|
||||
@@ -8,6 +8,8 @@ const CONTAINER_STATUSES = ['WAIT_LOADING', 'EDITING', 'LOADING', 'COMPLETED']
|
||||
const PRELOAD_STATUSES = ['EDITING', 'LOADING']
|
||||
const PDA_STATUSES = ['UNASSIGNED', 'IN_PROGRESS', 'AWAITING_REVIEW', 'COMPLETED']
|
||||
|
||||
import { resolveOceanBookingAgent } from './ocean-booking-fixture.mjs'
|
||||
|
||||
function id(value) { return value == null ? '' : String(value) }
|
||||
function records(value) { return Array.isArray(value?.records) ? value.records : [] }
|
||||
function suffix(context, label) {
|
||||
@@ -128,14 +130,11 @@ async function createConfirmedContainer(context, source, label) {
|
||||
const value = suffix(context, label)
|
||||
const containerNo = iso6346ContainerNumber(`${context.marker}-manual-${label}`)
|
||||
const summary = source.detail.summary
|
||||
const agentResponse = await context.request('GET',
|
||||
'/api/platform/v1/suppliers?tenantId=0&category=BOOKING&status=ACTIVE&page=1&size=20')
|
||||
const agentPage = context.apiSuccess(MODULE, `${label} 读取 ACTIVE 订舱代理`, agentResponse, '', OPTIONS)
|
||||
const agent = agentPage?.records?.find?.((item) => item?.id && item?.name)
|
||||
if (!agent) throw new Error(`${label} 未取得 ACTIVE 订舱代理`)
|
||||
const { ensureMatsonCarrierPartner } = await import('./carrier-partner-fixture.mjs')
|
||||
const carrier = await ensureMatsonCarrierPartner(context, MODULE, OPTIONS)
|
||||
if (!carrier?.id) throw new Error(`${label} 未取得 ACTIVE 船公司`)
|
||||
const agent = await resolveOceanBookingAgent(context, MODULE, carrier.carrierCode, OPTIONS)
|
||||
if (!agent) throw new Error(`${label} 未取得当前船公司关联的 ACTIVE 订舱代理`)
|
||||
const draft = {
|
||||
customerId: source.tenantId, customerName: summary.customerName || 'IT 测试客户',
|
||||
channelCode: summary.channelCode, warehouseId: source.warehouseId,
|
||||
|
||||
@@ -85,3 +85,9 @@ test('all production booking fixtures use DRAFT release and the shared requireme
|
||||
assert.match(source, /containerRequirements/, name)
|
||||
}
|
||||
})
|
||||
|
||||
test('manual PDA state fixture resolves an agent bound to the selected carrier', () => {
|
||||
const source = read('manual-state-loading-pda.mjs')
|
||||
assert.match(source, /resolveOceanBookingAgent\(context, MODULE, carrier\.carrierCode, OPTIONS\)/)
|
||||
assert.doesNotMatch(source, /suppliers\?tenantId=0&category=BOOKING/)
|
||||
})
|
||||
|
||||
@@ -284,7 +284,7 @@ export async function run(context) {
|
||||
|| !Number.isInteger(Number(carryingSlice?.packageCount)) || Number(carryingSlice.packageCount) <= 0) return
|
||||
|
||||
const loginResponse = await request(context, 'POST', '/api/auth/login', {
|
||||
username: MERCHANT_USERNAME, password: MERCHANT_PASSWORD,
|
||||
loginId: MERCHANT_USERNAME, password: MERCHANT_PASSWORD,
|
||||
}, '')
|
||||
const merchantLogin = context.apiSuccess(MODULE, '客户账号登录用于真实报关文件协同', loginResponse,
|
||||
`username=${MERCHANT_USERNAME}`, OPTIONS)
|
||||
|
||||
@@ -694,7 +694,7 @@ export async function run(context) {
|
||||
`taskVersion=${unchangedAfterInvalid?.version ?? 'missing'}, items=${taskItemsSignature(unchangedAfterInvalid)}, operations=${afterInvalidOperations?.length ?? 'missing'}`, OPTIONS)
|
||||
|
||||
const merchantLogin = await context.request('POST', '/api/auth/login', {
|
||||
username: MERCHANT_USERNAME, password: MERCHANT_PASSWORD,
|
||||
loginId: MERCHANT_USERNAME, password: MERCHANT_PASSWORD,
|
||||
}, '')
|
||||
const merchantToken = merchantLogin.http === 200 && codeOf(merchantLogin) === '200'
|
||||
? merchantLogin.body?.data?.accessToken : null
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import { readFileSync } from 'node:fs'
|
||||
import test from 'node:test'
|
||||
|
||||
const source = readFileSync(new URL('./admin-test-env-acceptance.mjs', import.meta.url), 'utf8')
|
||||
|
||||
test('admin acceptance phone fixture keeps more than ten generated customers distinct', () => {
|
||||
assert.match(source, /slice\(-7\)\.padStart\(7, '0'\)/)
|
||||
assert.match(source, /phoneSequence % 100/)
|
||||
assert.doesNotMatch(source, /phoneSequence % 10\)/)
|
||||
})
|
||||
@@ -380,7 +380,7 @@ async function loginIdentifierModule() {
|
||||
}, ({ status, json }) => ({ status, rejectionCode: json?.code }))
|
||||
|
||||
const renamedLogin = await apiStep('login-identifiers', 'login with the changed username', {
|
||||
method: 'POST', path: '/api/auth/login', body: { username: temporaryUsername, password: clientPassword },
|
||||
method: 'POST', path: '/api/auth/login', body: { loginId: temporaryUsername, password: clientPassword },
|
||||
}, ({ json }) => {
|
||||
requireSuccess(json)
|
||||
assertPresent(json.data?.accessToken, 'accessToken')
|
||||
@@ -397,7 +397,7 @@ async function loginIdentifierModule() {
|
||||
}, ({ json }) => ({ username: json.data.username }))
|
||||
|
||||
const restoredLogin = await apiStep('login-identifiers', 'login after restoring the original username', {
|
||||
method: 'POST', path: '/api/auth/login', body: { username, password: clientPassword },
|
||||
method: 'POST', path: '/api/auth/login', body: { loginId: username, password: clientPassword },
|
||||
}, ({ json }) => {
|
||||
requireSuccess(json)
|
||||
assertPresent(json.data?.accessToken, 'accessToken')
|
||||
@@ -1770,7 +1770,7 @@ async function loadOrderMasterData(token, module) {
|
||||
requireSuccess(json)
|
||||
assertTrue(pageRecords(json.data).length > 0, 'at least one active DOMESTIC warehouse is required')
|
||||
}, ({ json }) => ({ total: json.data?.total, warehouseCount: pageRecords(json.data).length }))
|
||||
const receiving = pageRecords(receivingWarehouses.json.data)[0]
|
||||
const receivingCandidates = pageRecords(receivingWarehouses.json.data)
|
||||
|
||||
const destinationWarehouses = await apiStep(module, 'load active FBA destination warehouses', {
|
||||
method: 'GET', path: '/api/merchant/v1/warehouses?page=1&size=200&status=ACTIVE&warehouseType=FBA', token,
|
||||
@@ -1779,6 +1779,21 @@ async function loadOrderMasterData(token, module) {
|
||||
assertTrue(pageRecords(json.data).length > 0, 'at least one active FBA warehouse is required')
|
||||
}, ({ json }) => ({ total: json.data?.total, warehouseCount: pageRecords(json.data).length }))
|
||||
const destination = pageRecords(destinationWarehouses.json.data)[0]
|
||||
let receiving = null
|
||||
let pricedChannels = []
|
||||
for (const candidate of receivingCandidates) {
|
||||
const response = await httpRequest({
|
||||
method: 'GET', path: `/api/merchant/v1/first-leg/pricing/channels?originWarehouseId=${candidate.id}`, token,
|
||||
})
|
||||
const candidates = String(response?.json?.code) === '200' ? arrayData(response.json.data) : []
|
||||
const available = candidates.filter((item) => arrayData(item.pricingTaxModes).length > 0)
|
||||
if (available.length > 0) {
|
||||
receiving = candidate
|
||||
pricedChannels = available
|
||||
break
|
||||
}
|
||||
}
|
||||
assertPresent(receiving, 'active DOMESTIC warehouse with pricing channels')
|
||||
report.resources.receivingWarehouseId = receiving.id
|
||||
report.resources.destinationWarehouseId = destination.id
|
||||
|
||||
@@ -1796,7 +1811,7 @@ async function loadOrderMasterData(token, module) {
|
||||
requireSuccess(json)
|
||||
assertTrue(arrayData(json.data).length > 0, 'at least one active pricing channel is required')
|
||||
}, ({ json }) => ({ channels: arrayData(json.data).map((item) => ({ channelCode: item.channelCode, priceModel: item.priceModel, pricingTaxModes: item.pricingTaxModes })) }))
|
||||
const channel = arrayData(channels.json.data).find((item) => arrayData(item.pricingTaxModes).length > 0)
|
||||
const channel = pricedChannels.find((item) => arrayData(item.pricingTaxModes).length > 0)
|
||||
assertPresent(channel, 'pricing channel with pricingTaxModes')
|
||||
report.resources.channelCode = channel.channelCode
|
||||
|
||||
@@ -1812,7 +1827,7 @@ async function loadOrderMasterData(token, module) {
|
||||
destination,
|
||||
destinationCandidates: pageRecords(destinationWarehouses.json.data),
|
||||
channel,
|
||||
channelCandidates: arrayData(channels.json.data).filter((item) => arrayData(item.pricingTaxModes).length > 0),
|
||||
channelCandidates: pricedChannels,
|
||||
partner,
|
||||
}
|
||||
}
|
||||
@@ -2003,13 +2018,10 @@ async function softApiStep(module, name, request, validate, evidenceBuilder = de
|
||||
async function httpRequest({ method = 'GET', path, token, headers = {}, body, responseType = 'json' }) {
|
||||
const requestHeaders = { Accept: 'application/json', 'X-Request-Id': `client-e2e-${randomUUID()}`, ...headers }
|
||||
if (token) requestHeaders.Authorization = `Bearer ${token}`
|
||||
const normalizedBody = path === '/api/auth/login' && body?.username && !body?.loginId
|
||||
? { ...body, loginId: body.username, username: undefined }
|
||||
: body
|
||||
let requestBody = normalizedBody
|
||||
if (normalizedBody != null && !(normalizedBody instanceof FormData)) {
|
||||
let requestBody = body
|
||||
if (body != null && !(body instanceof FormData)) {
|
||||
requestHeaders['Content-Type'] = 'application/json'
|
||||
requestBody = JSON.stringify(normalizedBody)
|
||||
requestBody = JSON.stringify(body)
|
||||
}
|
||||
const response = await fetch(`${gateway}${path}`, {
|
||||
method,
|
||||
|
||||
Reference in New Issue
Block a user