fix: 修复TypeScript配置错误并更新项目文档

详细说明:
- 修复了@n8n/config包的TypeScript配置错误
- 移除了不存在的jest-expect-message类型引用
- 清理了所有TypeScript构建缓存
- 更新了可行性分析文档,添加了技术实施方案
- 更新了Agent prompt文档
- 添加了会展策划工作流文档
- 包含了n8n-chinese-translation子项目
- 添加了exhibition-demo展示系统框架
This commit is contained in:
Yep_Q
2025-09-08 10:49:45 +08:00
parent 8cf9d36d81
commit 3db7af209c
426 changed files with 71699 additions and 4401 deletions

View File

@@ -1,137 +0,0 @@
import { NodeTestHarness } from '@nodes-testing/node-test-harness';
import { mock } from 'jest-mock-extended';
import { DateTime } from 'luxon';
import { NodeOperationError, type IExecuteFunctions } from 'n8n-workflow';
import { Wait } from '../Wait.node';
describe('Execute Wait Node', () => {
let timer: NodeJS.Timeout;
const { clearInterval, setInterval } = global;
const nextDay = DateTime.now().startOf('day').plus({ days: 1 });
beforeAll(() => {
timer = setInterval(() => jest.advanceTimersByTime(1000), 10);
jest.useFakeTimers().setSystemTime(new Date('2025-01-01'));
});
afterAll(() => {
clearInterval(timer);
jest.useRealTimers();
});
test.each([
{ value: 'invalid_date', isValid: false },
{
value: nextDay.toISO(),
isValid: true,
expectedWaitTill: nextDay.toJSDate(),
},
{
value: nextDay.toISO({ includeOffset: true }),
isValid: true,
expectedWaitTill: nextDay.toUTC().toJSDate(),
},
{
value: nextDay.toJSDate(),
isValid: true,
expectedWaitTill: nextDay.toJSDate(),
},
{
value: nextDay,
isValid: true,
expectedWaitTill: nextDay.toJSDate(),
},
])(
'Test Wait Node with specificTime $value and isValid $isValid',
async ({ value, isValid, expectedWaitTill }) => {
const putExecutionToWaitSpy = jest.fn();
const waitNode = new Wait();
const executeFunctionsMock = mock<IExecuteFunctions>({
getNodeParameter: jest.fn().mockImplementation((paramName: string) => {
if (paramName === 'resume') return 'specificTime';
if (paramName === 'dateTime') return value;
}),
getTimezone: jest.fn().mockReturnValue('UTC'),
putExecutionToWait: putExecutionToWaitSpy,
getInputData: jest.fn(),
getNode: jest.fn(),
});
if (isValid) {
await expect(waitNode.execute(executeFunctionsMock)).resolves.not.toThrow();
expect(putExecutionToWaitSpy).toHaveBeenCalledWith(expectedWaitTill);
} else {
await expect(waitNode.execute(executeFunctionsMock)).rejects.toThrow(NodeOperationError);
}
},
);
describe('Validation', () => {
describe('Time interval', () => {
it.each([
{
unit: 'seconds',
amount: 300,
expectedWaitTill: () => DateTime.now().plus({ seconds: 300 }).toJSDate(),
},
{
unit: 'minutes',
amount: 2,
expectedWaitTill: () => DateTime.now().plus({ minutes: 2 }).toJSDate(),
},
{
unit: 'hours',
amount: 1,
expectedWaitTill: () => DateTime.now().plus({ hours: 1 }).toJSDate(),
},
{
unit: 'days',
amount: 10,
expectedWaitTill: () => DateTime.now().plus({ days: 10 }).toJSDate(),
},
{
unit: 'seconds',
amount: -10,
error: 'Invalid wait amount. It must be a positive number.',
},
{
unit: 'years',
amount: 10,
error: "Invalid wait unit. Valid units are 'seconds', 'minutes', 'hours', or 'days'.",
},
{
unit: 'minutes',
amount: 'test',
error: 'Invalid wait amount. It must be a positive number.',
},
])(
'Validate wait unit: $unit, amount: $amount',
async ({ unit, amount, expectedWaitTill, error }) => {
const putExecutionToWaitSpy = jest.fn();
const waitNode = new Wait();
const executeFunctionsMock = mock<IExecuteFunctions>({
getNodeParameter: jest.fn().mockImplementation((paramName: string) => {
if (paramName === 'resume') return 'timeInterval';
if (paramName === 'amount') return amount;
if (paramName === 'unit') return unit;
}),
getTimezone: jest.fn().mockReturnValue('UTC'),
putExecutionToWait: putExecutionToWaitSpy,
getInputData: jest.fn(),
getNode: jest.fn(),
});
if (!error) {
await expect(waitNode.execute(executeFunctionsMock)).resolves.not.toThrow();
expect(putExecutionToWaitSpy).toHaveBeenCalledWith(expectedWaitTill?.());
} else {
await expect(waitNode.execute(executeFunctionsMock)).rejects.toThrowError(error);
}
},
);
});
});
new NodeTestHarness().setupTests();
});

