test-autotest-generate-cache.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. #!/usr/bin/env node
  2. import assert from 'assert';
  3. import fs from 'fs';
  4. import os from 'os';
  5. import path from 'path';
  6. import { createAutoTestPipelineTool, buildPreviewCacheKey, buildWorkspaceFingerprint, buildPromptCacheKey, buildParseCacheKey, buildGeneratedCasesCacheKey, buildPageVisibilityCacheKey } from './src/tools/autotest-pipeline.js';
  7. import { WorkflowBuilder } from './src/tools/autotest/workflow-builder.js';
  8. import { TestRunner } from './src/tools/autotest/test-runner.js';
  9. import { WorkflowExecutor } from './src/vl/workflow-executor.js';
  10. console.log('\n── AutoTest Generate Cache ──');
  11. const workDir = fs.mkdtempSync(path.join(os.tmpdir(), 'vlcode-autotest-cache-'));
  12. const vlDir = path.join(workDir, '.vl-code');
  13. fs.mkdirSync(vlDir, { recursive: true });
  14. const baseUrl = 'https://example.test/app';
  15. const projectContext = {
  16. getAllFiles() {
  17. return [];
  18. },
  19. };
  20. fs.writeFileSync(path.join(vlDir, 'project.json'), JSON.stringify({
  21. previewUrls: { App: baseUrl },
  22. }, null, 2));
  23. fs.writeFileSync(path.join(vlDir, 'last-compile.json'), JSON.stringify({
  24. gid: 4242,
  25. timestamp: '2026-03-15T16:00:00.000Z',
  26. previewUrls: { App: baseUrl },
  27. }, null, 2));
  28. const metadata = { apps: [], sections: [], components: [], services: [], databases: [] };
  29. const navElements = [];
  30. const plan = {
  31. appName: 'App',
  32. appId: 'App',
  33. homePage: '/',
  34. pages: [{ path: '/', name: 'Home', navPath: [] }],
  35. criticalPaths: [],
  36. };
  37. const target = WorkflowBuilder.planCaseGenerationTargets(plan, 4)[0];
  38. const cachedCases = [{
  39. id: 'WF_001',
  40. name: 'Cached Smoke',
  41. priority: 'P0',
  42. page: '/',
  43. _generationTargetId: target.id,
  44. steps: [
  45. { action: 'navigate', selector: baseUrl },
  46. { action: 'assert_visible', selector: 'text=Home' },
  47. ],
  48. }];
  49. const workspaceFingerprint = buildWorkspaceFingerprint(projectContext);
  50. const previewCacheKey = buildPreviewCacheKey(workDir, baseUrl);
  51. const promptCacheKey = buildPromptCacheKey({ appId: 'App', workspaceFingerprint, appMeta: metadata, navElements });
  52. const parseCacheKey = buildParseCacheKey({ appId: 'App', workspaceFingerprint, appMeta: metadata, navElements });
  53. const casesCacheKey = buildGeneratedCasesCacheKey({
  54. appId: 'App',
  55. workspaceFingerprint,
  56. appMeta: metadata,
  57. baseUrl,
  58. navElements,
  59. target,
  60. workDir,
  61. });
  62. const visibilityCacheKey = buildPageVisibilityCacheKey({
  63. previewCacheKey,
  64. appId: 'App',
  65. testPlan: plan,
  66. });
  67. fs.writeFileSync(path.join(vlDir, 'autotest-cache.json'), JSON.stringify({
  68. version: 1,
  69. navDiscovery: {
  70. [previewCacheKey]: { updatedAt: '2026-03-15T16:00:00.000Z', lastUsedAt: Date.now(), value: navElements },
  71. },
  72. pageVisibility: {
  73. [visibilityCacheKey]: { updatedAt: '2026-03-15T16:00:00.000Z', lastUsedAt: Date.now(), value: { '/': { visibleIds: [] } } },
  74. },
  75. promptFragments: {
  76. [promptCacheKey]: { updatedAt: '2026-03-15T16:00:00.000Z', lastUsedAt: Date.now(), value: 'cached metadata context' },
  77. },
  78. parsedPlans: {
  79. [parseCacheKey]: { updatedAt: '2026-03-15T16:00:00.000Z', lastUsedAt: Date.now(), value: plan },
  80. },
  81. generatedCases: {
  82. [casesCacheKey]: { updatedAt: '2026-03-15T16:00:00.000Z', lastUsedAt: Date.now(), value: cachedCases },
  83. },
  84. }, null, 2));
  85. const originalDiscoverNav = TestRunner.discoverNavElementsOnce;
  86. const originalLaunch = TestRunner.prototype.launch;
  87. const originalExecute = WorkflowExecutor.prototype.execute;
  88. TestRunner.discoverNavElementsOnce = async () => {
  89. throw new Error('nav discovery should not run on cache hit');
  90. };
  91. TestRunner.prototype.launch = async function launchShouldNotRun() {
  92. throw new Error('browser launch should not run on cache hit');
  93. };
  94. WorkflowExecutor.prototype.execute = async function executeShouldNotRun() {
  95. throw new Error('workflow execution should not run on cache hit');
  96. };
  97. try {
  98. const tool = createAutoTestPipelineTool(
  99. {
  100. workDir,
  101. autotest: { useWorkflowEngine: true, maxCases: 4 },
  102. llmProvider: 'cli',
  103. cliAvailable: true,
  104. model: 'claude-opus-4-6',
  105. },
  106. projectContext
  107. );
  108. const result = await tool.execute({ action: 'generate', baseUrl, maxCases: 4 });
  109. assert.match(result.result, /Generated 1 test cases/);
  110. assert.equal(result.testCases.length, 1, 'cached generate should return cached cases');
  111. assert.equal(result.testCases[0].name, 'Cached Smoke');
  112. } finally {
  113. TestRunner.discoverNavElementsOnce = originalDiscoverNav;
  114. TestRunner.prototype.launch = originalLaunch;
  115. WorkflowExecutor.prototype.execute = originalExecute;
  116. fs.rmSync(workDir, { recursive: true, force: true });
  117. }
  118. console.log('PASS test-autotest-generate-cache.js');