@serenity-is/corelib
Version:
Serenity Core Library
946 lines (817 loc) • 42.6 kB
text/typescript
import * as formatting from "./formatting";
beforeEach(() => {
vi.resetModules();
vi.clearAllMocks();
});
afterEach(() => {
formatting.resetCultureSettings();
});
describe("formatDate", () => {
it('formats properly based on format string and culture', async function () {
const Culture = formatting.Culture;
const formatDate = formatting.formatDate;
const formatISODateTimeUTC = formatting.formatISODateTimeUTC;
Culture.dateSeparator = '/';
Culture.dateFormat = 'dd/MM/yyyy';
Culture.dateTimeFormat = 'dd/MM/yyyy HH:mm:ss';
var date = new Date(2029, 0, 2, 3, 4, 5, 6);
// 02.01.2029 03:04:05.006
expect(formatDate(date, 'dd/MM/yyyy')).toBe('02/01/2029')
expect(formatDate(date, 'd/M/yy')).toBe('2/1/29');
expect(formatDate(date, 'd.M.yyyy')).toBe('2.1.2029');
expect(formatDate(date, 'yyyyMMdd')).toBe('20290102');
expect(formatDate(date, 'hh:mm tt')).toBe('03:04 AM');
expect(formatDate(date, 'yyyy-MM-ddTHH:mm:ss.fff')).toBe('2029-01-02T03:04:05.006');
expect(formatDate(date, 'd')).toBe('02/01/2029');
expect(formatDate(date, 'g')).toBe('02/01/2029 03:04');
expect(formatDate(date, 'G')).toBe('02/01/2029 03:04:05');
expect(formatDate(date, 's')).toBe('2029-01-02T03:04:05');
expect(formatDate(date, 'u')).toBe(formatISODateTimeUTC(date));
expect(formatDate(date, 'U')).toContain('2029');
expect(formatDate(date, 'U', {} as any)).toContain('2029');
Culture.dateSeparator = '.';
expect(formatDate(date, 'dd/MM/yyyy')).toBe('02.01.2029');
expect(formatDate(date, 'd/M/yy')).toBe('2.1.29');
expect(formatDate(date, 'd-M-yyyy')).toBe('2-1-2029');
expect(formatDate(date, 'yyyy-MM-ddTHH:mm:ss.fff')).toBe('2029-01-02T03:04:05.006');
expect(formatDate(date, 'g')).toBe('02.01.2029 03:04');
expect(formatDate(date, 'G')).toBe('02.01.2029 03:04:05');
expect(formatDate(date, 's')).toBe('2029-01-02T03:04:05');
expect(formatDate(date, 'u')).toBe(formatISODateTimeUTC(date));
});
it('accepts iso datetime strings as input', async function () {
const Culture = formatting.Culture;
const formatDate = formatting.formatDate;
Culture.dateSeparator = '/';
Culture.dateFormat = 'dd/MM/yyyy';
Culture.dateTimeFormat = 'dd/MM/yyyy HH:mm:ss';
expect(formatDate('2029-01-02', null)).toBe('02/01/2029');
expect(formatDate('2029-01-02T16:35:24', null)).toBe('02/01/2029');
expect(formatDate('2029-01-02T16:35:24', 'g')).toBe('02/01/2029 16:35');
Culture.dateSeparator = '.';
expect(formatDate('2029-01-02', null)).toBe('02.01.2029');
expect(formatDate('2029-01-02T16:35:24', null)).toBe('02.01.2029');
expect(formatDate('2029-01-02T16:35:24', 'g')).toBe('02.01.2029 16:35');
});
it('accepts date string as input', async function () {
const Culture = formatting.Culture;
const formatDate = formatting.formatDate;
Culture.dateSeparator = '/';
Culture.dateFormat = 'dd/MM/yyyy';
Culture.dateTimeFormat = 'dd/MM/yyyy HH:mm:ss';
expect(formatDate('2/1/2029', null)).toBe('02/01/2029');
Culture.dateSeparator = '.';
expect(formatDate('2/1/2029', null)).toBe('02.01.2029');
});
});
describe("Invariant.stringCompare", () => {
it("uses string js string comparison", async function () {
const Invariant = formatting.Invariant;
expect(Invariant.stringCompare("a", "b")).toBe(-1);
expect(Invariant.stringCompare("b", "a")).toBe(1);
expect(Invariant.stringCompare("a", "a")).toBe(0);
});
});
describe("splitDateString", () => {
it("returns null for null, undefined and empty string", async function () {
expect(formatting.splitDateString(null)).toBeNull();
expect(formatting.splitDateString(undefined)).toBeNull();
expect(formatting.splitDateString("")).toBeNull();
expect(formatting.splitDateString(" ")).toBeNull();
});
it("can handle '/', '.', '\\', '-' as separator", async function () {
expect(formatting.splitDateString("2029/01/02")).toEqual(["2029", "01", "02"]);
expect(formatting.splitDateString("1/2/2029")).toEqual(["1", "2", "2029"]);
expect(formatting.splitDateString("2029.01.02")).toEqual(["2029", "01", "02"]);
expect(formatting.splitDateString("1.2.2029")).toEqual(["1", "2", "2029"]);
expect(formatting.splitDateString("2029\\01\\02")).toEqual(["2029", "01", "02"]);
expect(formatting.splitDateString("1\\2\\2029")).toEqual(["1", "2", "2029"]);
expect(formatting.splitDateString("2029-01-02")).toEqual(["2029", "01", "02"]);
expect(formatting.splitDateString("1-2-2029")).toEqual(["1", "2", "2029"]);
});
it("returns an array with the string if no known separators", async function () {
expect(formatting.splitDateString("2")).toEqual(["2"]);
expect(formatting.splitDateString("ab")).toEqual(["ab"]);
});
});
describe("parseDate", () => {
it("returns null for null, undefined, empty string and whitespace", async function () {
expect(formatting.parseDate(null)).toBeNull();
expect(formatting.parseDate(undefined)).toBeNull();
expect(formatting.parseDate("")).toBeNull();
expect(formatting.parseDate(" ")).toBeNull();
});
it("returns false for malformed iso date string", async function () {
expect(formatting.parseDate("2023-00-01")?.valueOf()).toBeNaN();
expect(formatting.parseDate("2023-01-X1")?.valueOf()).toBeNaN();
});
it("can handle iso like dates with space between date/time parts", async function () {
expect(formatting.parseDate("2023-01-05 16:30")).toEqual(new Date(2023, 0, 5, 16, 30));
expect(formatting.parseDate("2023-00-05 16:30")?.valueOf()).toBeNaN();
});
it("can handle date only with ymd order", async function () {
formatting.Culture.dateOrder = "ymd";
expect(formatting.parseDate("2023/03/05")).toEqual(new Date(2023, 2, 5));
});
it("can handle date only with mdy order", async function () {
formatting.Culture.dateOrder = "mdy";
expect(formatting.parseDate("11/23/2023")).toEqual(new Date(2023, 10, 23));
});
it("returns NaN if a part is not a number or out of range", async function () {
formatting.Culture.dateOrder = "dmy";
expect(formatting.parseDate("01/X1/2023")?.valueOf()).toBeNaN();
expect(formatting.parseDate("01/01/20X3")?.valueOf()).toBeNaN();
expect(formatting.parseDate("X1/01/2023")?.valueOf()).toBeNaN();
expect(formatting.parseDate("32/02/2023")?.valueOf()).toBeNaN();
expect(formatting.parseDate("15/14/2023")?.valueOf()).toBeNaN();
expect(formatting.parseDate("15/-1/2023")?.valueOf()).toBeNaN();
expect(formatting.parseDate("15/0/2023")?.valueOf()).toBeNaN();
expect(formatting.parseDate("15/1/-1")?.valueOf()).toBeNaN();
expect(formatting.parseDate("2014-25-23")?.valueOf()).toBeNaN();
expect(formatting.parseDate("2014/03")?.valueOf()).toBeNaN();
});
it("handles two digit years", async function () {
vi.useFakeTimers();
try {
vi.setSystemTime(new Date(2023, 1, 1));
expect(formatting.parseDate("15/1/01")).toEqual(new Date(2001, 0, 15));
expect(formatting.parseDate("15/1/99")).toEqual(new Date(1999, 0, 15));
}
finally {
vi.useRealTimers();
}
});
it("handles JS date string", async function () {
expect(formatting.parseDate("Tue May 02 2023")).toEqual(new Date(2023, 4, 2));
});
});
describe("parseISODateTime", () => {
it("returns null for null, undefined and empty string", async function () {
expect(formatting.parseISODateTime(null)).toBeNull();
expect(formatting.parseISODateTime(undefined)).toBeNull();
expect(formatting.parseISODateTime("")).toBeNull();
});
it("returns invalid date for malformed iso date string", async function () {
expect(formatting.parseISODateTime("2023-00-01")?.valueOf()).toBeNaN();
expect(formatting.parseISODateTime("2023-01-X1")?.valueOf()).toBeNaN();
});
it("returns invalid date for non string", async function () {
expect(formatting.parseISODateTime(5 as any as string)?.valueOf()).toBeNaN();
});
it("returns false for malformed iso date string", async function () {
expect(formatting.parseISODateTime("2023-00-01")?.valueOf()).toBeNaN();
expect(formatting.parseISODateTime("2023-01-X1")?.valueOf()).toBeNaN();
});
});
describe("formatISODateTimeUTC", () => {
it("returns empty string for null and undefined", async function () {
expect(formatting.formatISODateTimeUTC(null)).toBe("");
expect(formatting.formatISODateTimeUTC(undefined)).toBe("");
});
it("formats in ISO format with UTC timezone", async function () {
expect(formatting.formatISODateTimeUTC(new Date(Date.UTC(2023, 4, 2, 15, 10, 5, 32)))).toBe("2023-05-02T15:10:05.032Z");
expect(formatting.formatISODateTimeUTC(new Date(Date.UTC(2023, 4, 2, 15, 10, 5, 150)))).toBe("2023-05-02T15:10:05.15Z");
});
});
describe("formatDate", () => {
it("returns empty string for null and undefined", async function () {
expect(formatting.formatDate(null)).toBe("");
expect(formatting.formatDate(undefined)).toBe("");
});
it("returns date in format 'dd.MM.yyyy' by default if order is dmy", async function () {
formatting.Culture.dateFormat = "dd/MM/yyyy";
formatting.Culture.dateSeparator = ".";
expect(formatting.formatDate(new Date(2023, 4, 2, 15, 10, 5, 32))).toBe("02.05.2023");
});
it("returns date in format 'MM.dd.yyyy' if Culture.dateFormat is MM/dd/yyyy", async function () {
formatting.Culture.dateFormat = "MM/dd/yyyy";
formatting.Culture.dateSeparator = ".";
expect(formatting.formatDate(new Date(2023, 4, 2, 15, 10, 5, 32))).toBe("05.02.2023");
});
it("returns date in format 'yyyy.mm.dd' by default if order is yyyy/MM/dd", async function () {
formatting.Culture.dateFormat = "yyyy/MM/dd";
formatting.Culture.dateSeparator = ".";
expect(formatting.formatDate(new Date(2023, 4, 2, 15, 10, 5, 32))).toBe("2023.05.02");
});
it("uses passed locale", async function () {
var locale = Object.assign({}, formatting.Culture);
locale.dateOrder = "mdy";
locale.dateSeparator = "*";
expect(formatting.formatDate(new Date(2023, 4, 2, 15, 10, 5, 32), undefined, locale)).toBe("02*05*2023");
});
it("uses Culture.dateFormat if locale.dateFormat is null", async function () {
var locale = Object.assign({}, formatting.Culture);
formatting.Culture.dateFormat = "yyyy/MM/dd";
locale.dateFormat = null;
locale.dateSeparator = "*";
expect(formatting.formatDate(new Date(2023, 4, 2, 15, 10, 5, 32), undefined, locale)).toBe("2023*05*02");
});
it("uses Culture.dateFormat for 'd' if locale.dateFormat is null", async function () {
var locale = Object.assign({}, formatting.Culture);
formatting.Culture.dateFormat = "yyyy/MM/dd";
locale.dateFormat = null;
locale.dateSeparator = "*";
expect(formatting.formatDate(new Date(2023, 4, 2, 15, 10, 5, 32), 'd', locale)).toBe("2023*05*02");
});
it("uses Culture.dateTimeFormat for 'g' if locale.dateTimeFormat is null", async function () {
var locale = Object.assign({}, formatting.Culture);
formatting.Culture.dateTimeFormat = "yyyy/MM/dd HH:mm:ss";
locale.dateTimeFormat = null;
locale.dateSeparator = "*";
expect(formatting.formatDate(new Date(2023, 4, 2, 15, 10, 5, 32), 'g', locale)).toBe("2023*05*02 15:10");
});
it("uses Culture.dateTimeFormat for 'G' if locale.dateTimeFormat is null", async function () {
var locale = Object.assign({}, formatting.Culture);
formatting.Culture.dateTimeFormat = "yyyy/MM/dd HH:mm:ss";
locale.dateTimeFormat = null;
locale.dateSeparator = "*";
expect(formatting.formatDate(new Date(2023, 4, 2, 15, 10, 5, 32), 'G', locale)).toBe("2023*05*02 15:10:05");
});
it("uses Culture.dateTimeFormat and Culture.dateFormat for 't'", async function () {
formatting.Culture.dateTimeFormat = "yyyy/MM/dd H:m";
formatting.Culture.dateFormat = "yyyy/MM/dd";
expect(formatting.formatDate(new Date(2023, 4, 2, 3, 9, 5, 32), 't')).toBe("3:9");
});
it("returns browser toString() for 'i' format", async function () {
var date = new Date(2023, 4, 2, 15, 10, 5, 32);
expect(formatting.formatDate(date, "i")).toBe(date.toString());
});
it("returns browser toDateString() for 'id' format", async function () {
var date = new Date(2023, 4, 2, 15, 10, 5, 32);
expect(formatting.formatDate(date, "id")).toBe(date.toDateString());
});
it("returns browser toTimeString() for 'it' format", async function () {
var date = new Date(2023, 4, 2, 15, 10, 5, 32);
expect(formatting.formatDate(date, "it")).toBe(date.toTimeString());
});
it("can parse strings before formatting", async function () {
expect(formatting.formatDate(" ")).toBe("");
expect(formatting.formatDate("\t")).toBe("");
expect(formatting.formatDate("")).toBe("");
expect(formatting.formatDate("xyz")).toBe("xyz");
expect(formatting.formatDate("xyz", null, formatting.Culture)).toBe("xyz");
});
it("can use custom format strings", async function () {
var date = new Date(2023, 5, 2, 15, 10, 5, 32);
var locale = Object.assign({}, formatting.Culture);
formatting.Culture.dateSeparator = "*";
locale.dateSeparator = null;
locale.monthNames = null;
locale.dayNames = null;
locale.shortMonthNames = null;
locale.shortDayNames = null;
locale.amDesignator = null;
locale.pmDesignator = null;
locale.timeSeparator = null;
expect(formatting.formatDate(date, "yy/MM/d", locale)).toBe("23*06*2");
expect(formatting.formatDate(date, "dddd", locale)).toBe("Friday");
expect(formatting.formatDate(date, "dddd")).toBe("Friday");
expect(formatting.formatDate(date, "ddd", locale)).toBe("Fri");
expect(formatting.formatDate(date, "ddd")).toBe("Fri");
expect(formatting.formatDate(date, "MMMM", locale)).toBe("June");
expect(formatting.formatDate(date, "MMMM")).toBe("June");
expect(formatting.formatDate(date, "MMM", locale)).toBe("Jun");
expect(formatting.formatDate(date, "MMM")).toBe("Jun");
expect(formatting.formatDate(date, "y", locale)).toBe("23");
expect(formatting.formatDate(date, "y")).toBe("23");
expect(formatting.formatDate(date, "h")).toBe("3");
expect(formatting.formatDate(date, "hh")).toBe("03");
expect(formatting.formatDate(new Date(2023, 4, 2, 0, 0, 0, 32), "h")).toBe("12");
expect(formatting.formatDate(new Date(2023, 4, 2, 0, 0, 0, 32), "hh")).toBe("12");
expect(formatting.formatDate(date, "h:m:s")).toBe("3:10:5");
expect(formatting.formatDate(date, "H:m t", locale)).toBe("15:10 P");
expect(formatting.formatDate(date, "H:m t")).toBe("15:10 P");
expect(formatting.formatDate(date, "H:m tt", locale)).toBe("15:10 PM");
expect(formatting.formatDate(date, "H:m tt")).toBe("15:10 PM");
expect(formatting.formatDate(new Date(2023, 4, 2, 1, 0, 0, 32), "h t")).toBe("1 A");
expect(formatting.formatDate(new Date(2023, 4, 2, 1, 0, 0, 32), "h t", locale)).toBe("1 A");
expect(formatting.formatDate(new Date(2023, 4, 2, 1, 0, 0, 32), "h tt")).toBe("1 AM");
expect(formatting.formatDate(new Date(2023, 4, 2, 1, 0, 0, 32), "h tt", locale)).toBe("1 AM");
expect(formatting.formatDate(new Date(2023, 4, 2, 1, 0, 0, 32), "h f", locale)).toBe("1 0");
expect(formatting.formatDate(new Date(2023, 4, 2, 1, 0, 0, 32), "h f")).toBe("1 0");
expect(formatting.formatDate(new Date(2023, 4, 2, 1, 0, 0, 32), "h ff", locale)).toBe("1 03");
expect(formatting.formatDate(new Date(2023, 4, 2, 1, 0, 0, 32), "h ff")).toBe("1 03");
expect(formatting.formatDate(new Date(2023, 4, 2, 1, 0, 0, 32), "h fff", locale)).toBe("1 032");
expect(formatting.formatDate(new Date(2023, 4, 2, 1, 0, 0, 32), "h fff")).toBe("1 032");
expect(formatting.formatDate(date, "'dMy'", locale)).toBe("dMy");
expect(formatting.formatDate(date, "'dMy'")).toBe("dMy");
expect(formatting.formatDate(date, "%'dMy'", locale)).toBe("dMy");
expect(formatting.formatDate(date, "%'dMy'")).toBe("dMy");
date.getTimezoneOffset = function () { return +120 };
expect(formatting.formatDate(date, "h z", locale)).toBe("3 -2");
expect(formatting.formatDate(date, "h z")).toBe("3 -2");
expect(formatting.formatDate(date, "h zz", locale)).toBe("3 -02");
expect(formatting.formatDate(date, "h zz")).toBe("3 -02");
expect(formatting.formatDate(date, "h zzz", locale)).toBe("3 -02:00");
expect(formatting.formatDate(date, "h zzz")).toBe("3 -02:00");
date.getTimezoneOffset = function () { return -120 };
expect(formatting.formatDate(date, "h z", locale)).toBe("3 +2");
expect(formatting.formatDate(date, "h z")).toBe("3 +2");
expect(formatting.formatDate(date, "h zz", locale)).toBe("3 +02");
expect(formatting.formatDate(date, "h zz")).toBe("3 +02");
expect(formatting.formatDate(date, "h zzz", locale)).toBe("3 +02:00");
expect(formatting.formatDate(date, "h zzz")).toBe("3 +02:00");
});
});
describe("toId", () => {
it("returns null for undefined, null, empty string, whitespace", async function () {
expect(formatting.toId(undefined)).toBeNull();
expect(formatting.toId(null)).toBeNull();
expect(formatting.toId("")).toBeNull();
expect(formatting.toId(" ")).toBeNull();
});
it("returns numbers as is", async function () {
expect(formatting.toId(5)).toBe(5);
expect(formatting.toId(-1)).toBe(-1);
expect(formatting.toId(3.5)).toBe(3.5);
});
it("returns strings longer than 15 as is", async function () {
expect(formatting.toId("1234567890123456")).toBe("1234567890123456");
expect(formatting.toId("ab34567890123456")).toBe("ab34567890123456");
});
it("returns strings containing non digits as is", async function () {
expect(formatting.toId("ab3456789")).toBe("ab3456789");
});
it("returns strings containing all digits as number", async function () {
expect(formatting.toId("3456789")).toBe(3456789);
expect(formatting.toId("-1234567890")).toBe(-1234567890);
});
});
describe("parseDecimal", () => {
it("returns null for undefined, null, empty string, whitespace", async function () {
expect(formatting.parseDecimal(undefined)).toBeNull();
expect(formatting.parseDecimal(null)).toBeNull();
expect(formatting.parseDecimal("")).toBeNull();
expect(formatting.parseDecimal(" ")).toBeNull();
});
it("returns numbers as is", async function () {
expect(formatting.parseDecimal("5")).toBe(5);
expect(formatting.parseDecimal("-1")).toBe(-1);
expect(formatting.parseDecimal("3.5")).toBe(3.5);
});
it("trims strings", async function () {
expect(formatting.parseDecimal(" 5.0 ")).toBe(5);
expect(formatting.parseDecimal(" 5 ")).toBe(5);
});
it("returns NaN for strings containing non digits", async function () {
expect(formatting.parseDecimal("ab3456789")).toBeNaN();
});
it("can handle group separator", async function () {
formatting.Culture.groupSeparator = ",";
formatting.Culture.decimalSeparator = ".";
expect(formatting.parseDecimal("3,245,148.4")).toBe(3245148.4);
expect(formatting.parseDecimal("-3,245,148.4")).toBe(-3245148.4);
});
it("can use Culture decimal separator", async function () {
formatting.Culture.groupSeparator = ".";
formatting.Culture.decimalSeparator = ",";
expect(formatting.parseDecimal("3.245.148,4")).toBe(3245148.4);
expect(formatting.parseDecimal("-3.245.148,4")).toBe(-3245148.4);
expect(formatting.parseDecimal("-3245148,4")).toBe(-3245148.4);
});
});
describe("parseInteger", () => {
it("returns null for undefined, null, empty string, whitespace", async function () {
expect(formatting.parseInteger(undefined)).toBeNull();
expect(formatting.parseInteger(null)).toBeNull();
expect(formatting.parseInteger("")).toBeNull();
expect(formatting.parseInteger(" ")).toBeNull();
});
it("returns integer numbers as is", async function () {
expect(formatting.parseInteger("5")).toBe(5);
expect(formatting.parseInteger("-1")).toBe(-1);
expect(formatting.parseInteger("3")).toBe(3);
});
it("trims strings", async function () {
expect(formatting.parseInteger(" 5 ")).toBe(5);
});
it("returns NaN for strings containing non digits", async function () {
expect(formatting.parseInteger("ab3456789")).toBeNaN();
});
it("can handle group separator", async function () {
formatting.Culture.groupSeparator = ",";
formatting.Culture.decimalSeparator = ".";
expect(formatting.parseInteger("3,245,148")).toBe(3245148);
expect(formatting.parseInteger("-3,245,148")).toBe(-3245148);
});
it("can use Culture group separator", async function () {
formatting.Culture.groupSeparator = ".";
expect(formatting.parseDecimal("3.245.148")).toBe(3245148);
expect(formatting.parseDecimal("-3.245.148")).toBe(-3245148);
expect(formatting.parseDecimal("-3245148")).toBe(-3245148);
});
});
describe("formatNumber", () => {
it("returns empty string for undefined, null", async function () {
expect(formatting.formatNumber(undefined)).toBe("");
expect(formatting.formatNumber(null)).toBe("");
});
it("returns Culture.nanSymbol string for NaN", async function () {
formatting.Culture.nanSymbol = "NaN";
var locale = Object.assign({}, formatting.Culture);
locale.nanSymbol = "NaNNN";
expect(formatting.formatNumber(NaN, null, locale)).toBe("NaNNN");
locale.nanSymbol = null;
expect(formatting.formatNumber(NaN, null, locale)).toBe("NaN");
});
it('formats with "." as decimal separator', async function () {
const Culture = formatting.Culture;
const formatNumber = formatting.formatNumber;
Culture.decimalSeparator = '.';
Culture.groupSeparator = ',';
expect(formatNumber(1, '0.00')).toBe('1.00');
expect(formatNumber(1, '0.0000')).toBe('1.0000');
expect(formatNumber(1234, '#,##0')).toBe('1,234');
expect(formatNumber(1234.5, '#,##0.##')).toBe('1,234.5');
expect(formatNumber(1234.5678, '#,##0.##')).toBe('1,234.57');
expect(formatNumber(1234.5, '#,##0.00')).toBe('1,234.50');
});
it('formats with "," as decimal separator', async function () {
const Culture = formatting.Culture;
const formatNumber = formatting.formatNumber;
Culture.decimalSeparator = ',';
Culture.groupSeparator = '.';
expect(formatNumber(1, '0.00')).toBe('1,00');
expect(formatNumber(1, '0.0000')).toBe('1,0000');
expect(formatNumber(1234, '#,##0')).toBe('1.234');
expect(formatNumber(1234.5, '#,##0.##')).toBe('1.234,5');
expect(formatNumber(1234.5678, '#,##0.##')).toBe('1.234,57');
expect(formatNumber(1234.5, '#,##0.00')).toBe('1.234,50');
});
it('formats number with prefix and suffix', async function () {
const formatNumber = formatting.formatNumber;
const Culture = formatting.Culture;
Culture.decimalSeparator = '.';
expect(formatNumber(1234.5, '$#,##0.##')).toBe('$1,234.5');
expect(formatNumber(1234.5, 'R #,##0.##')).toBe('R 1,234.5');
expect(formatNumber(1234.5, '#,##0.## TL')).toBe('1,234.5 TL');
expect(formatNumber(1, "','0")).toBe(',1');
expect(formatNumber(1, "','0','")).toBe(',1,');
expect(formatNumber(1, "\\,0\\,")).toBe(',1,');
});
it('handles decimal format specifier', async function () {
const formatNumber = formatting.formatNumber;
const Culture = formatting.Culture;
Culture.decimalSeparator = '.';
expect(formatNumber(1234.5, 'D')).toBe('1234');
expect(formatNumber(1234.5, 'd')).toBe('1234');
expect(formatNumber(1234.5, 'D6')).toBe('001234');
expect(formatNumber(-1234.5, 'D6')).toBe('-001234');
expect(formatNumber(-1234.5, 'd6')).toBe('-001234');
});
it('handles hex format specifier', async function () {
const formatNumber = formatting.formatNumber;
const Culture = formatting.Culture;
Culture.decimalSeparator = '.';
expect(formatNumber(255, 'X')).toBe('FF');
expect(formatNumber(255, 'X4')).toBe('00FF');
expect(formatNumber(255, 'x')).toBe('ff');
expect(formatNumber(255, 'x4')).toBe('00ff');
// can't handle negative hex yet as it would require target number of bits
// expect(formatNumber(-1, 'x')).toBe('ff');
// expect(formatNumber(-1, 'x4')).toBe('ffff');
});
it('handles exponantional format specifier', async function () {
const formatNumber = formatting.formatNumber;
const Culture = formatting.Culture;
Culture.decimalSeparator = '.';
expect(formatNumber(1052.0329112756, 'E')).toBe('1.052033E+3');
expect(formatNumber(1052.0329112756, 'e')).toBe('1.052033e+3');
expect(formatNumber(-1052.0329112756, 'e2')).toBe('-1.05e+3');
expect(formatNumber(-1052.0329112756, 'E2')).toBe('-1.05E+3');
});
it("returns .toString() with decimal replaced if format is null or empty string", async function () {
formatting.Culture.groupSeparator = "!";
formatting.Culture.decimalSeparator = "*";
expect(formatting.formatNumber(5.3, null)).toBe("5*3");
expect(formatting.formatNumber(5.3, undefined)).toBe("5*3");
expect(formatting.formatNumber(5.3, "")).toBe("5*3");
});
it("returns .toString() if format is 'i'", async function () {
formatting.Culture.groupSeparator = "!";
formatting.Culture.decimalSeparator = "*";
expect(formatting.formatNumber(5.3, "i")).toBe("5.3");
});
it("uses group separator if specified in last argument", async function () {
expect(formatting.formatNumber(54321, "#,##0", null, "!")).toBe("54!321");
});
it("uses group separator if specified", async function () {
expect(formatting.formatNumber(54321.15, "#,##0.00", "!")).toBe("54,321!15");
});
it("handles fixed point format specifier", async function () {
const Culture = formatting.Culture;
Culture.decimalSeparator = '.';
expect(formatting.formatNumber(1234.567, "f")).toBe("1234.57");
expect(formatting.formatNumber(1234.567, "F1")).toBe("1234.6");
expect(formatting.formatNumber(1234.567, "F2")).toBe("1234.57");
expect(formatting.formatNumber(1234.567, "F3")).toBe("1234.567");
expect(formatting.formatNumber(1234.567, "F4")).toBe("1234.5670");
expect(formatting.formatNumber(-1234.567, "f")).toBe("-1234.57");
expect(formatting.formatNumber(-1234.567, "F1")).toBe("-1234.6");
expect(formatting.formatNumber(-1234.567, "F2")).toBe("-1234.57");
expect(formatting.formatNumber(-1234.567, "F3")).toBe("-1234.567");
expect(formatting.formatNumber(-1234.567, "F4")).toBe("-1234.5670");
Culture.decimalDigits = 3;
expect(formatting.formatNumber(1234.567, "f")).toBe("1234.567");
Culture.decimalDigits = 4;
var locale = Object.assign({}, Culture, {
decimalDigits: null
});
expect(formatting.formatNumber(1234.567, "f", locale)).toBe("1234.5670");
locale.decimalSeparator = ",";
expect(formatting.formatNumber(1234.567, "f", locale)).toBe("1234,5670");
});
it("handles numberic format specifier", async function () {
const Culture = formatting.Culture;
Culture.decimalSeparator = '.';
expect(formatting.formatNumber(1234.567, "n")).toBe("1,234.57");
expect(formatting.formatNumber(1234.567, "n1")).toBe("1,234.6");
expect(formatting.formatNumber(1234.567, "n2")).toBe("1,234.57");
expect(formatting.formatNumber(1234.567, "N3")).toBe("1,234.567");
expect(formatting.formatNumber(1234.567, "N4")).toBe("1,234.5670");
expect(formatting.formatNumber(-1234.567, "N")).toBe("-1,234.57");
expect(formatting.formatNumber(-1234.567, "N1")).toBe("-1,234.6");
expect(formatting.formatNumber(-1234.567, "N2")).toBe("-1,234.57");
expect(formatting.formatNumber(-1234.567, "N3")).toBe("-1,234.567");
expect(formatting.formatNumber(-1234.567, "N4")).toBe("-1,234.5670");
Culture.decimalDigits = 3;
expect(formatting.formatNumber(1234.567, "n")).toBe("1,234.567");
Culture.decimalDigits = 4;
var locale = Object.assign({}, Culture, {
decimalDigits: null
});
expect(formatting.formatNumber(1234.567, "n", locale)).toBe("1,234.5670");
locale.decimalSeparator = ",";
locale.groupSeparator = ".";
expect(formatting.formatNumber(1234.567, "n", locale)).toBe("1.234,5670");
expect(formatting.formatNumber(12.567, "n", locale)).toBe("12,5670");
});
it("handles currency format specifier", async function () {
const Culture = formatting.Culture;
Culture.decimalSeparator = '.';
Culture.currencySymbol = '₺';
expect(formatting.formatNumber(1234.567, "c")).toBe("1,234.57₺");
expect(formatting.formatNumber(1234.567, "c1")).toBe("1,234.6₺");
expect(formatting.formatNumber(1234.567, "c2")).toBe("1,234.57₺");
expect(formatting.formatNumber(1234.567, "C3")).toBe("1,234.567₺");
expect(formatting.formatNumber(1234.567, "c4")).toBe("1,234.5670₺");
expect(formatting.formatNumber(-1234.567, "C")).toBe("-1,234.57₺");
expect(formatting.formatNumber(-1234.567, "c1")).toBe("-1,234.6₺");
expect(formatting.formatNumber(-1234.567, "C2")).toBe("-1,234.57₺");
expect(formatting.formatNumber(-1234.567, "c3")).toBe("-1,234.567₺");
expect(formatting.formatNumber(-1234.567, "C4")).toBe("-1,234.5670₺");
Culture.decimalDigits = 3;
expect(formatting.formatNumber(1234.567, "c")).toBe("1,234.567₺");
Culture.decimalDigits = 4;
Culture.currencySymbol = '?';
var locale = Object.assign({}, Culture, {
decimalDigits: null
});
expect(formatting.formatNumber(1234.567, "c", locale)).toBe("1,234.5670?");
locale.decimalSeparator = ",";
locale.groupSeparator = ".";
expect(formatting.formatNumber(1234.567, "c", locale)).toBe("1.234,5670?");
expect(formatting.formatNumber(12.567, "c", locale)).toBe("12,5670?");
});
it("handles currency percent specifier", async function () {
const Culture = formatting.Culture;
Culture.decimalSeparator = '.';
Culture.currencySymbol = '₺';
expect(formatting.formatNumber(12.567, "p")).toBe("1,256.70%");
expect(formatting.formatNumber(12.567, "p1")).toBe("1,256.7%");
expect(formatting.formatNumber(12.567, "p2")).toBe("1,256.70%");
expect(formatting.formatNumber(12.567, "p3")).toBe("1,256.700%");
expect(formatting.formatNumber(12.567, "p4")).toBe("1,256.7000%");
expect(formatting.formatNumber(-12.567, "p")).toBe("-1,256.70%");
expect(formatting.formatNumber(-12.567, "p1")).toBe("-1,256.7%");
expect(formatting.formatNumber(-12.567, "p2")).toBe("-1,256.70%");
expect(formatting.formatNumber(-12.567, "p3")).toBe("-1,256.700%");
expect(formatting.formatNumber(-12.567, "p4")).toBe("-1,256.7000%");
Culture.decimalDigits = 3;
expect(formatting.formatNumber(12.567, "p")).toBe("1,256.700%");
Culture.decimalDigits = 4;
Culture.percentSymbol = '?';
var locale = Object.assign({}, Culture, {
decimalDigits: null
});
expect(formatting.formatNumber(12.567, "p", locale)).toBe("1,256.7000?");
locale.decimalSeparator = ",";
locale.groupSeparator = ".";
expect(formatting.formatNumber(12.567, "p", locale)).toBe("1.256,7000?");
});
it("handles start zero padding", async function () {
const Culture = formatting.Culture;
Culture.decimalSeparator = '.';
expect(formatting.formatNumber(1.23, "000")).toBe("001");
});
});
describe("format", () => {
it("handles double braces", async function () {
expect(formatting.stringFormat("{{{0}}}", "abc")).toBe("{abc}");
});
it("formats null and undefined as empty string", async function () {
expect(formatting.stringFormat("{0}", null)).toBe("");
expect(formatting.stringFormat("x{0}y", null)).toBe("xy");
expect(formatting.stringFormat("{0}", undefined)).toBe("");
expect(formatting.stringFormat("x{0}y", undefined)).toBe("xy");
});
it("handles number format specifiers", async function () {
expect(formatting.stringFormat("{0:000}", 5)).toBe("005");
});
it("handles date format specifiers", async function () {
expect(formatting.stringFormat("{0:yyyy-MM-dd}", new Date(2020, 1, 1))).toBe("2020-02-01");
});
it("calls obj.format if available", async function () {
expect(formatting.stringFormat("{0:x}", { format: (s: string) => s })).toBe("x");
});
});
describe("localeFormat", () => {
it("handles double braces", async function () {
var locale = Object.assign({}, formatting.Culture);
expect(formatting.stringFormatLocale(locale, "{{{0}}}", "abc")).toBe("{abc}");
});
it("formats null and undefined as empty string", async function () {
var locale = Object.assign({}, formatting.Culture);
expect(formatting.stringFormatLocale(locale, "{0}", null)).toBe("");
expect(formatting.stringFormatLocale(locale, "x{0}y", null)).toBe("xy");
expect(formatting.stringFormatLocale(locale, "{0}", undefined)).toBe("");
expect(formatting.stringFormatLocale(locale, "x{0}y", undefined)).toBe("xy");
});
it("handles number format specifiers", async function () {
var locale = Object.assign({}, formatting.Culture);
expect(formatting.stringFormatLocale(locale, "{0:000}", 5)).toBe("005");
});
it("handles date format specifiers", async function () {
var locale = Object.assign({}, formatting.Culture);
expect(formatting.stringFormatLocale(locale, "{0:yyyy-MM-dd}", new Date(2020, 1, 1))).toBe("2020-02-01");
});
it("calls obj.localeFormat if available", async function () {
var locale = Object.assign({}, formatting.Culture);
expect(formatting.stringFormatLocale(locale, "{0:x}", { format: (s: string) => s })).toBe("x");
});
});
describe("ScriptCulture", () => {
it("ignores a script element with ScriptCulture ID but empty content", async () => {
var script = document.head.appendChild(document.createElement('script'));
try {
script.type = "application/json";
script.id = "ScriptCulture";
script.innerText = " ";
formatting.resetCultureSettings();
expect(formatting.Culture).toBeDefined();
}
finally {
script.remove();
}
});
it("ignores a script element with ScriptCulture ID but empty JSON content", async () => {
var script = document.head.appendChild(document.createElement('script'));
try {
script.type = "application/json";
script.id = "ScriptCulture";
script.innerHTML = "{}";
formatting.resetCultureSettings();
expect(formatting.Culture).toBeDefined();
}
finally {
script.remove();
}
});
it("uses a script element with ScriptCulture ID", async () => {
var script = document.head.appendChild(document.createElement('script'));
try {
script.type = "application/json";
script.id = "ScriptCulture";
script.innerHTML = '{ "DecimalSeparator": "&" }';
formatting.resetCultureSettings();
expect(formatting.Culture.decimalSeparator).toBe('&');
}
finally {
script.remove();
}
});
it("can handle when GroupSeparator is specified same with DecimalSeparator", async () => {
var script = document.head.appendChild(document.createElement('script'));
try {
script.type = "application/json";
script.id = "ScriptCulture";
script.textContent = '{ "DecimalSeparator": "&", "GroupSeparator": "&" }';
formatting.resetCultureSettings();
expect(formatting.Culture.decimalSeparator).toBe('&');
expect(formatting.Culture.groupSeparator).toBe(',');
}
finally {
script.remove();
}
});
it("can handle when GroupSeparator is specified same with Culture.DecimalSeparator", async () => {
var script = document.head.appendChild(document.createElement('script'));
try {
script.type = "application/json";
script.id = "ScriptCulture";
script.textContent = '{ "GroupSeparator": "." }';
formatting.resetCultureSettings();
expect(formatting.Culture.decimalSeparator).toBe('.');
expect(formatting.Culture.groupSeparator).toBe(',');
}
finally {
script.remove();
}
});
it("can switch GroupSeparator when DecimalSeparator is specified the same", async () => {
var script = document.head.appendChild(document.createElement('script'));
try {
script.type = "application/json";
script.id = "ScriptCulture";
script.textContent = '{ "DecimalSeparator": "," }';
formatting.resetCultureSettings();
expect(formatting.Culture.decimalSeparator).toBe(',');
expect(formatting.Culture.groupSeparator).toBe('.');
}
finally {
script.remove();
}
});
it("can set GroupSeparator", async () => {
var script = document.head.appendChild(document.createElement('script'));
try {
script.type = "application/json";
script.id = "ScriptCulture";
script.textContent = '{ "GroupSeparator": "$" }';
formatting.resetCultureSettings();
expect(formatting.Culture.decimalSeparator).toBe('.');
expect(formatting.Culture.groupSeparator).toBe('$');
}
finally {
script.remove();
}
});
it("can set other Culture members by lowercasing first letter", async () => {
var script = document.head.appendChild(document.createElement('script'));
try {
script.type = "application/json";
script.id = "ScriptCulture";
script.textContent = '{ "DateSeparator": "_", "TimeSeparator": "?" }';
formatting.resetCultureSettings();
expect(formatting.Culture.dateSeparator).toBe('_');
expect(formatting.Culture.timeSeparator).toBe('?');
}
finally {
script.remove();
}
});
});
describe("round", () => {
it("rounds to nearest integer if no digits specified", async function () {
expect(formatting.round(1.5)).toBe(2);
expect(formatting.round(1.4)).toBe(1);
expect(formatting.round(-1.5)).toBe(-2);
expect(formatting.round(-1.4)).toBe(-1);
});
it("rounds to specified number of digits", async function () {
expect(formatting.round(1.555, 2)).toBe(1.56);
expect(formatting.round(1.554, 2)).toBe(1.55);
expect(formatting.round(-1.555, 2)).toBe(-1.56);
expect(formatting.round(-1.554, 2)).toBe(-1.55);
});
it("handles edge cases", async function () {
expect(formatting.round(0)).toBe(0);
expect(formatting.round(-0)).toBe(0);
expect(formatting.round(0.5)).toBe(1);
expect(formatting.round(-0.5)).toBe(-1);
expect(formatting.round(1.005, 2)).toBe(1.01);
expect(formatting.round(-1.005, 2)).toBe(-1.01);
expect(formatting.round(1.965, 2)).toBe(1.97);
expect(formatting.round(-1.965, 2)).toBe(-1.97);
expect(formatting.round(-1.965, 2)).toBe(-1.97);
expect(formatting.round(1.2345678e+2, 2)).toBe(123.46);
expect(formatting.round(1234.5678, -2)).toBe(1200);
});
});
describe("trunc", () => {
it("truncates positive numbers to integer", async function () {
expect(formatting.trunc(1.5)).toBe(1);
expect(formatting.trunc(1.4)).toBe(1);
expect(formatting.trunc(123.456)).toBe(123);
});
it("truncates negative numbers to integer", async function () {
expect(formatting.trunc(-1.5)).toBe(-1);
expect(formatting.trunc(-1.4)).toBe(-1);
expect(formatting.trunc(-123.456)).toBe(-123);
});
it("returns 0 for 0 and -0 for -0", async function () {
expect(formatting.trunc(0)).toBe(0);
expect(formatting.trunc(-0)).toBe(-0);
});
it("returns null for null and undefined", async function () {
expect(formatting.trunc(null)).toBeNull();
expect(formatting.trunc(undefined)).toBeNull();
});
it("handles edge cases", async function () {
expect(formatting.trunc(1)).toBe(1);
expect(formatting.trunc(-1)).toBe(-1);
expect(formatting.trunc(1.0000001)).toBe(1);
expect(formatting.trunc(-1.0000001)).toBe(-1);
});
});
export { };