mc-publish/tests/unit/utils/convert.spec.ts
2023-05-19 16:49:51 +03:00

580 lines
23 KiB
TypeScript

import {
toUndefined,
toString,
toBoolean,
toInteger,
toFloat,
toDate,
toRegExp,
toType,
} from "@/utils/convert";
describe("toUndefined", () => {
test("always returns undefined", () => {
expect(toUndefined("something")).toBeUndefined();
expect(toUndefined(123)).toBeUndefined();
expect(toUndefined(null)).toBeUndefined();
expect(toUndefined(undefined)).toBeUndefined();
});
});
describe("toString", () => {
test("returns strings as is", () => {
expect(toString("test")).toBe("test");
});
test("converts valid values to strings", () => {
expect(toString(123)).toBe("123");
expect(toString(true)).toBe("true");
});
test("returns undefined for invalid values", () => {
expect(toString(null)).toBeUndefined();
expect(toString(undefined)).toBeUndefined();
expect(toString(NaN)).toBeUndefined();
});
});
describe("toBoolean", () => {
test("returns booleans as is", () => {
expect(toBoolean(false)).toBe(false);
expect(toBoolean(true)).toBe(true);
});
test("converts 'true' and 'false' strings to booleans ignoring their case", () => {
expect(toBoolean("true")).toBe(true);
expect(toBoolean("false")).toBe(false);
expect(toBoolean("TRUE")).toBe(true);
expect(toBoolean("FALSE")).toBe(false);
expect(toBoolean("True")).toBe(true);
expect(toBoolean("False")).toBe(false);
});
test("converts numbers to booleans", () => {
expect(toBoolean(0)).toBe(false);
expect(toBoolean(1)).toBe(true);
expect(toBoolean(2)).toBe(true);
});
test("returns undefined for invalid values", () => {
expect(toBoolean("invalid")).toBeUndefined();
expect(toBoolean(null)).toBeUndefined();
expect(toBoolean(undefined)).toBeUndefined();
expect(toBoolean(NaN)).toBeUndefined();
});
});
describe("toInteger", () => {
test("returns integers as is", () => {
expect(toInteger(-1)).toBe(-1);
expect(toInteger(0)).toBe(0);
expect(toInteger(123)).toBe(123);
});
test("converts floats to integers", () => {
expect(toInteger(123.456)).toBe(123);
expect(toInteger(true)).toBe(1);
expect(toInteger(false)).toBe(0);
});
test("converts dates to integers", () => {
const date = new Date();
expect(toInteger(date)).toBe(date.getTime());
});
test("converts valid strings to integers", () => {
expect(toInteger("-1")).toBe(-1);
expect(toInteger("-1.23")).toBe(-1);
expect(toInteger("123")).toBe(123);
expect(toInteger("123.456")).toBe(123);
});
test("converts booleans to integers", () => {
expect(toInteger(true)).toBe(1);
expect(toInteger(false)).toBe(0);
});
test("returns undefined for invalid values", () => {
expect(toInteger("invalid")).toBeUndefined();
expect(toInteger(null)).toBeUndefined();
expect(toInteger(undefined)).toBeUndefined();
expect(toInteger(NaN)).toBeUndefined();
});
});
describe("toFloat", () => {
test("returns numbers as is", () => {
expect(toFloat(-1)).toBe(-1);
expect(toFloat(0)).toBe(0);
expect(toFloat(123)).toBe(123);
expect(toFloat(123.456)).toBe(123.456);
});
test("converts dates to floats", () => {
const date = new Date();
expect(toFloat(date)).toBe(date.valueOf());
});
test("converts valid strings to floats", () => {
expect(toFloat("-1")).toBe(-1);
expect(toFloat("-1.23")).toBe(-1.23);
expect(toFloat("123")).toBe(123);
expect(toFloat("123.456")).toBe(123.456);
});
test("converts booleans to floats", () => {
expect(toFloat(true)).toBe(1);
expect(toFloat(false)).toBe(0);
});
test("returns undefined for invalid values", () => {
expect(toFloat("invalid")).toBeUndefined();
expect(toFloat(null)).toBeUndefined();
expect(toFloat(undefined)).toBeUndefined();
expect(toFloat(NaN)).toBeUndefined();
});
});
describe("toDate", () => {
test("returns dates as is", () => {
const date = new Date("1856-07-10T12:34:56.000Z");
expect(toDate(date)).toEqual(date);
});
test("converts valid values to Date objects", () => {
const date = new Date("1856-07-10T12:34:56.000Z");
expect(toDate(date.toISOString())).toEqual(date);
expect(toDate(date.getTime())).toEqual(date);
});
test("returns undefined for invalid values", () => {
expect(toDate(new Date("not a date"))).toBeUndefined();
expect(toDate("invalid")).toBeUndefined();
expect(toDate(null)).toBeUndefined();
expect(toDate(undefined)).toBeUndefined();
expect(toDate(NaN)).toBeUndefined();
});
});
describe("toRegExp", () => {
test("returns RegExps as is", () => {
const regex = /test/i;
expect(toRegExp(regex)).toEqual(regex);
});
test("converts valid string values to RegExp objects", () => {
const regex = /test/i;
expect(toRegExp(regex.toString())).toEqual(regex);
});
test("returns undefined for invalid values", () => {
expect(toDate("invalid")).toBeUndefined();
expect(toDate("/invalid")).toBeUndefined();
expect(toDate(null)).toBeUndefined();
expect(toDate(undefined)).toBeUndefined();
expect(toDate(NaN)).toBeUndefined();
});
});
describe("toType", () => {
describe("via 'typeof' type name", () => {
test("converts an object to a string", () => {
expect(toType("string", "string")).toBe("string");
expect(toType(123, "string")).toBe("123");
expect(toType(true, "string")).toBe("true");
expect(toType(false, "string")).toBe("false");
expect(toType(new Date("1856-07-10T12:34:56.000Z"), "string")).toBe(new Date("1856-07-10T12:34:56.000Z").toString());
expect(toType(/\d/, "string")).toBe(String(/\d/));
});
test("converts an object to a number", () => {
expect(toType(123, "number")).toBe(123);
expect(toType(123.456, "number")).toBe(123.456);
expect(toType("123", "number")).toBe(123);
expect(toType("123.456", "number")).toBe(123.456);
expect(toType(false, "number")).toBe(0);
expect(toType(true, "number")).toBe(1);
expect(toType(new Date("1856-07-10T12:34:56.000Z"), "number")).toBe(new Date("1856-07-10T12:34:56.000Z").getTime());
});
test("converts an object to a boolean", () => {
expect(toType(true, "boolean")).toBe(true);
expect(toType(false, "boolean")).toBe(false);
expect(toType(1, "boolean")).toBe(true);
expect(toType(0, "boolean")).toBe(false);
expect(toType(123.456, "boolean")).toBe(true);
expect(toType("true", "boolean")).toBe(true);
expect(toType("false", "boolean")).toBe(false);
expect(toType("TRUE", "boolean")).toBe(true);
expect(toType("FALSE", "boolean")).toBe(false);
expect(toType("True", "boolean")).toBe(true);
expect(toType("False", "boolean")).toBe(false);
});
test("converts an object to undefined", () => {
expect(toType(true, "undefined")).toBeUndefined();
expect(toType(false, "undefined")).toBeUndefined();
expect(toType("string", "undefined")).toBeUndefined();
expect(toType({}, "undefined")).toBeUndefined();
expect(toType(0, "undefined")).toBeUndefined();
expect(toType(1, "undefined")).toBeUndefined();
expect(toType(new Date(), "undefined")).toBeUndefined();
expect(toType(/\d/, "undefined")).toBeUndefined();
});
test("returns undefined when conversion is not possible", () => {
expect(toType(undefined, "string")).toBeUndefined();
expect(toType(undefined, "number")).toBeUndefined();
expect(toType(undefined, "boolean")).toBeUndefined();
expect(toType(null, "string")).toBeUndefined();
expect(toType(null, "number")).toBeUndefined();
expect(toType(null, "boolean")).toBeUndefined();
expect(toType(NaN, "string")).toBeUndefined();
expect(toType(NaN, "number")).toBeUndefined();
expect(toType(NaN, "boolean")).toBeUndefined();
expect(toType("abc", "number")).toBeUndefined();
expect(toType("abc", "boolean")).toBeUndefined();
expect(toType("123", "date")).toBeUndefined();
expect(toType("123", "void")).toBeUndefined();
});
});
describe("via constructor", () => {
test("converts an object to a string", () => {
expect(toType("string", String)).toBe("string");
expect(toType(123, String)).toBe("123");
expect(toType(true, String)).toBe("true");
expect(toType(false, String)).toBe("false");
expect(toType(new Date("1856-07-10T12:34:56.000Z"), String)).toBe(new Date("1856-07-10T12:34:56.000Z").toString());
expect(toType(/\d/, String)).toBe(String(/\d/));
});
test("converts an object to a number", () => {
expect(toType(123, Number)).toBe(123);
expect(toType(123.456, Number)).toBe(123.456);
expect(toType("123", Number)).toBe(123);
expect(toType("123.456", Number)).toBe(123.456);
expect(toType(false, Number)).toBe(0);
expect(toType(true, Number)).toBe(1);
expect(toType(new Date("1856-07-10T12:34:56.000Z"), Number)).toBe(new Date("1856-07-10T12:34:56.000Z").getTime());
});
test("converts an object to a boolean", () => {
expect(toType(true, Boolean)).toBe(true);
expect(toType(false, Boolean)).toBe(false);
expect(toType(1, Boolean)).toBe(true);
expect(toType(0, Boolean)).toBe(false);
expect(toType(123.456, Boolean)).toBe(true);
expect(toType("true", Boolean)).toBe(true);
expect(toType("false", Boolean)).toBe(false);
expect(toType("TRUE", Boolean)).toBe(true);
expect(toType("FALSE", Boolean)).toBe(false);
expect(toType("True", Boolean)).toBe(true);
expect(toType("False", Boolean)).toBe(false);
});
test("converts an object to a Date", () => {
const date = new Date("1856-07-10T12:34:56.000Z");
expect(toType(date, Date)).toEqual(date);
expect(toType(date.toISOString(), Date)).toEqual(date);
expect(toType(date.getTime(), Date)).toEqual(date);
});
test("converts an object to a RegExp", () => {
const regex = /^a+$/im;
expect(toType(regex, RegExp)).toEqual(regex);
expect(toType(String(regex), RegExp)).toEqual(regex);
});
test("returns undefined when conversion is not possible", () => {
expect(toType(undefined, String)).toBeUndefined();
expect(toType(undefined, Number)).toBeUndefined();
expect(toType(undefined, Boolean)).toBeUndefined();
expect(toType(undefined, Date)).toBeUndefined();
expect(toType(undefined, RegExp)).toBeUndefined();
expect(toType(null, String)).toBeUndefined();
expect(toType(null, Number)).toBeUndefined();
expect(toType(null, Boolean)).toBeUndefined();
expect(toType(null, Date)).toBeUndefined();
expect(toType(null, RegExp)).toBeUndefined();
expect(toType(NaN, String)).toBeUndefined();
expect(toType(NaN, Number)).toBeUndefined();
expect(toType(NaN, Boolean)).toBeUndefined();
expect(toType(NaN, Date)).toBeUndefined();
expect(toType(NaN, RegExp)).toBeUndefined();
expect(toType("abc", Number)).toBeUndefined();
expect(toType("abc", Boolean)).toBeUndefined();
expect(toType("abc", Date)).toBeUndefined();
expect(toType("123", RegExp)).toBeUndefined();
expect(toType("123", undefined)).toBeUndefined();
});
});
describe("via globalThis type name", () => {
test("converts an object to a string", () => {
expect(toType("string", "String")).toBe("string");
expect(toType(123, "String")).toBe("123");
expect(toType(true, "String")).toBe("true");
expect(toType(false, "String")).toBe("false");
expect(toType(new Date("1856-07-10T12:34:56.000Z"), "String")).toBe(new Date("1856-07-10T12:34:56.000Z").toString());
expect(toType(/\d/, "String")).toBe(String(/\d/));
});
test("converts an object to a number", () => {
expect(toType(123, "Number")).toBe(123);
expect(toType(123.456, "Number")).toBe(123.456);
expect(toType("123", "Number")).toBe(123);
expect(toType("123.456", "Number")).toBe(123.456);
expect(toType(false, "Number")).toBe(0);
expect(toType(true, "Number")).toBe(1);
expect(toType(new Date("1856-07-10T12:34:56.000Z"), "Number")).toBe(new Date("1856-07-10T12:34:56.000Z").getTime());
});
test("converts an object to a boolean", () => {
expect(toType(true, "Boolean")).toBe(true);
expect(toType(false, "Boolean")).toBe(false);
expect(toType(1, "Boolean")).toBe(true);
expect(toType(0, "Boolean")).toBe(false);
expect(toType(123.456, "Boolean")).toBe(true);
expect(toType("true", "Boolean")).toBe(true);
expect(toType("false", "Boolean")).toBe(false);
expect(toType("TRUE", "Boolean")).toBe(true);
expect(toType("FALSE", "Boolean")).toBe(false);
expect(toType("True", "Boolean")).toBe(true);
expect(toType("False", "Boolean")).toBe(false);
});
test("converts an object to a Date", () => {
const date = new Date("1856-07-10T12:34:56.000Z");
expect(toType(date, "Date")).toEqual(date);
expect(toType(date.toISOString(), "Date")).toEqual(date);
expect(toType(date.getTime(), "Date")).toEqual(date);
});
test("converts an object to a RegExp", () => {
const regex = /^a+$/im;
expect(toType(regex, "RegExp")).toEqual(regex);
expect(toType(String(regex), "RegExp")).toEqual(regex);
});
test("returns undefined when conversion is not possible", () => {
expect(toType(undefined, "String")).toBeUndefined();
expect(toType(undefined, "Number")).toBeUndefined();
expect(toType(undefined, "Boolean")).toBeUndefined();
expect(toType(undefined, "Date")).toBeUndefined();
expect(toType(undefined, "RegExp")).toBeUndefined();
expect(toType(null, "String")).toBeUndefined();
expect(toType(null, "Number")).toBeUndefined();
expect(toType(null, "Boolean")).toBeUndefined();
expect(toType(null, "Date")).toBeUndefined();
expect(toType(null, "RegExp")).toBeUndefined();
expect(toType(NaN, "String")).toBeUndefined();
expect(toType(NaN, "Number")).toBeUndefined();
expect(toType(NaN, "Boolean")).toBeUndefined();
expect(toType(NaN, "Date")).toBeUndefined();
expect(toType(NaN, "RegExp")).toBeUndefined();
expect(toType("abc", "Number")).toBeUndefined();
expect(toType("abc", "Boolean")).toBeUndefined();
expect(toType("abc", "Date")).toBeUndefined();
expect(toType("123", "RegExp")).toBeUndefined();
expect(toType("123", "NotAType")).toBeUndefined();
});
});
describe("from convertible object", () => {
test("converts a value via the standard 'convert' function in a class", () => {
const convert = jest.fn().mockImplementation(o => String(o));
class Convertible {
static convert(n: number): string {
return convert(n);
}
}
expect(toType(123, Convertible)).toBe("123");
expect(convert).toBeCalledTimes(1);
expect(convert).toBeCalledWith(123);
});
test("converts a value via the standard 'convert' function", () => {
const convertible = {
convert: jest.fn().mockImplementation(o => String(o)),
};
expect(toType(123, convertible)).toBe("123");
expect(convertible.convert).toBeCalledTimes(1);
expect(convertible.convert).toBeCalledWith(123);
});
test("converts a value via a first function that start with 'convert'", () => {
const convertible = {
convertObjectToNumber: jest.fn().mockImplementation(o => String(o)),
};
expect(toType(123, convertible)).toBe("123");
expect(convertible.convertObjectToNumber).toBeCalledTimes(1);
expect(convertible.convertObjectToNumber).toBeCalledWith(123);
});
test("converts a value via the prioritized 'convert' function", () => {
const convertible = {
convert: jest.fn().mockImplementation(o => String(o)),
convertObjectToNumber: jest.fn(),
from: jest.fn(),
fromObjectTonNumber: jest.fn(),
parse: jest.fn(),
parseToNumber: jest.fn(),
};
expect(toType(123, convertible)).toBe("123");
expect(convertible.convert).toBeCalledTimes(1);
expect(convertible.convert).toBeCalledWith(123);
expect(convertible.convertObjectToNumber).not.toHaveBeenCalled();
expect(convertible.from).not.toHaveBeenCalled();
expect(convertible.fromObjectTonNumber).not.toHaveBeenCalled();
expect(convertible.parse).not.toHaveBeenCalled();
expect(convertible.parseToNumber).not.toHaveBeenCalled();
});
test("converts a value via the prioritized 'from' function, if 'convert' is not present", () => {
const convertible = {
convertObjectToNumber: jest.fn(),
from: jest.fn().mockImplementation(o => String(o)),
fromObjectTonNumber: jest.fn(),
parse: jest.fn(),
parseToNumber: jest.fn(),
};
expect(toType(123, convertible)).toBe("123");
expect(convertible.from).toBeCalledTimes(1);
expect(convertible.from).toBeCalledWith(123);
expect(convertible.convertObjectToNumber).not.toHaveBeenCalled();
expect(convertible.fromObjectTonNumber).not.toHaveBeenCalled();
expect(convertible.parse).not.toHaveBeenCalled();
expect(convertible.parseToNumber).not.toHaveBeenCalled();
});
test("parses a string via the prioritized 'parse' function", () => {
const convertible = {
convert: jest.fn(),
convertObjectToNumber: jest.fn(),
from: jest.fn(),
fromObjectTonNumber: jest.fn(),
parse: jest.fn().mockImplementation(x => +x),
parseToNumber: jest.fn(),
};
expect(toType("123", convertible)).toBe(123);
expect(convertible.parse).toBeCalledTimes(1);
expect(convertible.parse).toBeCalledWith("123");
expect(convertible.parseToNumber).not.toHaveBeenCalled();
expect(convertible.convert).not.toHaveBeenCalled();
expect(convertible.convertObjectToNumber).not.toHaveBeenCalled();
expect(convertible.from).not.toHaveBeenCalled();
expect(convertible.fromObjectTonNumber).not.toHaveBeenCalled();
});
test("returns undefined when conversion is not possible", () => {
expect(toType(123, {})).toBeUndefined();
expect(toType(123, { notConvertFunction: () => 42 })).toBeUndefined();
});
test("returns undefined instead of throwing", () => {
const throwingConvertible = {
convert: jest.fn().mockImplementation(() => {
throw new Error("Conversion is impossible");
}),
};
const anotherThrowingConvertible = {
convertNothing: jest.fn().mockImplementation(() => {
throw new Error("Conversion is impossible");
}),
};
expect(toType(123, throwingConvertible)).toBeUndefined();
expect(throwingConvertible.convert).toHaveBeenCalledTimes(1);
expect(throwingConvertible.convert).toHaveBeenCalledWith(123);
expect(toType(123, anotherThrowingConvertible)).toBeUndefined();
expect(anotherThrowingConvertible.convertNothing).toHaveBeenCalledTimes(1);
expect(anotherThrowingConvertible.convertNothing).toHaveBeenCalledWith(123);
});
});
describe("from parsable object", () => {
test("parses a value via the standard 'parse' function", () => {
const parsable = {
parse: jest.fn().mockImplementation(s => +s),
};
expect(toType("123", parsable)).toBe(123);
expect(parsable.parse).toBeCalledTimes(1);
expect(parsable.parse).toBeCalledWith("123");
});
test("parses a value via a first function that start with 'parse'", () => {
const parsable = {
parseStringToNumber: jest.fn().mockImplementation(s => +s),
};
expect(toType("123", parsable)).toBe(123);
expect(parsable.parseStringToNumber).toBeCalledTimes(1);
expect(parsable.parseStringToNumber).toBeCalledWith("123");
});
test("returns undefined when the input value is not a string", () => {
const parsable = {
parse: jest.fn().mockImplementation(s => +s),
};
const anotherParsable = {
parseStringToNumber: jest.fn().mockImplementation(s => +s),
};
expect(toType(123, parsable)).toBeUndefined();
expect(parsable.parse).not.toBeCalled();
expect(toType(123, anotherParsable)).toBeUndefined();
expect(anotherParsable.parseStringToNumber).not.toBeCalled();
});
test("returns undefined when conversion is not possible", () => {
expect(toType("123", {})).toBeUndefined();
expect(toType("123", { notParseFunction: () => 42 })).toBeUndefined();
});
test("returns undefined instead of throwing", () => {
const throwingParsable = {
parse: jest.fn().mockImplementation(() => {
throw new Error("Parsing is impossible");
}),
};
const anotherThrowingParsable = {
parseNothing: jest.fn().mockImplementation(() => {
throw new Error("Parsing is impossible");
}),
};
expect(toType("123", throwingParsable)).toBeUndefined();
expect(throwingParsable.parse).toHaveBeenCalledTimes(1);
expect(throwingParsable.parse).toHaveBeenCalledWith("123");
expect(toType("123", anotherThrowingParsable)).toBeUndefined();
expect(anotherThrowingParsable.parseNothing).toHaveBeenCalledTimes(1);
expect(anotherThrowingParsable.parseNothing).toHaveBeenCalledWith("123");
});
});
});