feat(excel-analyst): restore enhanced report HTML template for excel_report
Memind CI / Test, build, and release guards (push) Successful in 4m34s
Memind CI / Test, build, and release guards (push) Successful in 4m34s
Move report generation into excel-report-html.mjs so excel_report matches the hand-enhanced layout with KPI cards, charts, and insight cards, while keeping fact-model validation in the analysis engine. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -238,6 +238,9 @@ test('Excel engine inspects, analyzes, and charts without changing source workbo
|
||||
});
|
||||
const reportHtml = fs.readFileSync(path.join(root, report.outputPath), 'utf8');
|
||||
assert.match(reportHtml, /excel-report-valid/);
|
||||
assert.match(reportHtml, /stats-grid/);
|
||||
assert.match(reportHtml, /chart-bar/);
|
||||
assert.match(reportHtml, /insight-card/);
|
||||
assert.match(reportHtml, /<script>alert\("cell"\)<\/script>/);
|
||||
assert.doesNotMatch(reportHtml, /<script>alert/);
|
||||
|
||||
@@ -280,6 +283,44 @@ test('Excel engine inspects, analyzes, and charts without changing source workbo
|
||||
);
|
||||
});
|
||||
|
||||
test('Excel engine reports the exact supported format boundary for XLSX, XLS, and CSV', async () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'excel-format-contract-'));
|
||||
await createWorkbook(root);
|
||||
const engine = createExcelAnalysisEngine({ workspaceRoot: root });
|
||||
|
||||
assert.equal((await engine.inspect({ path: 'oa/sales.xlsx' })).format, 'xlsx');
|
||||
for (const unsupportedPath of ['oa/legacy.xls', 'oa/export.csv']) {
|
||||
await assert.rejects(
|
||||
engine.inspect({ path: unsupportedPath }),
|
||||
(error) => (
|
||||
error?.code === 'UNSUPPORTED_FORMAT' &&
|
||||
/Phase 1 只支持 \.xlsx 文件/.test(error.message)
|
||||
),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test('Excel analysis keeps source workbooks private and isolated to one user workspace', async () => {
|
||||
const userOneRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'excel-user-one-'));
|
||||
const userTwoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'excel-user-two-'));
|
||||
const userOneWorkbook = await createWorkbook(userOneRoot);
|
||||
const userOneEngine = createExcelAnalysisEngine({ workspaceRoot: userOneRoot });
|
||||
const userTwoEngine = createExcelAnalysisEngine({ workspaceRoot: userTwoRoot });
|
||||
|
||||
await userOneEngine.inspect({ path: 'oa/sales.xlsx' });
|
||||
assert.equal(fs.existsSync(path.join(userOneRoot, 'public', 'sales.xlsx')), false);
|
||||
assert.equal(fs.existsSync(userOneWorkbook), true);
|
||||
|
||||
await assert.rejects(
|
||||
userTwoEngine.inspect({ path: userOneWorkbook }),
|
||||
(error) => error?.code === 'INVALID_PATH',
|
||||
);
|
||||
await assert.rejects(
|
||||
userTwoEngine.inspect({ path: 'oa/sales.xlsx' }),
|
||||
(error) => error?.code === 'FILE_NOT_FOUND',
|
||||
);
|
||||
});
|
||||
|
||||
test('Excel MCP exposes the Phase 1 analysis tools and verified report generator', async (t) => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'excel-mcp-'));
|
||||
await createWorkbook(root);
|
||||
|
||||
Reference in New Issue
Block a user