104 lines
3.4 KiB
JavaScript
104 lines
3.4 KiB
JavaScript
import fs from 'node:fs'
|
|
import os from 'node:os'
|
|
import path from 'node:path'
|
|
|
|
import { describe, expect, it } from 'vitest'
|
|
|
|
import {
|
|
buildPublicRobotsTxt,
|
|
buildPublicSearchAssetPlan,
|
|
buildPublicSitemapXml,
|
|
renderPublicSearchAssets,
|
|
} from './render-public-search-assets-lib.mjs'
|
|
|
|
function createRouteRegistry() {
|
|
return [
|
|
{ path: '/', crawlable: true },
|
|
{ path: '/features', crawlable: true },
|
|
{ path: '/login', crawlable: false },
|
|
{ path: '/register', crawlable: false },
|
|
]
|
|
}
|
|
|
|
function createPolicy() {
|
|
return {
|
|
baseUrl: 'https://hypertwist.app/',
|
|
explicitDisallowPaths: ['/app', '/api/', '/auth', '/health', '/app'],
|
|
}
|
|
}
|
|
|
|
describe('buildPublicSearchAssetPlan', () => {
|
|
it('derives crawlable routes and crawler disallow rules from shared inputs', () => {
|
|
const plan = buildPublicSearchAssetPlan(createRouteRegistry(), createPolicy())
|
|
|
|
expect(plan.baseUrl).toBe('https://hypertwist.app')
|
|
expect(plan.crawlableRoutes.map((route) => route.path)).toEqual(['/', '/features'])
|
|
expect(plan.crawlerDisallowPaths).toEqual([
|
|
'/app',
|
|
'/api/',
|
|
'/auth',
|
|
'/health',
|
|
'/login',
|
|
'/register',
|
|
])
|
|
})
|
|
})
|
|
|
|
describe('buildPublicSitemapXml', () => {
|
|
it('renders crawlable routes into sitemap XML', () => {
|
|
const xml = buildPublicSitemapXml(createRouteRegistry(), createPolicy())
|
|
|
|
expect(xml).toContain('<loc>https://hypertwist.app/</loc>')
|
|
expect(xml).toContain('<loc>https://hypertwist.app/features</loc>')
|
|
expect(xml).not.toContain('/login')
|
|
expect(xml).not.toContain('/register')
|
|
})
|
|
})
|
|
|
|
describe('buildPublicRobotsTxt', () => {
|
|
it('renders the shared protected-route boundary into robots posture', () => {
|
|
const robots = buildPublicRobotsTxt(createRouteRegistry(), createPolicy())
|
|
|
|
expect(robots).toContain('User-agent: *')
|
|
expect(robots).toContain('Allow: /')
|
|
expect(robots).toContain('Disallow: /app')
|
|
expect(robots).toContain('Disallow: /api/')
|
|
expect(robots).toContain('Disallow: /auth')
|
|
expect(robots).toContain('Disallow: /health')
|
|
expect(robots).toContain('Disallow: /login')
|
|
expect(robots).toContain('Disallow: /register')
|
|
expect(robots).toContain('Sitemap: https://hypertwist.app/sitemap.xml')
|
|
})
|
|
})
|
|
|
|
describe('renderPublicSearchAssets', () => {
|
|
it('writes both sitemap and robots assets from the same authority inputs', async () => {
|
|
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'hypertwist-public-search-assets-'))
|
|
const registryPath = path.join(tempRoot, 'public-route-registry.json')
|
|
const policyPath = path.join(tempRoot, 'public-search-policy.json')
|
|
const sitemapPath = path.join(tempRoot, 'sitemap.xml')
|
|
const robotsPath = path.join(tempRoot, 'robots.txt')
|
|
|
|
fs.writeFileSync(registryPath, JSON.stringify(createRouteRegistry(), null, 2))
|
|
fs.writeFileSync(policyPath, JSON.stringify(createPolicy(), null, 2))
|
|
|
|
const rendered = await renderPublicSearchAssets({
|
|
registryPath,
|
|
policyPath,
|
|
sitemapPath,
|
|
robotsPath,
|
|
})
|
|
|
|
expect(rendered.crawlableRoutes).toHaveLength(2)
|
|
expect(rendered.crawlerDisallowPaths).toEqual([
|
|
'/app',
|
|
'/api/',
|
|
'/auth',
|
|
'/health',
|
|
'/login',
|
|
'/register',
|
|
])
|
|
expect(fs.readFileSync(sitemapPath, 'utf8')).toContain('<loc>https://hypertwist.app/features</loc>')
|
|
expect(fs.readFileSync(robotsPath, 'utf8')).toContain('Disallow: /health')
|
|
})
|
|
})
|