Skip to content

Commit

Permalink
feat: added missing unit tests
Browse files Browse the repository at this point in the history
---

For more details, open the [Copilot Workspace session](https://copilot-workspace.githubnext.com/nodejs/nodejs.org?shareId=XXXX-XXXX-XXXX-XXXX).
  • Loading branch information
ovflowd committed Dec 28, 2024
1 parent c8e604f commit c71ba51
Show file tree
Hide file tree
Showing 19 changed files with 716 additions and 12 deletions.
88 changes: 88 additions & 0 deletions apps/site/hooks/react-client/__tests__/useNavigationState.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { renderHook, act } from '@testing-library/react';
import { useRef } from 'react';

import useNavigationState from '@/hooks/react-client/useNavigationState';
import { NavigationStateContext } from '@/providers/navigationStateProvider';

describe('useNavigationState', () => {
it('should save and restore scroll position', () => {
const mockElement = {
scrollLeft: 0,
scrollTop: 0,
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
scroll: jest.fn(),
};

const mockRef = { current: mockElement };
const mockContextValue = {};

const wrapper = ({ children }) => (
<NavigationStateContext.Provider value={mockContextValue}>
{children}
</NavigationStateContext.Provider>
);

renderHook(() => useNavigationState('test-id', mockRef), { wrapper });

expect(mockElement.addEventListener).toHaveBeenCalledWith(
'scroll',
expect.any(Function),
{ passive: true }
);

act(() => {
mockElement.scrollTop = 100;
mockElement.scrollLeft = 50;
mockElement.addEventListener.mock.calls[0][1]();
});

expect(mockContextValue['test-id']).toEqual({ x: 50, y: 100 });

act(() => {
mockElement.scrollTop = 0;
mockElement.scrollLeft = 0;
mockElement.scroll.mock.calls[0][0]();
});

expect(mockElement.scroll).toHaveBeenCalledWith({
top: 100,
behavior: 'instant',
});
});

it('should add and remove scroll event listener', () => {
const mockElement = {
scrollLeft: 0,
scrollTop: 0,
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
};

const mockRef = { current: mockElement };
const mockContextValue = {};

const wrapper = ({ children }) => (
<NavigationStateContext.Provider value={mockContextValue}>
{children}
</NavigationStateContext.Provider>
);

const { unmount } = renderHook(() => useNavigationState('test-id', mockRef), {
wrapper,
});

expect(mockElement.addEventListener).toHaveBeenCalledWith(
'scroll',
expect.any(Function),
{ passive: true }
);

unmount();

expect(mockElement.removeEventListener).toHaveBeenCalledWith(
'scroll',
expect.any(Function)
);
});
});
74 changes: 74 additions & 0 deletions apps/site/reducers/__tests__/releaseReducer.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import releaseReducer, { releaseState, getActions } from '@/reducers/releaseReducer';

describe('releaseReducer', () => {
it('should return the initial state', () => {
expect(releaseReducer(undefined, {})).toEqual(releaseState);
});

it('should handle SET_VERSION', () => {
const action = { type: 'SET_VERSION', payload: 'v14.17.0' };
const expectedState = { ...releaseState, version: 'v14.17.0' };
expect(releaseReducer(releaseState, action)).toEqual(expectedState);
});

it('should handle SET_OS', () => {
const action = { type: 'SET_OS', payload: 'WIN' };
const expectedState = { ...releaseState, os: 'WIN' };
expect(releaseReducer(releaseState, action)).toEqual(expectedState);
});

it('should handle SET_PLATFORM', () => {
const action = { type: 'SET_PLATFORM', payload: 'x64' };
const expectedState = { ...releaseState, platform: 'x64' };
expect(releaseReducer(releaseState, action)).toEqual(expectedState);
});

it('should handle SET_INSTALL_METHOD', () => {
const action = { type: 'SET_INSTALL_METHOD', payload: 'brew' };
const expectedState = { ...releaseState, installMethod: 'brew' };
expect(releaseReducer(releaseState, action)).toEqual(expectedState);
});

it('should handle SET_MANAGER', () => {
const action = { type: 'SET_MANAGER', payload: 'yarn' };
const expectedState = { ...releaseState, packageManager: 'yarn' };
expect(releaseReducer(releaseState, action)).toEqual(expectedState);
});
});

describe('getActions', () => {
it('should create setVersion action', () => {
const dispatch = jest.fn();
const actions = getActions(dispatch);
actions.setVersion('v14.17.0');
expect(dispatch).toHaveBeenCalledWith({ type: 'SET_VERSION', payload: 'v14.17.0' });
});

it('should create setOS action', () => {
const dispatch = jest.fn();
const actions = getActions(dispatch);
actions.setOS('WIN');
expect(dispatch).toHaveBeenCalledWith({ type: 'SET_OS', payload: 'WIN' });
});

it('should create setPlatform action', () => {
const dispatch = jest.fn();
const actions = getActions(dispatch);
actions.setPlatform('x64');
expect(dispatch).toHaveBeenCalledWith({ type: 'SET_PLATFORM', payload: 'x64' });
});

it('should create setInstallMethod action', () => {
const dispatch = jest.fn();
const actions = getActions(dispatch);
actions.setInstallMethod('brew');
expect(dispatch).toHaveBeenCalledWith({ type: 'SET_INSTALL_METHOD', payload: 'brew' });
});

it('should create setPackageManager action', () => {
const dispatch = jest.fn();
const actions = getActions(dispatch);
actions.setPackageManager('yarn');
expect(dispatch).toHaveBeenCalledWith({ type: 'SET_MANAGER', payload: 'yarn' });
});
});
24 changes: 24 additions & 0 deletions apps/site/util/__tests__/assignClientContext.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ describe('assignClientContext', () => {
expect(result.headings).toEqual(mockContext.headings);
expect(result.readingTime).toEqual(mockContext.readingTime);
expect(result.filename).toEqual(mockContext.filename);
expect(result.os).toEqual(mockContext.os);
expect(result.architecture).toEqual(mockContext.architecture);
expect(result.bitness).toEqual(mockContext.bitness);

expect(result).toEqual(mockContext);
});
Expand All @@ -42,5 +45,26 @@ describe('assignClientContext', () => {
words: 0,
});
expect(result.filename).toEqual('');
expect(result.os).toEqual('OTHER');
expect(result.architecture).toEqual('x64');
expect(result.bitness).toEqual(64);
});

