diff --git a/frontend/cypress/e2e/language.spec.ts b/frontend/cypress/e2e/language.spec.ts
deleted file mode 100644
index c2a47d82a..000000000
--- a/frontend/cypress/e2e/language.spec.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
- *
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-import { languages } from '../fixtures/languages'
-
-describe('Languages', () => {
- beforeEach(() => {
- cy.visitHome()
- cy.getByCypressId('settingsButton').click()
- })
-
- it('all languages are available', () => {
- cy.getByCypressId('language-picker').find('option').as('languages')
- cy.get('@languages').should('have.length', 28)
- languages.forEach((language) => {
- cy.get('@languages').contains(language)
- })
- })
-
- it('language changes affect the UI', () => {
- cy.getByCypressId('language-picker').select('English')
- cy.getByCypressId('new-note-button').contains('New Note')
- cy.getByCypressId('language-picker').select('Deutsch')
- cy.getByCypressId('new-note-button').contains('Neue Notiz')
- })
-})
diff --git a/frontend/src/components/layout/settings-dialog/global/__snapshots__/language-picker.spec.tsx.snap b/frontend/src/components/layout/settings-dialog/global/__snapshots__/language-picker.spec.tsx.snap
new file mode 100644
index 000000000..df6fb027b
--- /dev/null
+++ b/frontend/src/components/layout/settings-dialog/global/__snapshots__/language-picker.spec.tsx.snap
@@ -0,0 +1,22 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`language picker renders all languages 1`] = `
+
+
+
+`;
diff --git a/frontend/src/components/layout/settings-dialog/global/language-picker.spec.tsx b/frontend/src/components/layout/settings-dialog/global/language-picker.spec.tsx
new file mode 100644
index 000000000..df1f34db5
--- /dev/null
+++ b/frontend/src/components/layout/settings-dialog/global/language-picker.spec.tsx
@@ -0,0 +1,37 @@
+/*
+ * SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+import { mockI18n } from '../../../../test-utils/mock-i18n'
+import { LanguagePicker } from './language-picker'
+import { fireEvent, render, screen } from '@testing-library/react'
+import i18n from 'i18next'
+
+jest.mock('./available-languages', () => ({
+ availableLanguages: jest.fn(() => ['de', 'en'])
+}))
+
+describe('language picker', () => {
+ beforeAll(() => mockI18n())
+
+ it('renders all languages', () => {
+ const view = render()
+ expect(view.container).toMatchSnapshot()
+ expect(i18n.language).toBe('en')
+ })
+
+ it('can change the language', async () => {
+ render()
+
+ const option: HTMLOptionElement = await screen.findByText('Deutsch')
+
+ expect(option.selected).toBeFalsy()
+ expect(i18n.language).toBe('en')
+
+ fireEvent.change(screen.getByTestId('language-picker'), { target: { value: 'de' } })
+
+ expect(option.selected).toBeTruthy()
+ expect(i18n.language).toBe('de')
+ })
+})
diff --git a/frontend/src/components/layout/settings-dialog/global/language-picker.tsx b/frontend/src/components/layout/settings-dialog/global/language-picker.tsx
index ea5e4a42e..e5f424fe1 100644
--- a/frontend/src/components/layout/settings-dialog/global/language-picker.tsx
+++ b/frontend/src/components/layout/settings-dialog/global/language-picker.tsx
@@ -5,6 +5,7 @@
*/
import { cypressId } from '../../../../utils/cypress-attribute'
import { Logger } from '../../../../utils/logger'
+import { testId } from '../../../../utils/test-id'
import { availableLanguages } from './available-languages'
import { LanguageOption } from './language-option'
import React, { useCallback, useMemo } from 'react'
@@ -59,6 +60,7 @@ export const LanguagePicker: React.FC = () => {
className='w-auto'
value={languageCode}
onChange={onChangeLang}
+ {...testId('language-picker')}
{...cypressId('language-picker')}>
{languageOptions}