diff --git a/frontend/src/tests/LanguageSwitcher.test.tsx b/frontend/src/tests/LanguageSwitcher.test.tsx
new file mode 100644
index 00000000..bbba101f
--- /dev/null
+++ b/frontend/src/tests/LanguageSwitcher.test.tsx
@@ -0,0 +1,93 @@
+import { render, screen } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import { describe, it, expect, vi, beforeEach } from "vitest";
+import LanguageSwitcher from "../components/languageSwitcher/LanguageSwitcher";
+
+const changeLanguage = vi.fn();
+
+let mockLanguage = "no";
+
+vi.mock("react-i18next", () => ({
+ useTranslation: () => ({
+ i18n: {
+ get language() {
+ return mockLanguage;
+ },
+ changeLanguage,
+ },
+ }),
+}));
+
+describe("LanguageSwitcher", () => {
+ beforeEach(() => {
+ changeLanguage.mockClear();
+ mockLanguage = "no";
+ });
+
+ // When app is in language 'no'
+ describe("når språket er norsk (no)", () => {
+ it('viser "EN" som knappetekst', () => {
+ render();
+
+ expect(screen.getByRole("button")).toHaveTextContent("EN");
+ });
+
+ it('har aria-label "Switch to English"', () => {
+ render();
+
+ expect(screen.getByRole("button")).toHaveAccessibleName(
+ "Switch to English",
+ );
+ });
+
+ it('kaller changeLanguage med "en" ved klikk', async () => {
+ const user = userEvent.setup();
+ render();
+
+ await user.click(screen.getByRole("button"));
+
+ expect(changeLanguage).toHaveBeenCalledWith("en");
+ expect(changeLanguage).toHaveBeenCalledTimes(1);
+ });
+ });
+
+ // When app is in language 'en'
+ describe("når språket er engelsk (en)", () => {
+ beforeEach(() => {
+ mockLanguage = "en";
+ });
+
+ it('viser "NO" som knappetekst', () => {
+ render();
+ expect(screen.getByRole("button")).toHaveTextContent("NO");
+ });
+
+ it('har aria-label "Bytt til norsk"', () => {
+ render();
+ expect(screen.getByRole("button")).toHaveAccessibleName("Bytt til norsk");
+ });
+
+ it('kaller changeLanguage med "nb" ved klikk', async () => {
+ const user = userEvent.setup();
+ render();
+
+ await user.click(screen.getByRole("button"));
+
+ expect(changeLanguage).toHaveBeenCalledWith("no");
+ expect(changeLanguage).toHaveBeenCalledTimes(1);
+ });
+ });
+
+ // Snapshot tests
+ it("matcher snapshot (norsk)", () => {
+ mockLanguage = "no";
+ const { container } = render();
+ expect(container).toMatchSnapshot();
+ });
+
+ it("matcher snapshot (engelsk)", () => {
+ mockLanguage = "en";
+ const { container } = render();
+ expect(container).toMatchSnapshot();
+ });
+});
diff --git a/frontend/src/tests/Translation.test.tsx b/frontend/src/tests/Translation.test.tsx
new file mode 100644
index 00000000..49793bfe
--- /dev/null
+++ b/frontend/src/tests/Translation.test.tsx
@@ -0,0 +1,21 @@
+import { describe, it, expect } from "vitest";
+import no from "../i18n/locales/no/translation.json";
+import en from "../i18n/locales/en/translation.json";
+
+// Turns nested translations into a flat list of keys, e.g. "explorePage.watering"
+function flatten(obj: Record, prefix = ""): string[] {
+ return Object.entries(obj).flatMap(([key, value]) =>
+ typeof value === "object" && value !== null
+ ? flatten(value as Record, `${prefix}${key}.`)
+ : [`${prefix}${key}`],
+ );
+}
+
+// checks that Norwegian and English have exactly the same keys.
+// If a key is missing in one language, the test fails and shows
+// a diff of the two key lists, so you can see which keys differ.
+describe("translations", () => {
+ it("Norwegian and English have the same keys", () => {
+ expect(flatten(en).sort()).toEqual(flatten(no).sort());
+ });
+});
diff --git a/frontend/src/tests/__snapshots__/LanguageSwitcher.test.tsx.snap b/frontend/src/tests/__snapshots__/LanguageSwitcher.test.tsx.snap
new file mode 100644
index 00000000..07eedcb4
--- /dev/null
+++ b/frontend/src/tests/__snapshots__/LanguageSwitcher.test.tsx.snap
@@ -0,0 +1,25 @@
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
+
+exports[`LanguageSwitcher > matcher snapshot (engelsk) 1`] = `
+
+
+
+`;
+
+exports[`LanguageSwitcher > matcher snapshot (norsk) 1`] = `
+
+
+
+`;