优化
This commit is contained in:
@@ -6,12 +6,13 @@
|
||||
|
||||
import { mkdir, readFile, writeFile } from 'node:fs/promises'
|
||||
import { dirname, resolve } from 'node:path'
|
||||
import { pathToFileURL } from 'node:url'
|
||||
import process from 'node:process'
|
||||
|
||||
const DEFAULT_GATEWAY = 'http://8.163.30.128:9000'
|
||||
const DEFAULT_USERNAME = 'platform_admin'
|
||||
const DEFAULT_PASSWORD = 'ChangeMe123!'
|
||||
const DEFAULT_MODULES = ['customers', 'overseas-storage-fees', 'system', 'master-data', 'orders', 'fee-items', 'pricing', 'downloads', 'inbound-weight-ocr', 'inbound-measurement', 'phase3-container-loading', 'phase3-loading', 'supplemental', 'supplemental-boundaries', 'ocean-bookings', 'truck-appointments', 'service-center-flow', 'phase3-customs', 'phase3-port-schedules', 'phase3-carrier-schedule-queries', 'phase3-loading-finalize', 'phase3-outbound-dispatch', 'phase3-outbound-aggregate', 'phase3-dispatch-gate', 'phase3-waiting-for-loading', 'phase3-loading-model-bridge', 'phase3-pda-convergence', 'phase3-evidence-gate', 'phase3-warehouse-rbac', 'phase3-order-splitting', 'finance']
|
||||
const DEFAULT_MODULES = ['customers', 'overseas-storage-fees', 'system', 'master-data', 'orders', 'fee-items', 'pricing', 'downloads', 'inbound-weight-ocr', 'inbound-measurement', 'phase3-container-loading', 'phase3-loading', 'phase3-loading-model-bridge', 'phase3-pda-convergence', 'phase3-evidence-gate', 'supplemental', 'supplemental-boundaries', 'ocean-bookings', 'truck-appointments', 'service-center-flow', 'phase3-customs', 'phase3-port-schedules', 'phase3-carrier-schedule-queries', 'phase3-loading-finalize', 'phase3-outbound-dispatch', 'phase3-outbound-aggregate', 'phase3-dispatch-gate', 'phase3-waiting-for-loading', 'phase3-warehouse-rbac', 'phase3-order-splitting', 'finance', 'finance-full-fixtures', 'finance-reconciliation-full', 'finance-settlement-full']
|
||||
const WEIGHT_IMAGE_PATH = 'C:/Users/BY-OY/Desktop/上传图片包/测量图片/测量图片/orig_1cf27695-b2c3-44b3-98e3-c0be8b80f79a.JPG'
|
||||
const CUSTOMER_FIELDS = [
|
||||
'id', 'tenantCode', 'tenantName', 'status', 'legalName', 'legalRepresentative',
|
||||
@@ -82,7 +83,7 @@ function derived(length, width, height, edge) {
|
||||
return { outerLength, outerWidth, outerHeight, volume: halfUp3(outerLength * outerWidth * outerHeight / 1_000_000) }
|
||||
}
|
||||
|
||||
class AcceptanceRun {
|
||||
export class AcceptanceRun {
|
||||
constructor(options) {
|
||||
this.options = options
|
||||
this.marker = `ADMIN-API-${new Date().toISOString().replace(/\D/g, '').slice(0, 17)}`
|
||||
@@ -121,6 +122,36 @@ class AcceptanceRun {
|
||||
}
|
||||
}
|
||||
|
||||
async requestMultipart(method, path, file, token = this.token, extraHeaders = {}) {
|
||||
const form = file instanceof FormData ? file : new FormData()
|
||||
if (!(file instanceof FormData)) {
|
||||
if (!file || file.content === undefined) throw new TypeError('multipart file requires content')
|
||||
const content = file.content instanceof Uint8Array ? file.content : new Uint8Array(file.content)
|
||||
form.append('file', new Blob([content], { type: file.type || 'application/octet-stream' }), file.name || 'fixture.bin')
|
||||
}
|
||||
return this.requestWithBody(method, path, form, token, extraHeaders)
|
||||
}
|
||||
|
||||
async requestWithBody(method, path, body, token = this.token, extraHeaders = {}) {
|
||||
const headers = { Accept: 'application/json', ...extraHeaders }
|
||||
if (token) headers.Authorization = `Bearer ${token}`
|
||||
if (!(body instanceof FormData) && body !== undefined) headers['Content-Type'] = 'application/json; charset=utf-8'
|
||||
try {
|
||||
const response = await fetch(`${this.options.gateway}${path}`, {
|
||||
method, headers, body: body === undefined ? undefined : body instanceof FormData ? body : JSON.stringify(body),
|
||||
signal: AbortSignal.timeout(60_000),
|
||||
})
|
||||
const content = await response.text(); let payload = null
|
||||
try { payload = content ? JSON.parse(content) : null } catch { /* bounded raw response */ }
|
||||
return { method, path, http: response.status, body: payload,
|
||||
raw: payload === null ? content.slice(0, 500) : null,
|
||||
requestId: payload?.requestId || response.headers.get('x-request-id'),
|
||||
traceId: payload?.traceId || response.headers.get('x-trace-id') }
|
||||
} catch (error) {
|
||||
return { method, path, http: 0, body: null, raw: error instanceof Error ? error.message : String(error), requestId: null, traceId: null }
|
||||
}
|
||||
}
|
||||
|
||||
async requestBinary(method, path) {
|
||||
const headers = { Accept: '*/*', Authorization: `Bearer ${this.token}` }
|
||||
try {
|
||||
@@ -476,6 +507,51 @@ class AcceptanceRun {
|
||||
}
|
||||
}
|
||||
|
||||
async preparePhase3LoadingFixture() {
|
||||
const originalMarker = this.marker
|
||||
const fixtureMarker = `${originalMarker}-LOAD`
|
||||
const createdKeys = ['orders', 'ocrInbound', 'testInbound', 'inboundMeasurement']
|
||||
const contextKeys = ['inboundWeightOcr', 'ocrInbound', 'testInbound', 'createdInbound']
|
||||
const createdSnapshot = new Map(createdKeys.map((key) => [key, {
|
||||
present: Object.hasOwn(this.createdResources, key), value: this.createdResources[key],
|
||||
}]))
|
||||
const contextSnapshot = new Map(contextKeys.map((key) => [key, {
|
||||
present: Object.hasOwn(this.context, key), value: this.context[key],
|
||||
}]))
|
||||
|
||||
this.marker = fixtureMarker
|
||||
const orders = await import(new URL('./admin-test-env-modules/orders.mjs', import.meta.url))
|
||||
await this.executeModule('orders-phase3-loading-fixture', () => orders.run(this))
|
||||
const measurement = await import(new URL('./admin-test-env-modules/inbound-measurement.mjs', import.meta.url))
|
||||
await this.executeModule('inbound-measurement-phase3-loading-fixture', () => measurement.run(this))
|
||||
const fixture = this.createdResources.inboundMeasurement || this.createdResources.orders
|
||||
const loadingFixture = fixture ? {
|
||||
marker: originalMarker,
|
||||
sourceMarker: fixtureMarker,
|
||||
tenantId: fixture.tenantId,
|
||||
orderId: fixture.orderId || this.createdResources.orders?.orderId,
|
||||
inboundId: fixture.inboundId,
|
||||
} : { marker: originalMarker, sourceMarker: fixtureMarker, failed: true }
|
||||
this.createdResources.orchestrationFixtures = {
|
||||
...(this.createdResources.orchestrationFixtures || {}),
|
||||
phase3Loading: loadingFixture,
|
||||
inboundMeasurement: loadingFixture,
|
||||
}
|
||||
this.marker = originalMarker
|
||||
|
||||
return () => {
|
||||
this.marker = originalMarker
|
||||
for (const [key, snapshot] of createdSnapshot) {
|
||||
if (snapshot.present) this.createdResources[key] = snapshot.value
|
||||
else delete this.createdResources[key]
|
||||
}
|
||||
for (const [key, snapshot] of contextSnapshot) {
|
||||
if (snapshot.present) this.context[key] = snapshot.value
|
||||
else delete this.context[key]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async run() {
|
||||
const loginResponse = await this.request('POST', '/api/auth/login', { username: this.options.username, password: this.options.password }, '')
|
||||
const login = this.apiSuccess('authentication', '平台管理员登录', loginResponse)
|
||||
@@ -485,6 +561,11 @@ class AcceptanceRun {
|
||||
const handlers = { customers: () => this.runCustomers() }
|
||||
for (let moduleIndex = 0; moduleIndex < this.options.modules.length; moduleIndex += 1) {
|
||||
const module = this.options.modules[moduleIndex]
|
||||
const fullFinanceChain = ['finance-full-fixtures', 'finance-reconciliation-full', 'finance-settlement-full'].every((name) => this.options.modules.includes(name))
|
||||
if (module === 'finance' && fullFinanceChain) {
|
||||
this.modules.push({ name: module, startedAt: new Date().toISOString(), finishedAt: new Date().toISOString(), success: true, passed: 0, failed: 0, fatal: null, skipped: 'finance-full-chain owns the finance source locks' })
|
||||
continue
|
||||
}
|
||||
let restoreFixture = null
|
||||
const ocrIndex = this.options.modules.indexOf('inbound-weight-ocr')
|
||||
if (module === 'inbound-measurement' && ocrIndex >= 0 && ocrIndex < moduleIndex) {
|
||||
@@ -505,6 +586,16 @@ class AcceptanceRun {
|
||||
{ scenario: 'phase3-container-resource-isolation' })
|
||||
}
|
||||
}
|
||||
if (module === 'phase3-loading') {
|
||||
try {
|
||||
restoreFixture = await this.preparePhase3LoadingFixture()
|
||||
} catch (error) {
|
||||
this.marker = this.marker.replace(/-LOAD$/, '')
|
||||
const reason = error instanceof Error ? error.message : String(error)
|
||||
this.addStep('phase3-loading-fixture', '创建独立 WAIT_SPLIT 装柜入库单', null, false, reason,
|
||||
{ scenario: 'phase3-loading-resource-isolation' })
|
||||
}
|
||||
}
|
||||
let handler = handlers[module]
|
||||
if (!handler) {
|
||||
try {
|
||||
@@ -575,4 +666,6 @@ async function main() {
|
||||
process.exitCode = report.success ? 0 : 1
|
||||
}
|
||||
|
||||
main().catch((error) => { console.error(error instanceof Error ? error.message : String(error)); process.exitCode = 1 })
|
||||
if (process.argv[1] && import.meta.url === pathToFileURL(resolve(process.argv[1])).href) {
|
||||
main().catch((error) => { console.error(error instanceof Error ? error.message : String(error)); process.exitCode = 1 })
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user