startup-preview-smoke-test.js 4.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. 'use strict';
  2. const assert = require('assert/strict');
  3. const fs = require('fs');
  4. const os = require('os');
  5. const path = require('path');
  6. const { spawnSync } = require('child_process');
  7. const { resolveWorkspaceRoot, workspaceIdentity } = require('../mcp/src/core/runtime-context');
  8. const { buildStartupSummary, startupAssistantMessage } = require('../mcp/src/core/startup-summary');
  9. const { runtimeIsRunning } = require('./preview-dashboard');
  10. const ROOT = path.resolve(__dirname, '..');
  11. function testRuntimeContext(tempRoot) {
  12. const installedPackage = path.join(tempRoot, '.claude', 'plugins', 'qiwei-assistant');
  13. fs.mkdirSync(installedPackage, { recursive: true });
  14. assert.equal(resolveWorkspaceRoot({ packageRoot: installedPackage, cwd: installedPackage }), tempRoot);
  15. assert.equal(resolveWorkspaceRoot({ packageRoot: ROOT, workspaceRoot: tempRoot }), tempRoot);
  16. assert.match(workspaceIdentity(tempRoot), /^[0-9a-f]{12}$/);
  17. }
  18. function testStartupSummary() {
  19. const offline = buildStartupSummary(
  20. { summary: { authConfigured: true, subscribed: true } },
  21. { data: { account: { configured: true, online: false }, listener: { running: false }, config: { allowedSenderCount: 1 } } },
  22. );
  23. assert.equal(offline.ready, false);
  24. assert.equal(offline.nextAction, '在工作台点击“恢复登录”');
  25. assert.match(startupAssistantMessage(offline), /企微账号待处理/);
  26. const ready = buildStartupSummary(
  27. { summary: { authConfigured: true, subscribed: true } },
  28. { data: { account: { configured: true, online: true }, listener: { running: true }, config: { allowedSenderCount: 1 } } },
  29. );
  30. assert.equal(ready.ready, true);
  31. assert.match(ready.nextAction, /可以进入智能会话/);
  32. }
  33. function testWorkspaceInstall(tempRoot) {
  34. const target = path.join(tempRoot, 'customer-project');
  35. fs.mkdirSync(target, { recursive: true });
  36. fs.writeFileSync(path.join(target, '.gitignore'), '# Customer rules\ncustomer-cache/\n', 'utf8');
  37. const result = spawnSync(process.execPath, [path.join(ROOT, 'install.js'), 'workspace', target, '--skip-install'], {
  38. cwd: ROOT,
  39. encoding: 'utf8',
  40. windowsHide: true,
  41. });
  42. assert.equal(result.status, 0, result.stderr || result.stdout);
  43. const mcp = JSON.parse(fs.readFileSync(path.join(target, '.mcp.json'), 'utf8'));
  44. const config = mcp.mcpServers?.['qiwei-assistant'];
  45. assert.equal(config.cwd, target);
  46. assert.equal(config.env?.QIWEI_WORKSPACE_ROOT, target);
  47. assert.equal(config.env?.QIWEI_OUTPUTS_DIR, path.join(target, 'outputs'));
  48. assert.equal(config.env?.CLAUDE_CODE_WORKDIR, target);
  49. assert(fs.existsSync(path.join(target, '.claude', 'plugins', 'qiwei-assistant', 'scripts', 'preview-dashboard.js')));
  50. assert(!fs.existsSync(path.join(target, '.claude', 'plugins', 'qiwei-assistant', '.env.local')));
  51. const gitignorePath = path.join(target, '.gitignore');
  52. const firstGitignore = fs.readFileSync(gitignorePath, 'utf8');
  53. assert.match(firstGitignore, /# Customer rules\ncustomer-cache\//);
  54. assert.match(firstGitignore, /# >>> qiwei-assistant managed ignores >>>/);
  55. assert.match(firstGitignore, /\*\*\/\.env\.local/);
  56. assert.match(firstGitignore, /outputs\/messages\/\*\.db/);
  57. const repeated = spawnSync(process.execPath, [path.join(ROOT, 'install.js'), 'workspace', target, '--skip-install'], {
  58. cwd: ROOT,
  59. encoding: 'utf8',
  60. windowsHide: true,
  61. });
  62. assert.equal(repeated.status, 0, repeated.stderr || repeated.stdout);
  63. const secondGitignore = fs.readFileSync(gitignorePath, 'utf8');
  64. assert.equal((secondGitignore.match(/# >>> qiwei-assistant managed ignores >>>/g) || []).length, 1);
  65. assert.match(secondGitignore, /# Customer rules\ncustomer-cache\//);
  66. }
  67. function testIndependentRuntimeDetection() {
  68. assert.equal(runtimeIsRunning({ pid: 123, status: 'running' }, pid => pid === 123), true);
  69. assert.equal(runtimeIsRunning({ pid: 123, status: 'stopped' }, () => true), false);
  70. assert.equal(runtimeIsRunning({ pid: 123, status: 'running' }, () => false), false);
  71. }
  72. function main() {
  73. const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'qiwei-preview-smoke-'));
  74. try {
  75. testRuntimeContext(tempRoot);
  76. testStartupSummary();
  77. testWorkspaceInstall(tempRoot);
  78. testIndependentRuntimeDetection();
  79. } finally {
  80. fs.rmSync(tempRoot, { recursive: true, force: true });
  81. }
  82. process.stdout.write(`${JSON.stringify({ status: 'ok', checks: 4 }, null, 2)}\n`);
  83. }
  84. try { main(); }
  85. catch (error) {
  86. process.stderr.write(`${error.message}\n`);
  87. process.exit(1);
  88. }