Skip to content

Commit

Permalink
Added new helpers and completed existing helpers documentation. (#130)
Browse files Browse the repository at this point in the history
* Added new helpers and completed existing helpers documentation.

* CHANGELOG
  • Loading branch information
Utar94 authored Apr 23, 2024
1 parent a504429 commit a887ac1
Show file tree
Hide file tree
Showing 16 changed files with 1,770 additions and 3 deletions.
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

Nothing yet.
### Added

- New helpers: `arrayUtils`, `dateUtils`, `objectUtils`, `stringUtils` and `urlUtils`.

### Fixed

- Completed existing helpers documentation.

## [2.4.0] - 2024-04-18

Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

71 changes: 71 additions & 0 deletions src/helpers/__tests__/arrayUtils.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { describe, it, expect } from "vitest";

import { orderBy, orderByDescending } from "../arrayUtils";

type User = {
name: string;
email?: string;
};

describe("arrayUtils.orderBy", () => {
it.concurrent("should sort an empty array", () => {
expect(orderBy([]).join(";")).toBe("");
expect(orderBy([], "name").join(";")).toBe("");
expect(orderBy([], undefined, true).join(";")).toBe("");
expect(orderBy([], "name", true).join(";")).toBe("");
});

it.concurrent("should sort ascendingly a primitive array", () => {
expect(orderBy([3, undefined, 1, 2]).join(",")).toBe("1,2,3,");
expect(orderBy(["orange", "mango", "apple"], undefined, false).join("|")).toBe("apple|mango|orange");
});

it.concurrent("should sort ascendingly an object array by key", () => {
const users: User[] = [{ name: "Charles" }, { name: "Christopher" }, { name: "Abby" }];
expect(
orderBy(users, "name")
.map(({ name }) => name)
.join("|"),
).toBe("Abby|Charles|Christopher");
expect(
orderBy(users, "name", false)
.map(({ name }) => name)
.join("|"),
).toBe("Abby|Charles|Christopher");
});

it.concurrent("should sort descendingly a primitive array", () => {
expect(orderBy([3, 1, undefined, 2], undefined, true).join(",")).toBe("3,2,1,");
expect(orderBy(["orange", "apple", "mango"], undefined, true).join("|")).toBe("orange|mango|apple");
});

it.concurrent("should sort descendingly an object array by key", () => {
const users: User[] = [{ name: "Charles", email: "[email protected]" }, { name: "Christopher" }, { name: "Abby", email: "[email protected]" }];
expect(
orderBy(users, "email", true)
.map(({ name }) => name)
.join("|"),
).toBe("Abby|Charles|Christopher");
});
});

describe("arrayUtils.orderByDescending", () => {
it.concurrent("should sort descendingly a primitive array", () => {
expect(orderByDescending(["Acura", "Nissan", "Chevrolet"]).join(", ")).toBe("Nissan, Chevrolet, Acura");
expect(orderByDescending([undefined, "Acura", "Nissan", "Chevrolet"]).join(", ")).toBe("Nissan, Chevrolet, Acura, ");
});

it.concurrent("should sort descendingly an empty array", () => {
expect(orderByDescending([]).join("|")).toBe("");
expect(orderByDescending([], "name").join("|")).toBe("");
});

it.concurrent("should sort descendingly an object array", () => {
const users: User[] = [{ name: "Charles", email: "[email protected]" }, { name: "Christopher" }, { name: "Abby", email: "[email protected]" }];
expect(
orderByDescending(users, "email")
.map(({ name }) => name)
.join("|"),
).toBe("Abby|Charles|Christopher");
});
});
11 changes: 11 additions & 0 deletions src/helpers/__tests__/dateUtils.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { describe, it, expect } from "vitest";

import { toDateTimeLocal } from "../dateUtils";

describe("dateUtils.toDateTimeLocal", () => {
it.concurrent("should return the correct converted date", () => {
const date = new Date(2024, 3, 14, 23, 24, 25);
const local = toDateTimeLocal(date);
expect(local).toBe("2024-04-14T23:24");
});
});
45 changes: 45 additions & 0 deletions src/helpers/__tests__/objectUtils.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { describe, it, expect } from "vitest";

import { assign, isEmpty } from "../objectUtils";

type User = {
name: string;
email?: string;
};

describe("objectUtils.assign", () => {
it.concurrent("should assign a value to a key", () => {
const user: User = { name: "Charles Luiz" };
assign(user, "name", "Carlos Luyz");
expect(user.name).toBe("Carlos Luyz");
});

it.concurrent("should assign a value to an optional key", () => {
const user: User = { name: "Charles Luiz" };
assign(user, "email", "[email protected]");
expect(user.email).toBe("[email protected]");
});

it.concurrent("should assign undefined to an optional key", () => {
const user: User = { name: "Charles Luis", email: "[email protected]" };
assign(user, "email", undefined);
expect(user.email).toBeUndefined();
});
});

describe("objectUtils.isEmpty", () => {
it.concurrent("should return false if the object has at least one key", () => {
const user: User = { name: "Charles Luiz" };
expect(isEmpty(user)).toBe(false);
user.email = "[email protected]";
expect(isEmpty(user)).toBe(false);
});

it.concurrent("should return true if the object has no key", () => {
const obj: any = {};
expect(isEmpty(obj)).toBe(true);
obj.key = true;
delete obj.key;
expect(isEmpty(obj)).toBe(true);
});
});
239 changes: 239 additions & 0 deletions src/helpers/__tests__/stringUtils.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
import { describe, it, expect } from "vitest";

import {
cleanTrim,
combineURL,
isAbsoluteURL,
isDigit,
isLetter,
isLetterOrDigit,
isNullOrEmpty,
isNullOrWhiteSpace,
shortify,
slugify,
trim,
trimEnd,
trimStart,
unaccent,
} from "../stringUtils";

describe("stringUtils.cleanTrim", () => {
it.concurrent("should return undefined when the string is null, empty or white space", () => {
expect(cleanTrim(undefined)).toBeUndefined();
expect(cleanTrim("")).toBeUndefined();
expect(cleanTrim(" ")).toBeUndefined();
});

it.concurrent("should return the trimmed string when it is not null, empty nor white space", () => {
expect(cleanTrim(" test")).toBe("test");
expect(cleanTrim("test ")).toBe("test");
expect(cleanTrim(" test ")).toBe("test");
});
});

describe("stringUtils.combineURL", () => {
it.concurrent("should combine the segments with a slash (/)", () => {
expect(combineURL()).toBe("/");
expect(combineURL("Hello World!")).toBe("/Hello World!");
expect(combineURL("hello", "world")).toBe("/hello/world");
expect(combineURL("http://api.google.com", "users/123")).toBe("http://api.google.com/users/123");
expect(combineURL("https://api.google.com", "users", "123")).toBe("https://api.google.com/users/123");
});

it.concurrent("should ignore empty values", () => {
expect(combineURL("")).toBe("/");
expect(combineURL(" ")).toBe("/");
expect(combineURL("", "api", "user")).toBe("/api/user");
expect(combineURL(" ", "api", "user")).toBe("/api/user");
expect(combineURL("api", "", "user")).toBe("/api/user");
expect(combineURL("api", " ", "user")).toBe("/api/user");
expect(combineURL("api", "user", "")).toBe("/api/user");
expect(combineURL("api", "user", " ")).toBe("/api/user");
});

it.concurrent("should ignore undefined values", () => {
const u: any = undefined;
expect(combineURL(u)).toBe("/");
expect(combineURL(u, "api", "user")).toBe("/api/user");
expect(combineURL("api", u, "user")).toBe("/api/user");
expect(combineURL("api", "user", u)).toBe("/api/user");
});

it.concurrent("should remove starting & ending slashes (/) from segments", () => {
expect(combineURL("/api", "users/123")).toBe("/api/users/123");
expect(combineURL("api", "users/123/")).toBe("/api/users/123");
expect(combineURL("/api", "users/123/")).toBe("/api/users/123");
});
});

describe("stringUtils.isAbsoluteURL", () => {
it.concurrent("should return false when input string is not an absolute URL", () => {
expect(isAbsoluteURL("")).toBe(false);
expect(isAbsoluteURL(" ")).toBe(false);
expect(isAbsoluteURL("/api/users/123")).toBe(false);
});

it.concurrent("should return true when input string is an absolute URL", () => {
expect(isAbsoluteURL("http://api.test.com/users/123")).toBe(true);
expect(isAbsoluteURL("https://api.test.com/users/123")).toBe(true);
expect(isAbsoluteURL("ftp://api.test.com/users/123")).toBe(true);
});
});

describe("stringUtils.isDigit", () => {
it.concurrent("should return false when input character is not a digit", () => {
expect(isDigit("")).toBe(false);
expect(isDigit(" ")).toBe(false);
expect(isDigit("A")).toBe(false);
});

it.concurrent("should return true when input character is a digit", () => {
expect(isDigit("0")).toBe(true);
expect(isDigit("4")).toBe(true);
});
});

describe("stringUtils.isLetter", () => {
it.concurrent("should return false when input character is not a letter", () => {
expect(isLetter("")).toBe(false);
expect(isLetter(" ")).toBe(false);
expect(isLetter("0")).toBe(false);
expect(isLetter("|")).toBe(false);
});

it.concurrent("should return true when input character is a letter", () => {
expect(isLetter("A")).toBe(true);
expect(isLetter("Z")).toBe(true);
});
});

describe("stringUtils.isLetterOrDigit", () => {
it.concurrent("should return false when input character is not a letter, nor a digit", () => {
expect(isLetterOrDigit("")).toBe(false);
expect(isLetterOrDigit(" ")).toBe(false);
expect(isLetterOrDigit("|")).toBe(false);
});

it.concurrent("should return true when input character is a letter or a digit", () => {
expect(isLetterOrDigit("B")).toBe(true);
expect(isLetterOrDigit("D")).toBe(true);
expect(isLetterOrDigit("1")).toBe(true);
expect(isLetterOrDigit("3")).toBe(true);
});
});

describe("stringUtils.isNullOrEmpty", () => {
it.concurrent("should return false when the string is not null nor empty", () => {
expect(isNullOrEmpty(" ")).toBe(false);
expect(isNullOrEmpty("test")).toBe(false);
});

it.concurrent("should return true when the string is null or empty", () => {
expect(isNullOrEmpty(undefined)).toBe(true);
expect(isNullOrEmpty("")).toBe(true);
});
});

describe("stringUtils.isNullOrWhiteSpace", () => {
it.concurrent("should return false when the string is not null nor white space", () => {
expect(isNullOrWhiteSpace(" test ")).toBe(false);
});

it.concurrent("should return true when the string is null or white space", () => {
expect(isNullOrWhiteSpace(undefined)).toBe(true);
expect(isNullOrWhiteSpace("")).toBe(true);
expect(isNullOrWhiteSpace(" ")).toBe(true);
});
});

describe("stringUtils.shortify", () => {
it.concurrent("should return the same string when it is not too long", () => {
expect(shortify("", 20)).toBe("");
expect(shortify(" ", 20)).toBe(" ");
expect(shortify("Hello World!", 20)).toBe("Hello World!");
});

it.concurrent("should return the shortified string when it is too long", () => {
expect(shortify("", -1)).toBe("…");
expect(shortify(" ", 2)).toBe(" …");
expect(shortify("Hello World!", 10)).toBe("Hello Wor…");
});
});

describe("stringUtils.slugify", () => {
it.concurrent("should return an empty string when it is empty or undefined", () => {
expect(slugify(undefined)).toBe("");
expect(slugify("")).toBe("");
expect(slugify(" ")).toBe("");
});

it.concurrent(
"should separate the input string by non-alphanumeric characters, join them using hyphens (-), remove accents and return a lowercased slug",
() => {
expect(slugify("arc-en-ciel")).toBe("arc-en-ciel");
expect(slugify("Héllo Wôrld!")).toBe("hello-world");
},
);
});

describe("stringUtils.trim", () => {
it.concurrent("should return the original string when it does not start nor end with the specified character", () => {
expect(trim("", "")).toBe("");
expect(trim("f|oo", "|")).toBe("f|oo");
});

it.concurrent("should trim the start and end of the specified string, removing the specified character", () => {
expect(trim("||f|oo+", "|")).toBe("f|oo+");
expect(trim("+f|oo||", "|")).toBe("+f|oo");
expect(trim("|f|oo||", "|")).toBe("f|oo");
expect(trim("]f|oo]", "]")).toBe("f|oo");
expect(trim("^f|oo^", "^")).toBe("f|oo");
expect(trim("\\f|oo\\", "\\")).toBe("f|oo");
});
});

describe("stringUtils.trimEnd", () => {
it.concurrent("should return the original string when it does not end with the specified character", () => {
expect(trimEnd("", "")).toBe("");
expect(trimEnd("||f|oo", "|")).toBe("||f|oo");
});

it.concurrent("should trim the end of the specified string, removing the specified character", () => {
expect(trimEnd("||f|oo+", "|")).toBe("||f|oo+");
expect(trimEnd("+f|oo||", "|")).toBe("+f|oo");
expect(trimEnd("|f|oo||", "|")).toBe("|f|oo");
expect(trimEnd("]f|oo]", "]")).toBe("]f|oo");
expect(trimEnd("^f|oo^", "^")).toBe("^f|oo");
expect(trimEnd("\\f|oo\\", "\\")).toBe("\\f|oo");
});
});

describe("stringUtils.trimStart", () => {
it.concurrent("should return the original string when it does not start with the specified character", () => {
expect(trimStart("", "")).toBe("");
expect(trimStart("f|oo||", "|")).toBe("f|oo||");
});

it.concurrent("should trim the start of the specified string, removing the specified character", () => {
expect(trimStart("||f|oo+", "|")).toBe("f|oo+");
expect(trimStart("+f|oo||", "|")).toBe("+f|oo||");
expect(trimStart("|f|oo||", "|")).toBe("f|oo||");
expect(trimStart("]f|oo]", "]")).toBe("f|oo]");
expect(trimStart("^f|oo^", "^")).toBe("f|oo^");
expect(trimStart("\\f|oo\\", "\\")).toBe("f|oo\\");
});
});

describe("stringUtils.unaccent", () => {
it.concurrent("should return the same string when it contains no supported accents", () => {
expect(unaccent("")).toBe("");
expect(unaccent(" ")).toBe(" ");
expect(unaccent("Hello World!")).toBe("Hello World!");
});

it.concurrent("should return the string without accents when it contains supported accents", () => {
expect(unaccent("français")).toBe("francais");
expect(unaccent(" Noël ")).toBe(" Noel ");
expect(unaccent("Héllo Wôrld!")).toBe("Hello World!");
});
});
Loading

0 comments on commit a887ac1

Please sign in to comment.