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.
86 lines
3.1 KiB
React
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(),
|
|
);
|
|
});
|
|
});
|