package scripts import ( "os" "os/exec" "path/filepath" "runtime" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestHydrateAssetsForceFetchesRemoteAssetBranches(t *testing.T) { tempDir := t.TempDir() remoteRepo := filepath.Join(tempDir, "remote") localRepo := filepath.Join(tempDir, "local") require.NoError(t, os.MkdirAll(localRepo, 0o755)) git(t, tempDir, "init", "--bare", remoteRepo) oldStaticDir := filepath.Join(tempDir, "old-static") writeStaticAssets(t, oldStaticDir, "old static") oldStaticCommit := commitBareAssetTree( t, remoteRepo, oldStaticDir, "old static assets", ) updateBareBranch(t, remoteRepo, "docs-assets", oldStaticCommit) git(t, localRepo, "init") git(t, localRepo, "remote", "add", "origin", remoteRepo) git(t, localRepo, "fetch", "origin", "docs-assets:refs/remotes/origin/docs-assets") newStaticDir := filepath.Join(tempDir, "new-static") writeStaticAssets(t, newStaticDir, "new static") newStaticCommit := commitBareAssetTree( t, remoteRepo, newStaticDir, "new static assets", ) updateBareBranch(t, remoteRepo, "docs-assets", newStaticCommit) generatedDir := filepath.Join(tempDir, "generated") writeGeneratedAssets(t, generatedDir, "generated") generatedCommit := commitBareAssetTree( t, remoteRepo, generatedDir, "generated assets", ) updateBareBranch(t, remoteRepo, "docs-generated-assets", generatedCommit) docsAssetsDir := filepath.Join(localRepo, "docs", "assets") require.NoError(t, os.MkdirAll(docsAssetsDir, 0o755)) writeStaticAssets(t, filepath.Join(docsAssetsDir, "static"), "stale local static") writeAssetFiles( t, filepath.Join(docsAssetsDir, "generated"), []string{"screenshots/dashboard.png"}, "stale local generated", ) script, err := os.ReadFile(filepath.Join("..", "docs", "assets", "hydrate-assets.sh")) require.NoError(t, err) scriptPath := filepath.Join(docsAssetsDir, "hydrate-assets.sh") require.NoError(t, os.WriteFile(scriptPath, script, 0o755)) cmd := exec.Command("bash", scriptPath) cmd.Dir = localRepo output, err := cmd.CombinedOutput() require.NoError(t, err, string(output)) logo, err := os.ReadFile(filepath.Join(localRepo, "docs", "assets", "static", "og-image.png")) require.NoError(t, err) assert.Equal(t, "new static", strings.TrimRight(string(logo), "\r\n")) screenshot, err := os.ReadFile(filepath.Join(localRepo, "docs", "assets", "generated", "screenshots", "dashboard.png")) require.NoError(t, err) assert.Equal(t, "generated", strings.TrimRight(string(screenshot), "\r\n")) } func TestAssetPublishersRejectUnexpectedFiles(t *testing.T) { cases := []struct { name string scriptRel string write func(*testing.T, string, string) }{ { name: "static", scriptRel: filepath.Join("docs", "assets", "update-static-assets-branch.sh"), write: writeStaticAssets, }, { name: "generated", scriptRel: filepath.Join("docs", "screenshots", "update-generated-assets-branch.sh"), write: writeGeneratedAssets, }, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { tempDir := t.TempDir() repo := filepath.Join(tempDir, "repo") sourceDir := filepath.Join(tempDir, "source") require.NoError(t, os.MkdirAll(repo, 0o755)) git(t, repo, "init") tc.write(t, sourceDir, "asset") require.NoError(t, os.WriteFile(filepath.Join(sourceDir, ".env.local"), []byte("TOKEN=secret\n"), 0o600)) scriptPath := installScript(t, repo, tc.scriptRel) cmd := exec.Command("bash", scriptPath, "--source", sourceDir) cmd.Dir = repo output, err := cmd.CombinedOutput() require.Error(t, err, string(output)) assert.Contains(t, string(output), "unexpected") assert.Contains(t, string(output), ".env.local") }) } } func TestCheckDocsRejectsCorruptedMarkdownSyntax(t *testing.T) { tempDir := t.TempDir() repo := filepath.Join(tempDir, "repo") require.NoError(t, os.MkdirAll(repo, 0o755)) checkScript := installScript(t, repo, filepath.Join("scripts", "check-docs.sh")) installScript(t, repo, filepath.Join("docs", "scripts", "check_markdown_sources.py")) require.NoError(t, os.MkdirAll(filepath.Join(repo, "docs", "assets"), 0o755)) require.NoError(t, os.WriteFile( filepath.Join(repo, "docs", "assets", "hydrate-assets.sh"), []byte("#!/usr/bin/env bash\nset -euo pipefail\n"), 0o755, )) require.NoError(t, os.WriteFile( filepath.Join(repo, "docs", "activity.md"), []byte(strings.Join([]string{ "______________________________________________________________________", "", "## title: Activity description: Activity, concurrency, and session-time reporting in AgentsView", "", "!!! warning \"Experimental\" This warning was collapsed by a formatter.", "", }, "\n")), 0o644, )) cmd := exec.Command("bash", checkScript) cmd.Dir = repo pythonPath := requireRunnablePython3(t) cmd.Env = append(envWithout("PATH", "PYTHON"), "PYTHON="+pythonPath, "PATH=/usr/bin:/bin") output, err := cmd.CombinedOutput() require.Error(t, err, string(output)) assert.Contains(t, string(output), "docs markdown") assert.Contains(t, string(output), "activity.md") } func TestCheckDocsRequiresRipgrepForMediaReferenceChecks(t *testing.T) { tempDir := t.TempDir() repo := filepath.Join(tempDir, "repo") require.NoError(t, os.MkdirAll(repo, 0o755)) checkScript := installScript(t, repo, filepath.Join("scripts", "check-docs.sh")) installScript(t, repo, filepath.Join("docs", "scripts", "check_markdown_sources.py")) require.NoError(t, os.MkdirAll(filepath.Join(repo, "docs", "assets"), 0o755)) require.NoError(t, os.WriteFile( filepath.Join(repo, "docs", "assets", "hydrate-assets.sh"), []byte("#!/usr/bin/env bash\nset -euo pipefail\n"), 0o755, )) require.NoError(t, os.WriteFile( filepath.Join(repo, "docs", "activity.md"), []byte(strings.Join([]string{ "---", "title: Activity", "description: Activity docs", "---", "", "Valid docs page.", "", }, "\n")), 0o644, )) bashPath, err := exec.LookPath("bash") require.NoError(t, err) cmd := exec.Command(bashPath, checkScript) cmd.Dir = repo pythonPath := requireRunnablePython3(t) emptyBin := filepath.Join(tempDir, "empty-bin") require.NoError(t, os.MkdirAll(emptyBin, 0o755)) cmd.Env = append(envWithout("PATH", "PYTHON"), "PYTHON="+pythonPath, "PATH="+emptyBin) output, err := cmd.CombinedOutput() require.Error(t, err, string(output)) assert.Contains(t, string(output), "rg not found") } func TestBuiltSiteCheckRequiresMarkdownCompanions(t *testing.T) { tempDir := t.TempDir() repo := filepath.Join(tempDir, "repo") require.NoError(t, os.MkdirAll(repo, 0o755)) checkScript := installScript(t, repo, filepath.Join("docs", "scripts", "check_built_site.py")) writeMinimalBuiltDocsSite(t, filepath.Join(repo, "docs", "site")) pythonPath := requireRunnablePython3(t) cmd := exec.Command(pythonPath, checkScript) cmd.Dir = filepath.Join(repo, "docs") output, err := cmd.CombinedOutput() require.Error(t, err, string(output)) assert.Contains(t, string(output), "missing route markdown /") } func TestBuiltSiteCheckRejectsSvgUsePlainHref(t *testing.T) { tests := []struct { name string useTag string wantPass bool }{ { name: "plain href breaks instant navigation", useTag: ``, wantPass: false, }, { name: "xlink href is allowed", useTag: ``, wantPass: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tempDir := t.TempDir() repo := filepath.Join(tempDir, "repo") require.NoError(t, os.MkdirAll(repo, 0o755)) checkScript := installScript(t, repo, filepath.Join("docs", "scripts", "check_built_site.py")) siteDir := filepath.Join(repo, "docs", "site") writeMinimalBuiltDocsSite(t, siteDir) writeBuiltSiteMarkdownCompanions(t, siteDir) indexPath := filepath.Join(siteDir, "index.html") page, err := os.ReadFile(indexPath) require.NoError(t, err) patched := strings.Replace(string(page), "
`) b.WriteString(`Discord`) for _, id := range ids { b.WriteString(`", tt.useTag+"", 1)
require.NoError(t, os.WriteFile(indexPath, []byte(patched), 0o644))
pythonPath := requireRunnablePython3(t)
cmd := exec.Command(pythonPath, checkScript)
cmd.Dir = filepath.Join(repo, "docs")
output, err := cmd.CombinedOutput()
if tt.wantPass {
require.NoError(t, err, string(output))
assert.Contains(t, string(output), "built site checks passed")
} else {
require.Error(t, err, string(output))
assert.Contains(t, string(output), "Use xlink:href instead")
}
})
}
}
func TestZensicalDocsBuildExcludesScreenshotToolchain(t *testing.T) {
tempDir := t.TempDir()
repo := filepath.Join(tempDir, "repo")
docsDir := filepath.Join(repo, "docs")
require.NoError(t, os.MkdirAll(docsDir, 0o755))
scriptPath := installScript(t, repo,
filepath.Join("docs", "zensical-docs.sh"))
require.NoError(t, os.WriteFile(
filepath.Join(docsDir, "zensical.toml"),
[]byte("[project]\ndocs_dir = \"docs\"\nsite_dir = \"site\"\n"),
0o644,
))
require.NoError(t, os.WriteFile(
filepath.Join(docsDir, "index.md"),
[]byte("---\ntitle: Home\ndescription: Home page\n---\n"),
0o644,
))
toolchainFile := filepath.Join(
docsDir, "screenshots", "node_modules", "playwright-core",
"trace-viewer.html",
)
require.NoError(t, os.MkdirAll(filepath.Dir(toolchainFile), 0o755))
require.NoError(t, os.WriteFile(
toolchainFile, []byte("private screenshot toolchain\n"), 0o644,
))
testResultFile := filepath.Join(
docsDir, "screenshots", "test-results", "trace.zip",
)
require.NoError(t, os.MkdirAll(filepath.Dir(testResultFile), 0o755))
require.NoError(t, os.WriteFile(
testResultFile, []byte("private test trace\n"), 0o644,
))
publicScreenshot := filepath.Join(
docsDir, "assets", "generated", "screenshots", "dashboard.png",
)
require.NoError(t, os.MkdirAll(filepath.Dir(publicScreenshot), 0o755))
require.NoError(t, os.WriteFile(
publicScreenshot, []byte("public screenshot\n"), 0o644,
))
fakeZensical := filepath.Join(docsDir, ".venv", "bin", "zensical")
require.NoError(t, os.MkdirAll(filepath.Dir(fakeZensical), 0o755))
require.NoError(t, os.WriteFile(fakeZensical, []byte(`#!/usr/bin/env bash
set -euo pipefail
public_docs="$(find . -maxdepth 1 -type d -name 'zensical-public-docs.*' -print -quit)"
mkdir -p site
cp -R "$public_docs"/. site/
`), 0o755))
cmd := exec.Command("bash", scriptPath, "build")
cmd.Dir = docsDir
output, err := cmd.CombinedOutput()
require.NoError(t, err, string(output))
assert.FileExists(t, filepath.Join(docsDir, "site", "index.md"))
assert.FileExists(t, filepath.Join(
docsDir, "site", "assets", "generated", "screenshots",
"dashboard.png",
))
assert.NoFileExists(t, filepath.Join(
docsDir, "site", "screenshots", "node_modules", "playwright-core",
"trace-viewer.html",
))
assert.NoFileExists(t, filepath.Join(
docsDir, "site", "screenshots", "test-results", "trace.zip",
))
}
func installScript(t *testing.T, repo, scriptRel string) string {
t.Helper()
script, err := os.ReadFile(filepath.Join("..", scriptRel))
require.NoError(t, err)
scriptPath := filepath.Join(repo, scriptRel)
require.NoError(t, os.MkdirAll(filepath.Dir(scriptPath), 0o755))
require.NoError(t, os.WriteFile(scriptPath, script, 0o755))
return scriptPath
}
func requireRunnablePython3(t *testing.T) string {
t.Helper()
pythonPath, err := exec.LookPath("python3")
if err != nil {
t.Skipf("python3 not available on PATH: %v", err)
}
cmd := exec.Command(pythonPath, "--version")
if out, err := cmd.CombinedOutput(); err != nil {
if runtime.GOOS == "windows" {
t.Skipf("python3 is not runnable: %v\n%s", err, out)
}
require.NoError(t, err, "python3 --version\n%s", out)
}
return pythonPath
}
var builtDocsRoutes = []string{
"/",
"/quickstart/",
"/usage/",
"/activity/",
"/recent-edits/",
"/session-intelligence/",
"/mcp/",
"/token-usage/",
"/chat-import/",
"/insights/",
"/commands/",
"/stats/",
"/session-api/",
"/configuration/",
"/remote-access/",
"/pg-sync/",
"/duckdb/",
"/changelog/",
}
func writeMinimalBuiltDocsSite(t *testing.T, siteDir string) {
t.Helper()
for _, route := range builtDocsRoutes {
path := filepath.Join(siteDir, strings.Trim(route, "/"), "index.html")
if route == "/" {
path = filepath.Join(siteDir, "index.html")
}
ids := []string{}
switch route {
case "/configuration/":
ids = append(ids, "session-discovery")
case "/token-usage/":
ids = append(ids, "how-it-compares-to-ccusage")
case "/session-api/":
ids = append(ids, "agentsview-session-usage")
}
require.NoError(t, os.MkdirAll(filepath.Dir(path), 0o755))
require.NoError(t, os.WriteFile(path, []byte(minimalDocsHTML(ids)), 0o644))
}
require.NoError(t, os.WriteFile(filepath.Join(siteDir, "404.html"), []byte(minimalDocsHTML(nil)), 0o644))
require.NoError(t, os.WriteFile(
filepath.Join(siteDir, "sitemap.xml"),
[]byte("
`) b.WriteString(``) b.WriteString(``) b.WriteString(``) b.WriteString(``) b.WriteString(``) b.WriteString(``) b.WriteString(``) b.WriteString(`