diff --git a/src/react/hooks/paragon/useParagonTheme.test.js b/src/react/hooks/paragon/useParagonTheme.test.js
new file mode 100644
index 000000000..b72307db8
--- /dev/null
+++ b/src/react/hooks/paragon/useParagonTheme.test.js
@@ -0,0 +1,38 @@
+import { act, renderHook } from '@testing-library/react-hooks';
+import useParagonTheme from './useParagonTheme';
+
+describe('useParagonTheme', () => {
+ it('should return an array with and object that indicates the theme status, and a function', () => {
+ const config = {
+ PARAGON_THEME_URLS: {
+ core: {
+ urls: {
+ default: 'https://cdn.jsdelivr.net/npm/@edx/paragon@$paragonVersion/dist/core.min.css',
+ },
+ },
+ defaults: {
+ light: 'light',
+ dark: 'dark',
+ },
+ variants: {
+ light: {
+ urls: {
+ default: 'https://cdn.jsdelivr.net/npm/@edx/paragon@$paragonVersion/dist/light.min.css',
+ },
+ },
+ dark: {
+ urls: {
+ default: 'https://cdn.jsdelivr.net/npm/@edx/paragon@$paragonVersion/dist/dark.min.css',
+ },
+ },
+ },
+ },
+ };
+
+ const { result } = renderHook(() => useParagonTheme(config));
+ const createdLinksTag = document.head.querySelectorAll('link');
+ act(() => { createdLinksTag.forEach((link) => link.onload()); });
+
+ expect(result.current).toEqual([{ isThemeLoaded: true, themeVariant: 'light' }, expect.any(Function)]);
+ });
+});
diff --git a/src/react/hooks/paragon/useParagonThemeCore.test.js b/src/react/hooks/paragon/useParagonThemeCore.test.js
index 1eecf876c..9df01d8ad 100644
--- a/src/react/hooks/paragon/useParagonThemeCore.test.js
+++ b/src/react/hooks/paragon/useParagonThemeCore.test.js
@@ -33,7 +33,7 @@ describe('useParagonThemeCore', () => {
themeCore: {
urls: {
default: 'https://cdn.jsdelivr.net/npm/@edx/paragon@$21.0.0/dist/core.min.css',
- brandOverride: 'https://cdn.jsdelivr.net/npm/@edx/brand@$2.0.0Version/dist/core.min.css',
+ brandOverride: 'https://cdn.jsdelivr.net/npm/@edx/brand@$2.0.0/dist/core.min.css',
},
},
onLoad: themeOnLoad,
diff --git a/src/react/hooks/paragon/utils.test.js b/src/react/hooks/paragon/utils.test.js
new file mode 100644
index 000000000..77edce2e6
--- /dev/null
+++ b/src/react/hooks/paragon/utils.test.js
@@ -0,0 +1,95 @@
+import { removeExistingLinks, getDefaultThemeVariant, handleVersionSubstitution } from './utils';
+
+Object.defineProperty(window, 'matchMedia', {
+ writable: true,
+ value: jest.fn().mockImplementation(query => ({
+ matches: true,
+ media: query,
+ })),
+});
+
+const mockGetItem = jest.fn();
+Object.defineProperty(window, 'localStorage', {
+ value: {
+ getItem: mockGetItem,
+ },
+});
+
+describe('removeExistingLinks', () => {
+ afterEach(() => {
+ document.head.innerHTML = '';
+ jest.clearAllMocks();
+ });
+
+ it('should remove all the links in the DOM', () => {
+ document.head.innerHTML = `
+
+
+
+ `;
+
+ removeExistingLinks(document.querySelectorAll('link'));
+ expect(document.querySelectorAll('link').length).toBe(0);
+ });
+});
+
+describe('getDefaultThemeVariant', () => {
+ it('should return the theme variant according with system preference', () => {
+ const variant = getDefaultThemeVariant({
+ themeVariantDefaults: {
+ light: 'light',
+ dark: 'dark',
+ },
+ themeVariants: {
+ light: {
+ fileName: 'light.min.css',
+ },
+ dark: {
+ fileName: 'dark.min.css',
+ },
+ },
+ });
+ expect(variant).toEqual({ metadata: { fileName: 'dark.min.css' }, name: 'dark' });
+ });
+
+ it('should return the theme variant according with local storage preference', () => {
+ mockGetItem.mockImplementation(() => 'light');
+ const variant = getDefaultThemeVariant({
+ themeVariantDefaults: {
+ light: 'light',
+ dark: 'dark',
+ },
+ themeVariants: {
+ light: {
+ fileName: 'light.min.css',
+ },
+ dark: {
+ fileName: 'dark.min.css',
+ },
+ },
+ });
+ expect(variant).toEqual({ metadata: { fileName: 'light.min.css' }, name: 'light' });
+ });
+
+ it('should return the theme variant configuration as default', () => {
+ const variant = getDefaultThemeVariant({
+ themeVariantDefaults: {
+ light: 'light',
+ },
+ themeVariants: {
+ light: {
+ fileName: 'light.min.css',
+ },
+ },
+ });
+ expect(variant).toEqual({ metadata: { fileName: 'light.min.css' }, name: 'light' });
+ });
+});
+
+describe('handleVersionSubstitution', () => {
+ it('should substitude the paragon version to use', () => {
+ const config = { localVersion: '21.1.1', wildcardKeyword: 'alpha', url: 'https://cdn.jsdelivr.net/npm/@edx/paragon@alpha/dist/core.min.css' };
+ const newLink = handleVersionSubstitution(config);
+ expect(newLink).toBe('https://cdn.jsdelivr.net/npm/@edx/paragon@21.1.1/dist/core.min.css');
+ });
+});