Browse Source

fix(birthplace): guarantee strict country and city independence with test suite

master
mortezaei 3 days ago
parent
commit
c2fad42604
  1. 70
      src/components/Componentes/question-birthplace.test.ts
  2. 27
      src/components/Componentes/question-birthplace.tsx

70
src/components/Componentes/question-birthplace.test.ts

@ -0,0 +1,70 @@
import { describe, expect, it } from "vitest";
import { parseValue } from "./question-birthplace";
describe("QuestionBirthplace parseValue", () => {
it("parses empty and null values safely", () => {
expect(parseValue(null)).toEqual({ country: "", city: "" });
expect(parseValue(undefined)).toEqual({ country: "", city: "" });
expect(parseValue("")).toEqual({ country: "", city: "" });
});
it("parses structured objects", () => {
expect(parseValue({ country: "Iran", city: "Tehran" })).toEqual({
country: "Iran",
city: "Tehran",
});
});
it("parses standard 'City, Country' strings", () => {
expect(parseValue("Tehran, Iran")).toEqual({
city: "Tehran",
country: "Iran",
});
expect(parseValue("شیراز, ایران")).toEqual({
city: "شیراز",
country: "ایران",
});
});
it("never swaps city and country even when city equals country name", () => {
// City typed as 'albania' and country selected as 'Afghanistan'
expect(parseValue("albania, Afghanistan")).toEqual({
city: "albania",
country: "Afghanistan",
});
// City typed as 'Albania' and country selected as 'Albania'
expect(parseValue("Albania, Albania")).toEqual({
city: "Albania",
country: "Albania",
});
// City typed as 'Georgia' and country selected as 'United States (US)'
expect(parseValue("Georgia, United States (US)")).toEqual({
city: "Georgia",
country: "United States (US)",
});
});
it("parses single country string", () => {
expect(parseValue("Iran")).toEqual({
country: "Iran",
city: "",
});
expect(parseValue("ایران")).toEqual({
country: "ایران",
city: "",
});
expect(parseValue("Afghanistan")).toEqual({
country: "Afghanistan",
city: "",
});
});
it("parses single custom city string without matching country", () => {
expect(parseValue("Rey")).toEqual({
country: "",
city: "Rey",
});
});
});

27
src/components/Componentes/question-birthplace.tsx

@ -24,7 +24,7 @@ type BirthplaceValue = {
city?: string;
};
function parseValue(rawValue: unknown): { country: string; city: string } {
export function parseValue(rawValue: unknown): { country: string; city: string } {
if (!rawValue) return { country: "", city: "" };
if (typeof rawValue === "object" && rawValue !== null) {
@ -105,10 +105,11 @@ export function QuestionBirthplace({
const storedRegion = isResidence ? getStoredUserGeoRegion() : null;
const initial = parseValue(rawValue);
const localizedInitialCountry = resolveCountryName(
initial.country || storedRegion?.country,
locale,
);
const localizedInitialCountry =
resolveCountryName(initial.country || storedRegion?.country, locale) ||
initial.country ||
storedRegion?.country ||
"";
const initialCity = initial.city || storedRegion?.city || "";
const initialLoc =
localizedInitialCountry || initialCity
@ -193,7 +194,7 @@ export function QuestionBirthplace({
// If there is already a saved answer and we are not forcing, display it
if (rawValue && !force) {
const parsed = parseValue(rawValue);
const cName = resolveCountryName(parsed.country, locale);
const cName = resolveCountryName(parsed.country, locale) || parsed.country;
if (cName || parsed.city) {
const loc = [parsed.city, cName].filter(Boolean).join(", ");
if (cName) setSelectedCountry(cName);
@ -254,12 +255,16 @@ export function QuestionBirthplace({
}
setMode("manual");
const parsed = parseValue(rawValue);
const resolvedC = resolveCountryName(selectedCountry || parsed.country, locale);
const country = resolvedC || selectedCountry || parsed.country;
const resolvedC =
resolveCountryName(selectedCountry || parsed.country, locale) ||
selectedCountry ||
parsed.country;
const country = resolvedC;
const city = cityInput || parsed.city;
setSelectedCountry(country);
setCityInput(city);
updateAnswers(country, city);
setDetectedLocation([city, country].filter(Boolean).join(", "));
};
// Synchronize state ONLY if rawValue changes externally (e.g. draft fetch or reset)
@ -268,11 +273,11 @@ export function QuestionBirthplace({
return;
}
const updated = parseValue(rawValue);
const resolvedC = resolveCountryName(updated.country, locale);
if (resolvedC && resolvedC !== selectedCountry) {
const resolvedC = resolveCountryName(updated.country, locale) || updated.country;
if (resolvedC !== selectedCountry) {
setSelectedCountry(resolvedC);
}
if (updated.city && updated.city.trim() !== cityInput.trim()) {
if (updated.city !== cityInput) {
setCityInput(updated.city);
}
if (resolvedC || updated.city) {

Loading…
Cancel
Save