feat: unit tests for utils (#92)
* init * get unit test working for course.ts file * added some other tests * tests halfway + change config to accomodate js files * utility functions tests done * fix: config file + miscellaneous fixes * fix: prepare script * fix lock file --------- Co-authored-by: Rotimi Best <best@classroomio.com>
This commit is contained in:
co-authored by
Rotimi Best
parent
4b2e58b1de
commit
6d689ede45
+2
-1
@@ -1,4 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { browser } from '$app/environment';
|
||||
import Modal from '$lib/components/Modal/index.svelte';
|
||||
import TextField from '$lib/components/Form/TextField.svelte';
|
||||
import PrimaryButton from '$lib/components/PrimaryButton/index.svelte';
|
||||
@@ -98,7 +99,7 @@
|
||||
}, 500);
|
||||
}
|
||||
|
||||
$: note = getTextFromHTML($lesson?.materials?.note || '');
|
||||
$: note = browser ? getTextFromHTML($lesson?.materials?.note || '') : '';
|
||||
</script>
|
||||
|
||||
<Modal
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { browser } from '$app/environment';
|
||||
import isEmpty from 'lodash/isEmpty';
|
||||
import { useCompletion } from 'ai/svelte';
|
||||
import MODES from '$lib/utils/constants/mode.js';
|
||||
@@ -84,7 +85,7 @@
|
||||
|
||||
if (!document) return false;
|
||||
|
||||
return getTextFromHTML(note) === '';
|
||||
return browser ? getTextFromHTML(note) === '' : false;
|
||||
}
|
||||
|
||||
function isMaterialsEmpty(materials: LessonPage['materials']) {
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import isSubmissionEarly from './isSubmissionEarly';
|
||||
|
||||
describe('isSubmissionEarly', () => {
|
||||
test('should return true when createdAt is earlier than dueDate', () => {
|
||||
const dueDate = Date.now();
|
||||
const createdAt = new Date('2023-12-15');
|
||||
const result = isSubmissionEarly(createdAt, dueDate);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when both createdAt and dueDate are null', () => {
|
||||
const dueDate = null;
|
||||
const createdAt = null;
|
||||
const result = isSubmissionEarly(createdAt, dueDate);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
test('should return true when createdAt is the same as dueDate', () => {
|
||||
const dueDate = new Date('2023-12-15');
|
||||
const createdAt = new Date('2023-12-15');
|
||||
const result = isSubmissionEarly(createdAt, dueDate);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
test('should return false when createdAt is later than dueDate', () => {
|
||||
const dueDate = new Date('2023-12-15');
|
||||
const createdAt = new Date('2023-12-16');
|
||||
const result = isSubmissionEarly(createdAt, dueDate);
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
import { isCourseFree } from './course';
|
||||
|
||||
describe('course.ts', () => {
|
||||
test('Should return True when cost is 0', () => {
|
||||
const result = isCourseFree(0);
|
||||
expect(result).toBeTruthy();
|
||||
});
|
||||
|
||||
test('Should return true when cost is negative', () => {
|
||||
const result = isCourseFree(-10);
|
||||
expect(result).toBeTruthy();
|
||||
});
|
||||
|
||||
test('Should return True when cost is Not A Number', () => {
|
||||
const result = isCourseFree(NaN);
|
||||
expect(result).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,3 @@
|
||||
import { browser } from '$app/environment';
|
||||
import type { Course } from '../types';
|
||||
|
||||
export const isCourseFree = (cost: number) => !(Number(cost) > 0);
|
||||
@@ -19,8 +18,6 @@ export const getStudentInviteLink = (_course: Course, orgSiteName: string, origi
|
||||
};
|
||||
|
||||
export const getTextFromHTML = (html: string): string => {
|
||||
if (!browser) return html;
|
||||
|
||||
const dummyDiv = document.createElement('div');
|
||||
dummyDiv.innerHTML = html;
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import { calDateDiff, getGreeting } from './date';
|
||||
|
||||
describe('calDateDiff', () => {
|
||||
test('should return the correct time difference when the input date is in the past', () => {
|
||||
const inputDate = new Date('2022-01-01');
|
||||
const expectedOutput = '2 years ago';
|
||||
|
||||
const result = calDateDiff(inputDate);
|
||||
|
||||
expect(result).toBe(expectedOutput);
|
||||
});
|
||||
|
||||
test('should return the correct time difference when the input date is a number', () => {
|
||||
const inputDate = new Date(1640995200000); // January 1, 2022
|
||||
const expectedOutput = '2 years ago';
|
||||
|
||||
const result = calDateDiff(inputDate);
|
||||
|
||||
expect(result).toBe(expectedOutput);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getGreeting', () => {
|
||||
test("should return 'Good Morning' when the current time is before 12pm", () => {
|
||||
jest.useFakeTimers().setSystemTime(new Date('2023-12-10T00:21:01.691Z'));
|
||||
expect(getGreeting()).toBe('Good Morning');
|
||||
});
|
||||
test("should return 'Good Afternoon' when the current time is after 12pm", () => {
|
||||
jest.useFakeTimers().setSystemTime(new Date('2023-12-10T14:21:01.691Z'));
|
||||
expect(getGreeting()).toBe('Good Afternoon');
|
||||
});
|
||||
test("should return 'Good Evening' when the current time is after 6pm", () => {
|
||||
jest.useFakeTimers().setSystemTime(new Date('2023-12-10T19:21:01.691Z'));
|
||||
expect(getGreeting()).toBe('Good Evening');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,46 @@
|
||||
import { formatYoutubeVideo, getEmbedId } from './formatYoutubeVideo';
|
||||
|
||||
describe('format youtube video', () => {
|
||||
test('should return the same url when given a valid youtube embed url', () => {
|
||||
const url = 'https://www.youtube.com/embed/qajK1J1neAM';
|
||||
const errors = { video: '' };
|
||||
const result = formatYoutubeVideo(url, errors);
|
||||
expect(result).toBe(url);
|
||||
});
|
||||
|
||||
test('should return the correct embed url when given a youtube url with a start time parameter', () => {
|
||||
const url = 'https://www.youtube.com/watch?v=qajK1J1neAM&start=123';
|
||||
const errors = { video: '' };
|
||||
const result = formatYoutubeVideo(url, errors);
|
||||
expect(result).toBe('https://www.youtube.com/embed/qajK1J1neAM');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getEmbedId', () => {
|
||||
test('should return the correct embed id when the url contains "embed"', () => {
|
||||
const url = 'https://www.youtube.com/embed/qajK1J1neAM';
|
||||
const expectedEmbedId = 'qajK1J1neAM';
|
||||
|
||||
const result = getEmbedId(url);
|
||||
|
||||
expect(result).toBe(expectedEmbedId);
|
||||
});
|
||||
|
||||
test('should return an empty string when the url does not contain "watch" or "embed" and is not in the format "youtu.be/"', () => {
|
||||
const url = 'https://www.youtube.com/invalid-url';
|
||||
const expectedEmbedId = '';
|
||||
|
||||
const result = getEmbedId(url);
|
||||
|
||||
expect(result).toBe(expectedEmbedId);
|
||||
});
|
||||
|
||||
test('should return an empty string when the url is an empty string', () => {
|
||||
const url = '';
|
||||
const expectedEmbedId = '';
|
||||
|
||||
const result = getEmbedId(url);
|
||||
|
||||
expect(result).toBe(expectedEmbedId);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,25 @@
|
||||
import genUniqueId from './genUniqueId';
|
||||
|
||||
describe('Generate Unique Ids', () => {
|
||||
test('should start with letter', () => {
|
||||
const result = genUniqueId();
|
||||
const firstChar = result.charAt(0);
|
||||
expect(firstChar).toMatch(/[a-zA-Z]/);
|
||||
});
|
||||
|
||||
test('should not contain special characters', () => {
|
||||
const result = genUniqueId();
|
||||
expect(result).toMatch(/^[a-zA-Z0-9]+$/);
|
||||
});
|
||||
|
||||
test('should return different ids on multiple calls', () => {
|
||||
const result1 = genUniqueId();
|
||||
const result2 = genUniqueId();
|
||||
expect(result1).not.toEqual(result2);
|
||||
});
|
||||
test('multiple calls in closer time frames should have same first 3 letters', () => {
|
||||
const result1 = genUniqueId();
|
||||
const result2 = genUniqueId();
|
||||
expect(result1.substring(0, 4)).toEqual(result2.substring(0, 4));
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,17 @@
|
||||
import generateSlug from './generateSlug';
|
||||
|
||||
describe('generateSlug', () => {
|
||||
test('should return a string with lowercase letters and hyphens when given a valid title', () => {
|
||||
const title = 'This is a Valid Title';
|
||||
const expected = 'this-is-a-valid-title' + `-${new Date().getTime()}`;
|
||||
const result = generateSlug(title);
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
test('should include the current timestamp at the end of the string', () => {
|
||||
const title = 'This is a Valid Title';
|
||||
const result = generateSlug(title);
|
||||
const timestamp = result.split('-').pop();
|
||||
expect(Number(timestamp)).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
import generateUUID from './generateUUID';
|
||||
import { isUUID } from './isUUID';
|
||||
|
||||
// This test suite tests both the generateUUID and isUUID functions
|
||||
describe('GenerateUUID', () => {
|
||||
test('should be true when tested with the uuid function', () => {
|
||||
const result = generateUUID();
|
||||
expect(isUUID(result)).toBe(true);
|
||||
});
|
||||
|
||||
test('should generate unique UUIDs each time', () => {
|
||||
const uuid1 = generateUUID();
|
||||
const uuid2 = generateUUID();
|
||||
expect(uuid1).not.toBe(uuid2);
|
||||
});
|
||||
|
||||
test('should return true for a valid UUID', () => {
|
||||
const uuid = '123e4567-e89b-12d3-a456-426614174000';
|
||||
expect(isUUID(uuid)).toBe(true);
|
||||
});
|
||||
|
||||
test('should return false for an invalid UUID', () => {
|
||||
const uuid = 'invalid-uuid';
|
||||
expect(isUUID(uuid)).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,27 @@
|
||||
import getCurrencyFormatter from './getCurrencyFormatter';
|
||||
|
||||
describe('GetCurrencyFormatter', () => {
|
||||
test('should return a new instance of Intl.NumberFormat with the correct locale and currency options when currency is "NGN"', () => {
|
||||
const result = getCurrencyFormatter('NGN');
|
||||
expect(result).toBeInstanceOf(Intl.NumberFormat);
|
||||
expect(result.resolvedOptions().locale).toBe('en-NG');
|
||||
expect(result.resolvedOptions().currency).toBe('NGN');
|
||||
expect(result.resolvedOptions().minimumFractionDigits).toBe(2);
|
||||
});
|
||||
|
||||
test('should return a new instance of Intl.NumberFormat with the correct locale and currency options when currency is "USD"', () => {
|
||||
const result = getCurrencyFormatter('USD');
|
||||
expect(result).toBeInstanceOf(Intl.NumberFormat);
|
||||
expect(result.resolvedOptions().locale).toBe('en-US');
|
||||
expect(result.resolvedOptions().currency).toBe('USD');
|
||||
expect(result.resolvedOptions().minimumFractionDigits).toBe(2);
|
||||
});
|
||||
|
||||
test('should return a new instance of Intl.NumberFormat with the correct locale and currency options when currency is "EUR"', () => {
|
||||
const result = getCurrencyFormatter('EUR');
|
||||
expect(result).toBeInstanceOf(Intl.NumberFormat);
|
||||
expect(result.resolvedOptions().locale).toBe('en-US');
|
||||
expect(result.resolvedOptions().currency).toBe('EUR');
|
||||
expect(result.resolvedOptions().minimumFractionDigits).toBe(2);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
import { isObject } from './isObject';
|
||||
|
||||
describe('isObject', () => {
|
||||
test('should return true for an empty object', () => {
|
||||
const obj = {};
|
||||
expect(isObject(obj)).toBe(true);
|
||||
});
|
||||
|
||||
test('should return false for a non-object', () => {
|
||||
const obj = 'not an object';
|
||||
expect(isObject(obj)).toBe(false);
|
||||
});
|
||||
|
||||
test('should return true for a nested object', () => {
|
||||
const obj = { prop1: { prop2: 'value2' } };
|
||||
expect(isObject(obj)).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true for an object with properties', () => {
|
||||
const obj = { prop1: 'value1', prop2: 'value2' };
|
||||
expect(isObject(obj)).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -1,3 +1,4 @@
|
||||
//
|
||||
export function isObject(obj) {
|
||||
return obj === Object(obj);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
import { genQuizPin, generateSitename } from './org';
|
||||
|
||||
describe('Generate Quiz Pin', () => {
|
||||
test('should return a random 6-digit pin', () => {
|
||||
const result = genQuizPin();
|
||||
expect(result.toString().length).toBe(6);
|
||||
});
|
||||
|
||||
test('should return random pin each time', () => {
|
||||
const result1 = genQuizPin();
|
||||
const result2 = genQuizPin();
|
||||
expect(result1).not.toBe(result2);
|
||||
});
|
||||
|
||||
test('should generate a pin between 100000 and 999999', () => {
|
||||
const result = genQuizPin();
|
||||
expect(result).toBeGreaterThanOrEqual(100000);
|
||||
expect(result).toBeLessThanOrEqual(999999);
|
||||
});
|
||||
|
||||
test('should not generate a negative pin', () => {
|
||||
const result = genQuizPin();
|
||||
expect(result).toBeGreaterThanOrEqual(0);
|
||||
});
|
||||
|
||||
test('should generate an integer pin', () => {
|
||||
const result = genQuizPin();
|
||||
expect(Number.isInteger(result)).toBe(true);
|
||||
});
|
||||
|
||||
test('should not generate a zero pin', () => {
|
||||
const result = genQuizPin();
|
||||
expect(result).not.toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Generate Site name', () => {
|
||||
test('should return slug-like string', () => {
|
||||
const result = generateSitename('classroom org international');
|
||||
const expected = 'classroom-org-international';
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
test('should remove special characters', () => {
|
||||
const result = generateSitename('classroom@ org! international');
|
||||
const expected = 'classroom-org-international';
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
test('should return empty string when orgName is an empty string', () => {
|
||||
const result = generateSitename('');
|
||||
const expected = '';
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
test('should return slug-like string with all uppercase characters converted to lowercase', () => {
|
||||
const result = generateSitename('Classroom Org International');
|
||||
const expected = 'classroom-org-international';
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,38 @@
|
||||
import { removeDuplicate } from './removeDuplicate';
|
||||
|
||||
describe('removeDuplicate', () => {
|
||||
test('should remove duplicate elements of an array', () => {
|
||||
const result = removeDuplicate([1, 1, 2, 3, 3, 4, 5]);
|
||||
const expected = [1, 2, 3, 4, 5];
|
||||
expect(result).toStrictEqual(expected);
|
||||
expect(result.length).toBe(5);
|
||||
});
|
||||
|
||||
test('should return an empty array', () => {
|
||||
const result = removeDuplicate([]);
|
||||
const expected = [];
|
||||
expect(result).toStrictEqual(expected);
|
||||
expect(result.length).toBe(0);
|
||||
});
|
||||
|
||||
test('should return an array with the same element', () => {
|
||||
const result = removeDuplicate([1]);
|
||||
const expected = [1];
|
||||
expect(result).toStrictEqual(expected);
|
||||
expect(result.length).toBe(1);
|
||||
});
|
||||
|
||||
test('should return an array with only one element', () => {
|
||||
const result = removeDuplicate([1, 1, 1, 1]);
|
||||
const expected = [1];
|
||||
expect(result).toStrictEqual(expected);
|
||||
expect(result.length).toBe(1);
|
||||
});
|
||||
|
||||
test('should return an array with the unique elements in the same order as the original array', () => {
|
||||
const result = removeDuplicate([1, 2, 3, 4, 5, 1, 2, 3, 4, 5]);
|
||||
const expected = [1, 2, 3, 4, 5];
|
||||
expect(result).toStrictEqual(expected);
|
||||
expect(result.length).toBe(5);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
import showAppsSideBar from './showAppsSideBar';
|
||||
describe('ShowAppSideBar', () => {
|
||||
test("should return true when path includes '/lessons/' and does not include 'landingpage'", () => {
|
||||
const path = '/lessons/example';
|
||||
const result = showAppsSideBar(path);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
test("should return false when path does not include '/lessons/'", () => {
|
||||
const path = '/home';
|
||||
const result = showAppsSideBar(path);
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
test("should return false when path includes 'landingpage'", () => {
|
||||
const path = '/lessons/landingpage';
|
||||
const result = showAppsSideBar(path);
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
test('should return false when path is empty', () => {
|
||||
const path = '';
|
||||
const result = showAppsSideBar(path);
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,28 @@
|
||||
import { capitalizeFirstLetter } from './string';
|
||||
|
||||
describe('capitalize first letter', () => {
|
||||
test('should return the same string with the first letter capitalized', () => {
|
||||
const result = capitalizeFirstLetter('classroom');
|
||||
expect(result).toEqual('Classroom');
|
||||
});
|
||||
|
||||
test('should return an empty string when given an empty string', () => {
|
||||
const result = capitalizeFirstLetter('');
|
||||
expect(result).toEqual('');
|
||||
});
|
||||
|
||||
test('should return the same string when given a string with all uppercase letters', () => {
|
||||
const result = capitalizeFirstLetter('UPPERCASE');
|
||||
expect(result).toEqual('UPPERCASE');
|
||||
});
|
||||
|
||||
test('should return the same string when given a string with a non-alphabetical first character', () => {
|
||||
const result = capitalizeFirstLetter('123abc');
|
||||
expect(result).toEqual('123abc');
|
||||
});
|
||||
|
||||
test('should return the first letter of the first word capitalized when given a sentence', () => {
|
||||
const result = capitalizeFirstLetter('classroomio is an open source project');
|
||||
expect(result).toEqual('Classroomio is an open source project');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,28 @@
|
||||
import { validateEmail } from './validateEmail';
|
||||
|
||||
describe('validate email', () => {
|
||||
test('should return true for a valid email format', () => {
|
||||
const result = validateEmail('test@example.com');
|
||||
expect(result).toBeTruthy();
|
||||
});
|
||||
|
||||
test('should return false for an empty email', () => {
|
||||
const result = validateEmail('');
|
||||
expect(result).toBeFalsy();
|
||||
});
|
||||
|
||||
test('should return true for a valid email with uppercase letters', () => {
|
||||
const result = validateEmail('Test@Example.com');
|
||||
expect(result).toBeTruthy();
|
||||
});
|
||||
|
||||
test('should return false for an invalid email format', () => {
|
||||
const result = validateEmail('test@example');
|
||||
expect(result).toBeFalsy();
|
||||
});
|
||||
|
||||
test('should return true for a valid email with special characters', () => {
|
||||
const result = validateEmail('test+123@example.com');
|
||||
expect(result).toBeTruthy();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user