diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 33d76ce..2cb25cc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,15 +17,17 @@ jobs: - name: Checkout uses: actions/checkout@v4 + - name: Install pnpm + uses: pnpm/action-setup@v4 + - name: Setup Node uses: actions/setup-node@v4 with: node-version: ${{ matrix.node }} + cache: 'pnpm' - name: Install Dependencies - run: | - npm install -g pnpm - pnpm install + run: pnpm install - name: Run Lint run: pnpm run lint diff --git a/package.json b/package.json index a74eb68..d724083 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "engines": { "node": ">=20.0.0" }, + "packageManager": "pnpm@9.15.0", "dependencies": { "vite": "7.3.1" } diff --git a/plugins/cli/src/utils/exportRunner.ts b/plugins/cli/src/utils/exportRunner.ts index a7590cf..86451f0 100644 --- a/plugins/cli/src/utils/exportRunner.ts +++ b/plugins/cli/src/utils/exportRunner.ts @@ -3,7 +3,6 @@ import fs from 'node:fs/promises'; import chalk from 'chalk'; import { generateHtml, - SITEGRAPH_HTML, renderSitegraphMarkdown, renderSitegraphCsvNodes, renderSitegraphCsvEdges, @@ -44,19 +43,8 @@ export async function runSitegraphExports( } if (formats.includes('visualize')) { - const vizGraphData = { - ...graphData, - nodes: graphData.nodes.map((n: any) => { - const { html: _unusedHtml, ...rest } = n; - return rest; - }) - }; - const siteGraphHtml = SITEGRAPH_HTML.replace('', ` - `); - await fs.writeFile(path.join(outputDir, 'sitegraph.html'), siteGraphHtml); + const html = generateHtml(graphData, metrics); + await fs.writeFile(path.join(outputDir, 'sitegraph.html'), html); console.log(chalk.green(`Visualization saved to ${path.join(outputDir, 'sitegraph.html')}`)); } diff --git a/plugins/cli/tests/exportRunner.test.ts b/plugins/cli/tests/exportRunner.test.ts new file mode 100644 index 0000000..20cb464 --- /dev/null +++ b/plugins/cli/tests/exportRunner.test.ts @@ -0,0 +1,91 @@ +import { describe, expect, test, vi, beforeEach } from 'vitest'; +import { runSitegraphExports } from '../src/utils/exportRunner.js'; +import fs from 'node:fs/promises'; + +// Mock fs and path +vi.mock('node:fs/promises'); + +describe('runSitegraphExports', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + test('generates visualize report correctly', async () => { + const mockGraphData = { + nodes: [ + { url: 'https://example.com/', depth: 0, inLinks: 5, outLinks: 2, status: 200, html: 'Big content' } + ], + edges: [] + }; + const mockMetrics = { + totalPages: 10, + totalEdges: 20, + orphanPages: [], + sessionStats: { + pagesFetched: 5, + pagesCached: 2, + pagesSkipped: 0, + totalFound: 7 + } + }; + + const outputDir = '/tmp/reports'; + const url = 'https://example.com'; + + await runSitegraphExports( + ['visualize'], + outputDir, + url, + mockGraphData, + mockMetrics, + {} // graphObj mock + ); + + expect(fs.mkdir).toHaveBeenCalledWith(outputDir, { recursive: true }); + + const writeFileCalls = (fs.writeFile as any).mock.calls; + const visualizeCall = writeFileCalls.find((call: any[]) => call[0].endsWith('sitegraph.html')); + + expect(visualizeCall).toBeDefined(); + const content = visualizeCall[1]; + + // Check for injected data + expect(content).toContain('window.GRAPH_DATA ='); + expect(content).toContain('window.METRICS_DATA ='); + + // Verify metrics injection + // Handles both minified (generateHtml) and pretty-printed (current visualize) + expect(content).toMatch(/"totalPages":\s*10/); + + // Verify graph injection + expect(content).toMatch(/"url":\s*"https:\/\/example\.com\/"/); + + // Verify HTML property removed (if using generateHtml or current implementation) + // Current implementation: + // const { html: _unusedHtml, ...rest } = n; + expect(content).not.toContain('Big content'); + }); + + test('generates html report correctly', async () => { + const mockGraphData = { + nodes: [], + edges: [] + }; + const mockMetrics = {}; + const outputDir = '/tmp/reports'; + const url = 'https://example.com'; + + await runSitegraphExports( + ['html'], + outputDir, + url, + mockGraphData, + mockMetrics, + {} + ); + + const writeFileCalls = (fs.writeFile as any).mock.calls; + const htmlCall = writeFileCalls.find((call: any[]) => call[0].endsWith('graph.html')); + expect(htmlCall).toBeDefined(); + }); +}); diff --git a/plugins/core/src/crawler/crawler.ts b/plugins/core/src/crawler/crawler.ts index 124c7fa..05ddae2 100644 --- a/plugins/core/src/crawler/crawler.ts +++ b/plugins/core/src/crawler/crawler.ts @@ -3,7 +3,7 @@ import pLimit from 'p-limit'; import chalk from 'chalk'; import robotsParser from 'robots-parser'; import { Graph } from '../graph/graph.js'; -import { Fetcher, FetchOptions } from './fetcher.js'; +import { Fetcher } from './fetcher.js'; import { Parser } from './parser.js'; import { Sitemap } from './sitemap.js'; import { normalizeUrl } from './normalize.js'; diff --git a/plugins/core/tests/audit/transport.test.ts b/plugins/core/tests/audit/transport.test.ts index 6fbb770..44ff7aa 100644 --- a/plugins/core/tests/audit/transport.test.ts +++ b/plugins/core/tests/audit/transport.test.ts @@ -1,7 +1,6 @@ import { describe, it, expect, vi, afterEach } from 'vitest'; import { analyzeTransport } from '../../src/audit/transport.js'; import https from 'node:https'; -import http from 'node:http'; import tls from 'node:tls'; import { EventEmitter } from 'events';