Files
creator-hub/web/tests/account-memory-edit.test.cjs
T
rogee e50bed9ad8
douyin-release-gate / verify (push) Failing after 18m54s
feat: add account events and private message management
Add Douyin notification polling, event details, and manual multi-account private messaging.

Refine environment memory settings, account operations, login collection recovery, and message UI; update tests and documentation.
2026-10-07 10:23:05 +08:00

105 lines
6.6 KiB
JavaScript

const assert = require('node:assert/strict');
const { readFileSync } = require('node:fs');
const { test } = require('node:test');
const { Module, createRequire } = require('node:module');
const { resolve } = require('node:path');
const ts = require('typescript');
const requireWeb = createRequire(resolve(__dirname, '../package.json'));
const file = resolve(__dirname, '../src/pages/accounts/$id/edit.tsx');
function setup({ environment = { alias: 'env-a', memory_limit_mb: 8192, runtime_id: 'running', fingerprint: { seed: 42 }, profile_id: 'existing', gateway: 'gw-a' }, saveError } = {}) {
const states = [], forms = [], effects = [], calls = [], messages = [];
let cursor = 0, formCursor = 0;
const marker = name => Object.assign(() => null, { displayName: name });
const Form = Object.assign(marker('Form'), {
Item: marker('Form.Item'),
useForm() {
const index = formCursor++;
forms[index] ||= { values: {}, setFieldsValue(values) { Object.assign(this.values, values); }, getFieldValue(name) { return this.values[name]; }, async validateFields() { return this.values; } };
return [forms[index]];
},
});
const antd = { Form, App: { useApp: () => ({ message: { success: text => messages.push(text), error: text => messages.push(text) } }) } };
for (const name of ['Alert', 'Button', 'Card', 'Col', 'Flex', 'Row', 'Select', 'Space', 'InputNumber']) antd[name] = marker(name);
antd.Input = Object.assign(marker('Input'), { Password: marker('Password'), TextArea: marker('TextArea') });
antd.Descriptions = Object.assign(marker('Descriptions'), { Item: marker('Descriptions.Item') });
antd.Typography = { Title: marker('Title'), Text: marker('Text'), Paragraph: marker('Paragraph') };
const loaded = new Module(file, module);
loaded.require = id => {
if (id === 'react') return {
useState(value) { const index = cursor++; if (!(index in states)) states[index] = value; return [states[index], next => { states[index] = typeof next === 'function' ? next(states[index]) : next; }]; },
useCallback: callback => callback,
useEffect(effect) { if (!effects.length) effects.push(effect); },
};
if (id === 'antd') return antd;
if (id === '@umijs/max') return { useParams: () => ({ id: 'account-a' }), history: { push() {} } };
if (id === '@/components/PageActions') return { usePageActions() {}, usePageInfo() {} };
if (id === '@/services/api') return {
async getList() { return { data: [{ id: 'account-a', platform: 'douyin' }] }; },
async getOne() { return { environment }; },
async creatorUpdate(path, data) { calls.push({ path, data }); if (saveError) throw saveError; return { ...environment, ...data }; },
};
if (id === '@/utils/helpers') return { conflictMessage: (error, fallback) => error.message || fallback, dateTime: String };
if (id === '@/components/accounts/FingerprintFields') return { default: marker('FingerprintFields'), fingerprintFormValues: fingerprint => ({ fingerprint }), fingerprintPayload: value => value };
if (id.startsWith('@/components/')) return { default: marker(id) };
return requireWeb(id);
};
loaded._compile(ts.transpileModule(readFileSync(file, 'utf8'), { fileName: file, compilerOptions: { module: ts.ModuleKind.CommonJS, jsx: ts.JsxEmit.ReactJSX, inlineSourceMap: true, inlineSources: true } }).outputText, file);
let tree;
function render() { cursor = 0; formCursor = 0; tree = loaded.exports.default(); return tree; }
function all(name, node = tree) {
if (!node || typeof node !== 'object') return [];
return [...(node.type?.displayName === name ? [node] : []), ...[node.props?.children].flat(Infinity).flatMap(child => child == null ? [] : all(name, child))];
}
render();
return { forms, calls, messages, render, all, async load() { effects[0](); for (let i = 0; i < 8; i++) await Promise.resolve(); render(); } };
}
test('编辑回填真实内存上限,运行中独立保存只发内存字段,不触发stop/start或指纹保存', async () => {
const s = setup(); await s.load();
const field = s.all('Form.Item').find(node => node.props.name === 'memory_limit_mb');
assert.ok(field, '编辑页必须提供独立内存设置');
const memoryForm = s.forms.find(form => Object.hasOwn(form.values, 'memory_limit_mb'));
assert.equal(memoryForm.values.memory_limit_mb, 8192);
assert.equal(field.props.initialValue, undefined);
assert.equal(s.all('InputNumber')[0].props.disabled, undefined);
const form = s.all('Form').find(node => node.props.form === memoryForm);
assert.equal(form.props.disabled, false, '运行中也允许保存内存设置');
memoryForm.values.memory_limit_mb = 4096;
const saving = form.props.onFinish(memoryForm.values);
s.render();
assert.equal(s.all('Form').find(node => node.props.form === memoryForm).props.disabled, true);
await saving;
assert.deepEqual(s.calls, [{ path: '/creator/accounts/account-a/fingerprint', data: { memory_limit_mb: 4096 } }]);
assert.match(s.messages.at(-1), /下次启动.*生效/);
});
test('编辑缺失内存字段不伪造2048;原生规则拒绝空值、越界与小数', async () => {
const s = setup({ environment: { alias: 'env-a' } }); await s.load();
const field = s.all('Form.Item').find(node => node.props.name === 'memory_limit_mb');
assert.ok(field);
const memoryForm = s.forms.find(form => Object.hasOwn(form.values, 'memory_limit_mb'));
assert.equal(memoryForm.values.memory_limit_mb, undefined);
const Schema = requireWeb('@rc-component/async-validator').default;
const schema = new Schema({ memory_limit_mb: field.props.rules });
for (const value of [512, 65536]) await schema.validate({ memory_limit_mb: value });
for (const value of [undefined, null, 511, 65537, 512.5]) await assert.rejects(schema.validate({ memory_limit_mb: value }));
});
test('未绑定环境不允许保存内存上限,也不创建环境', async () => {
const s = setup({ environment: null }); await s.load();
const memoryForm = s.forms.find(form => Object.hasOwn(form.values, 'memory_limit_mb'));
const form = s.all('Form').find(node => node.props.form === memoryForm);
assert.equal(form.props.disabled, true);
await form.props.onFinish({ memory_limit_mb: 4096 });
assert.deepEqual(s.calls, []);
});
test('内存保存失败明确显示原因,不提示成功', async () => {
const s = setup({ saveError: new Error('环境不可用') }); await s.load();
const memoryForm = s.forms.find(form => Object.hasOwn(form.values, 'memory_limit_mb'));
assert.ok(memoryForm);
await s.all('Form').find(node => node.props.form === memoryForm).props.onFinish({ memory_limit_mb: 4096 });
assert.deepEqual(s.messages, ['环境不可用']);
});