Files
VoiceStudio/frontend/src/test/LanguageSwitchPrompt.test.jsx
T
Palash Debnath 5cab8e0149 feat: rename the product to VoiceStudio (previously OmniVoice-Studio)
Renames what users see. The app, the installers, the window title, the
docs and all 21 locales now say VoiceStudio, with "(previously
OmniVoice-Studio)" noted near the title of each doc surface so people
recognise it.

Deliberately NOT renamed, because renaming any of them silently breaks
an existing install — there is no legacy-path fallback anywhere in this
codebase:

  - bundle identifier com.debpalash.omnivoice-studio (MSI UpgradeCode,
    macOS TCC grants, managed venv, WebView localStorage, the
    single-instance lock)
  - data directories OmniVoice / .omnivoice and omnivoice.db
  - the ~150 OMNIVOICE_* environment variables
  - the X-OmniVoice-* HTTP headers (a wire protocol)
  - the published Docker image paths
  - the OmniVoice ENGINE, which is a model name and not this product

tests/test_identity_paths_survive_the_rename.py pins every one of those
so a future well-meaning sweep cannot orphan a user's library.

Linux .deb users install a new package name and should apt remove
omnivoice-studio; that note is in the changelog.
2026-08-07 01:30:58 +05:30

86 lines
3.1 KiB
React

import React from 'react';
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { I18nextProvider } from 'react-i18next';
import i18n from '../i18n';
import { useAppStore } from '../store';
import LanguageSwitchPrompt from '../components/LanguageSwitchPrompt';
const withI18n = (node) => <I18nextProvider i18n={i18n}>{node}</I18nextProvider>;
// The real store's persist has already hydrated (empty localStorage, sync
// storage), so `hasHydrated()` is true and the component renders immediately.
function seed(partial) {
useAppStore.setState({
locale: 'de',
localeChosen: false,
langPromptSeen: false,
...partial,
});
}
beforeEach(() => {
seed({});
});
afterEach(() => {
vi.restoreAllMocks();
});
describe('LanguageSwitchPrompt — first-run offer to switch the UI to English', () => {
it('shows for a non-English first run with no prior choice', async () => {
render(withI18n(<LanguageSwitchPrompt />));
expect(await screen.findByTestId('language-switch-prompt')).toBeInTheDocument();
// Bilingual: the English offer line is always present (native name = Deutsch).
expect(
screen.getByText(/VoiceStudio opened in Deutsch\. Prefer English\?/),
).toBeInTheDocument();
expect(screen.getByTestId('language-switch-english')).toBeInTheDocument();
});
it('never shows for an English UI', () => {
seed({ locale: 'en' });
const { container } = render(withI18n(<LanguageSwitchPrompt />));
expect(container.firstChild).toBeNull();
});
it('never shows once the seen flag is set (one-time)', () => {
seed({ langPromptSeen: true });
const { container } = render(withI18n(<LanguageSwitchPrompt />));
expect(container.firstChild).toBeNull();
});
it('never shows once the user has explicitly chosen a language', () => {
seed({ localeChosen: true });
const { container } = render(withI18n(<LanguageSwitchPrompt />));
expect(container.firstChild).toBeNull();
});
it('"Switch to English" changes the language, records the choice, sets the flag', async () => {
const changeSpy = vi.spyOn(i18n, 'changeLanguage');
render(withI18n(<LanguageSwitchPrompt />));
fireEvent.click(await screen.findByTestId('language-switch-english'));
expect(changeSpy).toHaveBeenCalledWith('en');
const s = useAppStore.getState();
expect(s.locale).toBe('en');
expect(s.localeChosen).toBe(true); // setLocale records the explicit choice
expect(s.langPromptSeen).toBe(true);
await waitFor(() =>
expect(screen.queryByTestId('language-switch-prompt')).not.toBeInTheDocument(),
);
});
it('"Keep" dismisses and sets the flag without touching the language', async () => {
render(withI18n(<LanguageSwitchPrompt />));
fireEvent.click(await screen.findByTestId('language-switch-keep'));
const s = useAppStore.getState();
expect(s.locale).toBe('de'); // language untouched
expect(s.localeChosen).toBe(false);
expect(s.langPromptSeen).toBe(true);
await waitFor(() =>
expect(screen.queryByTestId('language-switch-prompt')).not.toBeInTheDocument(),
);
});
});