Skip to content

Commit

Permalink
fix: Broken tests and coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
davidkarolyi committed Mar 6, 2022
1 parent 9d1ea01 commit 23e170e
Show file tree
Hide file tree
Showing 5 changed files with 272 additions and 14 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,13 @@ interface Post {
// 2. Unfortunatelly these types are only exist in TypeScript world.
// So let's represent those types as type guards:
const TPost = new Guard({
id: TStringUUID(4);
id: TStringUUID({version: 4});
title: TString,
body: TString,
});

const TUser = new Guard({
id: TStringUUID(4);
id: TStringUUID({version: 4});
name: TString,
posts: TArray(TPost),
});
Expand Down
246 changes: 246 additions & 0 deletions __tests__/validators.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,18 @@ import {
TNumberAsString,
TAnd,
TStringMatch,
TStringBase64,
TStringEmail,
TStringISODate,
TStringJSON,
TStringJWT,
TStringMIMEType,
TStringPhoneNumber,
TStringOfLength,
TStringSemVer,
TStringURL,
TStringUUID,
TValidate,
} from "../src/validators";

describe("Validators", () => {
Expand Down Expand Up @@ -364,5 +376,239 @@ describe("Validators", () => {
expect(validator.isValid("foomatchbar")).toBe(true);
});
});

describe("TStringBase64", () => {
const validator = TStringBase64({ urlSafe: false });

it("is an instance of Validator", () => {
expect(validator).toBeInstanceOf(Validator);
});

it("it's name is 'string(base64(?URL))'", () => {
expect(validator.name).toBe("string(base64)");
expect(TStringBase64({ urlSafe: true }).name).toBe("string(base64URL)");
});

it("returns false, if the input is not a base64 string", () => {
expect(validator.isValid("foobar")).toBe(false);
});

it("returns true, if the input is a base64 string", () => {
expect(validator.isValid("c29tZXRoaW5n")).toBe(true);
});
});

describe("TStringEmail", () => {
it("is an instance of Validator", () => {
expect(TStringEmail).toBeInstanceOf(Validator);
});

it("it's name is 'string(email)'", () => {
expect(TStringEmail.name).toBe("string(email)");
});

it("returns false, if the input is not an email", () => {
expect(TStringEmail.isValid("foobar")).toBe(false);
});

it("returns true, if the input is an email", () => {
expect(TStringEmail.isValid("foobar@email.com")).toBe(true);
});
});

describe("TStringISODate", () => {
it("is an instance of Validator", () => {
expect(TStringISODate).toBeInstanceOf(Validator);
});

it("it's name is 'string(date)'", () => {
expect(TStringISODate.name).toBe("string(date)");
});

it("returns false, if the input is not a ISO date string", () => {
expect(TStringISODate.isValid("foobar")).toBe(false);
});

it("returns true, if the input is a ISO date string", () => {
expect(TStringISODate.isValid("2022-03-06T22:01:41.160Z")).toBe(true);
});
});

describe("TStringJSON", () => {
it("is an instance of Validator", () => {
expect(TStringJSON).toBeInstanceOf(Validator);
});

it("it's name is 'string(JSON)'", () => {
expect(TStringJSON.name).toBe("string(JSON)");
});

it("returns false, if the input is not a JSON string", () => {
expect(TStringJSON.isValid("foobar")).toBe(false);
});

it("returns true, if the input is a JSON string", () => {
expect(TStringJSON.isValid('{"foo": 2}')).toBe(true);
});
});

describe("TStringJWT", () => {
it("is an instance of Validator", () => {
expect(TStringJWT).toBeInstanceOf(Validator);
});

it("it's name is 'string(JWT)'", () => {
expect(TStringJWT.name).toBe("string(JWT)");
});

it("returns false, if the input is not a JWT string", () => {
expect(TStringJWT.isValid("foobar")).toBe(false);
});

it("returns true, if the input is a JWT string", () => {
expect(
TStringJWT.isValid(
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
)
).toBe(true);
});
});

describe("TStringMIMEType", () => {
it("is an instance of Validator", () => {
expect(TStringMIMEType).toBeInstanceOf(Validator);
});

it("it's name is 'string(MIME type)'", () => {
expect(TStringMIMEType.name).toBe("string(MIME type)");
});

it("returns false, if the input is not a MIME type string", () => {
expect(TStringMIMEType.isValid("foobar")).toBe(false);
});

it("returns true, if the input is a MIME type string", () => {
expect(TStringMIMEType.isValid("application/json")).toBe(true);
});
});

describe("TStringPhoneNumber", () => {
it("is an instance of Validator", () => {
expect(TStringPhoneNumber).toBeInstanceOf(Validator);
});

it("it's name is 'string(phone number)'", () => {
expect(TStringPhoneNumber.name).toBe("string(phone number)");
});

it("returns false, if the input is not a phone number string", () => {
expect(TStringPhoneNumber.isValid("foobar")).toBe(false);
});

it("returns true, if the input is a phone number string", () => {
expect(TStringPhoneNumber.isValid("061555555")).toBe(true);
});
});

describe("TStringSemVer", () => {
it("is an instance of Validator", () => {
expect(TStringSemVer).toBeInstanceOf(Validator);
});

it("it's name is 'string(SemVer)'", () => {
expect(TStringSemVer.name).toBe("string(SemVer)");
});

it("returns false, if the input is not a SemVer string", () => {
expect(TStringSemVer.isValid("foobar")).toBe(false);
});

it("returns true, if the input is a SemVer string", () => {
expect(TStringSemVer.isValid("1.0.7")).toBe(true);
});
});

describe("TStringOfLength", () => {
const validator = TStringOfLength({ min: 5 });

it("is an instance of Validator", () => {
expect(validator).toBeInstanceOf(Validator);
});

it("it's name is 'string([min=<min>][,max=<max>])'", () => {
expect(validator.name).toBe("string(min=5)");
expect(TStringOfLength({ min: 5, max: 10 }).name).toBe(
"string(min=5,max=10)"
);
expect(TStringOfLength({ max: 10 }).name).toBe("string(max=10)");
});

it("returns false, if the input is not a string of the given length constraint", () => {
expect(validator.isValid("1234")).toBe(false);
});

it("returns true, if the input is a string of the given length constraint", () => {
expect(validator.isValid("123456")).toBe(true);
});
});

describe("TStringURL", () => {
it("is an instance of Validator", () => {
expect(TStringURL).toBeInstanceOf(Validator);
});

it("it's name is 'string(URL)'", () => {
expect(TStringURL.name).toBe("string(URL)");
});

it("returns false, if the input is not a URL", () => {
expect(TStringURL.isValid("foobar")).toBe(false);
});

it("returns true, if the input is a URL", () => {
expect(TStringURL.isValid("foobar.com")).toBe(true);
});
});

describe("TStringUUID", () => {
const validator = TStringUUID({ version: 4 });

it("is an instance of Validator", () => {
expect(validator).toBeInstanceOf(Validator);
});

it("it's name is 'string(UUID-v4)'", () => {
expect(validator.name).toBe("string(UUID-v4)");
expect(TStringUUID({ version: "all" }).name).toBe("string(UUID-all)");
});

it("returns false, if the input is not UUID", () => {
expect(validator.isValid("foobar")).toBe(false);
});

it("returns true, if the input is UUID", () => {
expect(validator.isValid("936a0dd4-cf7f-497d-a0cd-7c891416c719")).toBe(
true
);
});
});

describe("TValidate", () => {
it("is an instance of Validator", () => {
expect(TValidate("custom", () => true)).toBeInstanceOf(Validator);
});

it("it's name is the name provided as an argument", () => {
expect(TValidate("custom", () => true).name).toBe("custom");
});

it("returns false, if the given function return false", () => {
expect(TValidate("custom", () => false).isValid("foobar")).toBe(false);
});

it("returns true, if the input is UUID", () => {
expect(TValidate("custom", () => true).isValid("foobar")).toBe(true);
});
});
});
});
6 changes: 5 additions & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ module.exports = {
preset: "ts-jest",
testEnvironment: "node",
testPathIgnorePatterns: ["<rootDir>/node_modules/", "<rootDir>/lib/"],
coveragePathIgnorePatterns: ["<rootDir>/node_modules/", "<rootDir>/lib/"],
coveragePathIgnorePatterns: [
"<rootDir>/node_modules/",
"<rootDir>/lib/",
"<rootDir>/src/index.ts",
],
collectCoverageFrom: ["<rootDir>/src/**/*.ts"],
coverageThreshold: {
global: { branches: 100, statements: 100, functions: 100, lines: 100 },
Expand Down
14 changes: 10 additions & 4 deletions src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@ export class ValidationError extends Error {

export class InvalidValueError extends ValidationError {
constructor(path: Array<string>, expectedType: string) {
const pathInfo = path.length ? ` at "${path.join(".")}"` : "";
super(
`Invalid value${pathInfo}, expected type: ${expectedType}`,
"Invalid " + getValueDescription(path, expectedType),
path,
expectedType
);
Expand All @@ -22,11 +21,18 @@ export class InvalidValueError extends ValidationError {

export class MissingValueError extends ValidationError {
constructor(path: Array<string>, expectedType: string) {
const pathInfo = path.length ? ` at "${path.join(".")}"` : "";
super(
`Missing value${pathInfo}, expected type: ${expectedType}`,
"Missing " + getValueDescription(path, expectedType),
path,
expectedType
);
}
}

function getValueDescription(
path: Array<string>,
expectedType: string
): string {
const pathInfo = path.length ? ` at "${path.join(".")}"` : "";
return `value${pathInfo}, expected type: ${expectedType}`;
}
16 changes: 9 additions & 7 deletions src/validators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,18 +170,19 @@ export function TStringMatch(

export function TStringBase64(options: { urlSafe: boolean }) {
return TValidate<string>(
"string(base64)",
`string(base64${options.urlSafe ? "URL" : ""})`,
(value: any) => typeof value === "string" && isBase64(value, options)
);
}

export function TStringOfLength(options: { min?: number; max?: number }) {
let name = "string";
const isOptionEmpty = options.min === undefined && options.max === undefined;
if (isOptionEmpty) name += "(";
if (options.min !== undefined) name += options.min;
if (options.max !== undefined) name += options.max;
if (isOptionEmpty) name += ")";
if (!isOptionEmpty) name += "(";
if (options.min !== undefined) name += `min=${options.min}`;
if (options.min !== undefined && options.max !== undefined) name += ",";
if (options.max !== undefined) name += `max=${options.max}`;
if (!isOptionEmpty) name += ")";

return TValidate<string>(
name,
Expand Down Expand Up @@ -214,7 +215,7 @@ export const TStringMIMEType = TValidate<string>(
(value: any) => typeof value === "string" && isMimeType(value)
);

export const TStringMobilePhone = TValidate<string>(
export const TStringPhoneNumber = TValidate<string>(
"string(phone number)",
(value: any) => typeof value === "string" && isMobilePhone(value)
);
Expand All @@ -229,7 +230,8 @@ export const TStringURL = TValidate<string>(
(value: any) => typeof value === "string" && isURL(value)
);

export function TStringUUID(version: UUIDVersion) {
export function TStringUUID(options: { version: UUIDVersion }) {
const { version } = options;
return TValidate<string>(
`string(UUID-${version === "all" ? version : "v" + version})`,
(value: any) => typeof value === "string" && isUUID(value, version)
Expand Down

0 comments on commit 23e170e

Please sign in to comment.