Tests for extension methods

This commit is contained in:
Rory& 2025-10-04 18:00:25 +02:00
parent 027392488b
commit ac9c21d58e
7 changed files with 201 additions and 8 deletions

View File

@ -0,0 +1,96 @@
import moduleAlias from "module-alias";
moduleAlias();
import './Array';
import { describe, it } from 'node:test';
import assert from 'node:assert/strict';
describe("Array extensions", () => {
it("containsAll", () => {
const arr = [1, 2, 3, 4, 5];
assert(arr.containsAll([1, 2]));
assert(!arr.containsAll([1, 6]));
assert(arr.containsAll([]));
assert([].containsAll([]));
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
assert(![].containsAll([1]));
});
it("partition", () => {
const arr = [1, 2, 3, 4, 5];
const [even, odd] = arr.partition((n) => n % 2 === 0);
assert.deepEqual(even, [2, 4]);
assert.deepEqual(odd, [1, 3, 5]);
});
it("single", () => {
const arr = [1, 2, 3, 4, 5];
assert.strictEqual(arr.single((n) => n === 3), 3);
assert.strictEqual(arr.single((n) => n === 6), null);
assert.throws(() => arr.single((n) => n > 2));
});
it("forEachAsync", async () => {
const arr = [1, 2, 3];
let sum = 0;
await arr.forEachAsync(async (n) => {
sum += n;
});
assert.strictEqual(sum, 6);
});
it("remove", () => {
const arr = [1, 2, 3, 4, 5];
arr.remove(3);
assert.deepEqual(arr, [1, 2, 4, 5]);
arr.remove(6);
assert.deepEqual(arr, [1, 2, 4, 5]);
});
it("first", () => {
const arr = [1, 2, 3];
assert.strictEqual(arr.first(), 1);
assert.strictEqual([].first(), undefined);
});
it("last", () => {
const arr = [1, 2, 3];
assert.strictEqual(arr.last(), 3);
assert.strictEqual([].last(), undefined);
});
it("distinct", () => {
const arr = [1, 2, 2, 3, 3, 3];
assert.deepEqual(arr.distinct(), [1, 2, 3]);
assert.deepEqual([].distinct(), []);
});
it("distinctBy", () => {
const arr = [{ id: 1 }, { id: 2 }, { id: 1 }, { id: 3 }];
assert.deepEqual(arr.distinctBy((x) => x.id), [{ id: 1 }, { id: 2 }, { id: 3 }]);
assert.deepEqual([].distinctBy((x) => x), []);
});
it("intersect", () => {
const arr1 = [1, 2, 3, 4];
const arr2 = [3, 4, 5, 6];
assert.deepEqual(arr1.intersect(arr2), [3, 4]);
assert.deepEqual(arr1.intersect([]), []);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
assert.deepEqual([].intersect(arr2), []);
});
it("except", () => {
const arr1 = [1, 2, 3, 4];
const arr2 = [3, 4, 5, 6];
assert.deepEqual(arr1.except(arr2), [1, 2]);
assert.deepEqual(arr1.except([]), [1, 2, 3, 4]);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
assert.deepEqual([].except(arr2), []);
});
});

View File

@ -0,0 +1,16 @@
import moduleAlias from "module-alias";
moduleAlias();
import './Global';
import { describe, it } from 'node:test';
import assert from 'node:assert/strict';
describe("Global extensions", () => {
it("sleep", async () => {
const start = Date.now();
await sleep(100);
const duration = Date.now() - start;
assert(duration >= 100, `Sleep duration was less than expected: ${duration}ms`);
});
});

View File

@ -6,10 +6,7 @@ export function globalSleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
if (!globalThis.sleep) {
if (!globalThis.sleep)
globalThis.sleep = function (ms: number): Promise<void> {
return globalSleep(ms);
};
}
export {};

View File

@ -0,0 +1,19 @@
import moduleAlias from "module-alias";
moduleAlias();
import './Math';
import { describe, it } from 'node:test';
import assert from 'node:assert/strict';
describe("Math extensions", () => {
it("clamp", async () => {
assert.strictEqual(Math.clamp(5, 1, 10), 5);
assert.strictEqual(Math.clamp(0, 1, 10), 1);
assert.strictEqual(Math.clamp(15, 1, 10), 10);
assert.strictEqual(Math.clamp(-5, -10, -1), -5);
assert.strictEqual(Math.clamp(-15, -10, -1), -10);
assert.strictEqual(Math.clamp(-0.5, -1, 0), -0.5);
assert.strictEqual(Math.clamp(1.5, 1, 2), 1.5);
});
});

