diff --git a/package/src/lib/Assertion.ts b/package/src/lib/Assertion.ts index 83c1c97..f7b07a1 100644 --- a/package/src/lib/Assertion.ts +++ b/package/src/lib/Assertion.ts @@ -11,6 +11,17 @@ export interface Constructor extends Function { prototype: T; } +export type DataType = + | "array" + | "bigint" + | "boolean" + | "function" + | "number" + | "object" + | "string" + | "symbol" + | "undefined"; + export interface ExecuteOptions { /** * The condition for when the assertion should pass. The negation of this @@ -429,6 +440,43 @@ export class Assertion { }); } + /** + * Checks if the value is of a specific data type. The supported data types + * are the same as the `typeof` operator, plus an additional `array` which + * allows desabiguation between `object` (which can also be an array). + * + * @example + * ``` + * const arr = [1, 2, 3]; + * + * expect(arr).toBeOfType("array"); + * expect(arr[0]).toBeOfType("number"); + * expect(arr[9]).toBeOfType("undefined"); + * ``` + * + * @param expected the expected data type + * @returns the assertion instance + */ + public toBeOfType(expected: DataType): this { + const error = new AssertionError({ + actual: typeof this.actual, + expected, + message: `Expected <${prettify(this.actual)}> to be of type <${expected}>`, + }); + const invertedError = new AssertionError({ + actual: typeof this.actual, + message: `Expected <${prettify(this.actual)}> NOT to be of type <${expected}>`, + }); + + return this.execute({ + assertWhen: expected === "array" + ? Array.isArray(this.actual) + : typeof this.actual === expected, + error, + invertedError, + }); + } + /** * Check first if the value is of some specific type, in which case returns * an assertion instance for that specific type. The new assertion is built diff --git a/package/test/lib/Assertion.test.ts b/package/test/lib/Assertion.test.ts index 886df2e..520bb4e 100644 --- a/package/test/lib/Assertion.test.ts +++ b/package/test/lib/Assertion.test.ts @@ -1,7 +1,8 @@ -import { Assertion } from "../../src/lib/Assertion"; +import { Assertion, DataType } from "../../src/lib/Assertion"; import { StringAssertion } from "../../src/lib/StringAssertion"; import { UnsupportedOperationError } from "../../src/lib/errors/UnsupportedOperationError"; import { TypeFactories } from "../../src/lib/helpers/TypeFactories"; +import { prettify } from "../../src/lib/helpers/messages"; import assert, { AssertionError } from "assert"; @@ -471,6 +472,60 @@ describe("[Unit] Assertion.test.ts", () => { }); }); + describe(".toBeOfType", () => { + context("when the type of the value is of the expected type", () => { + const variants: Array<[DataType, unknown]> = [ + ["array", [1, 2, 3]], + ["bigint", BigInt(9)], + ["boolean", true], + ["function", () => undefined], + ["number", 10], + ["object", { foo: 1 }], + ["string", "foo"], + ["symbol", Symbol("id")], + ["undefined", undefined], + ]; + + variants.forEach(([expected, value]) => { + it(`[${expected}] returns the assertion instance`, () => { + const test = new Assertion(value); + + assert.deepStrictEqual(test.toBeOfType(expected), test); + assert.throws(() => test.not.toBeOfType(expected), { + message: `Expected <${prettify(value)}> NOT to be of type <${expected}>`, + name: AssertionError.name, + }); + }); + }); + }); + + context("when the type of the value is NOT of the expected type", () => { + const variants: Array<[DataType, unknown]> = [ + ["array", { x: [1, 2, 3] }], + ["bigint", 9], + ["boolean", "false"], + ["function", { foo: () => undefined }], + ["number", BigInt(10)], + ["object", "foo"], + ["string", Symbol("id")], + ["symbol", undefined], + ["undefined", null], + ]; + + variants.forEach(([expected, value]) => { + it(`[${expected}] throws an assertion error`, () => { + const test = new Assertion(value); + + assert.throws(() => test.toBeOfType(expected), { + message: `Expected <${prettify(value)}> to be of type <${expected}>`, + name: AssertionError.name, + }); + assert.deepStrictEqual(test.not.toBeOfType(expected), test); + }); + }); + }); + }); + describe(".asType", () => { context("when the type predicate is true", () => { it("returns a new instance of the assertion passed to the type factory", () => {