- {locs.map((loc) => (
-
- {editingLocId === loc.id ? (
-
-
-
{loc.locale}
-
-
-
-
-
- {renderFieldInputs(editFields, setEditFields, "edit")}
-
- ) : (
-
-
-
- {loc.locale}
-
- {loc.description && (
-
{loc.description}
- )}
-
-
-
-
-
-
- )}
+ {/* Fields */}
+
+ {FIELDS.map((f) => {
+ const val = formFields[f.key] || "";
+ const remaining = f.limit ? f.limit - val.length : null;
+ const isUrlRow = f.key === "supportUrl";
+
+ if (isUrlRow) {
+ const marketingField = FIELDS.find((ff) => ff.key === "marketingUrl");
+ const marketingVal = formFields.marketingUrl || "";
+ return (
+
+
+
+ updateField(f.key, e.target.value)}
+ placeholder={f.label}
+ />
- ))}
-
- )}
-
- {/* Add new locale */}
-
-
Add Locale
-
+ );
+ }
+
+ if (f.key === "marketingUrl") return null;
+
+ return (
+
+
+
+ {remaining !== null && (
+
+ {remaining.toLocaleString()} remaining
+
+ )}
+
+ {f.type === "textarea" ? (
+
- {renderFieldInputs(newFields, setNewFields, "new")}
-
-
- >
- )}
+ );
+ })}
+
+
+ {/* Action buttons */}
+
= 2 ? "justify-between" : "justify-end"}`}>
+ {locs.length >= 2 && (
+
+ )}
+
+
+
+
+
>
)}
diff --git a/src/constants/index.js b/src/constants/index.js
index 87595fe..af482c3 100644
--- a/src/constants/index.js
+++ b/src/constants/index.js
@@ -52,6 +52,48 @@ export const CI_PROGRESS_STATUS_MAP = {
COMPLETE: { label: "Complete", color: "#34c759", bg: "rgba(52,199,89,0.12)" },
};
+export const LOCALE_DISPLAY_NAMES = {
+ "ar-SA": "Arabic",
+ "ca": "Catalan",
+ "cs": "Czech",
+ "da": "Danish",
+ "de-DE": "German",
+ "el": "Greek",
+ "en-AU": "English (Australia)",
+ "en-CA": "English (Canada)",
+ "en-GB": "English (U.K.)",
+ "en-US": "English (U.S.)",
+ "es-ES": "Spanish (Spain)",
+ "es-MX": "Spanish (Mexico)",
+ "fi": "Finnish",
+ "fr-CA": "French (Canada)",
+ "fr-FR": "French (France)",
+ "he": "Hebrew",
+ "hi": "Hindi",
+ "hr": "Croatian",
+ "hu": "Hungarian",
+ "id": "Indonesian",
+ "it": "Italian",
+ "ja": "Japanese",
+ "ko": "Korean",
+ "ms": "Malay",
+ "nl-NL": "Dutch",
+ "no": "Norwegian",
+ "pl": "Polish",
+ "pt-BR": "Portuguese (Brazil)",
+ "pt-PT": "Portuguese (Portugal)",
+ "ro": "Romanian",
+ "ru": "Russian",
+ "sk": "Slovak",
+ "sv": "Swedish",
+ "th": "Thai",
+ "tr": "Turkish",
+ "uk": "Ukrainian",
+ "vi": "Vietnamese",
+ "zh-Hans": "Chinese (Simplified)",
+ "zh-Hant": "Chinese (Traditional)",
+};
+
export const SUBSCRIPTION_PERIODS = [
{ value: "ONE_WEEK", label: "1 Week" },
{ value: "ONE_MONTH", label: "1 Month" },
diff --git a/tests/components/VersionLocalizationsSection.test.jsx b/tests/components/VersionLocalizationsSection.test.jsx
index d609fdb..1261df0 100644
--- a/tests/components/VersionLocalizationsSection.test.jsx
+++ b/tests/components/VersionLocalizationsSection.test.jsx
@@ -56,25 +56,14 @@ describe("VersionLocalizationsSection", () => {
fetchVersionLocalizations.mockResolvedValue(MOCK_LOCS);
});
- it("renders collapsed by default", () => {
+ it("fetches localizations on mount without user interaction", async () => {
render(
);
- expect(screen.getByText("Localizations")).toBeInTheDocument();
- expect(screen.queryByText("en-US")).not.toBeInTheDocument();
- expect(fetchVersionLocalizations).not.toHaveBeenCalled();
- });
-
- it("fetches and displays localizations when expanded", async () => {
- render(
);
-
- await user.click(screen.getByText("Localizations"));
+ expect(fetchVersionLocalizations).toHaveBeenCalledWith("app-1", "ver-1", "acc-1");
await waitFor(() => {
- expect(screen.getByText("en-US")).toBeInTheDocument();
- expect(screen.getByText("ja")).toBeInTheDocument();
+ expect(screen.getByText("Localizable Information")).toBeInTheDocument();
});
-
- expect(fetchVersionLocalizations).toHaveBeenCalledWith("app-1", "ver-1", "acc-1");
});
it("shows loading state while fetching", async () => {
@@ -84,7 +73,6 @@ describe("VersionLocalizationsSection", () => {
);
render(
);
- await user.click(screen.getByText("Localizations"));
expect(screen.getByText("Loading localizations...")).toBeInTheDocument();
@@ -98,7 +86,6 @@ describe("VersionLocalizationsSection", () => {
fetchVersionLocalizations.mockRejectedValue(new Error("Network error"));
render(
);
- await user.click(screen.getByText("Localizations"));
await waitFor(() => {
expect(screen.getByText("Failed to load localizations")).toBeInTheDocument();
@@ -110,70 +97,248 @@ describe("VersionLocalizationsSection", () => {
fetchVersionLocalizations.mockResolvedValue([]);
render(
);
- await user.click(screen.getByText("Localizations"));
await waitFor(() => {
expect(screen.getByText("No localizations yet")).toBeInTheDocument();
});
});
- it("displays count badge after loading", async () => {
+ it("renders locale dropdown with loaded locales", async () => {
render(
);
- await user.click(screen.getByText("Localizations"));
await waitFor(() => {
- expect(screen.getByText("2")).toBeInTheDocument();
+ const dropdown = screen.getByLabelText("Select locale");
+ expect(dropdown).toBeInTheDocument();
+
+ const options = within(dropdown).getAllByRole("option");
+ expect(options).toHaveLength(3);
+ expect(options[0]).toHaveTextContent("English (U.S.) (en-US)");
+ expect(options[1]).toHaveTextContent("Japanese (ja)");
+ expect(options[2]).toHaveTextContent("Add Locale...");
});
});
- it("shows truncated description in collapsed locale row", async () => {
+ it("auto-selects en-US locale and populates form", async () => {
render(
);
- await user.click(screen.getByText("Localizations"));
await waitFor(() => {
- expect(screen.getByText("English description")).toBeInTheDocument();
+ expect(screen.getByDisplayValue("Try now")).toBeInTheDocument();
+ expect(screen.getByDisplayValue("English description")).toBeInTheDocument();
+ expect(screen.getByDisplayValue("Bug fixes")).toBeInTheDocument();
+ expect(screen.getByDisplayValue("test,app")).toBeInTheDocument();
+ expect(screen.getByDisplayValue("https://support.example.com")).toBeInTheDocument();
+ expect(screen.getByDisplayValue("https://example.com")).toBeInTheDocument();
});
});
- describe("Edit mode", () => {
- async function expandAndWait() {
+ describe("Prev/Next locale buttons", () => {
+ it("disables Previous button on first locale and enables Next", async () => {
+ render(
);
+
+ await waitFor(() => {
+ expect(screen.getByLabelText("Previous locale")).toBeDisabled();
+ expect(screen.getByLabelText("Next locale")).not.toBeDisabled();
+ });
+ });
+
+ it("navigates to next locale when Next is clicked", async () => {
render(
);
- await user.click(screen.getByText("Localizations"));
- await waitFor(() => expect(screen.getByText("en-US")).toBeInTheDocument());
- }
- it("enters edit mode when Edit is clicked", async () => {
- await expandAndWait();
+ await waitFor(() => {
+ expect(screen.getByDisplayValue("English description")).toBeInTheDocument();
+ });
+
+ await user.click(screen.getByLabelText("Next locale"));
+
+ expect(screen.getByDisplayValue("Japanese description")).toBeInTheDocument();
+ expect(screen.getByLabelText("Previous locale")).not.toBeDisabled();
+ expect(screen.getByLabelText("Next locale")).toBeDisabled();
+ });
- const editButtons = screen.getAllByText("Edit");
- await user.click(editButtons[0]);
+ it("navigates back to previous locale when Previous is clicked", async () => {
+ render(
);
+
+ await waitFor(() => {
+ expect(screen.getByDisplayValue("English description")).toBeInTheDocument();
+ });
+ await user.click(screen.getByLabelText("Next locale"));
+ expect(screen.getByDisplayValue("Japanese description")).toBeInTheDocument();
+
+ await user.click(screen.getByLabelText("Previous locale"));
expect(screen.getByDisplayValue("English description")).toBeInTheDocument();
- expect(screen.getByDisplayValue("Bug fixes")).toBeInTheDocument();
- expect(screen.getByDisplayValue("test,app")).toBeInTheDocument();
- expect(screen.getByDisplayValue("Try now")).toBeInTheDocument();
- expect(screen.getByDisplayValue("https://support.example.com")).toBeInTheDocument();
- expect(screen.getByDisplayValue("https://example.com")).toBeInTheDocument();
});
+ });
- it("cancels edit mode", async () => {
- await expandAndWait();
+ it("preserves edits when switching locales and back", async () => {
+ render(
);
- await user.click(screen.getAllByText("Edit")[0]);
+ await waitFor(() => {
expect(screen.getByDisplayValue("English description")).toBeInTheDocument();
+ });
- await user.click(screen.getByText("Cancel"));
- expect(screen.queryByDisplayValue("English description")).not.toBeInTheDocument();
+ // Edit en-US description
+ const descField = screen.getByDisplayValue("English description");
+ await user.clear(descField);
+ await user.type(descField, "Modified English");
+
+ // Switch to ja
+ const dropdown = screen.getByLabelText("Select locale");
+ await user.selectOptions(dropdown, "loc-2");
+ expect(screen.getByDisplayValue("Japanese description")).toBeInTheDocument();
+
+ // Switch back to en-US -- edits should be preserved
+ await user.selectOptions(dropdown, "loc-1");
+ expect(screen.getByDisplayValue("Modified English")).toBeInTheDocument();
+
+ // Save should be enabled since form is dirty
+ expect(screen.getByText("Save")).not.toBeDisabled();
+ });
+
+ it("preserves edits on multiple locales independently", async () => {
+ render(
);
+
+ await waitFor(() => {
+ expect(screen.getByDisplayValue("English description")).toBeInTheDocument();
});
- it("saves changes and updates the list", async () => {
+ // Edit en-US
+ const descField = screen.getByDisplayValue("English description");
+ await user.clear(descField);
+ await user.type(descField, "Modified English");
+
+ // Switch to ja and edit it too
+ const dropdown = screen.getByLabelText("Select locale");
+ await user.selectOptions(dropdown, "loc-2");
+ const jaDescField = screen.getByDisplayValue("Japanese description");
+ await user.clear(jaDescField);
+ await user.type(jaDescField, "Modified Japanese");
+
+ // Switch back to en-US -- should have its own edits
+ await user.selectOptions(dropdown, "loc-1");
+ expect(screen.getByDisplayValue("Modified English")).toBeInTheDocument();
+
+ // Switch to ja -- should have its own edits
+ await user.selectOptions(dropdown, "loc-2");
+ expect(screen.getByDisplayValue("Modified Japanese")).toBeInTheDocument();
+ });
+
+ it("discard clears drafts for all locales", async () => {
+ render(
);
+
+ await waitFor(() => {
+ expect(screen.getByDisplayValue("English description")).toBeInTheDocument();
+ });
+
+ // Edit en-US
+ const descField = screen.getByDisplayValue("English description");
+ await user.clear(descField);
+ await user.type(descField, "Temp English");
+
+ // Switch to ja and edit it
+ const dropdown = screen.getByLabelText("Select locale");
+ await user.selectOptions(dropdown, "loc-2");
+ const jaField = screen.getByDisplayValue("Japanese description");
+ await user.clear(jaField);
+ await user.type(jaField, "Temp Japanese");
+
+ // Discard should clear all
+ await user.click(screen.getByText("Discard"));
+ expect(screen.getByDisplayValue("Japanese description")).toBeInTheDocument();
+ expect(screen.getByText("Save")).toBeDisabled();
+
+ // Switch back to en-US -- should also be reset
+ await user.selectOptions(dropdown, "loc-1");
+ expect(screen.getByDisplayValue("English description")).toBeInTheDocument();
+ });
+
+ it("defaults to en-US even when it is not first in the array", async () => {
+ fetchVersionLocalizations.mockResolvedValue([MOCK_LOCS[1], MOCK_LOCS[0]]);
+
+ render(
);
+
+ await waitFor(() => {
+ const dropdown = screen.getByLabelText("Select locale");
+ expect(dropdown.value).toBe("loc-1");
+ expect(screen.getByDisplayValue("English description")).toBeInTheDocument();
+ });
+ });
+
+ it("switches locale and updates form fields", async () => {
+ render(
);
+
+ await waitFor(() => {
+ expect(screen.getByDisplayValue("English description")).toBeInTheDocument();
+ });
+
+ const dropdown = screen.getByLabelText("Select locale");
+ await user.selectOptions(dropdown, "loc-2");
+
+ expect(screen.getByDisplayValue("Japanese description")).toBeInTheDocument();
+ expect(screen.queryByDisplayValue("English description")).not.toBeInTheDocument();
+ });
+
+ it("displays character counters with remaining characters", async () => {
+ render(
);
+
+ await waitFor(() => {
+ expect(screen.getByDisplayValue("Try now")).toBeInTheDocument();
+ });
+
+ // "Try now" = 7 chars, 170 - 7 = 163
+ expect(screen.getByText("163 remaining")).toBeInTheDocument();
+ // "test,app" = 8 chars, 100 - 8 = 92
+ expect(screen.getByText("92 remaining")).toBeInTheDocument();
+ });
+
+ it("updates character counter in real-time when typing", async () => {
+ render(
);
+
+ await waitFor(() => {
+ expect(screen.getByDisplayValue("test,app")).toBeInTheDocument();
+ });
+
+ const keywordsField = screen.getByDisplayValue("test,app");
+ await user.type(keywordsField, ",new");
+
+ expect(screen.getByText("88 remaining")).toBeInTheDocument();
+ });
+
+ describe("Save and Discard", () => {
+ it("disables Save button when form is clean", async () => {
+ render(
);
+
+ await waitFor(() => {
+ expect(screen.getByText("Save")).toBeInTheDocument();
+ });
+
+ expect(screen.getByText("Save")).toBeDisabled();
+ });
+
+ it("enables Save button when form is dirty", async () => {
+ render(
);
+
+ await waitFor(() => {
+ expect(screen.getByDisplayValue("English description")).toBeInTheDocument();
+ });
+
+ const descField = screen.getByDisplayValue("English description");
+ await user.type(descField, " updated");
+
+ expect(screen.getByText("Save")).not.toBeDisabled();
+ });
+
+ it("saves changes and resets dirty state", async () => {
updateVersionLocalization.mockResolvedValue({
...MOCK_LOCS[0],
description: "Updated description",
});
- await expandAndWait();
- await user.click(screen.getAllByText("Edit")[0]);
+ render(
);
+
+ await waitFor(() => {
+ expect(screen.getByDisplayValue("English description")).toBeInTheDocument();
+ });
const descField = screen.getByDisplayValue("English description");
await user.clear(descField);
@@ -192,65 +357,123 @@ describe("VersionLocalizationsSection", () => {
});
await waitFor(() => {
- expect(screen.getByText("Updated description")).toBeInTheDocument();
+ expect(screen.getByText("Save")).toBeDisabled();
});
});
- it("shows error when save fails", async () => {
- updateVersionLocalization.mockRejectedValue(new Error("Save failed"));
+ it("saves all dirty locales at once", async () => {
+ updateVersionLocalization
+ .mockResolvedValueOnce({ ...MOCK_LOCS[0], description: "New English" })
+ .mockResolvedValueOnce({ ...MOCK_LOCS[1], description: "New Japanese" });
- await expandAndWait();
- await user.click(screen.getAllByText("Edit")[0]);
- await user.click(screen.getByText("Save"));
+ render(
);
await waitFor(() => {
- expect(screen.getByText("Save failed")).toBeInTheDocument();
+ expect(screen.getByDisplayValue("English description")).toBeInTheDocument();
});
- });
- });
- describe("Delete", () => {
- it("deletes a localization and removes it from the list", async () => {
- deleteVersionLocalization.mockResolvedValue({ success: true });
+ // Edit en-US
+ const enField = screen.getByDisplayValue("English description");
+ await user.clear(enField);
+ await user.type(enField, "New English");
- render(
);
- await user.click(screen.getByText("Localizations"));
- await waitFor(() => expect(screen.getByText("en-US")).toBeInTheDocument());
+ // Switch to ja and edit
+ const dropdown = screen.getByLabelText("Select locale");
+ await user.selectOptions(dropdown, "loc-2");
+ const jaField = screen.getByDisplayValue("Japanese description");
+ await user.clear(jaField);
+ await user.type(jaField, "New Japanese");
- const deleteButtons = screen.getAllByText("Delete");
- await user.click(deleteButtons[0]);
+ // Save should save both
+ await user.click(screen.getByText("Save"));
await waitFor(() => {
- expect(deleteVersionLocalization).toHaveBeenCalledWith("app-1", "ver-1", "loc-1", "acc-1");
+ expect(updateVersionLocalization).toHaveBeenCalledTimes(2);
});
await waitFor(() => {
- expect(screen.queryByText("English description")).not.toBeInTheDocument();
- expect(screen.getByText("ja")).toBeInTheDocument();
+ expect(screen.getByText("Save")).toBeDisabled();
});
});
- it("shows error when delete fails", async () => {
- deleteVersionLocalization.mockRejectedValue(new Error("Cannot delete primary"));
+ it("keeps Save enabled when a non-selected locale has unsaved changes", async () => {
+ render(
);
+
+ await waitFor(() => {
+ expect(screen.getByDisplayValue("English description")).toBeInTheDocument();
+ });
+
+ // Edit en-US
+ const descField = screen.getByDisplayValue("English description");
+ await user.type(descField, " changed");
+
+ // Switch to ja (clean locale) -- Save should still be enabled
+ const dropdown = screen.getByLabelText("Select locale");
+ await user.selectOptions(dropdown, "loc-2");
+
+ expect(screen.getByText("Save")).not.toBeDisabled();
+ });
+
+ it("shows error when save fails", async () => {
+ updateVersionLocalization.mockRejectedValue(new Error("Save failed"));
render(
);
- await user.click(screen.getByText("Localizations"));
- await waitFor(() => expect(screen.getByText("en-US")).toBeInTheDocument());
- await user.click(screen.getAllByText("Delete")[0]);
+ await waitFor(() => {
+ expect(screen.getByDisplayValue("English description")).toBeInTheDocument();
+ });
+
+ const descField = screen.getByDisplayValue("English description");
+ await user.type(descField, " changed");
+
+ await user.click(screen.getByText("Save"));
await waitFor(() => {
- expect(screen.getByText("Cannot delete primary")).toBeInTheDocument();
+ expect(screen.getByText("Save failed")).toBeInTheDocument();
});
});
+
+ it("discards changes and resets form to stored values", async () => {
+ render(
);
+
+ await waitFor(() => {
+ expect(screen.getByDisplayValue("English description")).toBeInTheDocument();
+ });
+
+ const descField = screen.getByDisplayValue("English description");
+ await user.clear(descField);
+ await user.type(descField, "Temporary changes");
+
+ expect(screen.getByDisplayValue("Temporary changes")).toBeInTheDocument();
+
+ await user.click(screen.getByText("Discard"));
+
+ expect(screen.getByDisplayValue("English description")).toBeInTheDocument();
+ expect(screen.queryByDisplayValue("Temporary changes")).not.toBeInTheDocument();
+ expect(screen.getByText("Save")).toBeDisabled();
+ });
});
- describe("Add localization", () => {
- it("creates a new localization and appends to the list", async () => {
+ describe("Add Locale", () => {
+ it("shows locale code input when Add Locale is selected", async () => {
+ render(
);
+
+ await waitFor(() => {
+ expect(screen.getByLabelText("Select locale")).toBeInTheDocument();
+ });
+
+ const dropdown = screen.getByLabelText("Select locale");
+ await user.selectOptions(dropdown, "__add__");
+
+ expect(screen.getByLabelText("New locale code")).toBeInTheDocument();
+ expect(screen.getByPlaceholderText("e.g. de-DE")).toBeInTheDocument();
+ });
+
+ it("creates a new locale and selects it", async () => {
const newLoc = {
id: "loc-3",
- locale: "de",
- description: "German desc",
+ locale: "de-DE",
+ description: "",
whatsNew: "",
keywords: "",
promotionalText: "",
@@ -260,84 +483,124 @@ describe("VersionLocalizationsSection", () => {
createVersionLocalization.mockResolvedValue(newLoc);
render(
);
- await user.click(screen.getByText("Localizations"));
- await waitFor(() => expect(screen.getByText("en-US")).toBeInTheDocument());
- const localeInput = screen.getByPlaceholderText("e.g. en-US, ja, de");
- await user.type(localeInput, "de");
+ await waitFor(() => {
+ expect(screen.getByLabelText("Select locale")).toBeInTheDocument();
+ });
- const descFields = screen.getAllByPlaceholderText("Description");
- const addDescField = descFields[descFields.length - 1];
- await user.type(addDescField, "German desc");
+ await user.selectOptions(screen.getByLabelText("Select locale"), "__add__");
- await user.click(screen.getByText("Add Localization"));
+ const codeInput = screen.getByLabelText("New locale code");
+ await user.type(codeInput, "de-DE");
+ await user.click(screen.getByText("Add"));
await waitFor(() => {
expect(createVersionLocalization).toHaveBeenCalledWith(
"app-1", "ver-1",
expect.objectContaining({
accountId: "acc-1",
- locale: "de",
- description: "German desc",
+ locale: "de-DE",
})
);
});
await waitFor(() => {
- expect(screen.getByText("de")).toBeInTheDocument();
+ const dropdown = screen.getByLabelText("Select locale");
+ expect(dropdown.value).toBe("loc-3");
});
});
- it("disables Add button when locale is empty", async () => {
+ it("shows error when add locale fails", async () => {
+ createVersionLocalization.mockRejectedValue(new Error("Duplicate locale"));
+
render(
);
- await user.click(screen.getByText("Localizations"));
- await waitFor(() => expect(screen.getByText("en-US")).toBeInTheDocument());
- expect(screen.getByText("Add Localization")).toBeDisabled();
+ await waitFor(() => {
+ expect(screen.getByLabelText("Select locale")).toBeInTheDocument();
+ });
+
+ await user.selectOptions(screen.getByLabelText("Select locale"), "__add__");
+
+ await user.type(screen.getByLabelText("New locale code"), "en-US");
+ await user.click(screen.getByText("Add"));
+
+ await waitFor(() => {
+ expect(screen.getByText("Duplicate locale")).toBeInTheDocument();
+ });
});
- it("clears form after successful add", async () => {
- createVersionLocalization.mockResolvedValue({
- id: "loc-3", locale: "fr", description: "", whatsNew: "",
- keywords: "", promotionalText: "", supportUrl: "", marketingUrl: "",
+ it("cancels add locale flow", async () => {
+ render(
);
+
+ await waitFor(() => {
+ expect(screen.getByLabelText("Select locale")).toBeInTheDocument();
});
+ await user.selectOptions(screen.getByLabelText("Select locale"), "__add__");
+ expect(screen.getByLabelText("New locale code")).toBeInTheDocument();
+
+ await user.click(screen.getByText("Cancel"));
+ expect(screen.queryByLabelText("New locale code")).not.toBeInTheDocument();
+ expect(screen.getByLabelText("Select locale")).toBeInTheDocument();
+ });
+ });
+
+ describe("Delete Locale", () => {
+ it("shows Delete Locale button when 2+ locales exist", async () => {
render(
);
- await user.click(screen.getByText("Localizations"));
- await waitFor(() => expect(screen.getByText("en-US")).toBeInTheDocument());
- const localeInput = screen.getByPlaceholderText("e.g. en-US, ja, de");
- await user.type(localeInput, "fr");
- await user.click(screen.getByText("Add Localization"));
+ await waitFor(() => {
+ expect(screen.getByText("Delete Locale")).toBeInTheDocument();
+ });
+ });
+
+ it("hides Delete Locale button when only 1 locale exists", async () => {
+ fetchVersionLocalizations.mockResolvedValue([MOCK_LOCS[0]]);
+
+ render(
);
await waitFor(() => {
- expect(localeInput).toHaveValue("");
+ expect(screen.getByDisplayValue("English description")).toBeInTheDocument();
});
+
+ expect(screen.queryByText("Delete Locale")).not.toBeInTheDocument();
});
- it("shows error when add fails", async () => {
- createVersionLocalization.mockRejectedValue(new Error("Duplicate locale"));
+ it("deletes a locale and switches to another", async () => {
+ deleteVersionLocalization.mockResolvedValue({ success: true });
render(
);
- await user.click(screen.getByText("Localizations"));
- await waitFor(() => expect(screen.getByText("en-US")).toBeInTheDocument());
- const localeInput = screen.getByPlaceholderText("e.g. en-US, ja, de");
- await user.type(localeInput, "en-US");
- await user.click(screen.getByText("Add Localization"));
+ await waitFor(() => {
+ expect(screen.getByText("Delete Locale")).toBeInTheDocument();
+ });
+
+ await user.click(screen.getByText("Delete Locale"));
await waitFor(() => {
- expect(screen.getByText("Duplicate locale")).toBeInTheDocument();
+ expect(deleteVersionLocalization).toHaveBeenCalledWith("app-1", "ver-1", "loc-1", "acc-1");
+ });
+
+ await waitFor(() => {
+ expect(screen.getByDisplayValue("Japanese description")).toBeInTheDocument();
+ expect(screen.queryByText("Delete Locale")).not.toBeInTheDocument();
});
});
- });
- it("collapses when clicking the header again", async () => {
- render(
);
- await user.click(screen.getByText("Localizations"));
- await waitFor(() => expect(screen.getByText("en-US")).toBeInTheDocument());
+ it("shows error when delete fails", async () => {
+ deleteVersionLocalization.mockRejectedValue(new Error("Cannot delete primary"));
- await user.click(screen.getByText("Localizations"));
- expect(screen.queryByText("en-US")).not.toBeInTheDocument();
+ render(
);
+
+ await waitFor(() => {
+ expect(screen.getByText("Delete Locale")).toBeInTheDocument();
+ });
+
+ await user.click(screen.getByText("Delete Locale"));
+
+ await waitFor(() => {
+ expect(screen.getByText("Cannot delete primary")).toBeInTheDocument();
+ });
+ });
});
});