it('should handle invalid inputs gracefully', () => {
const result = assignClientContext(null);

expect(result.frontmatter).toEqual({});
expect(result.pathname).toEqual('');
expect(result.headings).toEqual([]);
expect(result.readingTime).toEqual({
text: '',
minutes: 0,
time: 0,
words: 0,
});
expect(result.filename).toEqual('');
expect(result.os).toEqual('OTHER');
expect(result.architecture).toEqual('x64');
expect(result.bitness).toEqual(64);
});
});
45 changes: 45 additions & 0 deletions apps/site/util/__tests__/authorUtils.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import {
mapAuthorToCardAuthors,
getAuthorWithId,
getAuthorWithName,
getAuthorName,
getAuthorBio,
getAuthorImage,
} from '../authorUtils';

describe('mapAuthorToCardAuthors', () => {
Expand Down Expand Up @@ -96,3 +99,45 @@ describe('getAuthorWithName', () => {
]);
});
});

describe('getAuthorName', () => {
it('should return the correct author name', () => {
const authorId = 'tjfontaine';
const result = getAuthorName(authorId);
expect(result).toBe('Timothy J Fontaine');
});

it('should return undefined for an unknown author', () => {
const authorId = 'unknown';
const result = getAuthorName(authorId);
expect(result).toBeUndefined();
});
});

describe('getAuthorBio', () => {
it('should return the correct author bio', () => {
const authorId = 'tjfontaine';
const result = getAuthorBio(authorId);
expect(result).toBeUndefined(); // Assuming no bio is provided in the authors.json
});

it('should return undefined for an unknown author', () => {
const authorId = 'unknown';
const result = getAuthorBio(authorId);
expect(result).toBeUndefined();
});
});

