详细说明: - 基于文旅订单班框架复制创建food-order-demo项目 - 修改端口配置为4174避免冲突 - 更新LandingPage为青莳轻食主题(绿色健康风格) - 重新定义7个食品行业专业Agent: * 市场研究专家:轻食市场分析、客群画像 * 营养配方师:营养成分配比、低卡高蛋白设计 * 供应链管理专家:有机食材供应、溯源体系 * 品牌策划师:品牌定位、店铺空间布局 * 财务分析师:投资预算、ROI分析 * 运营管理专家:运营流程、品控标准 * 食品创业导师:中央协调、方案整合 - 创建专用启动脚本start.sh - 验证系统可正常运行在端口4174 - 实现代码复用率90%,符合预期目标 影响文件: web_frontend/food-order-demo/ 技术栈: React 18 + TypeScript + Tailwind CSS + Zustand
292 lines
6.2 KiB
JavaScript
292 lines
6.2 KiB
JavaScript
'use strict'
|
|
|
|
const test = require('tape')
|
|
const buildQueue = require('../').promise
|
|
const { promisify } = require('util')
|
|
const sleep = promisify(setTimeout)
|
|
const immediate = promisify(setImmediate)
|
|
|
|
test('concurrency', function (t) {
|
|
t.plan(2)
|
|
t.throws(buildQueue.bind(null, worker, 0))
|
|
t.doesNotThrow(buildQueue.bind(null, worker, 1))
|
|
|
|
async function worker (arg) {
|
|
return true
|
|
}
|
|
})
|
|
|
|
test('worker execution', async function (t) {
|
|
const queue = buildQueue(worker, 1)
|
|
|
|
const result = await queue.push(42)
|
|
|
|
t.equal(result, true, 'result matches')
|
|
|
|
async function worker (arg) {
|
|
t.equal(arg, 42)
|
|
return true
|
|
}
|
|
})
|
|
|
|
test('limit', async function (t) {
|
|
const queue = buildQueue(worker, 1)
|
|
|
|
const [res1, res2] = await Promise.all([queue.push(10), queue.push(0)])
|
|
t.equal(res1, 10, 'the result matches')
|
|
t.equal(res2, 0, 'the result matches')
|
|
|
|
async function worker (arg) {
|
|
await sleep(arg)
|
|
return arg
|
|
}
|
|
})
|
|
|
|
test('multiple executions', async function (t) {
|
|
const queue = buildQueue(worker, 1)
|
|
const toExec = [1, 2, 3, 4, 5]
|
|
const expected = ['a', 'b', 'c', 'd', 'e']
|
|
let count = 0
|
|
|
|
await Promise.all(toExec.map(async function (task, i) {
|
|
const result = await queue.push(task)
|
|
t.equal(result, expected[i], 'the result matches')
|
|
}))
|
|
|
|
async function worker (arg) {
|
|
t.equal(arg, toExec[count], 'arg matches')
|
|
return expected[count++]
|
|
}
|
|
})
|
|
|
|
test('drained', async function (t) {
|
|
const queue = buildQueue(worker, 2)
|
|
|
|
const toExec = new Array(10).fill(10)
|
|
let count = 0
|
|
|
|
async function worker (arg) {
|
|
await sleep(arg)
|
|
count++
|
|
}
|
|
|
|
toExec.forEach(function (i) {
|
|
queue.push(i)
|
|
})
|
|
|
|
await queue.drained()
|
|
|
|
t.equal(count, toExec.length)
|
|
|
|
toExec.forEach(function (i) {
|
|
queue.push(i)
|
|
})
|
|
|
|
await queue.drained()
|
|
|
|
t.equal(count, toExec.length * 2)
|
|
})
|
|
|
|
test('drained with exception should not throw', async function (t) {
|
|
const queue = buildQueue(worker, 2)
|
|
|
|
const toExec = new Array(10).fill(10)
|
|
|
|
async function worker () {
|
|
throw new Error('foo')
|
|
}
|
|
|
|
toExec.forEach(function (i) {
|
|
queue.push(i)
|
|
})
|
|
|
|
await queue.drained()
|
|
})
|
|
|
|
test('drained with drain function', async function (t) {
|
|
let drainCalled = false
|
|
const queue = buildQueue(worker, 2)
|
|
|
|
queue.drain = function () {
|
|
drainCalled = true
|
|
}
|
|
|
|
const toExec = new Array(10).fill(10)
|
|
let count = 0
|
|
|
|
async function worker (arg) {
|
|
await sleep(arg)
|
|
count++
|
|
}
|
|
|
|
toExec.forEach(function () {
|
|
queue.push()
|
|
})
|
|
|
|
await queue.drained()
|
|
|
|
t.equal(count, toExec.length)
|
|
t.equal(drainCalled, true)
|
|
})
|
|
|
|
test('drained while idle should resolve', async function (t) {
|
|
const queue = buildQueue(worker, 2)
|
|
|
|
async function worker (arg) {
|
|
await sleep(arg)
|
|
}
|
|
|
|
await queue.drained()
|
|
})
|
|
|
|
test('drained while idle should not call the drain function', async function (t) {
|
|
let drainCalled = false
|
|
const queue = buildQueue(worker, 2)
|
|
|
|
queue.drain = function () {
|
|
drainCalled = true
|
|
}
|
|
|
|
async function worker (arg) {
|
|
await sleep(arg)
|
|
}
|
|
|
|
await queue.drained()
|
|
|
|
t.equal(drainCalled, false)
|
|
})
|
|
|
|
test('set this', async function (t) {
|
|
t.plan(1)
|
|
const that = {}
|
|
const queue = buildQueue(that, worker, 1)
|
|
|
|
await queue.push(42)
|
|
|
|
async function worker (arg) {
|
|
t.equal(this, that, 'this matches')
|
|
}
|
|
})
|
|
|
|
test('unshift', async function (t) {
|
|
const queue = buildQueue(worker, 1)
|
|
const expected = [1, 2, 3, 4]
|
|
|
|
await Promise.all([
|
|
queue.push(1),
|
|
queue.push(4),
|
|
queue.unshift(3),
|
|
queue.unshift(2)
|
|
])
|
|
|
|
t.is(expected.length, 0)
|
|
|
|
async function worker (arg) {
|
|
t.equal(expected.shift(), arg, 'tasks come in order')
|
|
}
|
|
})
|
|
|
|
test('push with worker throwing error', async function (t) {
|
|
t.plan(5)
|
|
const q = buildQueue(async function (task, cb) {
|
|
throw new Error('test error')
|
|
}, 1)
|
|
q.error(function (err, task) {
|
|
t.ok(err instanceof Error, 'global error handler should catch the error')
|
|
t.match(err.message, /test error/, 'error message should be "test error"')
|
|
t.equal(task, 42, 'The task executed should be passed')
|
|
})
|
|
try {
|
|
await q.push(42)
|
|
} catch (err) {
|
|
t.ok(err instanceof Error, 'push callback should catch the error')
|
|
t.match(err.message, /test error/, 'error message should be "test error"')
|
|
}
|
|
})
|
|
|
|
test('unshift with worker throwing error', async function (t) {
|
|
t.plan(2)
|
|
const q = buildQueue(async function (task, cb) {
|
|
throw new Error('test error')
|
|
}, 1)
|
|
try {
|
|
await q.unshift(42)
|
|
} catch (err) {
|
|
t.ok(err instanceof Error, 'push callback should catch the error')
|
|
t.match(err.message, /test error/, 'error message should be "test error"')
|
|
}
|
|
})
|
|
|
|
test('no unhandledRejection (push)', async function (t) {
|
|
function handleRejection () {
|
|
t.fail('unhandledRejection')
|
|
}
|
|
process.once('unhandledRejection', handleRejection)
|
|
const q = buildQueue(async function (task, cb) {
|
|
throw new Error('test error')
|
|
}, 1)
|
|
|
|
q.push(42)
|
|
|
|
await immediate()
|
|
process.removeListener('unhandledRejection', handleRejection)
|
|
})
|
|
|
|
test('no unhandledRejection (unshift)', async function (t) {
|
|
function handleRejection () {
|
|
t.fail('unhandledRejection')
|
|
}
|
|
process.once('unhandledRejection', handleRejection)
|
|
const q = buildQueue(async function (task, cb) {
|
|
throw new Error('test error')
|
|
}, 1)
|
|
|
|
q.unshift(42)
|
|
|
|
await immediate()
|
|
process.removeListener('unhandledRejection', handleRejection)
|
|
})
|
|
|
|
test('drained should resolve after async tasks complete', async function (t) {
|
|
const logs = []
|
|
|
|
async function processTask () {
|
|
await new Promise(resolve => setTimeout(resolve, 0))
|
|
logs.push('processed')
|
|
}
|
|
|
|
const queue = buildQueue(processTask, 1)
|
|
queue.drain = () => logs.push('called drain')
|
|
|
|
queue.drained().then(() => logs.push('drained promise resolved'))
|
|
|
|
await Promise.all([
|
|
queue.push(),
|
|
queue.push(),
|
|
queue.push()
|
|
])
|
|
|
|
t.deepEqual(logs, [
|
|
'processed',
|
|
'processed',
|
|
'processed',
|
|
'called drain',
|
|
'drained promise resolved'
|
|
], 'events happened in correct order')
|
|
})
|
|
|
|
test('drained should handle undefined drain function', async function (t) {
|
|
const queue = buildQueue(worker, 1)
|
|
|
|
async function worker (arg) {
|
|
await sleep(10)
|
|
return arg
|
|
}
|
|
|
|
queue.drain = undefined
|
|
queue.push(1)
|
|
await queue.drained()
|
|
|
|
t.pass('drained resolved successfully with undefined drain')
|
|
})
|