mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2025-11-17 10:11:31 +10:00
design nosepass template, add tests, add template previews
This commit is contained in:
@ -1,10 +1,9 @@
|
||||
export * from "./namespaces/array";
|
||||
export * from "./namespaces/cefr";
|
||||
export * from "./namespaces/csv";
|
||||
export * from "./namespaces/date";
|
||||
export * from "./namespaces/error";
|
||||
export * from "./namespaces/fonts";
|
||||
export * from "./namespaces/languages";
|
||||
export * from "./namespaces/language";
|
||||
export * from "./namespaces/number";
|
||||
export * from "./namespaces/object";
|
||||
export * from "./namespaces/page";
|
||||
|
||||
@ -1,33 +1,5 @@
|
||||
import { LayoutLocator } from "./types";
|
||||
|
||||
type CombinationsInput<T> = {
|
||||
[K in keyof T]: T[K][];
|
||||
};
|
||||
|
||||
export const generateCombinations = <T>(obj: CombinationsInput<T>): Array<T> => {
|
||||
const keys = Object.keys(obj) as (keyof T)[];
|
||||
|
||||
const results: Array<T> = [];
|
||||
|
||||
function backtrack(combination: Partial<T>, index: number): void {
|
||||
if (index === keys.length) {
|
||||
results.push(combination as T);
|
||||
return;
|
||||
}
|
||||
|
||||
const key = keys[index];
|
||||
const values = obj[key];
|
||||
|
||||
for (const value of values) {
|
||||
backtrack({ ...combination, [key]: value }, index + 1);
|
||||
}
|
||||
}
|
||||
|
||||
backtrack({}, 0);
|
||||
|
||||
return results;
|
||||
};
|
||||
|
||||
// Function to find a specific item in a layout
|
||||
export const findItemInLayout = (item: string, layout: string[][][]): LayoutLocator | null => {
|
||||
for (let page = 0; page < layout.length; page++) {
|
||||
@ -60,17 +32,21 @@ export const moveItemInLayout = (
|
||||
target: LayoutLocator,
|
||||
layout: string[][][],
|
||||
): string[][][] => {
|
||||
// Create a deep copy of the layout to avoid mutating the original array
|
||||
const newLayout = JSON.parse(JSON.stringify(layout)) as string[][][];
|
||||
try {
|
||||
// Create a deep copy of the layout to avoid mutating the original array
|
||||
const newLayout = JSON.parse(JSON.stringify(layout)) as string[][][];
|
||||
|
||||
// Get the item from the current location
|
||||
const item = newLayout[current.page][current.column][current.section];
|
||||
// Get the item from the current location
|
||||
const item = newLayout[current.page][current.column][current.section];
|
||||
|
||||
// Remove the item from the current location
|
||||
newLayout[current.page][current.column].splice(current.section, 1);
|
||||
// Remove the item from the current location
|
||||
newLayout[current.page][current.column].splice(current.section, 1);
|
||||
|
||||
// Insert the item at the target location
|
||||
newLayout[target.page][target.column].splice(target.section, 0, item);
|
||||
// Insert the item at the target location
|
||||
newLayout[target.page][target.column].splice(target.section, 0, item);
|
||||
|
||||
return newLayout;
|
||||
return newLayout;
|
||||
} catch (error) {
|
||||
return layout;
|
||||
}
|
||||
};
|
||||
|
||||
@ -1,13 +0,0 @@
|
||||
// CEFR Levels
|
||||
const cefrMap = {
|
||||
1: "A1",
|
||||
2: "A2",
|
||||
3: "B1",
|
||||
4: "B2",
|
||||
5: "C1",
|
||||
6: "C2",
|
||||
};
|
||||
|
||||
export const getCEFRLevel = (level: number) => {
|
||||
return cefrMap[level as keyof typeof cefrMap];
|
||||
};
|
||||
@ -4,6 +4,7 @@ export const sortByDate = <T>(a: T, b: T, key: keyof T, desc = true) => {
|
||||
if (!a[key] || !b[key]) return 0;
|
||||
if (!(a[key] instanceof Date) || !(b[key] instanceof Date)) return 0;
|
||||
|
||||
if (dayjs(a[key] as Date).isSame(dayjs(b[key] as Date))) return 0;
|
||||
if (desc) return dayjs(a[key] as Date).isBefore(dayjs(b[key] as Date)) ? 1 : -1;
|
||||
else return dayjs(a[key] as Date).isBefore(dayjs(b[key] as Date)) ? -1 : 1;
|
||||
};
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
// Languages
|
||||
export type Language = {
|
||||
id: string;
|
||||
name: string;
|
||||
@ -4,4 +4,9 @@ export const linearTransform = (
|
||||
inMax: number,
|
||||
outMin: number,
|
||||
outMax: number,
|
||||
) => ((value - inMin) * (outMax - outMin)) / (inMax - inMin) + outMin;
|
||||
) => {
|
||||
if (inMax === inMin) return value === inMax ? outMin : NaN;
|
||||
return ((value - inMin) * (outMax - outMin)) / (inMax - inMin) + outMin;
|
||||
};
|
||||
|
||||
// Handle this case: returns output minimum if input maximum equals input minimum
|
||||
|
||||
@ -1,11 +1 @@
|
||||
export const delay = (time: number) => new Promise((resolve) => setTimeout(resolve, time));
|
||||
|
||||
export const withTimeout = async <T>(promise: Promise<T>, time: number): Promise<T> => {
|
||||
const timeout = new Promise((_, reject) =>
|
||||
setTimeout(() => {
|
||||
return reject(new Error(`Operation timed out after ${time}ms`));
|
||||
}, time),
|
||||
);
|
||||
|
||||
return Promise.race([promise, timeout]) as T;
|
||||
};
|
||||
|
||||
@ -1,46 +1,13 @@
|
||||
export type TemplateKey =
|
||||
| "onyx"
|
||||
| "kakuna"
|
||||
| "rhyhorn"
|
||||
| "azurill"
|
||||
| "ditto"
|
||||
| "chikorita"
|
||||
| "bronzor"
|
||||
| "pikachu";
|
||||
export const templatesList = [
|
||||
"azurill",
|
||||
"bronzor",
|
||||
"chikorita",
|
||||
"ditto",
|
||||
"kakuna",
|
||||
"nosepass",
|
||||
"onyx",
|
||||
"pikachu",
|
||||
"rhyhorn",
|
||||
] as const;
|
||||
|
||||
export type Template = { id: TemplateKey; name: string };
|
||||
|
||||
export const templatesList: Template[] = [
|
||||
{
|
||||
id: "onyx",
|
||||
name: "Onyx",
|
||||
},
|
||||
{
|
||||
id: "kakuna",
|
||||
name: "Kakuna",
|
||||
},
|
||||
{
|
||||
id: "rhyhorn",
|
||||
name: "Rhyhorn",
|
||||
},
|
||||
{
|
||||
id: "azurill",
|
||||
name: "Azurill",
|
||||
},
|
||||
{
|
||||
id: "ditto",
|
||||
name: "Ditto",
|
||||
},
|
||||
{
|
||||
id: "chikorita",
|
||||
name: "Chikorita",
|
||||
},
|
||||
{
|
||||
id: "bronzor",
|
||||
name: "Bronzor",
|
||||
},
|
||||
{
|
||||
id: "pikachu",
|
||||
name: "Pikachu",
|
||||
},
|
||||
];
|
||||
export type Template = (typeof templatesList)[number];
|
||||
|
||||
162
libs/utils/src/namespaces/tests/array.test.ts
Normal file
162
libs/utils/src/namespaces/tests/array.test.ts
Normal file
@ -0,0 +1,162 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { findItemInLayout, moveItemInLayout, removeItemInLayout } from "../array";
|
||||
|
||||
describe("findItemInLayout", () => {
|
||||
it("should find the correct location of an item", () => {
|
||||
const layout = [
|
||||
[["item1"], ["item2"]],
|
||||
[["item3"], ["item4"]],
|
||||
];
|
||||
const item = "item3";
|
||||
const expectedLocation = { page: 1, column: 0, section: 0 };
|
||||
|
||||
const location = findItemInLayout(item, layout);
|
||||
|
||||
expect(location).toEqual(expectedLocation);
|
||||
});
|
||||
|
||||
it("should return null if the item is not found", () => {
|
||||
const layout = [
|
||||
[["item1"], ["item2"]],
|
||||
[["item3"], ["item4"]],
|
||||
];
|
||||
const item = "item5";
|
||||
|
||||
const location = findItemInLayout(item, layout);
|
||||
|
||||
expect(location).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe("removeItemInLayout", () => {
|
||||
it("should remove the item and return its location", () => {
|
||||
const layout = [
|
||||
[["item1"], ["item2"]],
|
||||
[["item3"], ["item4"]],
|
||||
];
|
||||
const item = "item3";
|
||||
const expectedLocation = { page: 1, column: 0, section: 0 };
|
||||
|
||||
const location = removeItemInLayout(item, layout);
|
||||
|
||||
expect(location).toEqual(expectedLocation);
|
||||
expect(layout[1][0]).not.toContain(item);
|
||||
});
|
||||
|
||||
it("should return null and not modify layout if the item is not found", () => {
|
||||
const layout = [
|
||||
[["item1"], ["item2"]],
|
||||
[["item3"], ["item4"]],
|
||||
];
|
||||
const item = "item5";
|
||||
|
||||
const location = removeItemInLayout(item, layout);
|
||||
|
||||
expect(location).toBeNull();
|
||||
expect(layout).toEqual([
|
||||
[["item1"], ["item2"]],
|
||||
[["item3"], ["item4"]],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("moveItemInLayout", () => {
|
||||
it("should move an item from the current location to the target location", () => {
|
||||
const layout = [
|
||||
[["item1"], ["item2"]],
|
||||
[["item3"], ["item4"]],
|
||||
];
|
||||
const current = { page: 0, column: 1, section: 0 };
|
||||
const target = { page: 1, column: 0, section: 1 };
|
||||
const expectedLayout = [
|
||||
[["item1"], []],
|
||||
[["item3", "item2"], ["item4"]],
|
||||
];
|
||||
|
||||
const newLayout = moveItemInLayout(current, target, layout);
|
||||
|
||||
expect(newLayout).toEqual(expectedLayout);
|
||||
});
|
||||
|
||||
it("should not mutate the original layout array", () => {
|
||||
const layout = [
|
||||
[["item1"], ["item2"]],
|
||||
[["item3"], ["item4"]],
|
||||
];
|
||||
const layoutCopy = JSON.parse(JSON.stringify(layout));
|
||||
const current = { page: 0, column: 1, section: 0 };
|
||||
const target = { page: 1, column: 0, section: 1 };
|
||||
|
||||
moveItemInLayout(current, target, layout);
|
||||
|
||||
expect(layout).toEqual(layoutCopy);
|
||||
});
|
||||
|
||||
it("should handle the case where the current and target locations are the same", () => {
|
||||
const layout = [
|
||||
[["item1"], ["item2"]],
|
||||
[["item3"], ["item4"]],
|
||||
];
|
||||
const current = { page: 1, column: 0, section: 0 };
|
||||
const target = { page: 1, column: 0, section: 0 };
|
||||
|
||||
const newLayout = moveItemInLayout(current, target, layout);
|
||||
|
||||
expect(newLayout).toEqual(layout);
|
||||
});
|
||||
|
||||
it("moves an item to the specified target location", () => {
|
||||
const layout = [
|
||||
[["A", "B"], ["C"]],
|
||||
[["D"], ["E", "F"]],
|
||||
];
|
||||
const current = { page: 0, column: 0, section: 1 };
|
||||
const target = { page: 1, column: 1, section: 1 };
|
||||
const result = moveItemInLayout(current, target, layout);
|
||||
expect(result).toEqual([
|
||||
[["A"], ["C"]],
|
||||
[["D"], ["E", "B", "F"]],
|
||||
]);
|
||||
});
|
||||
|
||||
it("handles moving an item within the same column", () => {
|
||||
const layout = [[["A", "B"]], [["C", "D"]]];
|
||||
const current = { page: 0, column: 0, section: 0 };
|
||||
const target = { page: 0, column: 0, section: 1 };
|
||||
const result = moveItemInLayout(current, target, layout);
|
||||
expect(result).toEqual([[["B", "A"]], [["C", "D"]]]);
|
||||
});
|
||||
|
||||
it("handles moving an item to the beginning of a column", () => {
|
||||
const layout = [[["A"], ["B", "C"]], [["D"]]];
|
||||
const current = { page: 1, column: 0, section: 0 };
|
||||
const target = { page: 0, column: 1, section: 0 };
|
||||
const result = moveItemInLayout(current, target, layout);
|
||||
expect(result).toEqual([[["A"], ["D", "B", "C"]], [[]]]);
|
||||
});
|
||||
|
||||
it("handles moving an item to an empty column", () => {
|
||||
const layout = [[["A"], []], [["B"]]];
|
||||
const current = { page: 0, column: 0, section: 0 };
|
||||
const target = { page: 0, column: 1, section: 0 };
|
||||
const result = moveItemInLayout(current, target, layout);
|
||||
expect(result).toEqual([[[], ["A"]], [["B"]]]);
|
||||
});
|
||||
|
||||
it("returns the same layout if the current location is invalid", () => {
|
||||
const layout = [[["A"], ["B"]]];
|
||||
const current = { page: 2, column: 0, section: 0 };
|
||||
const target = { page: 0, column: 1, section: 0 };
|
||||
const result = moveItemInLayout(current, target, layout);
|
||||
expect(result).toEqual(layout);
|
||||
});
|
||||
|
||||
it("returns the same layout if the target location is invalid", () => {
|
||||
const layout = [[["A"], ["B"]]];
|
||||
const current = { page: 0, column: 0, section: 0 };
|
||||
const target = { page: 2, column: 0, section: 0 };
|
||||
const result = moveItemInLayout(current, target, layout);
|
||||
expect(result).toEqual(layout);
|
||||
});
|
||||
});
|
||||
107
libs/utils/src/namespaces/tests/date.test.ts
Normal file
107
libs/utils/src/namespaces/tests/date.test.ts
Normal file
@ -0,0 +1,107 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { deepSearchAndParseDates, sortByDate } from "../date";
|
||||
|
||||
type TestType = { date?: Date };
|
||||
|
||||
describe("sortByDate", () => {
|
||||
it("sorts by date in descending order when desc is true", () => {
|
||||
const a: TestType = { date: new Date("2023-01-01") };
|
||||
const b: TestType = { date: new Date("2023-01-02") };
|
||||
expect(sortByDate(a, b, "date")).toBe(1);
|
||||
expect(sortByDate(b, a, "date")).toBe(-1);
|
||||
});
|
||||
|
||||
it("sorts by date in ascending order when desc is false", () => {
|
||||
const a: TestType = { date: new Date("2023-01-01") };
|
||||
const b: TestType = { date: new Date("2023-01-02") };
|
||||
expect(sortByDate(a, b, "date", false)).toBe(-1);
|
||||
expect(sortByDate(b, a, "date", false)).toBe(1);
|
||||
});
|
||||
|
||||
it("returns 0 if one of the dates is missing", () => {
|
||||
const a: TestType = { date: new Date("2023-01-01") };
|
||||
const b: TestType = {};
|
||||
expect(sortByDate(a, b, "date")).toBe(0);
|
||||
});
|
||||
|
||||
it("returns 0 if one of the values is not a date", () => {
|
||||
const a: TestType = { date: new Date("2023-01-01") };
|
||||
const b: TestType = { date: "2023-01-02" as unknown as Date };
|
||||
expect(sortByDate(a, b, "date")).toBe(0);
|
||||
});
|
||||
|
||||
it("handles equal dates", () => {
|
||||
const a: TestType = { date: new Date("2023-01-01") };
|
||||
const b: TestType = { date: new Date("2023-01-01") };
|
||||
expect(sortByDate(a, b, "date")).toBe(0);
|
||||
expect(sortByDate(a, b, "date", false)).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("deepSearchAndParseDates", () => {
|
||||
it("parses dates at various nesting levels", () => {
|
||||
const input = {
|
||||
level1: {
|
||||
date: "2021-08-17T00:00:00Z",
|
||||
nested: {
|
||||
date: "2022-08-17T00:00:00Z",
|
||||
},
|
||||
},
|
||||
otherKey: "value",
|
||||
};
|
||||
const dateKeys = ["date"];
|
||||
const output = deepSearchAndParseDates(input, dateKeys);
|
||||
|
||||
expect(output.level1.date).toBeInstanceOf(Date);
|
||||
expect(output.level1.nested.date).toBeInstanceOf(Date);
|
||||
expect(output.otherKey).toBe("value");
|
||||
});
|
||||
|
||||
it("does not parse invalid date strings", () => {
|
||||
const input = {
|
||||
date: "not a date",
|
||||
};
|
||||
const dateKeys = ["date"];
|
||||
const output = deepSearchAndParseDates(input, dateKeys);
|
||||
|
||||
expect(output.date).toBe("not a date");
|
||||
});
|
||||
|
||||
it("does not modify non-object input", () => {
|
||||
const input = "2021-08-17T00:00:00Z";
|
||||
const dateKeys = ["date"];
|
||||
const output = deepSearchAndParseDates(input, dateKeys);
|
||||
|
||||
expect(output).toBe(input);
|
||||
});
|
||||
|
||||
it("returns null for null input", () => {
|
||||
const input = null;
|
||||
const dateKeys = ["date"];
|
||||
const output = deepSearchAndParseDates(input, dateKeys);
|
||||
|
||||
expect(output).toBeNull();
|
||||
});
|
||||
|
||||
it("handles arrays with date strings", () => {
|
||||
const input = ["2021-08-17T00:00:00Z", "2022-08-17"];
|
||||
const dateKeys = ["0", "1"]; // Assuming the keys are stringified indices
|
||||
const output = deepSearchAndParseDates(input, dateKeys);
|
||||
|
||||
expect(output[0]).toBeInstanceOf(Date);
|
||||
expect(output[1]).toBeInstanceOf(Date);
|
||||
});
|
||||
|
||||
it("ignores keys that are not in the dateKeys", () => {
|
||||
const input = {
|
||||
date: "2021-08-17T00:00:00Z",
|
||||
notADate: "2021-08-17T00:00:00Z",
|
||||
};
|
||||
const dateKeys = ["date"];
|
||||
const output = deepSearchAndParseDates(input, dateKeys);
|
||||
|
||||
expect(output.date).toBeInstanceOf(Date);
|
||||
expect(output.notADate).toBe("2021-08-17T00:00:00Z");
|
||||
});
|
||||
});
|
||||
53
libs/utils/src/namespaces/tests/number.test.ts
Normal file
53
libs/utils/src/namespaces/tests/number.test.ts
Normal file
@ -0,0 +1,53 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { linearTransform } from "../number";
|
||||
|
||||
describe("linearTransform", () => {
|
||||
it("transforms values from one range to another", () => {
|
||||
const value = 5;
|
||||
const result = linearTransform(value, 0, 10, 0, 100);
|
||||
expect(result).toBe(50);
|
||||
});
|
||||
|
||||
it("handles negative ranges", () => {
|
||||
const value = -5;
|
||||
const result = linearTransform(value, -10, 0, 0, 100);
|
||||
expect(result).toBe(50);
|
||||
});
|
||||
|
||||
it("correctly transforms the minimum input value to the minimum output value", () => {
|
||||
const value = 0;
|
||||
const result = linearTransform(value, 0, 10, 0, 100);
|
||||
expect(result).toBe(0);
|
||||
});
|
||||
|
||||
it("correctly transforms the maximum input value to the maximum output value", () => {
|
||||
const value = 10;
|
||||
const result = linearTransform(value, 0, 10, 0, 100);
|
||||
expect(result).toBe(100);
|
||||
});
|
||||
|
||||
it("transforms values outside the input range", () => {
|
||||
const value = 15;
|
||||
const result = linearTransform(value, 0, 10, 0, 100);
|
||||
expect(result).toBe(150);
|
||||
});
|
||||
|
||||
it("handles inverted output ranges", () => {
|
||||
const value = 5;
|
||||
const result = linearTransform(value, 0, 10, 100, 0);
|
||||
expect(result).toBe(50);
|
||||
});
|
||||
|
||||
it("returns NaN if input maximum equals input minimum", () => {
|
||||
const value = 5;
|
||||
const result = linearTransform(value, 0, 0, 0, 100);
|
||||
expect(result).toBe(NaN);
|
||||
});
|
||||
|
||||
it("returns NaN if input range is zero (avoids division by zero)", () => {
|
||||
const value = 5;
|
||||
const result = linearTransform(value, 10, 10, 0, 100);
|
||||
expect(result).toBeNaN();
|
||||
});
|
||||
});
|
||||
75
libs/utils/src/namespaces/tests/object.test.ts
Normal file
75
libs/utils/src/namespaces/tests/object.test.ts
Normal file
@ -0,0 +1,75 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { exclude } from "../object";
|
||||
|
||||
describe("exclude", () => {
|
||||
type TestObject = {
|
||||
id: number;
|
||||
name: string;
|
||||
age: number;
|
||||
email: string;
|
||||
};
|
||||
|
||||
it("excludes specified keys from the object", () => {
|
||||
const object: TestObject = {
|
||||
id: 1,
|
||||
name: "Alice",
|
||||
age: 30,
|
||||
email: "alice@example.com",
|
||||
};
|
||||
const result = exclude(object, ["age", "email"]);
|
||||
|
||||
expect(result).toEqual({ id: 1, name: "Alice" });
|
||||
expect(result).not.toHaveProperty("age");
|
||||
expect(result).not.toHaveProperty("email");
|
||||
});
|
||||
|
||||
it("returns the same object if no keys are specified", () => {
|
||||
const object: TestObject = {
|
||||
id: 1,
|
||||
name: "Alice",
|
||||
age: 30,
|
||||
email: "alice@example.com",
|
||||
};
|
||||
const keysToExclude: Array<keyof TestObject> = [];
|
||||
const result = exclude(object, keysToExclude);
|
||||
|
||||
expect(result).toEqual(object);
|
||||
});
|
||||
|
||||
it("does not modify the original object", () => {
|
||||
const object: TestObject = {
|
||||
id: 1,
|
||||
name: "Alice",
|
||||
age: 30,
|
||||
email: "alice@example.com",
|
||||
};
|
||||
exclude(object, ["age", "email"]);
|
||||
|
||||
expect(object).toHaveProperty("age");
|
||||
expect(object).toHaveProperty("email");
|
||||
});
|
||||
|
||||
it("handles cases where keys to exclude are not present in the object", () => {
|
||||
const object: TestObject = {
|
||||
id: 1,
|
||||
name: "Alice",
|
||||
age: 30,
|
||||
email: "alice@example.com",
|
||||
};
|
||||
const keysToExclude = ["nonExistentKey" as keyof TestObject];
|
||||
const result = exclude(object, keysToExclude);
|
||||
|
||||
expect(result).toEqual(object);
|
||||
});
|
||||
|
||||
it("returns the input if it is not an object", () => {
|
||||
const object: unknown = null;
|
||||
const keysToExclude = ["id"];
|
||||
|
||||
// @ts-expect-error passing invalid input type for tests
|
||||
const result = exclude(object, keysToExclude);
|
||||
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
});
|
||||
66
libs/utils/src/namespaces/tests/string.test.ts
Normal file
66
libs/utils/src/namespaces/tests/string.test.ts
Normal file
@ -0,0 +1,66 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import {
|
||||
extractUrl,
|
||||
generateRandomName,
|
||||
getInitials,
|
||||
isEmptyString,
|
||||
isUrl,
|
||||
kebabCase,
|
||||
processUsername,
|
||||
} from "../string";
|
||||
|
||||
describe("getInitials", () => {
|
||||
it("returns the initials of a name", () => {
|
||||
expect(getInitials("John Doe")).toBe("JD");
|
||||
expect(getInitials("Mary Jane Watson")).toBe("MW");
|
||||
});
|
||||
});
|
||||
|
||||
describe("isUrl", () => {
|
||||
it("checks if a string is a URL", () => {
|
||||
expect(isUrl("https://example.com")).toBe(true);
|
||||
expect(isUrl("not a url")).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("isEmptyString", () => {
|
||||
it("checks if a string is empty or only contains whitespace", () => {
|
||||
expect(isEmptyString("")).toBe(true);
|
||||
expect(isEmptyString(" ")).toBe(true);
|
||||
expect(isEmptyString("<p></p>")).toBe(true);
|
||||
expect(isEmptyString("not empty")).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("extractUrl", () => {
|
||||
it("extracts a URL from a string", () => {
|
||||
expect(extractUrl("Visit https://example.com today!")).toBe("https://example.com");
|
||||
expect(extractUrl("No URL here.")).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe("kebabCase", () => {
|
||||
it("converts a string to kebab-case", () => {
|
||||
expect(kebabCase("fooBar")).toBe("foo-bar");
|
||||
expect(kebabCase("Foo Bar")).toBe("foo-bar");
|
||||
expect(kebabCase("foo_bar")).toBe("foo-bar");
|
||||
expect(kebabCase("")).toBe("");
|
||||
expect(kebabCase(null)).toBe("");
|
||||
});
|
||||
});
|
||||
|
||||
describe("generateRandomName", () => {
|
||||
it("generates a random name", () => {
|
||||
const name = generateRandomName();
|
||||
expect(name).toMatch(/^[A-Z][a-z]+ [A-Z][a-z]+ [A-Z][a-z]+$/);
|
||||
});
|
||||
});
|
||||
|
||||
describe("processUsername", () => {
|
||||
it("processes a username by removing non-alphanumeric characters", () => {
|
||||
expect(processUsername("User@Name!")).toBe("username");
|
||||
expect(processUsername("")).toBe("");
|
||||
expect(processUsername(null)).toBe("");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user