describe('getAuthorImage', () => {
it('should return the correct author image URL', () => {
const authorId = 'tjfontaine';
const result = getAuthorImage(authorId);
expect(result).toBe('https://avatars.githubusercontent.com/tjfontaine');
});

it('should return undefined for an unknown author', () => {
const authorId = 'unknown';
const result = getAuthorImage(authorId);
expect(result).toBeUndefined();
});
});
27 changes: 27 additions & 0 deletions apps/site/util/__tests__/blogUtils.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { getBlogPosts, getBlogCategories, getBlogTags } from '@/util/blogUtils';

describe('blogUtils', () => {
describe('getBlogPosts', () => {
it('should retrieve blog posts', () => {
const blogPosts = getBlogPosts();
expect(blogPosts).toBeDefined();
expect(Array.isArray(blogPosts)).toBe(true);
});
});

describe('getBlogCategories', () => {
it('should retrieve blog categories', () => {
const blogCategories = getBlogCategories();
expect(blogCategories).toBeDefined();
expect(Array.isArray(blogCategories)).toBe(true);
});
});

describe('getBlogTags', () => {
it('should retrieve blog tags', () => {
const blogTags = getBlogTags();
expect(blogTags).toBeDefined();
expect(Array.isArray(blogTags)).toBe(true);
});
});
});
40 changes: 39 additions & 1 deletion apps/site/util/__tests__/dateUtils.test.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { dateIsBetween } from '@/util/dateUtils';
import { dateIsBetween, formatDate, parseDate, isValidDate } from '@/util/dateUtils';

describe('dateIsBetween', () => {
it('returns true when the current date is between start and end dates', () => {
Expand Down Expand Up @@ -28,3 +28,41 @@ describe('dateIsBetween', () => {
);
});
});

describe('formatDate', () => {
it('formats a valid date correctly', () => {
const date = new Date('2024-02-17T00:00:00.000Z');
const formattedDate = formatDate(date, 'yyyy-MM-dd');
expect(formattedDate).toBe('2024-02-17');
});

it('throws an error for an invalid date', () => {
const invalidDate = new Date('Invalid Date');
expect(() => formatDate(invalidDate, 'yyyy-MM-dd')).toThrow('Invalid date');
});
});

describe('parseDate', () => {
it('parses a valid date string correctly', () => {
const dateString = '2024-02-17';
const parsedDate = parseDate(dateString, 'yyyy-MM-dd');
expect(parsedDate).toEqual(new Date('2024-02-17T00:00:00.000Z'));
});

it('throws an error for an invalid date string', () => {
const invalidDateString = 'Invalid Date';
expect(() => parseDate(invalidDateString, 'yyyy-MM-dd')).toThrow('Invalid date string');
});
});

describe('isValidDate', () => {
it('returns true for a valid date', () => {
const validDate = new Date('2024-02-17T00:00:00.000Z');
expect(isValidDate(validDate)).toBe(true);
});

it('returns false for an invalid date', () => {
const invalidDate = new Date('Invalid Date');
expect(isValidDate(invalidDate)).toBe(false);
});
});
29 changes: 29 additions & 0 deletions apps/site/util/__tests__/debounce.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,33 @@ describe('debounce', () => {

expect(fn).toHaveBeenCalledWith(3);
});

it('should delay the execution of the function', () => {
const fn = jest.fn();
const debouncedFn = debounce(fn, 1000);

debouncedFn();

expect(fn).not.toHaveBeenCalled();

jest.advanceTimersByTime(500);
expect(fn).not.toHaveBeenCalled();

jest.advanceTimersByTime(500);
expect(fn).toHaveBeenCalled();
});

it('should execute only once within the delay', () => {
const fn = jest.fn();
const debouncedFn = debounce(fn, 1000);

debouncedFn();
jest.advanceTimersByTime(500);
debouncedFn();
jest.advanceTimersByTime(500);
debouncedFn();
jest.advanceTimersByTime(1000);

expect(fn).toHaveBeenCalledTimes(1);
});
});
Loading

0 comments on commit c71ba51

Please sign in to comment.