Skip to content

Commit 3683ef1

Browse files
dcoaArturGaspar
authored andcommitted
test: add testing to useParagonTheme hooks (openedx#514)
* test: add testing to useParagonThemeCore * test: add test to useThemeVariants hook * fix: Paragon definition and remove onload mock * test: change test message to be clear
1 parent e60efac commit 3683ef1

File tree

2 files changed

+241
-0
lines changed

2 files changed

+241
-0
lines changed
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import { renderHook, act } from '@testing-library/react-hooks';
2+
import { getConfig } from '../../../config';
3+
import { logError } from '../../../logging';
4+
import useParagonThemeCore from './useParagonThemeCore';
5+
6+
jest.mock('../../../logging');
7+
8+
describe('useParagonThemeCore', () => {
9+
const themeOnLoad = jest.fn();
10+
11+
afterEach(() => {
12+
document.head.innerHTML = '';
13+
jest.clearAllMocks();
14+
});
15+
16+
it('should load the core url and change the loading state to true', () => {
17+
const coreConfig = {
18+
themeCore: {
19+
urls: { default: 'https://cdn.jsdelivr.net/npm/@edx/paragon@$21.0.0/dist/core.min.css' },
20+
},
21+
onLoad: themeOnLoad,
22+
};
23+
24+
renderHook(() => useParagonThemeCore(coreConfig));
25+
const createdLinkTag = document.head.querySelector('link');
26+
act(() => createdLinkTag.onload());
27+
expect(createdLinkTag.href).toBe(coreConfig.themeCore.urls.default);
28+
expect(themeOnLoad).toHaveBeenCalledTimes(1);
29+
});
30+
31+
it('should load the core default and brand url and change the loading state to true', () => {
32+
const coreConfig = {
33+
themeCore: {
34+
urls: {
35+
default: 'https://cdn.jsdelivr.net/npm/@edx/paragon@$21.0.0/dist/core.min.css',
36+
brandOverride: 'https://cdn.jsdelivr.net/npm/@edx/brand@$2.0.0Version/dist/core.min.css',
37+
},
38+
},
39+
onLoad: themeOnLoad,
40+
};
41+
42+
renderHook(() => useParagonThemeCore(coreConfig));
43+
const createdLinkTag = document.head.querySelector('link[data-paragon-theme-core="true"]');
44+
const createdBrandLinkTag = document.head.querySelector('link[data-brand-theme-core="true"]');
45+
46+
act(() => { createdLinkTag.onload(); createdBrandLinkTag.onload(); });
47+
expect(createdLinkTag.href).toBe(coreConfig.themeCore.urls.default);
48+
expect(createdBrandLinkTag.href).toBe(coreConfig.themeCore.urls.brandOverride);
49+
expect(themeOnLoad).toHaveBeenCalledTimes(1);
50+
});
51+
52+
it('should dispatch a log error and fallback to PARAGON_THEME if can not load the core theme link', () => {
53+
global.PARAGON_THEME = {
54+
paragon: {
55+
version: '1.0.0',
56+
themeUrls: {
57+
core: {
58+
fileName: 'core.min.css',
59+
},
60+
defaults: {
61+
light: 'light',
62+
},
63+
variants: {
64+
light: {
65+
fileName: 'light.min.css',
66+
},
67+
},
68+
},
69+
},
70+
};
71+
const coreConfig = {
72+
themeCore: {
73+
urls: {
74+
default: 'https://cdn.jsdelivr.net/npm/@edx/paragon@$21.0.0/dist/core.min.css',
75+
},
76+
},
77+
onLoad: themeOnLoad,
78+
};
79+
80+
renderHook(() => useParagonThemeCore(coreConfig));
81+
const createdLinkTag = document.head.querySelector('link[data-paragon-theme-core="true"]');
82+
83+
act(() => { createdLinkTag.onerror(); });
84+
expect(logError).toHaveBeenCalledTimes(1);
85+
expect(logError).toHaveBeenCalledWith(`Failed to load core theme CSS from ${coreConfig.themeCore.urls.default}`);
86+
expect(document.querySelector('link').href).toBe(`${getConfig().BASE_URL}/${PARAGON_THEME.paragon.themeUrls.core.fileName}`);
87+
});
88+
89+
it('should not create any core link if can not find themeCore urls definition', () => {
90+
const coreConfig = {
91+
themeCore: {
92+
default: 'https://cdn.jsdelivr.net/npm/@edx/paragon@$21.0.0/dist/core.min.css',
93+
},
94+
onLoad: themeOnLoad,
95+
};
96+
97+
renderHook(() => useParagonThemeCore(coreConfig));
98+
expect(document.head.querySelectorAll('link').length).toBe(0);
99+
expect(themeOnLoad).toHaveBeenCalledTimes(1);
100+
});
101+
});
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
import { act, renderHook } from '@testing-library/react-hooks';
2+
import { getConfig } from '../../../config';
3+
import { logError } from '../../../logging';
4+
import useParagonThemeVariants from './useParagonThemeVariants';
5+
6+
jest.mock('../../../logging');
7+
8+
const mockAddEventListener = jest.fn();
9+
const mockRemoveEventListener = jest.fn();
10+
const mockOnChange = jest.fn();
11+
12+
Object.defineProperty(window, 'matchMedia', {
13+
value: jest.fn(() => ({
14+
addEventListener: mockAddEventListener,
15+
removeEventListener: mockRemoveEventListener,
16+
onchange: mockOnChange,
17+
})),
18+
});
19+
20+
describe('useParagonThemeVariants', () => {
21+
const themeOnLoad = jest.fn();
22+
23+
afterEach(() => {
24+
document.head.innerHTML = '';
25+
jest.clearAllMocks();
26+
});
27+
28+
it('should create the links tags for each theme variant and change the state to true when all variants are loaded', () => {
29+
const themeVariants = {
30+
light: {
31+
urls: {
32+
default: 'https://cdn.jsdelivr.net/npm/@edx/paragon@$21.0.0/dist/light.min.css',
33+
brandOverride: 'https://cdn.jsdelivr.net/npm/@edx/brand@$2.0.0/dist/light.min.css',
34+
},
35+
},
36+
dark: {
37+
urls: {
38+
default: 'https://cdn.jsdelivr.net/npm/@edx/paragon@$21.0.0/dist/dark.min.css',
39+
brandOverride: 'https://cdn.jsdelivr.net/npm/@edx/brand@$2.0.0/dist/dark.min.css',
40+
},
41+
},
42+
};
43+
const currentThemeVariant = 'light';
44+
45+
renderHook(() => useParagonThemeVariants({ themeVariants, currentThemeVariant, onLoad: themeOnLoad }));
46+
const themeLinks = document.head.querySelectorAll('link');
47+
act(() => { themeLinks.forEach((link) => link.onload()); });
48+
49+
expect(themeLinks.length).toBe(4);
50+
});
51+
52+
it('should dispatch a log error and fallback to PARAGON_THEME if can not load the variant theme link', () => {
53+
global.PARAGON_THEME = {
54+
paragon: {
55+
version: '1.0.0',
56+
themeUrls: {
57+
core: {
58+
fileName: 'core.min.css',
59+
},
60+
defaults: {
61+
light: 'light',
62+
},
63+
variants: {
64+
light: {
65+
fileName: 'light.min.css',
66+
},
67+
},
68+
},
69+
},
70+
};
71+
const themeVariants = {
72+
light: {
73+
urls: {
74+
default: 'https://cdn.jsdelivr.net/npm/@edx/paragon@$21.0.0/dist/light.min.css',
75+
},
76+
},
77+
};
78+
const currentThemeVariant = 'light';
79+
80+
renderHook(() => useParagonThemeVariants({ themeVariants, currentThemeVariant, onLoad: themeOnLoad }));
81+
const createdLinkTag = document.head.querySelector('link');
82+
act(() => { createdLinkTag.onerror(); });
83+
expect(logError).toHaveBeenCalledTimes(1);
84+
expect(logError).toHaveBeenCalledWith(`Failed to load theme variant (${currentThemeVariant}) CSS from ${themeVariants.light.urls.default}`);
85+
expect(document.querySelector('link').href).toBe(`${getConfig().BASE_URL}/${PARAGON_THEME.paragon.themeUrls.variants.light.fileName}`);
86+
});
87+
88+
it('should configure theme variants according with system preference and add the change event listener', () => {
89+
window.matchMedia['prefers-color-scheme'] = 'dark';
90+
91+
const themeVariants = {
92+
light: {
93+
urls: {
94+
default: 'https://cdn.jsdelivr.net/npm/@edx/paragon@$21.0.0/dist/light.min.css',
95+
brandOverride: 'https://cdn.jsdelivr.net/npm/@edx/brand@$2.0.0/dist/light.min.css',
96+
},
97+
},
98+
dark: {
99+
urls: {
100+
default: 'https://cdn.jsdelivr.net/npm/@edx/paragon@$21.0.0/dist/dark.min.css',
101+
brandOverride: 'https://cdn.jsdelivr.net/npm/@edx/brand@$2.0.0/dist/dark.min.css',
102+
},
103+
},
104+
};
105+
106+
const currentThemeVariant = 'light';
107+
108+
renderHook(() => useParagonThemeVariants({ themeVariants, currentThemeVariant, onLoad: themeOnLoad }));
109+
110+
const themeLinks = document.head.querySelectorAll('link');
111+
act(() => { themeLinks.forEach((link) => link.onload()); });
112+
113+
expect(mockAddEventListener).toHaveBeenCalledTimes(1);
114+
});
115+
116+
it('should do nothing if themeVariants is not configured', () => {
117+
const themeVariants = null;
118+
const currentTheme = 'light';
119+
120+
renderHook(() => useParagonThemeVariants({ themeVariants, currentTheme, onLoad: themeOnLoad }));
121+
expect(document.head.querySelectorAll('link').length).toBe(0);
122+
});
123+
124+
it('should not create any core link if can not find themeVariant urls definition', () => {
125+
const themeVariants = {
126+
light: {
127+
default: 'https://cdn.jsdelivr.net/npm/@edx/paragon@$21.0.0/dist/light.min.css',
128+
},
129+
dark: {
130+
default: 'https://cdn.jsdelivr.net/npm/@edx/paragon@$21.0.0/dist/dark.min.css',
131+
},
132+
};
133+
134+
const currentTheme = 'light';
135+
136+
renderHook(() => useParagonThemeVariants({ themeVariants, currentTheme, onLoad: themeOnLoad }));
137+
138+
expect(document.head.querySelectorAll('link').length).toBe(0);
139+
});
140+
});

0 commit comments

Comments
 (0)