Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: add testing to useParagonTheme hooks #514

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 additions & 0 deletions src/react/hooks/paragon/useParagonThemeCore.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import { renderHook, act } from '@testing-library/react-hooks';
import { getConfig } from '../../../config';
import { logError } from '../../../logging';
import useParagonThemeCore from './useParagonThemeCore';

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

describe('useParagonThemeCore', () => {
const themeOnLoad = jest.fn();

afterEach(() => {
document.head.innerHTML = '';
jest.clearAllMocks();
});

it('should load the core url and change the loading state to true', () => {
const coreConfig = {
themeCore: {
urls: { default: 'https://cdn.jsdelivr.net/npm/@edx/paragon@$21.0.0/dist/core.min.css' },
},
onLoad: themeOnLoad,
};

renderHook(() => useParagonThemeCore(coreConfig));
const createdLinkTag = document.head.querySelector('link');
act(() => createdLinkTag.onload());
expect(createdLinkTag.href).toBe(coreConfig.themeCore.urls.default);
expect(themeOnLoad).toHaveBeenCalledTimes(1);
});

it('should load the core default and brand url and change the loading state to true', () => {
const coreConfig = {
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',
},
},
onLoad: themeOnLoad,
};

renderHook(() => useParagonThemeCore(coreConfig));
const createdLinkTag = document.head.querySelector('link[data-paragon-theme-core="true"]');
const createdBrandLinkTag = document.head.querySelector('link[data-brand-theme-core="true"]');

act(() => { createdLinkTag.onload(); createdBrandLinkTag.onload(); });
expect(createdLinkTag.href).toBe(coreConfig.themeCore.urls.default);
expect(createdBrandLinkTag.href).toBe(coreConfig.themeCore.urls.brandOverride);
expect(themeOnLoad).toHaveBeenCalledTimes(1);
});

it('should dispatch a log error and fallback to PARAGON_THEME if can not load the core theme link', () => {
global.PARAGON_THEME = {
paragon: {
version: '1.0.0',
themeUrls: {
core: {
fileName: 'core.min.css',
},
defaults: {
light: 'light',
},
variants: {
light: {
fileName: 'light.min.css',
},
},
},
},
};
const coreConfig = {
themeCore: {
urls: {
default: 'https://cdn.jsdelivr.net/npm/@edx/paragon@$21.0.0/dist/core.min.css',
},
},
onLoad: themeOnLoad,
};

renderHook(() => useParagonThemeCore(coreConfig));
const createdLinkTag = document.head.querySelector('link[data-paragon-theme-core="true"]');

act(() => { createdLinkTag.onerror(); });
expect(logError).toHaveBeenCalledTimes(1);
expect(logError).toHaveBeenCalledWith(`Failed to load core theme CSS from ${coreConfig.themeCore.urls.default}`);
expect(document.querySelector('link').href).toBe(`${getConfig().BASE_URL}/${PARAGON_THEME.paragon.themeUrls.core.fileName}`);
});

it('should not create any core link if can not find themeCore urls definition', () => {
const coreConfig = {
themeCore: {
default: 'https://cdn.jsdelivr.net/npm/@edx/paragon@$21.0.0/dist/core.min.css',
},
onLoad: themeOnLoad,
};

renderHook(() => useParagonThemeCore(coreConfig));
expect(document.head.querySelectorAll('link').length).toBe(0);
expect(themeOnLoad).toHaveBeenCalledTimes(1);
});
});
140 changes: 140 additions & 0 deletions src/react/hooks/paragon/useParagonThemeVariants.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import { act, renderHook } from '@testing-library/react-hooks';
import { getConfig } from '../../../config';
import { logError } from '../../../logging';
import useParagonThemeVariants from './useParagonThemeVariants';

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

const mockAddEventListener = jest.fn();
const mockRemoveEventListener = jest.fn();
const mockOnChange = jest.fn();

Object.defineProperty(window, 'matchMedia', {
value: jest.fn(() => ({
addEventListener: mockAddEventListener,
removeEventListener: mockRemoveEventListener,
onchange: mockOnChange,
})),
});

