From 77eff19ace1b4466a203ecec5a1ef6769b42274c Mon Sep 17 00:00:00 2001 From: Anan Zhuang Date: Thu, 15 Aug 2024 02:14:36 +0000 Subject: [PATCH] fix tests Signed-off-by: Anan Zhuang --- packages/osd-i18n/src/core/i18n.test.ts | 34 ++++++++++- .../public/application/scoped_history.test.ts | 60 +++++++++++++++++++ src/core/public/application/scoped_history.ts | 3 +- src/core/public/locale_helper.test.ts | 12 ++-- src/core/public/locale_helper.ts | 6 +- src/core/public/osd_bootstrap.ts | 5 +- 6 files changed, 107 insertions(+), 13 deletions(-) diff --git a/packages/osd-i18n/src/core/i18n.test.ts b/packages/osd-i18n/src/core/i18n.test.ts index 0ee114c78c9..ebfd546f856 100644 --- a/packages/osd-i18n/src/core/i18n.test.ts +++ b/packages/osd-i18n/src/core/i18n.test.ts @@ -899,8 +899,17 @@ describe('I18n engine', () => { describe('load', () => { let mockFetch: jest.SpyInstance; + let originalWindow: any; + beforeEach(() => { mockFetch = jest.spyOn(global as any, 'fetch').mockImplementation(); + originalWindow = global.window; + global.window = { ...originalWindow }; + }); + + afterEach(() => { + global.window = originalWindow; + delete (window as any).__i18nWarning; // Clear the warning after each test }); test('fails if server returns >= 300 status code', async () => { @@ -928,7 +937,7 @@ describe('I18n engine', () => { mockFetch.mockResolvedValue({ status: 200, - json: jest.fn().mockResolvedValue(translations), + json: jest.fn().mockResolvedValue({ translations }), }); await expect(i18n.load('some-url')).resolves.toBeUndefined(); @@ -938,5 +947,28 @@ describe('I18n engine', () => { expect(i18n.getTranslation()).toEqual(translations); }); + + test('sets warning on window when present in response', async () => { + const warning = { title: 'Warning', text: 'This is a warning' }; + mockFetch.mockResolvedValue({ + status: 200, + json: jest.fn().mockResolvedValue({ translations: { locale: 'en' }, warning }), + }); + + await i18n.load('some-url'); + + expect((window as any).__i18nWarning).toEqual(warning); + }); + + test('does not set warning on window when not present in response', async () => { + mockFetch.mockResolvedValue({ + status: 200, + json: jest.fn().mockResolvedValue({ translations: { locale: 'en' } }), + }); + + await i18n.load('some-url'); + + expect((window as any).__i18nWarning).toBeUndefined(); + }); }); }); diff --git a/src/core/public/application/scoped_history.test.ts b/src/core/public/application/scoped_history.test.ts index 067c33256bd..6575a6aa1ab 100644 --- a/src/core/public/application/scoped_history.test.ts +++ b/src/core/public/application/scoped_history.test.ts @@ -30,8 +30,23 @@ import { ScopedHistory } from './scoped_history'; import { createMemoryHistory } from 'history'; +import { getLocaleInUrl } from '../locale_helper'; +import { i18n } from '@osd/i18n'; + +jest.mock('../locale_helper', () => ({ + getLocaleInUrl: jest.fn(), +})); + +jest.mock('@osd/i18n', () => ({ + i18n: { + getLocale: jest.fn(), + }, +})); describe('ScopedHistory', () => { + beforeEach(() => { + (getLocaleInUrl as jest.Mock).mockReturnValue('en'); + }); describe('construction', () => { it('succeeds if current location matches basePath', () => { const gh = createMemoryHistory(); @@ -358,4 +373,49 @@ describe('ScopedHistory', () => { expect(gh.length).toBe(4); }); }); + + describe('locale handling', () => { + let originalLocation: Location; + + beforeEach(() => { + originalLocation = window.location; + delete (window as any).location; + window.location = { href: 'http://localhost/app/wow', reload: jest.fn() } as any; + (i18n.getLocale as jest.Mock).mockReturnValue('en'); + }); + + afterEach(() => { + window.location = originalLocation; + jest.resetAllMocks(); + }); + + it('reloads the page when locale changes', () => { + const gh = createMemoryHistory(); + gh.push('/app/wow'); + const h = new ScopedHistory(gh, '/app/wow'); + // Use the 'h' variable to trigger the listener + h.push('/new-page'); + + // Mock getLocaleInUrl to return a different locale + (getLocaleInUrl as jest.Mock).mockReturnValue('fr'); + + // Simulate navigation + gh.push('/app/wow/new-page'); + + expect(window.location.reload).toHaveBeenCalled(); + }); + + it('does not reload the page when locale changes', () => { + const gh = createMemoryHistory(); + gh.push('/app/wow'); + + // Mock getLocaleInUrl to return a different locale + (getLocaleInUrl as jest.Mock).mockReturnValue('en'); + + // Simulate navigation + gh.push('/app/wow/new-page'); + + expect(window.location.reload).not.toHaveBeenCalled(); + }); + }); }); diff --git a/src/core/public/application/scoped_history.ts b/src/core/public/application/scoped_history.ts index 2befe5335bc..74e4bb068d3 100644 --- a/src/core/public/application/scoped_history.ts +++ b/src/core/public/application/scoped_history.ts @@ -317,8 +317,9 @@ export class ScopedHistory this.isActive = false; return; } - // const fullUrl = `${location.pathname}${location.search}${location.hash}`; + const localeValue = getLocaleInUrl(window.location.href); + if (localeValue !== currentLocale) { // Force a full page reload window.location.reload(); diff --git a/src/core/public/locale_helper.test.ts b/src/core/public/locale_helper.test.ts index 0ba878feae3..238dbced389 100644 --- a/src/core/public/locale_helper.test.ts +++ b/src/core/public/locale_helper.test.ts @@ -21,21 +21,21 @@ describe('getLocaleInUrl', () => { expect(getLocaleInUrl(url)).toBe('fr-FR'); }); - it('should return null for a URL without locale', () => { + it('should return en for a URL without locale', () => { const url = 'http://localhost:5603/app/home'; - expect(getLocaleInUrl(url)).toBeNull(); + expect(getLocaleInUrl(url)).toBe('en'); }); - it('should return null and set a warning for an invalid locale format in hash', () => { + it('should return en and set a warning for an invalid locale format in hash', () => { const url = 'http://localhost:5603/app/home#/&locale=de-DE'; - expect(getLocaleInUrl(url)).toBeNull(); + expect(getLocaleInUrl(url)).toBe('en'); expect((window as any).__localeWarning).toBeDefined(); expect((window as any).__localeWarning.title).toBe('Invalid URL Format'); }); - it('should return null for an empty locale value', () => { + it('should return en for an empty locale value', () => { const url = 'http://localhost:5603/app/home?locale='; - expect(getLocaleInUrl(url)).toBeNull(); + expect(getLocaleInUrl(url)).toBe('en'); }); it('should handle URLs with other query parameters', () => { diff --git a/src/core/public/locale_helper.ts b/src/core/public/locale_helper.ts index 77ac4b4583f..38a734a523b 100644 --- a/src/core/public/locale_helper.ts +++ b/src/core/public/locale_helper.ts @@ -43,11 +43,11 @@ export function getLocaleInUrl(url: string): string | null { // Check for non standard query format: if (localeValue === null && url.includes('&locale=')) { setInvalidUrlWithLocaleWarning(); - return null; + return 'en'; } - // Return the locale value if found, or null if not found - return localeValue && localeValue.trim() !== '' ? localeValue : null; + // Return the locale value if found, or 'en' if not found + return localeValue && localeValue.trim() !== '' ? localeValue : 'en'; } function setInvalidUrlWarning(): void { diff --git a/src/core/public/osd_bootstrap.ts b/src/core/public/osd_bootstrap.ts index b1f00d25ca1..5190fdc37e2 100644 --- a/src/core/public/osd_bootstrap.ts +++ b/src/core/public/osd_bootstrap.ts @@ -40,9 +40,10 @@ export async function __osdBootstrap__() { ); // Extract the locale from the URL if present + const currentLocale = i18n.getLocale(); const urlLocale = getLocaleInUrl(window.location.href); - if (urlLocale) { + if (urlLocale && urlLocale !== currentLocale) { // If a locale is specified in the URL, update the i18n settings // This enables dynamic language switching // Note: This works in conjunction with server-side changes: @@ -61,7 +62,7 @@ export async function __osdBootstrap__() { /\/([^/]+)\.json$/, `/${urlLocale}.json` ); - } else { + } else if (!urlLocale) { i18n.setLocale('en'); }