b0ab6cc729
React/Vite landing with RU/EN i18n, live USD pricing, download links to updates.mailib.ru, and donate.stream checkout. Co-authored-by: Cursor <cursoragent@cursor.com>
186 lines
5.6 KiB
TypeScript
186 lines
5.6 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { describe, it } from "node:test";
|
|
|
|
import {
|
|
DOWNLOAD_ARTIFACTS,
|
|
DOWNLOAD_LINKS,
|
|
FAQ_IDS,
|
|
FEATURE_VARIANTS,
|
|
NAV_LINK_KEYS,
|
|
NAV_HREFS,
|
|
PRICING_TIER_IDS,
|
|
RECOMMENDED_PRICING_TIER,
|
|
REQUIRED_SECTION_IDS,
|
|
SITE_LINKS,
|
|
UPDATE_FEED_BASE,
|
|
} from "./data/siteContent";
|
|
import {
|
|
SCREENSHOT_SRC,
|
|
getEffectsScreenshotDisplaySize,
|
|
} from "./data/siteAssets";
|
|
import { MESSAGES, inferLocaleFromLanguages } from "./i18n/messages";
|
|
import {
|
|
detectCpuArch,
|
|
detectOs,
|
|
resolveDownloadHref,
|
|
resolvePlatformDownloadHref,
|
|
} from "./lib/detectOs";
|
|
|
|
describe("siteContent", () => {
|
|
it("exposes all required section anchor ids", () => {
|
|
for (const id of REQUIRED_SECTION_IDS) {
|
|
const inNav = NAV_LINK_KEYS.some((key) => NAV_HREFS[key] === `#${id}`);
|
|
assert.equal(inNav || id.length > 0, true, `missing section #${id}`);
|
|
}
|
|
});
|
|
|
|
it("defines four feature variants", () => {
|
|
assert.deepEqual(FEATURE_VARIANTS, [
|
|
"editor",
|
|
"control",
|
|
"presentation",
|
|
"atmosphere",
|
|
]);
|
|
});
|
|
|
|
it("defines three pricing tiers with one recommended", () => {
|
|
assert.equal(PRICING_TIER_IDS.length, 3);
|
|
assert.equal(RECOMMENDED_PRICING_TIER, "master");
|
|
});
|
|
|
|
it("includes five FAQ entries", () => {
|
|
assert.equal(FAQ_IDS.length, 5);
|
|
});
|
|
|
|
it("points download buttons to update feed artifacts", () => {
|
|
assert.equal(UPDATE_FEED_BASE, "https://updates.mailib.ru/");
|
|
assert.equal(
|
|
DOWNLOAD_LINKS.windows,
|
|
`${UPDATE_FEED_BASE}${DOWNLOAD_ARTIFACTS.windows}`,
|
|
);
|
|
assert.equal(
|
|
DOWNLOAD_LINKS.macos.arm64,
|
|
`${UPDATE_FEED_BASE}${DOWNLOAD_ARTIFACTS.macos.arm64}`,
|
|
);
|
|
assert.equal(
|
|
DOWNLOAD_LINKS.linux.x64,
|
|
`${UPDATE_FEED_BASE}${DOWNLOAD_ARTIFACTS.linux.x64}`,
|
|
);
|
|
});
|
|
|
|
it("wires download anchor and external buy link", () => {
|
|
assert.equal(SITE_LINKS.download, "#platforms");
|
|
assert.equal(SITE_LINKS.buy, "https://donate.stream/ttrpgplayer");
|
|
});
|
|
|
|
it("maps each feature variant to a screenshot asset", () => {
|
|
for (const variant of FEATURE_VARIANTS) {
|
|
assert.match(SCREENSHOT_SRC[variant], /^\/images\/screenshot-.+\.png$/u);
|
|
}
|
|
assert.equal(SCREENSHOT_SRC.atmosphere, "/images/screenshot-effects.png");
|
|
});
|
|
|
|
it("shows effects screenshot at 70% of intrinsic pixel size", () => {
|
|
const size = getEffectsScreenshotDisplaySize();
|
|
assert.equal(size.width, 206);
|
|
assert.equal(size.height, 220);
|
|
});
|
|
});
|
|
|
|
describe("i18n messages", () => {
|
|
it("has ru and en locales without DND key mentions", () => {
|
|
for (const locale of ["ru", "en"] as const) {
|
|
const json = JSON.stringify(MESSAGES[locale]);
|
|
assert.doesNotMatch(json, /DND-/u);
|
|
assert.doesNotMatch(json, /\.dnd\.zip/u);
|
|
assert.equal(Object.keys(MESSAGES[locale].faq.items).length, 5);
|
|
}
|
|
});
|
|
|
|
it("documents download and buy labels in both locales", () => {
|
|
assert.equal(MESSAGES.ru.cta.download, "Скачать");
|
|
assert.equal(MESSAGES.en.cta.download, "Download");
|
|
assert.equal(MESSAGES.ru.cta.buy, "Купить");
|
|
assert.equal(MESSAGES.en.cta.buy, "Buy");
|
|
});
|
|
});
|
|
|
|
describe("inferLocaleFromLanguages", () => {
|
|
it("uses ru only for Russian browser languages", () => {
|
|
assert.equal(inferLocaleFromLanguages(["ru-RU"]), "ru");
|
|
assert.equal(inferLocaleFromLanguages(["ru"]), "ru");
|
|
assert.equal(inferLocaleFromLanguages(["ru-BY", "en-US"]), "ru");
|
|
});
|
|
|
|
it("defaults to en for non-Russian browser languages", () => {
|
|
assert.equal(inferLocaleFromLanguages(["en-US"]), "en");
|
|
assert.equal(inferLocaleFromLanguages(["de-DE"]), "en");
|
|
assert.equal(inferLocaleFromLanguages(["uk-UA"]), "en");
|
|
assert.equal(inferLocaleFromLanguages([]), "en");
|
|
});
|
|
});
|
|
|
|
describe("detectOs", () => {
|
|
it("detects Windows from user agent", () => {
|
|
assert.equal(detectOs("Mozilla/5.0 (Windows NT 10.0)"), "windows");
|
|
});
|
|
|
|
it("detects macOS from user agent", () => {
|
|
assert.equal(detectOs("Mozilla/5.0 (Macintosh; Intel Mac OS X)"), "macos");
|
|
});
|
|
|
|
it("detects Linux from user agent", () => {
|
|
assert.equal(detectOs("Mozilla/5.0 (X11; Linux x86_64)"), "linux");
|
|
});
|
|
|
|
it("detects Linux arm64 from user agent", () => {
|
|
assert.equal(detectCpuArch("Mozilla/5.0 (X11; Linux aarch64)"), "arm64");
|
|
});
|
|
|
|
it("resolves download href by OS", () => {
|
|
const hints = { userAgent: "Mozilla/5.0 (Windows NT 10.0)" };
|
|
assert.equal(
|
|
resolveDownloadHref("windows", DOWNLOAD_LINKS, hints),
|
|
DOWNLOAD_LINKS.windows,
|
|
);
|
|
assert.equal(
|
|
resolveDownloadHref("macos", DOWNLOAD_LINKS, {
|
|
userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X)",
|
|
maxTouchPoints: 0,
|
|
}),
|
|
DOWNLOAD_LINKS.macos.x64,
|
|
);
|
|
assert.equal(
|
|
resolveDownloadHref("linux", DOWNLOAD_LINKS, {
|
|
userAgent: "Mozilla/5.0 (X11; Linux aarch64)",
|
|
}),
|
|
DOWNLOAD_LINKS.linux.arm64,
|
|
);
|
|
assert.equal(
|
|
resolveDownloadHref("unknown", DOWNLOAD_LINKS, hints),
|
|
DOWNLOAD_LINKS.windows,
|
|
);
|
|
});
|
|
|
|
it("resolves per-platform card href", () => {
|
|
assert.equal(
|
|
resolvePlatformDownloadHref("windows", DOWNLOAD_LINKS, {
|
|
userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X)",
|
|
}),
|
|
DOWNLOAD_LINKS.windows,
|
|
);
|
|
assert.equal(
|
|
resolvePlatformDownloadHref("macos", DOWNLOAD_LINKS, {
|
|
userAgent: "Mozilla/5.0 (Windows NT 10.0)",
|
|
}),
|
|
DOWNLOAD_LINKS.macos.arm64,
|
|
);
|
|
assert.equal(
|
|
resolvePlatformDownloadHref("linux", DOWNLOAD_LINKS, {
|
|
userAgent: "Mozilla/5.0 (X11; Linux x86_64)",
|
|
}),
|
|
DOWNLOAD_LINKS.linux.x64,
|
|
);
|
|
});
|
|
});
|