mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-10 05:12:14 +00:00
With NEXT_PUBLIC_APP_URL unset, some providers spliced the missing value into their redirect template and the integration cards told the reader to register 'undefined/api/polar/callback'. A callback that is not an absolute http(s) URL now counts as not configured, so the card shows the fixed path it shows for every other unconfigured provider.
126 lines
4.6 KiB
TypeScript
126 lines
4.6 KiB
TypeScript
/**
|
|
* `getIntegrationCallbackUrls()` must hand the Settings → Integrations cards
|
|
* the exact `redirect_uri` each provider's client registers: the explicit
|
|
* `<PROVIDER>_REDIRECT_URI` when the operator set one, the
|
|
* `${NEXT_PUBLIC_APP_URL}/api/<provider>/callback` form otherwise. The map
|
|
* goes through the provider functions themselves rather than restating the
|
|
* rule, so this test pins that the wiring reaches every provider and that a
|
|
* provider whose validation throws surfaces as `null` instead of taking the
|
|
* page down.
|
|
*/
|
|
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
|
|
import {
|
|
INTEGRATION_CALLBACK_PROVIDERS,
|
|
getIntegrationCallbackUrls,
|
|
} from "../callback-urls";
|
|
|
|
const OVERRIDE_VARS: Record<
|
|
(typeof INTEGRATION_CALLBACK_PROVIDERS)[number],
|
|
string
|
|
> = {
|
|
withings: "WITHINGS_REDIRECT_URI",
|
|
whoop: "WHOOP_REDIRECT_URI",
|
|
fitbit: "FITBIT_REDIRECT_URI",
|
|
"google-health": "GOOGLE_HEALTH_REDIRECT_URI",
|
|
polar: "POLAR_REDIRECT_URI",
|
|
oura: "OURA_REDIRECT_URI",
|
|
strava: "STRAVA_REDIRECT_URI",
|
|
};
|
|
|
|
const TOUCHED = ["NEXT_PUBLIC_APP_URL", ...Object.values(OVERRIDE_VARS)];
|
|
let saved: Record<string, string | undefined>;
|
|
|
|
beforeEach(() => {
|
|
saved = Object.fromEntries(TOUCHED.map((k) => [k, process.env[k]]));
|
|
for (const k of TOUCHED) delete process.env[k];
|
|
});
|
|
|
|
afterEach(() => {
|
|
for (const k of TOUCHED) {
|
|
if (saved[k] === undefined) delete process.env[k];
|
|
else process.env[k] = saved[k];
|
|
}
|
|
});
|
|
|
|
describe("getIntegrationCallbackUrls", () => {
|
|
it("derives ${NEXT_PUBLIC_APP_URL}/api/<provider>/callback when nothing overrides it", () => {
|
|
process.env.NEXT_PUBLIC_APP_URL = "https://health.example";
|
|
const urls = getIntegrationCallbackUrls();
|
|
for (const provider of INTEGRATION_CALLBACK_PROVIDERS) {
|
|
expect(urls[provider], provider).toBe(
|
|
`https://health.example/api/${provider}/callback`,
|
|
);
|
|
}
|
|
});
|
|
|
|
it("lets the explicit <PROVIDER>_REDIRECT_URI win over the derived form", () => {
|
|
// Withings / WHOOP / Polar / Oura / Strava accept any explicit value.
|
|
process.env.NEXT_PUBLIC_APP_URL = "https://health.example";
|
|
for (const provider of [
|
|
"withings",
|
|
"whoop",
|
|
"polar",
|
|
"oura",
|
|
"strava",
|
|
] as const) {
|
|
process.env[OVERRIDE_VARS[provider]] =
|
|
`https://edge.example/api/${provider}/callback`;
|
|
}
|
|
const urls = getIntegrationCallbackUrls();
|
|
for (const provider of [
|
|
"withings",
|
|
"whoop",
|
|
"polar",
|
|
"oura",
|
|
"strava",
|
|
] as const) {
|
|
expect(urls[provider], provider).toBe(
|
|
`https://edge.example/api/${provider}/callback`,
|
|
);
|
|
}
|
|
// No override for these two, so they still derive.
|
|
expect(urls.fitbit).toBe("https://health.example/api/fitbit/callback");
|
|
expect(urls["google-health"]).toBe(
|
|
"https://health.example/api/google-health/callback",
|
|
);
|
|
});
|
|
|
|
it("uses the explicit Fitbit / Google Health override when the app URL is unset", () => {
|
|
// Those two pin an explicit override to the app origin when both are set;
|
|
// with only the override present it is taken verbatim.
|
|
process.env.FITBIT_REDIRECT_URI =
|
|
"https://edge.example/api/fitbit/callback";
|
|
process.env.GOOGLE_HEALTH_REDIRECT_URI =
|
|
"https://edge.example/api/google-health/callback";
|
|
const urls = getIntegrationCallbackUrls();
|
|
expect(urls.fitbit).toBe("https://edge.example/api/fitbit/callback");
|
|
expect(urls["google-health"]).toBe(
|
|
"https://edge.example/api/google-health/callback",
|
|
);
|
|
});
|
|
|
|
it("reports null for a provider whose redirect URI fails validation, leaving the rest intact", () => {
|
|
// Fitbit refuses a plain-http, non-loopback origin; the others do not
|
|
// validate and keep deriving.
|
|
process.env.NEXT_PUBLIC_APP_URL = "http://health.example";
|
|
const urls = getIntegrationCallbackUrls();
|
|
expect(urls.fitbit).toBeNull();
|
|
expect(urls["google-health"]).toBeNull();
|
|
expect(urls.withings).toBe("http://health.example/api/withings/callback");
|
|
expect(urls.whoop).toBe("http://health.example/api/whoop/callback");
|
|
});
|
|
|
|
it("reports null rather than 'undefined/api/…' when the app URL is unset", () => {
|
|
// A resolver that splices the unset variable into its template would
|
|
// otherwise hand the card "undefined/api/polar/callback" to show.
|
|
const urls = getIntegrationCallbackUrls();
|
|
for (const provider of INTEGRATION_CALLBACK_PROVIDERS) {
|
|
expect(urls[provider] ?? "", provider).not.toMatch(/^undefined/);
|
|
if (urls[provider] !== null) {
|
|
expect(urls[provider], provider).toMatch(/^https?:\/\//);
|
|
}
|
|
}
|
|
});
|
|
});
|