View File

@ -0,0 +1,26 @@
import moduleAlias from "module-alias";
moduleAlias();
import "./Object";
import { describe, it } from "node:test";
import assert from "node:assert/strict";
describe("Object extensions", () => {
it("forEach", async () => {
const obj = { a: 1, b: 2, c: 3 };
const keys: string[] = [];
const values: number[] = [];
obj.forEach((value, key) => {
keys.push(key);
values.push(value);
});
console.log(keys, values);
assert.deepEqual(keys, ["a", "b", "c"]);
assert.deepEqual(values, [1, 2, 3]);
});
it("map", async () => {
const obj = { a: 1, b: 2, c: 3 };
const result = obj.map((value, key) => `${key}:${value}`);
assert.deepEqual(result, { a: "a:1", b: "b:2", c: "c:3" });
});
});

View File

@ -1,17 +1,17 @@
declare global {
interface Object {
forEach(callback: (value: any, key: string, object: any) => void): void;
map<T>(callback: (value: any, key: string, object: any) => T): T[];
forEach(callback: (value: unknown, key: string, object: unknown) => void): void;
map<T>(callback: (value: unknown, key: string, object: unknown) => T): object;
}
}
export function objectForEach(obj: any, callback: (value: any, key: string, object: any) => void): void {
export function objectForEach<T>(obj: never, callback: (value: T, key: string, object: unknown) => void): void {
Object.keys(obj).forEach((key) => {
callback(obj[key], key, obj);
});
}
export function objectMap<T>(obj: any, callback: (value: any, key: string, object: any) => T): T[] {
export function objectMap<T>(obj: object, callback: (value: unknown, key: string, object: unknown) => T): T[] {
return Object.keys(obj).map((key) => {
return callback(obj[key], key, obj);
});
@ -21,9 +21,11 @@ if (!Object.prototype.forEach)
Object.defineProperty(Object.prototype, "forEach", {
value: objectForEach,
enumerable: false,
writable: true
});
if (!Object.prototype.map)
Object.defineProperty(Object.prototype, "map", {
value: objectMap,
enumerable: false,
writable: true
});

View File

@ -0,0 +1,37 @@
import moduleAlias from "module-alias";
moduleAlias();
import './Url';
import { describe, it } from 'node:test';
import assert from 'node:assert/strict';
describe("URL extensions", () => {
it("normalize", async () => {
const tests: [string, string][] = [
["http://example.com", "http://example.com/"],
["http://example.com/", "http://example.com/"],
["http://example.com/path/", "http://example.com/path"],
["http://example.com/path//", "http://example.com/path/"],
["http://example.com/path?b=2&a=1", "http://example.com/path?a=1&b=2"],
["http://example.com/path?b=2&a=1&", "http://example.com/path?a=1&b=2"],
["http://example.com/path?", "http://example.com/path"],
["http://example.com/path#fragment", "http://example.com/path"],
["http://example.com/path/?b=2&a=1#fragment", "http://example.com/path?a=1&b=2"],
["ftp://example.com/resource/", "ftp://example.com/resource"],
["https://example.com/resource?z=3&y=2&x=1", "https://example.com/resource?x=1&y=2&z=3"],
["https://example.com/resource?z=3&y=2&x=1#", "https://example.com/resource?x=1&y=2&z=3"],
["https://example.com/resource?z=3&y=2&x=1#section", "https://example.com/resource?x=1&y=2&z=3"],
["https://example.com/resource/?z=3&y=2&x=1#section", "https://example.com/resource?x=1&y=2&z=3"],
["https://example.com/resource//?z=3&y=2&x=1#section", "https://example.com/resource/?x=1&y=2&z=3"],
["https://example.com/", "https://example.com/"],
["https://example.com", "https://example.com/"],
];
for (const [input, expected] of tests) {
assert.doesNotThrow(() => new URL(input), `URL("${input}") should not throw`);
const url = new URL(input);
const normalized = url.normalize();
assert.strictEqual(normalized, expected, `normalize("${input}") = "${normalized}", expected "${expected}"`);
}
});
});