32fb2cdeaf
Add chat file/image upload UX, attachment proxying, vision thumbnails, and per-turn image scoping so agents only use the current upload. Extend MindSpace asset context, billing token state, OA/scenario verify scripts, and related runtime config. Co-authored-by: Cursor <cursoragent@cursor.com>
106 lines
3.7 KiB
JavaScript
106 lines
3.7 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import fs from 'node:fs';
|
|
import fsPromises from 'node:fs/promises';
|
|
import http from 'node:http';
|
|
import os from 'node:os';
|
|
import path from 'node:path';
|
|
import test from 'node:test';
|
|
import express from 'express';
|
|
import { attachShenmeiOpinionFormRoutes } from './shenmei-opinion-form-routes.mjs';
|
|
|
|
async function request(baseUrl, method, pathname, { body, headers } = {}) {
|
|
const response = await fetch(`${baseUrl}${pathname}`, {
|
|
method,
|
|
headers: {
|
|
...(body ? { 'content-type': 'application/json' } : {}),
|
|
...headers,
|
|
},
|
|
body: body ? JSON.stringify(body) : undefined,
|
|
});
|
|
const text = await response.text();
|
|
return {
|
|
status: response.status,
|
|
body: text ? JSON.parse(text) : null,
|
|
};
|
|
}
|
|
|
|
async function withApp(t, dataFile) {
|
|
const app = express();
|
|
app.use(express.json());
|
|
const api = express.Router();
|
|
attachShenmeiOpinionFormRoutes(api, { dataFile });
|
|
app.use('/api', api);
|
|
const server = http.createServer(app);
|
|
await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve));
|
|
t.after(() => new Promise((resolve) => server.close(resolve)));
|
|
const { port } = server.address();
|
|
return `http://127.0.0.1:${port}`;
|
|
}
|
|
|
|
test('shenmei form route appends valid records and lists them with admin header', async (t) => {
|
|
const dir = await fsPromises.mkdtemp(path.join(os.tmpdir(), 'shenmei-form-'));
|
|
const dataFile = path.join(dir, 'responses.ndjson');
|
|
const baseUrl = await withApp(t, dataFile);
|
|
|
|
const record = {
|
|
id: 'shenmei_test_1',
|
|
name: '测试用户',
|
|
goodPeople: '正向内容',
|
|
goodBehaviors: '推广做法',
|
|
badPeople: '负向内容',
|
|
badSuggestions: '改进建议',
|
|
time: '2026/7/10 12:30:00',
|
|
timestamp: 1783657800000,
|
|
};
|
|
|
|
const submitted = await request(baseUrl, 'POST', '/api/public/forms/shenmei-opinion-unified/submit', {
|
|
body: { records: [record] },
|
|
});
|
|
assert.equal(submitted.status, 200);
|
|
assert.equal(submitted.body.ok, true);
|
|
assert.equal(submitted.body.inserted, 1);
|
|
assert.equal(fs.readFileSync(dataFile, 'utf8').trim().split(/\n/).length, 1);
|
|
|
|
const listed = await request(baseUrl, 'GET', '/api/public/forms/shenmei-opinion-unified/responses', {
|
|
headers: { 'x-shenmei-admin': 'sm6666' },
|
|
});
|
|
assert.equal(listed.status, 200);
|
|
assert.equal(listed.body.data.length, 1);
|
|
assert.equal(listed.body.data[0].name, '测试用户');
|
|
});
|
|
|
|
test('shenmei form route skips duplicate submissions', async (t) => {
|
|
const dir = await fsPromises.mkdtemp(path.join(os.tmpdir(), 'shenmei-form-'));
|
|
const dataFile = path.join(dir, 'responses.ndjson');
|
|
const baseUrl = await withApp(t, dataFile);
|
|
const body = {
|
|
records: [
|
|
{
|
|
id: 'one',
|
|
name: '测试用户',
|
|
goodPeople: '正向内容',
|
|
badPeople: '负向内容',
|
|
time: '2026/7/10 12:30:00',
|
|
timestamp: 1783657800000,
|
|
},
|
|
],
|
|
};
|
|
|
|
const first = await request(baseUrl, 'POST', '/api/public/forms/shenmei-opinion-unified/submit', { body });
|
|
const second = await request(baseUrl, 'POST', '/api/public/forms/shenmei-opinion-unified/submit', { body });
|
|
|
|
assert.equal(first.body.inserted, 1);
|
|
assert.equal(second.body.inserted, 0);
|
|
assert.equal(second.body.skipped, 1);
|
|
assert.equal(fs.readFileSync(dataFile, 'utf8').trim().split(/\n/).length, 1);
|
|
});
|
|
|
|
test('shenmei form responses require admin header', async (t) => {
|
|
const dir = await fsPromises.mkdtemp(path.join(os.tmpdir(), 'shenmei-form-'));
|
|
const dataFile = path.join(dir, 'responses.ndjson');
|
|
const baseUrl = await withApp(t, dataFile);
|
|
|
|
const denied = await request(baseUrl, 'GET', '/api/public/forms/shenmei-opinion-unified/responses');
|
|
assert.equal(denied.status, 403);
|
|
});
|