Files
PolyWeather/frontend/components/auth/__tests__/turnstileIntegration.test.ts
2026-06-16 03:40:47 +08:00

94 lines
4.2 KiB
TypeScript

import fs from "node:fs";
import path from "node:path";
function assert(condition: unknown, message: string) {
if (!condition) throw new Error(message);
}
export function runTests() {
const projectRoot = process.cwd();
const turnstileLibPath = path.join(projectRoot, "lib", "turnstile.ts");
const widgetPath = path.join(projectRoot, "components", "security", "TurnstileWidget.tsx");
const loginPath = path.join(projectRoot, "components", "auth", "LoginClient.tsx");
const feedbackModalPath = path.join(
projectRoot,
"components",
"dashboard",
"scan-terminal",
"UserFeedbackModal.tsx",
);
const feedbackRoutePath = path.join(projectRoot, "app", "api", "feedback", "route.ts");
const paymentIntentRoutePath = path.join(projectRoot, "app", "api", "payments", "intents", "route.ts");
const paymentSubmitRoutePath = path.join(
projectRoot,
"app",
"api",
"payments",
"intents",
"[intentId]",
"submit",
"route.ts",
);
const paymentFlowPath = path.join(projectRoot, "components", "account", "usePaymentFlow.ts");
assert(fs.existsSync(turnstileLibPath), "shared Turnstile verifier module must exist");
assert(fs.existsSync(widgetPath), "Turnstile widget component must exist");
const turnstileLib = fs.readFileSync(turnstileLibPath, "utf8");
const widgetSource = fs.readFileSync(widgetPath, "utf8");
const loginSource = fs.readFileSync(loginPath, "utf8");
const feedbackModalSource = fs.readFileSync(feedbackModalPath, "utf8");
const feedbackRouteSource = fs.readFileSync(feedbackRoutePath, "utf8");
const paymentIntentRouteSource = fs.readFileSync(paymentIntentRoutePath, "utf8");
const paymentSubmitRouteSource = fs.readFileSync(paymentSubmitRoutePath, "utf8");
const paymentFlowSource = fs.readFileSync(paymentFlowPath, "utf8");
assert(
turnstileLib.includes("POLYWEATHER_TURNSTILE_SECRET_KEY") &&
turnstileLib.includes("NEXT_PUBLIC_TURNSTILE_SITE_KEY") &&
turnstileLib.includes("https://challenges.cloudflare.com/turnstile/v0/siteverify") &&
turnstileLib.includes("requireTurnstileForRequest") &&
turnstileLib.includes("POLYWEATHER_TURNSTILE_BYPASS"),
"Turnstile verifier must be optional, use Cloudflare siteverify, and expose a request guard",
);
assert(
widgetSource.includes("NEXT_PUBLIC_TURNSTILE_SITE_KEY") &&
widgetSource.includes("challenges.cloudflare.com/turnstile/v0/api.js") &&
widgetSource.includes("window.turnstile.render") &&
widgetSource.includes("data-turnstile-action"),
"Turnstile widget must render Cloudflare Turnstile only when a site key is configured",
);
assert(
loginSource.includes("TurnstileWidget") &&
loginSource.includes("getTurnstileTokenForAction") &&
loginSource.includes("captchaToken") &&
loginSource.includes("signInWithPassword") &&
loginSource.includes("signUp"),
"login/signup must attach a Turnstile captchaToken to Supabase auth calls",
);
assert(
feedbackModalSource.includes("TurnstileWidget") &&
feedbackModalSource.includes("getTurnstileTokenForAction") &&
feedbackModalSource.includes("turnstile_token"),
"feedback modal must include a Turnstile token in feedback submissions",
);
assert(
feedbackRouteSource.includes('requireTurnstileForRequest(req, "feedback_submit"') &&
feedbackRouteSource.indexOf('requireTurnstileForRequest(req, "feedback_submit"') <
feedbackRouteSource.indexOf("fetch(`${API_BASE}/api/feedback`"),
"feedback POST proxy must verify Turnstile before forwarding user feedback",
);
assert(
paymentIntentRouteSource.includes('requireTurnstileForRequest(req, "payment_intent_create"') &&
paymentSubmitRouteSource.includes('requireTurnstileForRequest(req, "payment_tx_submit"'),
"payment mutation proxies must verify Turnstile before forwarding create and submit requests",
);
assert(
paymentFlowSource.includes("getTurnstileTokenForAction") &&
paymentFlowSource.includes("turnstile_token") &&
paymentFlowSource.includes("payment_intent_create") &&
paymentFlowSource.includes("payment_tx_submit"),
"payment flow must include Turnstile tokens in intent creation and tx submit payloads",
);
}