describe('useParagonThemeVariants', () => {
const themeOnLoad = jest.fn();

afterEach(() => {
document.head.innerHTML = '';
jest.clearAllMocks();
});

it('should create the links tags for each theme variant and change the state to true when all variants are loaded', () => {
const themeVariants = {
light: {
urls: {
default: 'https://cdn.jsdelivr.net/npm/@edx/paragon@$21.0.0/dist/light.min.css',
brandOverride: 'https://cdn.jsdelivr.net/npm/@edx/brand@$2.0.0/dist/light.min.css',
},
},
dark: {
urls: {
default: 'https://cdn.jsdelivr.net/npm/@edx/paragon@$21.0.0/dist/dark.min.css',
brandOverride: 'https://cdn.jsdelivr.net/npm/@edx/brand@$2.0.0/dist/dark.min.css',
},
},
};
const currentThemeVariant = 'light';

renderHook(() => useParagonThemeVariants({ themeVariants, currentThemeVariant, onLoad: themeOnLoad }));
const themeLinks = document.head.querySelectorAll('link');
act(() => { themeLinks.forEach((link) => link.onload()); });

expect(themeLinks.length).toBe(4);
});

it('should dispatch a log error and fallback to PARAGON_THEME if can not load the variant theme link', () => {
global.PARAGON_THEME = {
paragon: {
version: '1.0.0',
themeUrls: {
core: {
fileName: 'core.min.css',
},
defaults: {
light: 'light',
},
variants: {
light: {
fileName: 'light.min.css',
},
},
},
},
};
const themeVariants = {
light: {
urls: {
default: 'https://cdn.jsdelivr.net/npm/@edx/paragon@$21.0.0/dist/light.min.css',
},
},
};
const currentThemeVariant = 'light';

renderHook(() => useParagonThemeVariants({ themeVariants, currentThemeVariant, onLoad: themeOnLoad }));
const createdLinkTag = document.head.querySelector('link');
act(() => { createdLinkTag.onerror(); });
expect(logError).toHaveBeenCalledTimes(1);
expect(logError).toHaveBeenCalledWith(`Failed to load theme variant (${currentThemeVariant}) CSS from ${themeVariants.light.urls.default}`);
expect(document.querySelector('link').href).toBe(`${getConfig().BASE_URL}/${PARAGON_THEME.paragon.themeUrls.variants.light.fileName}`);
});

it('should configure theme variants according with system preference and add the change event listener', () => {
window.matchMedia['prefers-color-scheme'] = 'dark';

const themeVariants = {
light: {
urls: {
default: 'https://cdn.jsdelivr.net/npm/@edx/paragon@$21.0.0/dist/light.min.css',
brandOverride: 'https://cdn.jsdelivr.net/npm/@edx/brand@$2.0.0/dist/light.min.css',
},
},
dark: {
urls: {
default: 'https://cdn.jsdelivr.net/npm/@edx/paragon@$21.0.0/dist/dark.min.css',
brandOverride: 'https://cdn.jsdelivr.net/npm/@edx/brand@$2.0.0/dist/dark.min.css',
},
},
};

const currentThemeVariant = 'light';

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

const themeLinks = document.head.querySelectorAll('link');
act(() => { themeLinks.forEach((link) => link.onload()); });

expect(mockAddEventListener).toHaveBeenCalledTimes(1);
});

it('should do nothing if themeVariants is not configured', () => {
const themeVariants = null;
const currentTheme = 'light';

renderHook(() => useParagonThemeVariants({ themeVariants, currentTheme, onLoad: themeOnLoad }));
expect(document.head.querySelectorAll('link').length).toBe(0);
});

it('should not create any core link if can not find themeVariant urls definition', () => {
const themeVariants = {
light: {
default: 'https://cdn.jsdelivr.net/npm/@edx/paragon@$21.0.0/dist/light.min.css',
},
dark: {
default: 'https://cdn.jsdelivr.net/npm/@edx/paragon@$21.0.0/dist/dark.min.css',
},
};

const currentTheme = 'light';

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

expect(document.head.querySelectorAll('link').length).toBe(0);
});
});