Add unit tests to several API utility functions (#16662)

* add unit tests to several API util functions

* fix timezone tests to account for daylight saving

* add a note for future reference

* Update api/src/utils/get-date-formatted.test.ts

Co-authored-by: Brainslug <br41nslug@users.noreply.github.com>

* remove unnecessary note as it is not an issue

* fix getEnv mock in validate-env test

Co-authored-by: Brainslug <br41nslug@users.noreply.github.com>
Co-authored-by: Rijk van Zanten <rijkvanzanten@me.com>
This commit is contained in:
Azri Kahar
2022-12-24 00:51:49 +08:00
committed by GitHub
parent 6bf5de1f9d
commit e899244ef3
7 changed files with 177 additions and 0 deletions

View File

@@ -0,0 +1,12 @@
import { expect, test } from 'vitest';
import { applyFunctionToColumnName } from './apply-function-to-column-name';
test.each([
{ input: 'test', expected: 'test' },
{ input: 'year(date_created)', expected: 'date_created_year' },
{ input: `hour(timestamp)`, expected: 'timestamp_hour' },
{ input: `count(value)`, expected: 'value_count' },
])('should return "$expected" for "$input"', ({ input, expected }) => {
expect(applyFunctionToColumnName(input)).toBe(expected);
});

View File

@@ -0,0 +1,37 @@
import { afterEach, beforeEach, expect, test, vi } from 'vitest';
import { getDateFormatted } from './get-date-formatted';
beforeEach(() => {
vi.useFakeTimers();
});
afterEach(() => {
vi.useRealTimers();
});
function getUtcDateForString(date: string) {
const now = new Date(date);
// account for timezone difference depending on the machine where this test is ran
const timezoneOffsetInMinutes = now.getTimezoneOffset();
const timezoneOffsetInMilliseconds = timezoneOffsetInMinutes * 60 * 1000;
const nowUTC = new Date(now.valueOf() + timezoneOffsetInMilliseconds);
return nowUTC;
}
test.each([
{ utc: '2023-01-01T01:23:45.678Z', expected: '20230101-12345' },
{ utc: '2023-01-11T01:23:45.678Z', expected: '20230111-12345' },
{ utc: '2023-11-01T01:23:45.678Z', expected: '20231101-12345' },
{ utc: '2023-11-11T12:34:56.789Z', expected: '20231111-123456' },
{ utc: '2023-06-01T01:23:45.678Z', expected: '20230601-12345' },
{ utc: '2023-06-11T12:34:56.789Z', expected: '20230611-123456' },
])('should format $utc into "$expected"', ({ utc, expected }) => {
const nowUTC = getUtcDateForString(utc);
vi.setSystemTime(nowUTC);
expect(getDateFormatted()).toBe(expected);
});

11
api/src/utils/md.test.ts Normal file
View File

@@ -0,0 +1,11 @@
import { expect, test } from 'vitest';
import { md } from './md';
test.each([
{ str: 'test', expected: '<p>test</p>\n' },
{ str: `<a href="/test" download />`, expected: '<a href="/test"></a>' },
{ str: `test<script>alert('alert')</script>`, expected: '<p>test</p>\n' },
])('should sanitize "$str" into "$expected"', ({ str, expected }) => {
expect(md(str)).toBe(expected);
});

View File

@@ -0,0 +1,41 @@
import { afterAll, beforeAll, expect, SpyInstance, test, vi } from 'vitest';
import { stall } from './stall';
let performanceNowSpy: SpyInstance;
beforeAll(() => {
vi.useFakeTimers();
// fake timers doesn't fake performance.now(), so this is used to mock it
performanceNowSpy = vi.spyOn(performance, 'now').mockReturnValue(0);
});
afterAll(() => {
vi.useRealTimers();
});
const STALL_TIME = 100;
test('does not stall if elapsed time has already past the stall time', () => {
const startTime = performance.now();
// intentionally advance past the stall time first
performanceNowSpy.mockReturnValueOnce(1000);
stall(STALL_TIME, startTime);
expect(vi.getTimerCount()).toBe(0);
});
test('should stall for a set amount of time', () => {
const startTime = performance.now();
stall(STALL_TIME, startTime);
expect(vi.getTimerCount()).toBe(1);
vi.advanceTimersByTime(STALL_TIME);
expect(vi.getTimerCount()).toBe(0);
});

View File

@@ -0,0 +1,10 @@
import { expect, test } from 'vitest';
import { stripFunction } from './strip-function';
test.each([
{ field: 'year(date_created)', expected: 'date_created' },
{ field: 'test', expected: 'test' },
])('should return "$expected" for "$field"', ({ field, expected }) => {
expect(stripFunction(field)).toBe(expected);
});

View File

@@ -0,0 +1,25 @@
import { expect, test } from 'vitest';
import { userName } from './user-name';
const unknownUser = 'Unknown User';
test('should return "Unknown User" when user is undefined', () => {
expect(userName(undefined as any)).toBe(unknownUser);
});
test('should return "Test User" when user first name is "Test" and last name is "User"', () => {
expect(userName({ first_name: 'Test', last_name: 'User' })).toBe('Test User');
});
test('should return "Test" when user first name is "Test" but does not have last name', () => {
expect(userName({ first_name: 'Test' })).toBe('Test');
});
test('should return user email when user only has email without first name and last name', () => {
expect(userName({ email: 'test@example.com' })).toBe('test@example.com');
});
test('should return "Unknown User" when user is empty', () => {
expect(userName({})).toBe(unknownUser);
});

View File

@@ -0,0 +1,41 @@
import { afterEach, beforeAll, expect, test, vi } from 'vitest';
import { validateEnv } from './validate-env';
import logger from '../logger';
vi.mock('../env', () => ({
getEnv: vi.fn().mockReturnValue({
PRESENT_TEST_VARIABLE: true,
}),
}));
vi.mock('../logger', () => ({
default: {
error: vi.fn(),
},
}));
vi.mock('process', () => ({
exit: vi.fn(),
}));
beforeAll(() => {
vi.spyOn(process, 'exit').mockImplementation(() => undefined as never);
});
afterEach(() => {
vi.clearAllMocks();
});
test('should not have any error when key is present', () => {
validateEnv(['PRESENT_TEST_VARIABLE']);
expect(logger.error).not.toHaveBeenCalled();
expect(process.exit).not.toHaveBeenCalled();
});
test('should have error when key is missing', () => {
validateEnv(['ABSENT_TEST_VARIABLE']);
expect(logger.error).toHaveBeenCalled();
expect(process.exit).toHaveBeenCalled();
});