feat: add location autocomplete

This commit is contained in:
2026-04-10 15:40:38 -04:00
parent 12849b2362
commit 27492ee01f
6 changed files with 679 additions and 47 deletions

View File

@@ -0,0 +1,111 @@
import { describe, expect, test } from "bun:test";
import { createElement } from "react";
import { renderToStaticMarkup } from "react-dom/server";
import {
getGoogleMapsLocationCapability,
getGoogleMapsPlaceLabel,
mapGooglePlacesSuggestions,
} from "@/lib/google-maps";
const renderLocationAutocomplete = async (capability: {
enabled: boolean;
region: string;
reason: "configured" | "missing_server_api_key" | "disabled";
}) => {
const { LocationAutocomplete } = await import("@/components/location-autocomplete");
return renderToStaticMarkup(
createElement(LocationAutocomplete, {
capability,
id: "event-location",
onChange: () => {},
value: "",
}),
);
};
describe("Google Maps location capability boundary", () => {
test("disables Google Maps search when the server API key is missing", () => {
expect(getGoogleMapsLocationCapability({ serverApiKey: "" })).toEqual({
enabled: false,
reason: "missing_server_api_key",
region: "us",
});
});
test("enables Google Maps search when the server API key is present", () => {
expect(
getGoogleMapsLocationCapability({ serverApiKey: "maps-server-key", region: "gb" }),
).toEqual({
enabled: true,
reason: "configured",
region: "gb",
});
});
});
describe("LocationAutocomplete fallback mode", () => {
test("renders a plain text location field when Google Maps configuration is unavailable", async () => {
const markup = await renderLocationAutocomplete({
enabled: false,
reason: "missing_server_api_key",
region: "us",
});
expect(markup).toContain('data-location-mode="manual"');
expect(markup).toContain('placeholder="Location"');
expect(markup).not.toContain("Search Google Maps");
});
});
describe("LocationAutocomplete configured mode", () => {
test("renders a server-backed Google Maps-assisted input path while keeping manual typing available", async () => {
const markup = await renderLocationAutocomplete({
enabled: true,
reason: "configured",
region: "us",
});
expect(markup).toContain('data-location-mode="google-maps-server"');
expect(markup).toContain('placeholder="Search Google Maps or type a location"');
expect(markup).toContain("Search Google Maps or keep typing a custom location.");
});
});
describe("Google Maps place label selection", () => {
test("prefers the chosen prediction label for the visible location value", () => {
expect(
getGoogleMapsPlaceLabel({
displayName: "Google HQ",
formattedAddress: "1600 Amphitheatre Parkway, Mountain View, CA",
predictionText: "Googleplex",
}),
).toBe("Googleplex");
});
});
describe("Google Places server response mapping", () => {
test("maps server autocomplete predictions into lightweight suggestion records", () => {
expect(
mapGooglePlacesSuggestions({
suggestions: [
{
placePrediction: {
place: "places/abc123",
structuredFormat: {
secondaryText: { text: "Mountain View, CA" },
},
text: { text: "Googleplex" },
},
},
],
}),
).toEqual([
{
formattedAddress: "Mountain View, CA",
placeId: "abc123",
text: "Googleplex",
},
]);
});
});