diff --git a/docs-site/build_dir b/docs-site/build_dir deleted file mode 100644 index e5c7b92c..00000000 --- a/docs-site/build_dir +++ /dev/null @@ -1 +0,0 @@ -export BUILD_DIR="./build/CapRover" \ No newline at end of file diff --git a/docs-site/package.json b/docs-site/package.json index b41ae6d8..5ae0fb01 100644 --- a/docs-site/package.json +++ b/docs-site/package.json @@ -8,7 +8,7 @@ "preclean-build": "npm run prepare-content", "start": "docusaurus start", "build": "docusaurus build", - "clean-build": "docusaurus clear && docusaurus build && cp ./CNAME ./build/CNAME", + "clean-build": "docusaurus clear && docusaurus build", "serve": "docusaurus serve", "write-translations": "docusaurus write-translations --locale en && node ../scripts/capture-docs-ui.js" }, diff --git a/docs-site/publish-from-actions.sh b/docs-site/publish-from-actions.sh index b1786f3d..e4e90dfa 100755 --- a/docs-site/publish-from-actions.sh +++ b/docs-site/publish-from-actions.sh @@ -26,9 +26,7 @@ set -e -if [ -z "${BUILD_DIR:-}" ]; then - source ./build_dir -fi +: "${BUILD_DIR:?BUILD_DIR is required}" echo "#################################################" echo "Changing directory to 'BUILD_DIR' $BUILD_DIR ..." diff --git a/docs-site/CNAME b/docs-site/static/CNAME similarity index 100% rename from docs-site/CNAME rename to docs-site/static/CNAME diff --git a/marketing-site/app/sitemap.ts b/marketing-site/app/sitemap.ts index f9e0eeb9..70bcd804 100644 --- a/marketing-site/app/sitemap.ts +++ b/marketing-site/app/sitemap.ts @@ -1,20 +1,13 @@ import type { MetadataRoute } from "next"; import { DEFAULT_LOCALE, ENABLED_LOCALES, localizedPath } from "@/i18n/config"; +import routes from "@/routes.json"; export const dynamic = "force-static"; export default function sitemap(): MetadataRoute.Sitemap { const base = "https://caprover.com"; const lastModified = new Date("2026-08-20"); - const paths = [ - { path: "/", priority: 1 }, - { path: "/compare/", priority: 0.7 }, - { path: "/compare/coolify/", priority: 0.7 }, - { path: "/compare/dokploy/", priority: 0.7 }, - { path: "/compare/dokku/", priority: 0.6 }, - ]; - - return paths.flatMap(({ path, priority }) => { + return Object.values(routes).flatMap(({ path, sitemapPriority }) => { const defaultUrl = `${base}${localizedPath(path, DEFAULT_LOCALE)}`; const languages = Object.fromEntries( ENABLED_LOCALES.map((locale) => [ @@ -28,7 +21,7 @@ export default function sitemap(): MetadataRoute.Sitemap { url: `${base}${localizedPath(path, locale.code)}`, lastModified, changeFrequency: "monthly" as const, - priority, + priority: sitemapPriority, alternates, })); }); diff --git a/marketing-site/features/comparison/components.tsx b/marketing-site/features/comparison/components.tsx index b4b8b048..11b76ea9 100644 --- a/marketing-site/features/comparison/components.tsx +++ b/marketing-site/features/comparison/components.tsx @@ -7,6 +7,7 @@ import { } from "@/i18n/config"; import { getMessages, messageList } from "@/i18n/messages"; import { LocaleSwitcher } from "@/app/locale-switcher"; +import routes from "@/routes.json"; import { getComparisonData, type ComparisonRow, @@ -28,7 +29,7 @@ function Logo({ locale }: { locale: Locale }) { return ( - {copy.navigation.hub} + + {copy.navigation.hub} + {copy.navigation.docs} {copy.navigation.github} ( ].path, + locale, + )} key={link.key} > {copy.kicker} diff --git a/marketing-site/features/comparison/coolify/page-content.tsx b/marketing-site/features/comparison/coolify/page-content.tsx index 9f80b5bb..0da33fa5 100644 --- a/marketing-site/features/comparison/coolify/page-content.tsx +++ b/marketing-site/features/comparison/coolify/page-content.tsx @@ -1,5 +1,6 @@ import { DEFAULT_LOCALE, docsUrl, type Locale } from "@/i18n/config"; import { getMessages, messageList } from "@/i18n/messages"; +import routes from "@/routes.json"; import { ChoiceGrid, ComparePage, @@ -23,7 +24,7 @@ export function CoolifyComparisonPage({ const copy = getMessages(locale).comparisonPages.coolify; const sources = copy.sourceLabels; return ( - +
{copy.hero.verdictTitle} diff --git a/marketing-site/features/comparison/dokku/page-content.tsx b/marketing-site/features/comparison/dokku/page-content.tsx index e9ce4bbc..44bd15ce 100644 --- a/marketing-site/features/comparison/dokku/page-content.tsx +++ b/marketing-site/features/comparison/dokku/page-content.tsx @@ -1,5 +1,6 @@ import { DEFAULT_LOCALE, docsUrl, type Locale } from "@/i18n/config"; import { getMessages, messageList } from "@/i18n/messages"; +import routes from "@/routes.json"; import { ChoiceGrid, ComparePage, @@ -23,7 +24,7 @@ export function DokkuComparisonPage({ const copy = getMessages(locale).comparisonPages.dokku; const sources = copy.sourceLabels; return ( - +
{copy.hero.verdictTitle} diff --git a/marketing-site/features/comparison/dokploy/page-content.tsx b/marketing-site/features/comparison/dokploy/page-content.tsx index db9cf92c..347a1384 100644 --- a/marketing-site/features/comparison/dokploy/page-content.tsx +++ b/marketing-site/features/comparison/dokploy/page-content.tsx @@ -1,5 +1,6 @@ import { DEFAULT_LOCALE, docsUrl, type Locale } from "@/i18n/config"; import { getMessages, messageList } from "@/i18n/messages"; +import routes from "@/routes.json"; import { ChoiceGrid, ComparePage, @@ -23,7 +24,7 @@ export function DokployComparisonPage({ const copy = getMessages(locale).comparisonPages.dokploy; const sources = copy.sourceLabels; return ( - +
{copy.hero.verdictTitle} diff --git a/marketing-site/features/comparison/page-content.tsx b/marketing-site/features/comparison/page-content.tsx index eda9f9f5..7123d023 100644 --- a/marketing-site/features/comparison/page-content.tsx +++ b/marketing-site/features/comparison/page-content.tsx @@ -1,5 +1,6 @@ import { DEFAULT_LOCALE, docsUrl, type Locale } from "@/i18n/config"; import { getMessages } from "@/i18n/messages"; +import routes from "@/routes.json"; import { ComparePage, ComparisonPrinciples, @@ -21,7 +22,7 @@ export function ComparisonHubPage({ const copy = getMessages(locale).comparisonPages.hub; const sources = copy.sourceLabels; return ( - + diff --git a/marketing-site/i18n/metadata.ts b/marketing-site/i18n/metadata.ts index a4bbc73b..e1ea26b4 100644 --- a/marketing-site/i18n/metadata.ts +++ b/marketing-site/i18n/metadata.ts @@ -1,4 +1,5 @@ import type { Metadata } from "next"; +import routes from "../routes.json"; import { getFlatMessages, type MessageKey } from "./messages"; import { DEFAULT_LOCALE, @@ -11,27 +12,27 @@ const SITE = "https://caprover.com"; const PAGE_METADATA = { home: { - path: "/", + path: routes.home.path, titleKey: "homepage.metadata.title", descriptionKey: "homepage.metadata.description", }, comparisonHub: { - path: "/compare/", + path: routes.comparisonHub.path, titleKey: "comparisonPages.hub.metadata.title", descriptionKey: "comparisonPages.hub.metadata.description", }, coolify: { - path: "/compare/coolify/", + path: routes.coolify.path, titleKey: "comparisonPages.coolify.metadata.title", descriptionKey: "comparisonPages.coolify.metadata.description", }, dokploy: { - path: "/compare/dokploy/", + path: routes.dokploy.path, titleKey: "comparisonPages.dokploy.metadata.title", descriptionKey: "comparisonPages.dokploy.metadata.description", }, dokku: { - path: "/compare/dokku/", + path: routes.dokku.path, titleKey: "comparisonPages.dokku.metadata.title", descriptionKey: "comparisonPages.dokku.metadata.description", }, diff --git a/marketing-site/routes.json b/marketing-site/routes.json new file mode 100644 index 00000000..8a91e8fb --- /dev/null +++ b/marketing-site/routes.json @@ -0,0 +1,22 @@ +{ + "home": { + "path": "/", + "sitemapPriority": 1 + }, + "comparisonHub": { + "path": "/compare/", + "sitemapPriority": 0.7 + }, + "coolify": { + "path": "/compare/coolify/", + "sitemapPriority": 0.7 + }, + "dokploy": { + "path": "/compare/dokploy/", + "sitemapPriority": 0.7 + }, + "dokku": { + "path": "/compare/dokku/", + "sitemapPriority": 0.6 + } +} diff --git a/marketing-site/tests/static-export.test.mjs b/marketing-site/tests/static-export.test.mjs index 41bbcd5e..2ee0d281 100644 --- a/marketing-site/tests/static-export.test.mjs +++ b/marketing-site/tests/static-export.test.mjs @@ -10,13 +10,18 @@ const expectedAssets = [ "caprover-workflow.png", "slack-icon.png", ]; -const routes = [ - { path: "/", titleKey: "homepage.hero.titleLine1" }, - { path: "/compare/", titleKey: "comparisonPages.hub.hero.title" }, - { path: "/compare/coolify/", titleKey: "comparisonPages.coolify.hero.title" }, - { path: "/compare/dokploy/", titleKey: "comparisonPages.dokploy.hero.title" }, - { path: "/compare/dokku/", titleKey: "comparisonPages.dokku.hero.title" }, -]; +const routeManifest = JSON.parse(await readFile("routes.json", "utf8")); +const routeTitleKeys = { + home: "homepage.hero.titleLine1", + comparisonHub: "comparisonPages.hub.hero.title", + coolify: "comparisonPages.coolify.hero.title", + dokploy: "comparisonPages.dokploy.hero.title", + dokku: "comparisonPages.dokku.hero.title", +}; +const routes = Object.entries(routeManifest).map(([name, route]) => ({ + path: route.path, + titleKey: routeTitleKeys[name], +})); const basePath = process.env.NEXT_PUBLIC_BASE_PATH ?? ""; const assetPath = "homepage-assets"; const locales = JSON.parse(await readFile("../content/locales.json", "utf8")); @@ -93,11 +98,26 @@ test("exports complete localized website routes", async () => { }); test("keeps comparison regressions covered across locales", async () => { - const homepage = await readFile("out/index.html", "utf8"); - const hub = await readFile("out/compare/index.html", "utf8"); - const coolify = await readFile("out/compare/coolify/index.html", "utf8"); - const dokploy = await readFile("out/compare/dokploy/index.html", "utf8"); - const dokku = await readFile("out/compare/dokku/index.html", "utf8"); + const homepage = await readFile( + `out${routeManifest.home.path}index.html`, + "utf8", + ); + const hub = await readFile( + `out${routeManifest.comparisonHub.path}index.html`, + "utf8", + ); + const coolify = await readFile( + `out${routeManifest.coolify.path}index.html`, + "utf8", + ); + const dokploy = await readFile( + `out${routeManifest.dokploy.path}index.html`, + "utf8", + ); + const dokku = await readFile( + `out${routeManifest.dokku.path}index.html`, + "utf8", + ); const sitemap = await readFile("out/sitemap.xml", "utf8"); assert.doesNotMatch(homepage, /href=["'][^"']*\/compare\/?["']/); diff --git a/scripts/capture-docs-ui.js b/scripts/capture-docs-ui.js index 190d2d6f..4c20cbfb 100644 --- a/scripts/capture-docs-ui.js +++ b/scripts/capture-docs-ui.js @@ -1,5 +1,6 @@ const fs = require("fs"); const path = require("path"); +const { fromDocusaurusCatalogs } = require("./docs-ui-catalogs"); const root = path.resolve(__dirname, ".."); const locales = require(path.join(root, "content", "locales.json")); @@ -25,39 +26,10 @@ function readCatalog(...parts) { return JSON.parse(fs.readFileSync(file, "utf8")); } -function message(catalog, key) { - if (!catalog[key] || typeof catalog[key].message !== "string") { - throw new Error(`Generated documentation UI key is missing: ${key}`); - } - return catalog[key].message; -} - const docs = readCatalog("docusaurus-plugin-content-docs", "current.json"); const navbar = readCatalog("docusaurus-theme-classic", "navbar.json"); const footer = readCatalog("docusaurus-theme-classic", "footer.json"); -const result = { - "version.label": message(docs, "version.label"), - "navbar.Docs": message(navbar, "item.label.Docs"), - "navbar.GitHub": message(navbar, "item.label.GitHub"), - "navbar.Slack Group": message(navbar, "item.label.Slack Group"), - "footer.column.Docs": message(footer, "link.title.Docs"), - "footer.column.Community": message(footer, "link.title.Community"), - "footer.column.More": message(footer, "link.title.More"), - "footer.Getting Started": message( - footer, - "link.item.label.Getting Started", - ), - "footer.X": message(footer, "link.item.label.X"), - "footer.Slack Group": message(footer, "link.item.label.Slack Group"), - "footer.GitHub": message(footer, "link.item.label.GitHub"), -}; - -for (const [key, value] of Object.entries(docs)) { - const prefix = "sidebar.docs.category."; - if (key.startsWith(prefix)) { - result[`sidebar.${key.slice(prefix.length)}`] = value.message; - } -} +const result = fromDocusaurusCatalogs({ docs, navbar, footer }); fs.writeFileSync(canonical, `${JSON.stringify(result, null, 2)}\n`); console.log(`Updated ${path.relative(root, canonical)}`); diff --git a/scripts/compose-site.mjs b/scripts/compose-site.mjs index 72de50b2..162b2cef 100644 --- a/scripts/compose-site.mjs +++ b/scripts/compose-site.mjs @@ -17,17 +17,14 @@ const root = process.cwd(); const docsSite = path.join(root, "docs-site/build"); const marketingSite = path.join(root, "marketing-site/out"); const combinedSite = path.join(root, "build/combined-site"); +const cnameSource = path.join(root, "docs-site/static/CNAME"); const locales = JSON.parse( await readFile(path.join(root, "content/locales.json"), "utf8"), ).filter((locale) => locale.enabled); const defaultLocale = locales.find((locale) => locale.default); -const marketingRoutes = [ - "", - "compare", - "compare/coolify", - "compare/dokploy", - "compare/dokku", -]; +const marketingRoutes = Object.values( + JSON.parse(await readFile(path.join(root, "marketing-site/routes.json"), "utf8")), +).map((route) => route.path.replace(/^\//, "").replace(/\/$/, "")); assert(defaultLocale, "An enabled default locale is required"); @@ -127,6 +124,7 @@ await Promise.all([ ), requirePath(path.join(docsSite, "img/logo.png")), requirePath(path.join(docsSite, "CNAME")), + requirePath(cnameSource), ...locales.flatMap((locale) => marketingRoutes.map((route) => requirePath(marketingRouteFile(locale, route))), ), @@ -139,7 +137,7 @@ await Promise.all([ requireNoCollision("compare"), ]); -const originalCname = await readFile(path.join(docsSite, "CNAME")); +const originalCname = await readFile(cnameSource); assert.equal(originalCname.toString().trim(), "caprover.com"); const [docsBefore, imagesBefore] = await Promise.all([ diff --git a/scripts/docs-ui-catalogs.js b/scripts/docs-ui-catalogs.js new file mode 100644 index 00000000..62b7e991 --- /dev/null +++ b/scripts/docs-ui-catalogs.js @@ -0,0 +1,60 @@ +const docsUiMappings = [ + ["docs", "version.label", "version.label"], + ["navbar", "navbar.Docs", "item.label.Docs"], + ["navbar", "navbar.GitHub", "item.label.GitHub"], + ["navbar", "navbar.Slack Group", "item.label.Slack Group"], + ["footer", "footer.column.Docs", "link.title.Docs"], + ["footer", "footer.column.Community", "link.title.Community"], + ["footer", "footer.column.More", "link.title.More"], + ["footer", "footer.Getting Started", "link.item.label.Getting Started"], + ["footer", "footer.X", "link.item.label.X"], + ["footer", "footer.Slack Group", "link.item.label.Slack Group"], + ["footer", "footer.GitHub", "link.item.label.GitHub"], +]; + +const docsUiSidebarPrefix = "sidebar."; +const docusaurusSidebarPrefix = "sidebar.docs.category."; + +function toDocusaurusCatalogs(docsUi) { + const catalogs = { docs: {}, navbar: {}, footer: {} }; + + for (const [catalog, docsUiKey, docusaurusKey] of docsUiMappings) { + catalogs[catalog][docusaurusKey] = docsUi[docsUiKey]; + } + + for (const [key, value] of Object.entries(docsUi)) { + if (key.startsWith(docsUiSidebarPrefix)) { + catalogs.docs[ + `${docusaurusSidebarPrefix}${key.slice(docsUiSidebarPrefix.length)}` + ] = value; + } + } + + return catalogs; +} + +function fromDocusaurusCatalogs(catalogs) { + const docsUi = {}; + + function message(catalog, key) { + if (!catalog[key] || typeof catalog[key].message !== "string") { + throw new Error(`Generated documentation UI key is missing: ${key}`); + } + return catalog[key].message; + } + + for (const [catalog, docsUiKey, docusaurusKey] of docsUiMappings) { + docsUi[docsUiKey] = message(catalogs[catalog], docusaurusKey); + } + + for (const [key, value] of Object.entries(catalogs.docs)) { + if (key.startsWith(docusaurusSidebarPrefix)) { + docsUi[`${docsUiSidebarPrefix}${key.slice(docusaurusSidebarPrefix.length)}`] = + value.message; + } + } + + return docsUi; +} + +module.exports = { fromDocusaurusCatalogs, toDocusaurusCatalogs }; diff --git a/scripts/prepare-localized-content.js b/scripts/prepare-localized-content.js index ae143f11..344b5afc 100644 --- a/scripts/prepare-localized-content.js +++ b/scripts/prepare-localized-content.js @@ -1,5 +1,6 @@ const fs = require("fs"); const path = require("path"); +const { toDocusaurusCatalogs } = require("./docs-ui-catalogs"); const root = path.resolve(__dirname, ".."); const contentRoot = path.join(root, "content"); @@ -263,43 +264,22 @@ for (const locale of enabledLocales) { ); const docsUi = require(path.join(localeRoot, "docs-ui.json")); + const catalogs = toDocusaurusCatalogs(docsUi); writeCatalog( path.join( localeI18n, "docusaurus-plugin-content-docs", "current.json", ), - { - "version.label": docsUi["version.label"], - ...Object.fromEntries( - Object.entries(docsUi) - .filter(([key]) => key.startsWith("sidebar.")) - .map(([key, value]) => [ - `sidebar.docs.category.${key.slice("sidebar.".length)}`, - value, - ]), - ), - }, + catalogs.docs, ); writeCatalog( path.join(localeI18n, "docusaurus-theme-classic", "navbar.json"), - { - "item.label.Docs": docsUi["navbar.Docs"], - "item.label.GitHub": docsUi["navbar.GitHub"], - "item.label.Slack Group": docsUi["navbar.Slack Group"], - }, + catalogs.navbar, ); writeCatalog( path.join(localeI18n, "docusaurus-theme-classic", "footer.json"), - { - "link.title.Docs": docsUi["footer.column.Docs"], - "link.title.Community": docsUi["footer.column.Community"], - "link.title.More": docsUi["footer.column.More"], - "link.item.label.Getting Started": docsUi["footer.Getting Started"], - "link.item.label.X": docsUi["footer.X"], - "link.item.label.Slack Group": docsUi["footer.Slack Group"], - "link.item.label.GitHub": docsUi["footer.GitHub"], - }, + catalogs.footer, ); } } diff --git a/scripts/smoke-combined-site.mjs b/scripts/smoke-combined-site.mjs index 3683f803..5fcc16bc 100644 --- a/scripts/smoke-combined-site.mjs +++ b/scripts/smoke-combined-site.mjs @@ -7,13 +7,9 @@ const siteRoot = path.resolve("build/combined-site"); const locales = JSON.parse( await readFile(path.resolve("content/locales.json"), "utf8"), ).filter((locale) => locale.enabled); -const localizedRoutes = [ - "", - "compare/", - "compare/coolify/", - "compare/dokploy/", - "compare/dokku/", -]; +const marketingRoutes = JSON.parse( + await readFile(path.resolve("marketing-site/routes.json"), "utf8"), +); const contentTypes = new Map([ [".css", "text/css"], @@ -78,7 +74,9 @@ try { assert(docsTitle, `${locale.code} documentation title is missing`); const outputPrefix = locale.pathPrefix ? `${locale.pathPrefix.slice(1)}/` : ""; const routeResponses = await Promise.all( - localizedRoutes.map((route) => fetch(`${origin}/${outputPrefix}${route}index.html`)), + Object.values(marketingRoutes).map((route) => + fetch(`${origin}/${outputPrefix}${route.path.slice(1)}index.html`), + ), ); const docsResponse = await fetch( `${origin}${locale.pathPrefix}/docs/get-started`, @@ -105,60 +103,75 @@ try { const nextAsset = homepage.match(/(?:href|src)=["'](\/_next\/[^"']+\.(?:css|js))["']/)?.[1]; assert(nextAsset, "Homepage does not reference a Next.js CSS or JavaScript asset"); - const checks = await Promise.all([ - fetch(`${origin}/.nojekyll`), - fetch(`${origin}/docs/get-started.html`), - fetch(`${origin}/docs/en/get-started.html`), - fetch(`${origin}/docs/es-ES/get-started.html`), - fetch(`${origin}/docs/get-started`), - fetch(`${origin}/es-ES/docs/get-started`), - fetch(`${origin}/en/index.html`), - fetch(`${origin}/es-ES/index.html`), - fetch(`${origin}/es-ES/compare/index.html`), - fetch(`${origin}/es-ES/compare/coolify/index.html`), - fetch(`${origin}/es-ES/compare/dokploy/index.html`), - fetch(`${origin}/es-ES/compare/dokku/index.html`), - fetch(`${origin}/homepage-assets/caprover-dashboard.png`), - fetch(`${origin}${nextAsset}`), - fetch(`${origin}/robots.txt`), - ]); - - for (const response of checks) { + const responseUrls = { + noJekyll: `${origin}/.nojekyll`, + docsHtml: `${origin}/docs/get-started.html`, + legacyEnglishDocs: `${origin}/docs/en/get-started.html`, + legacySpanishDocs: `${origin}/docs/es-ES/get-started.html`, + docs: `${origin}/docs/get-started`, + spanishDocs: `${origin}/es-ES/docs/get-started`, + englishHomepageAlias: `${origin}/en/index.html`, + spanishHomepage: `${origin}/es-ES/index.html`, + spanishComparisonHub: `${origin}/es-ES${marketingRoutes.comparisonHub.path}index.html`, + spanishCoolifyComparison: `${origin}/es-ES${marketingRoutes.coolify.path}index.html`, + spanishDokployComparison: `${origin}/es-ES${marketingRoutes.dokploy.path}index.html`, + spanishDokkuComparison: `${origin}/es-ES${marketingRoutes.dokku.path}index.html`, + dashboardImage: `${origin}/homepage-assets/caprover-dashboard.png`, + nextAsset: `${origin}${nextAsset}`, + robots: `${origin}/robots.txt`, + }; + const responses = Object.fromEntries( + await Promise.all( + Object.entries(responseUrls).map(async ([name, url]) => [name, await fetch(url)]), + ), + ); + + for (const response of Object.values(responses)) { assert.equal(response.status, 200, `${response.url} did not return HTTP 200`); } - assert.equal(await checks[0].text(), "", ".nojekyll must be empty"); - const legacyEnglishDocsRedirect = await checks[2].text(); + assert.equal(await responses.noJekyll.text(), "", ".nojekyll must be empty"); + const legacyEnglishDocsRedirect = await responses.legacyEnglishDocs.text(); assert.match(legacyEnglishDocsRedirect, /window\.location\.replace\(["']\/docs\/get-started["']/); - const legacySpanishDocsRedirect = await checks[3].text(); + const legacySpanishDocsRedirect = await responses.legacySpanishDocs.text(); assert.match(legacySpanishDocsRedirect, /window\.location\.replace\(["']\/es-ES\/docs\/get-started["']/); - const docs = await checks[4].text(); + const docs = await responses.docs.text(); assert.match(docs, /Getting Started/i); assert.match(docs, /href=["']?\/es-ES\/docs\/get-started(?:["'\s>])/); - const spanishDocs = await checks[5].text(); + const spanishDocs = await responses.spanishDocs.text(); assert.match(spanishDocs, /])/); assert.match(spanishDocs, /Primeros pasos/); assert.match(spanishDocs, /Conceptos básicos/); assert.match(spanishDocs, /href=["']?\/docs\/get-started(?:["'\s>])/); - const englishHomepageAlias = await checks[6].text(); + const englishHomepageAlias = await responses.englishHomepageAlias.text(); assert.match(englishHomepageAlias, /Deploy apps\./); assert.match(englishHomepageAlias, /rel=["']canonical["'][^>]+href=["']https:\/\/caprover\.com\/["']/); - const spanishHomepage = await checks[7].text(); + const spanishHomepage = await responses.spanishHomepage.text(); assert.match(spanishHomepage, /Despliega aplicaciones\./); assert.match(spanishHomepage, /href=["']https:\/\/caprover\.com\/es-ES\/docs\/get-started["']/); assert.match(spanishHomepage, /]+href=["']https:\/\/caprover\.com\/es-ES\/["']/); - const spanishComparisonPages = await Promise.all(checks.slice(8, 12).map((response) => response.text())); + const spanishComparisonPages = await Promise.all( + [ + responses.spanishComparisonHub, + responses.spanishCoolifyComparison, + responses.spanishDokployComparison, + responses.spanishDokkuComparison, + ].map((response) => response.text()), + ); assert.match(spanishComparisonPages[0], /Empieza de forma sencilla\./); for (const page of spanishComparisonPages) { assert.match(page, /\/es-ES\/compare\//); assert.match(page, /\/es-ES\/docs\/get-started/); } - assert(Number(checks[12].headers.get("content-length") ?? 0) > 0 || (await checks[12].arrayBuffer()).byteLength > 0); + assert( + Number(responses.dashboardImage.headers.get("content-length") ?? 0) > 0 || + (await responses.dashboardImage.arrayBuffer()).byteLength > 0, + ); assert.equal( - await checks[14].text(), + await responses.robots.text(), "User-agent: *\nAllow: /\nSitemap: https://caprover.com/sitemap.xml\n", );