douyin-release-gate / verify (push) Failing after 18m54s
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.
105 lines
6.6 KiB
JavaScript
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, ['环境不可用']);
|
|
});
|