Skip to content

Commit

Permalink
test: increase test coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
dcoa committed Feb 11, 2025
1 parent a62e8db commit 46448d2
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 29 deletions.
4 changes: 0 additions & 4 deletions src/react/hooks/paragon/useParagonTheme.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,6 @@ export const getDefaultThemeVariant = ({ themeVariants, themeVariantDefaults = {

const themeVariantKeys = Object.keys(themeVariants);

// Return early if there are no theme variants configured.
if (themeVariantKeys.length === 0) {
return undefined;
}
// If there is only one theme variant, return it since it's the only one that may be used.
if (themeVariantKeys.length === 1) {
const themeVariantKey = themeVariantKeys[0];
Expand Down
40 changes: 36 additions & 4 deletions src/react/hooks/paragon/useParagonTheme.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import { act, renderHook } from '@testing-library/react-hooks';

import useParagonTheme from './useParagonTheme';
import { getConfig } from '../../../config';
import { logError } from '../../../logging';

jest.mock('../../../logging');

const PARAGON_THEME_URLS = {
core: {
Expand All @@ -16,12 +19,12 @@ const PARAGON_THEME_URLS = {
variants: {
light: {
urls: {
default: 'https://cdn.jsdelivr.net/npm/@edx/paragon@$21.0.0/dist/light.min.css',
default: 'https://cdn.jsdelivr.net/npm/@edx/paragon@21.0.0/dist/light.min.css',
},
},
dark: {
urls: {
default: 'https://cdn.jsdelivr.net/npm/@edx/paragon@$21.0.0/dist/dark.min.css',
default: 'https://cdn.jsdelivr.net/npm/@edx/paragon@21.0.0/dist/dark.min.css',
},
},
},
Expand Down Expand Up @@ -93,7 +96,7 @@ describe('useParagonTheme', () => {
isThemeLoaded: true,
themeVariant: initialPreference,
});
// Unmount the hook

unmount();
expect(mockRemoveEventListener).toHaveBeenCalled();
},
Expand Down Expand Up @@ -134,12 +137,41 @@ describe('useParagonTheme', () => {
expect(mockRemoveEventListener).toHaveBeenCalled();
});
it('should not configure any theme if PARAGON_THEME_URLS is undefined', () => {
getConfig.mockReturnValue({ PUBLIC_PATH: '/', PARAGON_THEME_URLS: undefined });
getConfig.mockReturnValueOnce({ PUBLIC_PATH: '/', PARAGON_THEME_URLS: undefined });
const { result, unmount } = renderHook(() => useParagonTheme());
const themeLinks = document.head.querySelectorAll('link');

expect(result.current[0]).toEqual({ isThemeLoaded: true, themeVariant: undefined });
expect(themeLinks.length).toBe(0);
unmount();
});
it('should return themeVariant undefined if can not configure the default theme or fallback in the light theme', () => {
getConfig.mockReturnValueOnce({ PUBLIC_PATH: '/', PARAGON_THEME_URLS: { ...PARAGON_THEME_URLS, defaults: { red: 'red' }, variants: { light: PARAGON_THEME_URLS.variants.light, green: { urls: { default: 'green-url' } } } } });
window.localStorage.getItem.mockReturnValue();

const { result, unmount } = renderHook(() => useParagonTheme());
const themeLinks = document.head.querySelectorAll('link');
const themeVariantLinks = document.head.querySelectorAll('link[data-paragon-theme-variant]');
act(() => { themeLinks.forEach((link) => link.onload()); });

expect(result.current[0]).toEqual({ isThemeLoaded: true, themeVariant: undefined });
expect(themeLinks.length).toBe(3);
themeVariantLinks.forEach(link => expect(link.rel).toBe('alternate stylesheet'));
unmount();
});
it('should log a error if can not configure the theme variant base on preference system', () => {
getConfig.mockReturnValueOnce({ PUBLIC_PATH: '/', PARAGON_THEME_URLS: { ...PARAGON_THEME_URLS, defaults: { dark: 'dark' }, variants: { light: PARAGON_THEME_URLS.variants.light, green: { urls: { default: 'green-url' } } } } });
window.localStorage.getItem.mockReturnValue();

const { result, unmount } = renderHook(() => useParagonTheme());
const themeLinks = document.head.querySelectorAll('link');
const themeVariantLinks = document.head.querySelectorAll('link[data-paragon-theme-variant]');
act(() => { themeLinks.forEach((link) => link.onload()); });

expect(result.current[0]).toEqual({ isThemeLoaded: true, themeVariant: 'dark' });
expect(logError.mock.calls[0][0]).toBe('Could not set theme variant based on system preference (prefers dark mode: true)');
expect(themeVariantLinks.length).toBe(2);
themeVariantLinks.forEach(link => expect(link.rel).toBe('alternate stylesheet'));
unmount();
});
});
32 changes: 17 additions & 15 deletions src/react/hooks/paragon/useParagonThemeCore.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ describe('useParagonThemeCore', () => {
coreConfig = {
themeCore: {
urls: {
default: 'https://cdn.jsdelivr.net/npm/@edx/paragon@$21.0.0/dist/core.min.css',
default: 'https://cdn.jsdelivr.net/npm/@edx/paragon@21.0.0/dist/core.min.css',
},
},
onLoad: themeOnLoad,
Expand All @@ -33,7 +33,7 @@ describe('useParagonThemeCore', () => {
});

it('should load the core default and brand url and change the loading state to true', () => {
coreConfig.themeCore.urls.brandOverride = 'https://cdn.jsdelivr.net/npm/@edx/brand@$2.0.0Version/dist/core.min.css';
coreConfig.themeCore.urls.brandOverride = 'https://cdn.jsdelivr.net/npm/@edx/brand@2.0.0/dist/core.min.css';

renderHook(() => useParagonThemeCore(coreConfig));
const createdLinkTag = document.head.querySelector('link[data-paragon-theme-core="true"]');
Expand All @@ -46,7 +46,7 @@ describe('useParagonThemeCore', () => {
});

it('should dispatch a log error and fallback to PARAGON_THEME if can not load the core theme link (either default or brandOverride)', () => {
coreConfig.themeCore.urls.brandOverride = 'https://cdn.jsdelivr.net/npm/@edx/brand@$2.0.0Version/dist/core.min.css';
coreConfig.themeCore.urls.brandOverride = 'https://cdn.jsdelivr.net/npm/@edx/brand@2.0.0/dist/core.min.css';
renderHook(() => useParagonThemeCore(coreConfig));

const createdLinkTag = document.head.querySelector('link[data-paragon-theme-core="true"]');
Expand All @@ -65,7 +65,7 @@ describe('useParagonThemeCore', () => {
expect(fallbackLinks[1].href).toBe(brandFallbackUrl);
});
it('should dispatch a log error if the fallback url is not loaded (either default or brandOverride)', () => {
coreConfig.themeCore.urls.brandOverride = 'https://cdn.jsdelivr.net/npm/@edx/brand@$2.0.0Version/dist/core.min.css';
coreConfig.themeCore.urls.brandOverride = 'https://cdn.jsdelivr.net/npm/@edx/brand@2.0.0/dist/core.min.css';

renderHook(() => useParagonThemeCore(coreConfig));
const createdLinkTag = document.head.querySelector('link[data-paragon-theme-core="true"]');
Expand Down Expand Up @@ -104,25 +104,27 @@ describe('useParagonThemeCore', () => {
});

it('should not create a new link if the core theme is already loaded (either default or brandOverride)', () => {
coreConfig.themeCore.urls.brandOverride = 'https://cdn.jsdelivr.net/npm/@edx/brand@$2.0.0/dist/core.min.css';
coreConfig.themeCore.urls.brandOverride = 'https://cdn.jsdelivr.net/npm/@edx/brand@2.0.0/dist/core.min.css';

document.head.innerHTML = `<link rel="preload" as="style" href="https://cdn.jsdelivr.net/npm/@edx/paragon@$21.0.0/dist/core.min.css" onerror="this.remove();">
<link rel="preload" as="style" href="https://cdn.jsdelivr.net/npm/@edx/brand@$2.0.0/dist/core.min.css" onerror="this.remove();">`;
document.head.innerHTML = `<link rel="preload" as="style" href="https://cdn.jsdelivr.net/npm/@edx/paragon@21.0.0/dist/core.min.css" onerror="this.remove();">
<link rel="preload" as="style" href="https://cdn.jsdelivr.net/npm/@edx/brand@2.0.0/dist/core.min.css" onerror="this.remove();">`;

renderHook(() => useParagonThemeCore(coreConfig));
const themeCoreLinks = document.head.querySelectorAll('link');
expect(themeCoreLinks.length).toBe(2);
expect(themeCoreLinks[0].rel).toContain('stylesheet');
expect(themeCoreLinks[0]).not.toHaveAttribute('as', 'style');
expect(themeCoreLinks[1].rel).toContain('stylesheet');
expect(themeCoreLinks[1].href).toBe(coreConfig.themeCore.urls.brandOverride);
expect(themeCoreLinks[1]).not.toHaveAttribute('as', 'style');

const createdLinkTags = document.head.querySelectorAll('link');

expect(createdLinkTags.length).toBe(2);
expect(createdLinkTags[0].rel).toContain('stylesheet');
expect(createdLinkTags[0]).not.toHaveAttribute('as', 'style');
expect(createdLinkTags[1].rel).toContain('stylesheet');
expect(createdLinkTags[1].href).toBe(coreConfig.themeCore.urls.brandOverride);
expect(createdLinkTags[1]).not.toHaveAttribute('as', 'style');
});

it('should not create any core link if can not find themeCore urls definition', () => {
coreConfig = {
themeCore: {
default: 'https://cdn.jsdelivr.net/npm/@edx/paragon@$21.0.0/dist/core.min.css',
default: 'https://cdn.jsdelivr.net/npm/@edx/paragon@21.0.0/dist/core.min.css',
},
onLoad: themeOnLoad,
};
Expand Down
74 changes: 74 additions & 0 deletions src/react/hooks/paragon/useParagonThemeUrls.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,5 +139,79 @@ describe('useParagonThemeUrls', () => {
}),
);
});
it('returns expected undefined when core default and variants are not present and can not fallback to PARAGON_THEME', () => {
const config = {
PARAGON_THEME_URLS: {
core: {
urls: {
brandOverride: 'brand-core.css',
},
},
defaults: {
light: 'light',
},
variants: {},
},
};
const originalParagonTheme = global.PARAGON_THEME;
Object.defineProperty(global, 'PARAGON_THEME', {
value: 'mocked-theme',
writable: true,
});
mergeConfig(config);
const { result } = renderHook(() => useParagonThemeUrls());
expect(result.current).toBe(undefined);
// Restores the original PARAGON_THEME
Object.defineProperty(global, 'PARAGON_THEME', {
value: originalParagonTheme,
writable: false,
});
});
it('manage substitucion of keywords in the url with the local installed version', () => {
const config = {
PARAGON_THEME_URLS: {
core: {
urls: {
default: 'https://cdn.jsdelivr.net/npm/@edx/paragon@$paragonVersion/dist/core.min.css',
brandOverride: 'https://cdn.jsdelivr.net/npm/@edx/brand@$brandVersion/dist/core.min.css',
},
},
defaults: {
light: 'light',
},
variants: {
light: {
urls: {
default: 'https://cdn.jsdelivr.net/npm/@edx/paragon@$paragonVersion/dist/light.min.css',
brandOverride: 'https://cdn.jsdelivr.net/npm/@edx/brand@$brandVersion/dist/light.min.css',
},
},
},
},
};
mergeConfig(config);
const { result } = renderHook(() => useParagonThemeUrls(config));
expect(result.current).toEqual(
expect.objectContaining({
core: {
urls: {
default: 'https://cdn.jsdelivr.net/npm/@edx/paragon@1.0.0/dist/core.min.css',
brandOverride: 'https://cdn.jsdelivr.net/npm/@edx/brand@1.0.0/dist/core.min.css',
},
},
defaults: {
light: 'light',
},
variants: {
light: {
urls: {
default: 'https://cdn.jsdelivr.net/npm/@edx/paragon@1.0.0/dist/light.min.css',
brandOverride: 'https://cdn.jsdelivr.net/npm/@edx/brand@1.0.0/dist/light.min.css',
},
},
},
}),
);
});
});
});
12 changes: 6 additions & 6 deletions src/react/hooks/paragon/useParagonThemeVariants.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,11 @@ describe('useParagonThemeVariants', () => {

renderHook(() => useParagonThemeVariants({ themeVariants, currentThemeVariant, onLoad: themeOnLoad }));

const createdLinkTag = document.head.querySelectorAll('link');
const themeLinks = document.head.querySelectorAll('link');
const paragonFallbackURL = `${getConfig().BASE_URL}/${PARAGON_THEME.paragon.themeUrls.variants.light.fileName}`;
const brandFallbackURL = `${getConfig().BASE_URL}/${PARAGON_THEME.brand.themeUrls.variants.light.fileName}`;

act(() => { createdLinkTag.forEach((link) => link.onerror()); });
act(() => { themeLinks.forEach((link) => link.onerror()); });

expect(logInfo).toHaveBeenCalledTimes(2);
expect(logInfo).toHaveBeenCalledWith(`Failed to load theme variant (${currentThemeVariant}) CSS from ${themeVariants.light.urls.default}. Falling back to locally installed theme variant: ${paragonFallbackURL}`);
Expand All @@ -82,11 +82,11 @@ describe('useParagonThemeVariants', () => {
const currentThemeVariant = 'light';

renderHook(() => useParagonThemeVariants({ themeVariants, currentThemeVariant, onLoad: themeOnLoad }));
const createdLinkTag = document.head.querySelectorAll('link');
const themeLinks = document.head.querySelectorAll('link');
const paragonFallbackURL = `${getConfig().BASE_URL}/${PARAGON_THEME.paragon.themeUrls.variants.light.fileName}`;
const brandFallbackURL = `${getConfig().BASE_URL}/${PARAGON_THEME.brand.themeUrls.variants.light.fileName}`;

act(() => { createdLinkTag.forEach((link) => link.onerror()); });
act(() => { themeLinks.forEach((link) => link.onerror()); });

const fallbackLinks = document.querySelectorAll('link');
expect(fallbackLinks[0].href).toBe(paragonFallbackURL);
Expand Down Expand Up @@ -116,8 +116,8 @@ describe('useParagonThemeVariants', () => {
const currentThemeVariant = 'light';

renderHook(() => useParagonThemeVariants({ themeVariants, currentThemeVariant, onLoad: themeOnLoad }));
const createdLinkTag = document.head.querySelectorAll('link');
act(() => { createdLinkTag.forEach((link) => link.onerror()); });
const themeLinks = document.head.querySelectorAll('link');
act(() => { themeLinks.forEach((link) => link.onerror()); });
expect(logError).toHaveBeenCalledTimes(2);
expect(logError).toHaveBeenCalledWith(`Failed to load theme variant (${currentThemeVariant}) CSS from ${themeVariants.light.urls.default} and locally installed fallback URL is not available. Aborting.`);

Expand Down

0 comments on commit 46448d2

Please sign in to comment.