View File

@@ -1,162 +0,0 @@
{
"name": "[Unit Test] Wait Node",
"nodes": [
{
"parameters": {},
"id": "76e5dcfd-fdc7-472f-8832-bccc0eb122c0",
"name": "When clicking \"Execute Workflow\"",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [120, 420]
},
{
"parameters": {
"amount": 42,
"unit": "seconds"
},
"id": "37f2c758-6fb2-43ce-86ae-ca11ec957cbd",
"name": "Wait",
"type": "n8n-nodes-base.wait",
"typeVersion": 1,
"position": [560, 420],
"webhookId": "35edc971-c3e4-48cf-835d-4d73a4fd1fd8"
},
{
"parameters": {
"conditions": {
"number": [
{
"value1": "={{ parseInt($json.afterTimestamp) }}",
"operation": "largerEqual",
"value2": "={{ parseInt($json.startTimestamp) + 42 }}"
}
]
}
},
"id": "c5c53934-2677-4adf-a4df-b32f3b0642a2",
"name": "IF",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [960, 420]
},
{
"parameters": {
"keepOnlySet": true,
"values": {
"boolean": [
{
"name": "success",
"value": true
}
]
},
"options": {}
},
"id": "a78417b6-d3f5-4bbc-916a-d4b9d46961cc",
"name": "Set1",
"type": "n8n-nodes-base.set",
"typeVersion": 1,
"position": [1180, 400]
},
{
"parameters": {
"value": "={{ $now }}",
"dataPropertyName": "afterTimestamp",
"toFormat": "X",
"options": {}
},
"id": "94f042ea-49d5-44ea-9ccf-93dac8d27d4a",
"name": "After",
"type": "n8n-nodes-base.dateTime",
"typeVersion": 1,
"position": [760, 420]
},
{
"parameters": {
"value": "={{ $now }}",
"dataPropertyName": "startTimestamp",
"toFormat": "X",
"options": {}
},
"id": "43f8a396-1bf7-484e-962c-120f677dfa51",
"name": "Before",
"type": "n8n-nodes-base.dateTime",
"typeVersion": 1,
"position": [360, 420]
}
],
"pinData": {
"Set1": [
{
"json": {
"success": true
}
}
]
},
"connections": {
"When clicking \"Execute Workflow\"": {
"main": [
[
{
"node": "Before",
"type": "main",
"index": 0
}
]
]
},
"Wait": {
"main": [
[
{
"node": "After",
"type": "main",
"index": 0
}
]
]
},
"IF": {
"main": [
[
{
"node": "Set1",
"type": "main",
"index": 0
}
]
]
},
"After": {
"main": [
[
{
"node": "IF",
"type": "main",
"index": 0
}
]
]
},
"Before": {
"main": [
[
{
"node": "Wait",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {},
"versionId": "8ed794a0-5c04-4b8a-9a49-02c2c7f8003f",
"id": "500",
"meta": {
"instanceId": "8c8c5237b8e37b006a7adce87f4369350c58e41f3ca9de16196d3197f69eabcd"
},
"tags": []
}