mirror of
https://github.com/directus/directus.git
synced 2026-04-25 03:00:53 -04:00
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:
12
api/src/utils/apply-function-to-column-name.test.ts
Normal file
12
api/src/utils/apply-function-to-column-name.test.ts
Normal 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);
|
||||
});
|
||||
37
api/src/utils/get-date-formatted.test.ts
Normal file
37
api/src/utils/get-date-formatted.test.ts
Normal 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
11
api/src/utils/md.test.ts
Normal 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);
|
||||
});
|
||||
41
api/src/utils/stall.test.ts
Normal file
41
api/src/utils/stall.test.ts
Normal 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);
|
||||
});
|
||||
10
api/src/utils/strip-function.test.ts
Normal file
10
api/src/utils/strip-function.test.ts
Normal 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);
|
||||
});
|
||||
25
api/src/utils/user-name.test.ts
Normal file
25
api/src/utils/user-name.test.ts
Normal 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);
|
||||
});
|
||||
41
api/src/utils/validate-env.test.ts
Normal file
41
api/src/utils/validate-env.test.ts
Normal 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();
|
||||
});
|
||||
Reference in New Issue
Block a user