passbolt-styleguide
Version:
Passbolt styleguide contains common styling assets used by the different sites, plugin, etc.
942 lines (880 loc) • 38.9 kB
JavaScript
/**
* Passbolt ~ Open source password manager for teams
* Copyright (c) Passbolt SA (https://www.passbolt.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Passbolt SA (https://www.passbolt.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.passbolt.com Passbolt(tm)
* @since 2.13.0
*/
import each from "jest-each";
import EntitySchema from "./entitySchema";
import {
SCENARIO_ARRAY,
SCENARIO_ARRAY_EMPTY,
SCENARIO_BOOL_FALSE,
SCENARIO_BOOL_TRUE,
SCENARIO_DATE_YEAR,
SCENARIO_DATE_YEAR_MONTH,
SCENARIO_DATE_YEAR_MONTH_DAY,
SCENARIO_DATE_YEAR_MONTH_DAY_TIME,
SCENARIO_EMPTY,
SCENARIO_FLOAT,
SCENARIO_INTEGER,
SCENARIO_NULL,
SCENARIO_OBJECT,
SCENARIO_STRING,
SCENARIO_STRING_UTF8,
SCENARIO_UNDEFINED,
SCENARIO_UUID,
schemaValidateAnyOf,
schemaValidateEnum,
schemaValidateFormatDateTime,
schemaValidateFormatEmail,
schemaValidateFormatInvalid,
schemaValidateFormatUuid,
schemaValidateFormatXBase64,
schemaValidateFormatXHexColor,
schemaValidateMaxLength,
schemaValidateMinLength,
schemaValidateMinimumIntegerValue,
schemaValidateMaximumIntegerValue,
schemaValidateMinimumNumberValue,
schemaValidateMaximumNumberValue,
schemaValidateNullable,
schemaValidatePattern,
schemaValidateRequired,
schemaValidateSimple,
schemaValidateTypeArray,
schemaValidateTypeBoolean,
schemaValidateTypeInteger,
schemaValidateTypeInvalid,
schemaValidateTypeNumber,
schemaValidateTypeObject,
schemaValidateTypeString,
schemaValidateMinItemsArrayValue,
schemaValidateSimpleArray,
} from "./entitySchema.test.data";
describe("EntitySchema", () => {
describe("::validate", () => {
each([
SCENARIO_NULL,
SCENARIO_UNDEFINED,
// @todo The function should be reworked and assert the kind of expected data, additional test should be written to support it.
]).describe("throws a TyperError if the argument name is not valid.", (scenario) => {
it(`scenario: ${scenario.label}`, async () => {
expect.assertions(1);
expect(() => EntitySchema.validate(scenario.data, { name: "test" }, schemaValidateSimple)).toThrow(TypeError);
});
});
each([
SCENARIO_NULL,
SCENARIO_UNDEFINED,
// @todo The function should be reworked and assert the kind of expected data, additional test should be written to support it.
]).describe("throws a TyperError if the argument dto is not valid.", (scenario) => {
it(`scenario: ${scenario.label}`, async () => {
expect.assertions(1);
expect(() => EntitySchema.validate("TestObject", scenario.data, schemaValidateSimple)).toThrow(TypeError);
});
});
each([
SCENARIO_NULL,
SCENARIO_UNDEFINED,
// @todo The function should be reworked and assert the kind of expected data, additional test should be written to support it.
]).describe("throws a TyperError if the argument schema is not valid.", (scenario) => {
it(`scenario: ${scenario.label}`, async () => {
expect.assertions(1);
expect(() => EntitySchema.validate("TestObject", { name: "test" }, scenario.data)).toThrow(TypeError);
});
});
each([SCENARIO_NULL, SCENARIO_UNDEFINED, { label: "invalid-type", data: "invalid-type" }]).describe(
"throws a TyperError if the schema type is not supported.",
(scenario) => {
it(`scenario: ${scenario.label}`, async () => {
expect.assertions(1);
const schema = {
type: scenario.data,
};
expect(() => EntitySchema.validate("TestObject", {}, schema)).toThrow(
"Could not validate entity TestObject. Unsupported type.",
);
});
},
);
it("validates object schema.", () => {
expect.assertions(2);
const validObjectMock = jest.spyOn(EntitySchema, "validateObject").mockImplementationOnce(() => {});
const schema = { type: "object" };
expect(() => EntitySchema.validate("TestObject", {}, schema)).not.toThrow();
expect(validObjectMock).toHaveBeenCalled();
});
it("validates array schema.", () => {
expect.assertions(2);
const validateArrayMock = jest.spyOn(EntitySchema, "validateArray").mockImplementationOnce(() => {});
const schema = { type: "array" };
expect(() => EntitySchema.validate("TestObject", {}, schema)).not.toThrow();
expect(validateArrayMock).toHaveBeenCalled();
});
it("throws EntityValidationError id dto is invalid.", () => {
expect.assertions(1);
const testObject = {
id: "nope",
name: "ok",
type: "not in list",
};
expect(() => EntitySchema.validate("TestObject", testObject, schemaValidateSimple)).toThrowEntityValidationError(
"id",
"format",
);
});
});
describe("::validateObject", () => {
it("filters out props not part of the schema.", () => {
const testObject = {
name: "ok",
some: "type1",
not_in_schema: "must be removed",
};
const expected = {
name: "ok",
some: "type1",
};
const result = EntitySchema.validate("TestObject", testObject, schemaValidateSimple);
expect(result).toEqual(expected);
});
it("does not validate nested objects.", () => {
const testObject = {
name: "ok",
some: "type1",
nested: {
id: "invalid-id",
},
};
const result = EntitySchema.validate("TestObject", testObject, schemaValidateSimple);
expect(result.nested.id).toEqual(testObject.nested.id);
// Ensure it would have been validated if nested object validated directly.
expect(() =>
EntitySchema.validate("NestedTestObject", testObject.nested, schemaValidateSimple.properties.nested),
).toThrowEntityValidationError("id", "format");
});
/*
* *************************************************************
* Common assertions
***************************************************************
*/
describe("::required", () => {
it("throws an error if required and not present", () => {
// Note that if the property is present but undefined, it will not validate due to other constraint such as the type.
expect.assertions(1);
expect(() => EntitySchema.validate("TestObject", {}, schemaValidateRequired)).toThrowEntityValidationError(
"property",
"required",
);
});
each([
SCENARIO_NULL,
SCENARIO_INTEGER,
SCENARIO_FLOAT,
SCENARIO_OBJECT,
SCENARIO_ARRAY,
SCENARIO_ARRAY_EMPTY,
SCENARIO_EMPTY,
SCENARIO_STRING,
SCENARIO_UUID,
SCENARIO_DATE_YEAR,
SCENARIO_DATE_YEAR_MONTH,
SCENARIO_DATE_YEAR_MONTH_DAY,
SCENARIO_DATE_YEAR_MONTH_DAY_TIME,
{ label: "0 as an integer", data: 0 },
{ label: "0 as an string", data: "0" },
SCENARIO_BOOL_TRUE,
SCENARIO_BOOL_FALSE,
]).describe("validates if the property is valid.", (scenario) => {
it(`scenario: ${scenario.label}`, async () => {
expect.assertions(1);
const testObject = { property: scenario.data };
expect(() => EntitySchema.validate("TestObject", testObject, schemaValidateRequired)).not.toThrow();
});
});
});
describe("::nullable", () => {
it("does not throw if the property is nullable and null.", async () => {
expect.assertions(1);
const testObject = { property: null };
expect(() => EntitySchema.validate("TestObject", testObject, schemaValidateNullable)).not.toThrow();
});
});
describe("::anyOf", () => {
it("throws if none of the condition is valid.", () => {
expect.assertions(1);
const testObject = { name: 42 };
expect(() => EntitySchema.validate("TestObject", testObject, schemaValidateAnyOf)).toThrowEntityValidationError(
"name",
"type",
);
});
it("validates one or the other conditions.", () => {
expect.assertions(4);
const schema = schemaValidateAnyOf;
// Validate one condition of the anyOf.
let testObject = { name: null };
let result = EntitySchema.validate("TestObject", testObject, schema);
expect(Object.keys(result).length).toEqual(1); // The parsed object contains only one property.
expect(result.name).toBeNull();
// Validate the other condition of the anyOf.
testObject = { name: "test" };
result = EntitySchema.validate("TestObject", testObject, schema);
expect(Object.keys(result).length).toEqual(1); // The parsed object contains only one property.
expect(result.name).toEqual("test");
});
});
describe("::type", () => {
it("throws an error if type is not supported", () => {
expect.assertions(1);
expect(() => EntitySchema.validate("TestObject", { property: "" }, schemaValidateTypeInvalid)).toThrow(
"EntitySchema validation type not supported.",
);
});
describe("::type::boolean", () => {
each([
SCENARIO_NULL,
SCENARIO_UNDEFINED,
SCENARIO_INTEGER,
SCENARIO_FLOAT,
SCENARIO_OBJECT,
SCENARIO_ARRAY,
SCENARIO_ARRAY_EMPTY,
SCENARIO_EMPTY,
SCENARIO_STRING,
SCENARIO_UUID,
SCENARIO_DATE_YEAR,
SCENARIO_DATE_YEAR_MONTH,
SCENARIO_DATE_YEAR_MONTH_DAY,
SCENARIO_DATE_YEAR_MONTH_DAY_TIME,
{ label: "1 as an integer", data: 1 },
{ label: "0 as an integer", data: 0 },
{ label: "1 as a string", data: "1" },
{ label: "0 as a string", data: "0" },
]).describe("throws an EntityValidationError if the property is not valid.", (scenario) => {
it(`scenario: ${scenario.label}`, async () => {
expect.assertions(1);
const testObject = { property: scenario.data };
expect(() =>
EntitySchema.validate("TestObject", testObject, schemaValidateTypeBoolean),
).toThrowEntityValidationError("property", "type");
});
});
each([SCENARIO_BOOL_TRUE, SCENARIO_BOOL_FALSE]).describe("validates if the property is valid.", (scenario) => {
it(`scenario: ${scenario.label}`, async () => {
expect.assertions(1);
const testObject = { property: scenario.data };
expect(() => EntitySchema.validate("TestObject", testObject, schemaValidateTypeBoolean)).not.toThrow();
});
});
});
describe("::type::string", () => {
each([
SCENARIO_NULL,
SCENARIO_UNDEFINED,
SCENARIO_INTEGER,
SCENARIO_FLOAT,
SCENARIO_OBJECT,
SCENARIO_ARRAY,
SCENARIO_ARRAY_EMPTY,
SCENARIO_BOOL_TRUE,
SCENARIO_BOOL_FALSE,
]).describe("throws an EntityValidationError if the property is not valid.", (scenario) => {
it(`scenario: ${scenario.label}`, async () => {
expect.assertions(1);
const testObject = { property: scenario.data };
expect(() =>
EntitySchema.validate("TestObject", testObject, schemaValidateTypeString),
).toThrowEntityValidationError("property", "type");
});
});
each([
SCENARIO_EMPTY,
SCENARIO_STRING,
SCENARIO_STRING_UTF8,
SCENARIO_UUID,
SCENARIO_DATE_YEAR,
SCENARIO_DATE_YEAR_MONTH,
SCENARIO_DATE_YEAR_MONTH_DAY,
SCENARIO_DATE_YEAR_MONTH_DAY_TIME,
]).describe("validates if the property is valid.", (scenario) => {
it(`scenario: ${scenario.label}`, async () => {
expect.assertions(1);
const testObject = { property: scenario.data };
expect(() => EntitySchema.validate("TestObject", testObject, schemaValidateTypeString)).not.toThrow();
});
});
});
describe("::type::integer", () => {
each([
SCENARIO_NULL,
SCENARIO_UNDEFINED,
SCENARIO_FLOAT,
SCENARIO_OBJECT,
SCENARIO_ARRAY,
SCENARIO_ARRAY_EMPTY,
SCENARIO_BOOL_TRUE,
SCENARIO_BOOL_FALSE,
SCENARIO_EMPTY,
SCENARIO_STRING,
SCENARIO_UUID,
SCENARIO_DATE_YEAR,
SCENARIO_DATE_YEAR_MONTH,
SCENARIO_DATE_YEAR_MONTH_DAY,
SCENARIO_DATE_YEAR_MONTH_DAY_TIME,
]).describe("throws an EntityValidationError if the property is not valid.", (scenario) => {
it(`scenario: ${scenario.label}`, async () => {
expect.assertions(1);
const testObject = { property: scenario.data };
expect(() =>
EntitySchema.validate("TestObject", testObject, schemaValidateTypeInteger),
).toThrowEntityValidationError("property", "type");
});
});
each([SCENARIO_INTEGER]).describe("validates if the property is valid.", (scenario) => {
it(`scenario: ${scenario.label}`, async () => {
expect.assertions(1);
const testObject = { property: scenario.data };
expect(() => EntitySchema.validate("TestObject", testObject, schemaValidateTypeInteger)).not.toThrow();
});
});
});
describe("::type::number", () => {
each([
SCENARIO_NULL,
SCENARIO_UNDEFINED,
SCENARIO_OBJECT,
SCENARIO_ARRAY,
SCENARIO_ARRAY_EMPTY,
SCENARIO_BOOL_TRUE,
SCENARIO_BOOL_FALSE,
SCENARIO_EMPTY,
SCENARIO_STRING,
SCENARIO_UUID,
SCENARIO_DATE_YEAR,
SCENARIO_DATE_YEAR_MONTH,
SCENARIO_DATE_YEAR_MONTH_DAY,
SCENARIO_DATE_YEAR_MONTH_DAY_TIME,
]).describe("throws an EntityValidationError if the property is not valid.", (scenario) => {
it(`scenario: ${scenario.label}`, async () => {
expect.assertions(1);
const testObject = { property: scenario.data };
expect(() =>
EntitySchema.validate("TestObject", testObject, schemaValidateTypeNumber),
).toThrowEntityValidationError("property", "type");
});
});
each([SCENARIO_INTEGER, SCENARIO_FLOAT]).describe("validates if the property is valid.", (scenario) => {
it(`scenario: ${scenario.label}`, async () => {
expect.assertions(1);
const testObject = { property: scenario.data };
expect(() => EntitySchema.validate("TestObject", testObject, schemaValidateTypeNumber)).not.toThrow();
});
});
});
describe("::type::object", () => {
each([
SCENARIO_UNDEFINED,
/*
* @todo Entity schema validation should be strict
* SCENARIO_NULL,
* SCENARIO_ARRAY,
* SCENARIO_ARRAY_EMPTY,
*/
SCENARIO_BOOL_TRUE,
SCENARIO_BOOL_FALSE,
SCENARIO_INTEGER,
SCENARIO_FLOAT,
SCENARIO_EMPTY,
SCENARIO_STRING,
SCENARIO_UUID,
SCENARIO_DATE_YEAR,
SCENARIO_DATE_YEAR_MONTH,
SCENARIO_DATE_YEAR_MONTH_DAY,
SCENARIO_DATE_YEAR_MONTH_DAY_TIME,
]).describe("throws an EntityValidationError if the property is not valid.", (scenario) => {
it(`scenario: ${scenario.label}`, async () => {
expect.assertions(1);
const testObject = { property: scenario.data };
expect(() =>
EntitySchema.validate("TestObject", testObject, schemaValidateTypeObject),
).toThrowEntityValidationError("property", "type");
});
});
each([
SCENARIO_OBJECT,
// @todo Entity schema validation should be strict and the following should not validate.
SCENARIO_NULL,
SCENARIO_ARRAY,
SCENARIO_ARRAY_EMPTY,
]).describe("validates if the property is valid.", (scenario) => {
it(`scenario: ${scenario.label}`, async () => {
expect.assertions(1);
const testObject = { property: scenario.data };
expect(() => EntitySchema.validate("TestObject", testObject, schemaValidateTypeObject)).not.toThrow();
});
});
});
describe("::type::array", () => {
each([
SCENARIO_NULL,
SCENARIO_UNDEFINED,
SCENARIO_INTEGER,
SCENARIO_FLOAT,
SCENARIO_OBJECT,
SCENARIO_BOOL_TRUE,
SCENARIO_BOOL_FALSE,
SCENARIO_EMPTY,
SCENARIO_STRING,
SCENARIO_UUID,
SCENARIO_DATE_YEAR,
SCENARIO_DATE_YEAR_MONTH,
SCENARIO_DATE_YEAR_MONTH_DAY,
SCENARIO_DATE_YEAR_MONTH_DAY_TIME,
]).describe("throws an EntityValidationError if the property is not valid.", (scenario) => {
it(`scenario: ${scenario.label}`, async () => {
expect.assertions(1);
const testObject = { property: scenario.data };
expect(() =>
EntitySchema.validate("TestObject", testObject, schemaValidateTypeArray),
).toThrowEntityValidationError("property", "type");
});
});
each([SCENARIO_ARRAY, SCENARIO_ARRAY_EMPTY]).describe("validates if the property is valid.", (scenario) => {
it(`scenario: ${scenario.label}`, async () => {
expect.assertions(1);
const testObject = { property: scenario.data };
expect(() => EntitySchema.validate("TestObject", testObject, schemaValidateTypeArray)).not.toThrow();
});
});
});
describe.skip("::type::blob", () => {
// @todo
});
});
/*
* *************************************************************
* String assertions
***************************************************************
*/
describe("::format", () => {
it("throws an error if format is not supported", () => {
expect.assertions(1);
expect(() => EntitySchema.validate("TestObject", { property: "" }, schemaValidateFormatInvalid)).toThrow(
"EntitySchema string validation format invalid is not supported.",
);
});
describe("::format::uuid", () => {
each([
SCENARIO_EMPTY,
SCENARIO_STRING,
SCENARIO_STRING_UTF8,
SCENARIO_DATE_YEAR,
SCENARIO_DATE_YEAR_MONTH,
SCENARIO_DATE_YEAR_MONTH_DAY,
SCENARIO_DATE_YEAR_MONTH_DAY_TIME,
]).describe("throws an EntityValidationError if the property is not valid.", (scenario) => {
it(`scenario: ${scenario.label}`, async () => {
expect.assertions(1);
const testObject = { property: scenario.data };
expect(() =>
EntitySchema.validate("TestObject", testObject, schemaValidateFormatUuid),
).toThrowEntityValidationError("property", "format");
});
});
each([SCENARIO_UUID]).describe("validates if the property is valid.", (scenario) => {
it(`scenario: ${scenario.label}`, async () => {
expect.assertions(1);
const testObject = { property: scenario.data };
expect(() => EntitySchema.validate("TestObject", testObject, schemaValidateFormatUuid)).not.toThrow();
});
});
});
describe("::format::date-time", () => {
each([
SCENARIO_EMPTY,
SCENARIO_STRING,
SCENARIO_STRING_UTF8,
SCENARIO_UUID,
{ label: "Date expressed in common language", data: "yesterday" },
]).describe("throws an EntityValidationError if the property is not valid.", (scenario) => {
it(`scenario: ${scenario.label}`, async () => {
expect.assertions(1);
const testObject = { property: scenario.data };
expect(() =>
EntitySchema.validate("TestObject", testObject, schemaValidateFormatDateTime),
).toThrowEntityValidationError("property", "format");
});
});
each([
SCENARIO_DATE_YEAR,
SCENARIO_DATE_YEAR_MONTH,
SCENARIO_DATE_YEAR_MONTH_DAY,
SCENARIO_DATE_YEAR_MONTH_DAY_TIME,
]).describe("validates if the property is valid.", (scenario) => {
it(`scenario: ${scenario.label}`, async () => {
expect.assertions(1);
const testObject = { property: scenario.data };
expect(() => EntitySchema.validate("TestObject", testObject, schemaValidateFormatDateTime)).not.toThrow();
});
});
});
describe("::format::email", () => {
each([
SCENARIO_EMPTY,
SCENARIO_STRING,
SCENARIO_STRING_UTF8,
SCENARIO_UUID,
SCENARIO_DATE_YEAR,
SCENARIO_DATE_YEAR_MONTH,
SCENARIO_DATE_YEAR_MONTH_DAY,
SCENARIO_DATE_YEAR_MONTH_DAY_TIME,
{ label: "abc@example", data: "abc@example" },
{ label: "@example.com", data: "@example.com" },
{ label: "abc@", data: "abc@" },
{ label: "abc@example.c", data: "abc@example.c" },
{ label: "abc@example.com.", data: "abc@example.com." },
{ label: "abc.@example.com", data: "abc.@example.com" },
{ label: "abc@example..com", data: "abc@example..com" },
{ label: "abc@example.com.a", data: "abc@example.com.a" },
{ label: "abc;@example.com", data: "abc;@example.com" },
{ label: "abc@example.com;", data: "abc@example.com;" },
{ label: "abc@efg@example.com", data: "abc@efg@example.com" },
{ label: "abc@@example.com", data: "abc@@example.com" },
{ label: "abc efg@example.com", data: "abc efg@example.com" },
{ label: "abc,efg@example.com", data: "abc,efg@example.com" },
{ label: "abc@sub,example.com", data: "abc@sub,example.com" },
{ label: "abc@sub'example.com", data: "abc@sub'example.com" },
{ label: "abc@sub/example.com", data: "abc@sub/example.com" },
{ label: "abc@yahoo!.com", data: "abc@yahoo!.com" },
{ label: "abc@example_underscored.com", data: "abc@example_underscored.com" },
{ label: "raw@test.ra.ru....com", data: "raw@test.ra.ru....com" },
/*
* @todo Cleanup: does not validate in IsEmailValidator custom regex, but validate with the library Validator.isEmail
* {label: "ÊXÃMPLÊ@HÕST.ÇÕM", data: "ÊXÃMPLÊ@HÕST.ÇÕM"},
*/
]).describe("throws an EntityValidationError if the property is not valid.", (scenario) => {
it(`scenario: ${scenario.label}`, async () => {
expect.assertions(1);
const testObject = { property: scenario.data };
expect(() =>
EntitySchema.validate("TestObject", testObject, schemaValidateFormatEmail),
).toThrowEntityValidationError("property", "format");
});
});
each([
{ label: "abc.efg@domain.com", data: "abc.efg@domain.com" },
{ label: "efg@domain.com", data: "efg@domain.com" },
{ label: "abc-efg@domain.com", data: "abc-efg@domain.com" },
{ label: "abc_efg@domain.com", data: "abc_efg@domain.com" },
{ label: "raw@test.ra.ru", data: "raw@test.ra.ru" },
{ label: "abc-efg@domain-hyphened.com", data: "abc-efg@domain-hyphened.com" },
{ label: "p.o'malley@domain.com", data: "p.o'malley@domain.com" },
{ label: "abc+efg@domain.com", data: "abc+efg@domain.com" },
{ label: "abc&efg@domain.com", data: "abc&efg@domain.com" },
{ label: "abc.efg@12345.com", data: "abc.efg@12345.com" },
{ label: "abc.efg@12345.co.jp", data: "abc.efg@12345.co.jp" },
{ label: "abc@g.cn", data: "abc@g.cn" },
{ label: "abc@x.com", data: "abc@x.com" },
{ label: "henrik@sbcglobal.net", data: "henrik@sbcglobal.net" },
{ label: "sani@sbcglobal.net", data: "sani@sbcglobal.net" },
// all ICANN TLDs
{ label: "abc@example.aero", data: "abc@example.aero" },
{ label: "abc@example.asia", data: "abc@example.asia" },
{ label: "abc@example.biz", data: "abc@example.biz" },
{ label: "abc@example.cat", data: "abc@example.cat" },
{ label: "abc@example.com", data: "abc@example.com" },
{ label: "abc@example.coop", data: "abc@example.coop" },
{ label: "abc@example.edu", data: "abc@example.edu" },
{ label: "abc@example.gov", data: "abc@example.gov" },
{ label: "abc@example.info", data: "abc@example.info" },
{ label: "abc@example.int", data: "abc@example.int" },
{ label: "abc@example.jobs", data: "abc@example.jobs" },
{ label: "abc@example.mil", data: "abc@example.mil" },
{ label: "abc@example.mobi", data: "abc@example.mobi" },
{ label: "abc@example.museum", data: "abc@example.museum" },
{ label: "abc@example.name", data: "abc@example.name" },
{ label: "abc@example.net", data: "abc@example.net" },
{ label: "abc@example.org", data: "abc@example.org" },
{ label: "abc@example.pro", data: "abc@example.pro" },
{ label: "abc@example.tel", data: "abc@example.tel" },
{ label: "abc@example.travel", data: "abc@example.travel" },
{ label: "someone@st.t-com.hr", data: "someone@st.t-com.hr" },
// gTLD's
{ label: "example@host.local", data: "example@host.local" },
{ label: "example@x.org", data: "example@x.org" },
{ label: "example@host.xxx", data: "example@host.xxx" },
// strange, but technically valid email addresses
{
label: "S=postmaster/OU=rz/P=uni-frankfurt/A=d400/C=de@gateway.d400.de",
data: "S=postmaster/OU=rz/P=uni-frankfurt/A=d400/C=de@gateway.d400.de",
},
{ label: "customer/department=shipping@example.com", data: "customer/department=shipping@example.com" },
{ label: "$A12345@example.com", data: "$A12345@example.com" },
{ label: "!def!xyz%abc@example.com", data: "!def!xyz%abc@example.com" },
{ label: "_somename@example.com", data: "_somename@example.com" },
// Unicode
{ label: "some@eräume.foo", data: "some@eräume.foo" },
{ label: "äu@öe.eräume.foo", data: "äu@öe.eräume.foo" },
{ label: "Nyrée.surname@example.com", data: "Nyrée.surname@example.com" },
// Uppercase
{ label: "example@host.COM", data: "example@host.COM" },
{ label: "example@HOST.ORG", data: "example@HOST.ORG" },
{ label: "EXAMPLE@HOST.LU", data: "EXAMPLE@HOST.LU" },
{ label: "ÊXÃMPLÊ@HÕST.LU", data: "ÊXÃMPLÊ@HÕST.LU" },
// @todo Cleanup: does not validate in IsEmailValidator custom regex, but validate with the library Validator.isEmail
{ label: "ÊXÃMPLÊ@HÕST.ÇÕM", data: "ÊXÃMPLÊ@HÕST.ÇÕM" },
]).describe("validates if the property is valid.", (scenario) => {
it(`scenario: ${scenario.label}`, async () => {
expect.assertions(1);
const testObject = { property: scenario.data };
expect(() => EntitySchema.validate("TestObject", testObject, schemaValidateFormatEmail)).not.toThrow();
});
});
});
describe("::format::x-hex-color", () => {
each([
{ label: "", data: "" },
{ label: "#012#01", data: "#012#01" },
{ label: "##01201", data: "##01201" },
{ label: "012#", data: "012#" },
{ label: "#01", data: "#01" },
{ label: "34", data: "34" },
{ label: "#1", data: "#1" },
{ label: "2", data: "2" },
{ label: "#12345", data: "#12345" },
{ label: "12345", data: "12345" },
{ label: "#1234567", data: "#1234567" },
{ label: "1234567", data: "1234567" },
{ label: "#123456789", data: "#123456789" },
{ label: "123456789", data: "123456789" },
{ label: "#abcdefgh", data: "#abcdefgh" },
{ label: "abcdefgh", data: "abcdefgh" },
]).describe("throws an EntityValidationError if the property is not valid.", (scenario) => {
it(`scenario: ${scenario.label}`, async () => {
expect.assertions(1);
const testObject = { property: scenario.data };
expect(() =>
EntitySchema.validate("TestObject", testObject, schemaValidateFormatXHexColor),
).toThrowEntityValidationError("property", "format");
});
});
each([
{ label: "#012", data: "#012" },
{ label: "345", data: "345" },
{ label: "#678", data: "#678" },
{ label: "9aB", data: "9aB" },
{ label: "#cDeF01", data: "#cDeF01" },
{ label: "234567", data: "234567" },
{ label: "#89aBcDeF", data: "#89aBcDeF" },
{ label: "01234567", data: "01234567" },
]).describe("validates if the property is valid.", (scenario) => {
it(`scenario: ${scenario.label}`, async () => {
expect.assertions(1);
const testObject = { property: scenario.data };
expect(() => EntitySchema.validate("TestObject", testObject, schemaValidateFormatXHexColor)).not.toThrow();
});
});
});
describe("::format::x-base64", () => {
each([
{ label: "aGVsbG8gcGFzc2JvbHQ", data: "aGVsbG8gcGFzc2JvbHQ" },
{ label: "aGVsbG8gcG==Fzc2JvbHQ", data: "aGVsbG8gcG==Fzc2JvbHQ" },
{ label: "==aGVsbG8gcGFzc2JvbHQ", data: "==aGVsbG8gcGFzc2JvbHQ" },
{ label: "$€`£ù%*:", data: "$€`£ù%*:" },
]).describe("throws an EntityValidationError if the property is not valid.", (scenario) => {
it(`scenario: ${scenario.label}`, async () => {
expect.assertions(1);
const testObject = { property: scenario.data };
expect(() =>
EntitySchema.validate("TestObject", testObject, schemaValidateFormatXBase64),
).toThrowEntityValidationError("property", "format");
});
});
each([
{ label: "aGVsbG8gcGFzc2JvbHQ=", data: "aGVsbG8gcGFzc2JvbHQ=" },
{ label: "aGVsbG8gcGFzc2JvbHQ+", data: "aGVsbG8gcGFzc2JvbHQ+" },
{
label: "aHR0cHM6Ly93d3cueW91dHViZS5jb20vd2F0Y2g/dj02LUhVZ3pZUG05Zw==",
data: "aHR0cHM6Ly93d3cueW91dHViZS5jb20vd2F0Y2g/dj02LUhVZ3pZUG05Zw==",
},
]).describe("validates if the property is valid.", (scenario) => {
it(`scenario: ${scenario.label}`, async () => {
expect.assertions(1);
const testObject = { property: scenario.data };
expect(() => EntitySchema.validate("TestObject", testObject, schemaValidateFormatXBase64)).not.toThrow();
});
});
});
});
describe("::enum", () => {
it("throws if the prop value is not part of the enum list.", () => {
expect.assertions(1);
const testObject = { property: "invalid" };
expect(() => EntitySchema.validate("TestObject", testObject, schemaValidateEnum)).toThrowEntityValidationError(
"property",
"enum",
);
});
it("validates if part of the valid enum list.", () => {
expect.assertions(2);
const schema = schemaValidateEnum;
// Validate first item.
let testObject = { property: "value1" };
expect(() => EntitySchema.validate("TestObject", testObject, schema)).not.toThrow();
// Validate first item.
testObject = { property: "value2" };
expect(() => EntitySchema.validate("TestObject", testObject, schema)).not.toThrow();
});
});
describe("::minLength", () => {
it("throws if the prop value length does not validate.", () => {
expect.assertions(1);
const testObject = { property: "12" };
expect(() =>
EntitySchema.validate("TestObject", testObject, schemaValidateMinLength),
).toThrowEntityValidationError("property", "minLength");
});
it("validates if the prop value length is above the minimum requirements.", () => {
expect.assertions(1);
const testObject = { property: "123" };
expect(() => EntitySchema.validate("TestObject", testObject, schemaValidateMinLength)).not.toThrow();
});
});
describe("::maxLength", () => {
it("throws if the prop value length does not validate.", () => {
expect.assertions(1);
const testObject = { property: "1234" };
expect(() =>
EntitySchema.validate("TestObject", testObject, schemaValidateMaxLength),
).toThrowEntityValidationError("property", "maxLength");
});
it("validates if the prop value length is bellow the minimum requirements.", () => {
expect.assertions(1);
const testObject = { property: "123" };
expect(() => EntitySchema.validate("TestObject", testObject, schemaValidateMaxLength)).not.toThrow();
});
});
describe("::minimum", () => {
describe("::type::number", () => {
it("throws if the prop value is lesser than expected.", () => {
expect.assertions(1);
const testObject = { property: 12 };
expect(() =>
EntitySchema.validate("TestObject", testObject, schemaValidateMinimumNumberValue),
).toThrowEntityValidationError("property", "minimum");
});
it("validates if the prop value length is above the minimum requirements.", () => {
expect.assertions(1);
const testObject = { property: 123 };
expect(() => EntitySchema.validate("TestObject", testObject, schemaValidateMinimumNumberValue)).not.toThrow();
});
});
describe("::type::integer", () => {
it("throws if the prop value is lesser than expected.", () => {
expect.assertions(1);
const testObject = { property: 12 };
expect(() =>
EntitySchema.validate("TestObject", testObject, schemaValidateMinimumIntegerValue),
).toThrowEntityValidationError("property", "minimum");
});
it("validates if the prop value length is above the minimum requirements.", () => {
expect.assertions(1);
const testObject = { property: 123 };
expect(() =>
EntitySchema.validate("TestObject", testObject, schemaValidateMinimumIntegerValue),
).not.toThrow();
});
});
});
describe("::maximum", () => {
describe("::type::number", () => {
it("throws if the prop value is lesser than expected.", () => {
expect.assertions(1);
const testObject = { property: 123 };
expect(() =>
EntitySchema.validate("TestObject", testObject, schemaValidateMaximumNumberValue),
).toThrowEntityValidationError("property", "maximum");
});
it("validates if the prop value length is above the minimum requirements.", () => {
expect.assertions(1);
const testObject = { property: 12 };
expect(() => EntitySchema.validate("TestObject", testObject, schemaValidateMaximumNumberValue)).not.toThrow();
});
});
describe("::type::integer", () => {
it("throws if the prop value is lesser than expected.", () => {
expect.assertions(1);
const testObject = { property: 123 };
expect(() =>
EntitySchema.validate("TestObject", testObject, schemaValidateMaximumIntegerValue),
).toThrowEntityValidationError("property", "maximum");
});
it("validates if the prop value length is above the minimum requirements.", () => {
expect.assertions(1);
const testObject = { property: 12 };
expect(() =>
EntitySchema.validate("TestObject", testObject, schemaValidateMaximumIntegerValue),
).not.toThrow();
});
});
});
describe("::pattern", () => {
it("throws if the prop value length does not validate.", () => {
expect.assertions(1);
const testObject = { property: "1+3" };
expect(() =>
EntitySchema.validate("TestObject", testObject, schemaValidatePattern),
).toThrowEntityValidationError("property", "pattern");
});
it("validates if the prop value length is bellow the minimum requirements.", () => {
expect.assertions(1);
const testObject = { property: "123" };
expect(() => EntitySchema.validate("TestObject", testObject, schemaValidatePattern)).not.toThrow();
});
});
});
describe("::validateArray", () => {
describe("::items", () => {
it("throws if the prop value is not an array.", () => {
expect.assertions(1);
const testArray = {};
expect(() =>
EntitySchema.validate("TestArray", testArray, schemaValidateSimpleArray),
).toThrowEntityValidationError("items", "type", "The items is not a valid array.");
});
it("validates if the prop value items is empty.", () => {
expect.assertions(1);
const testArray = [];
expect(() => EntitySchema.validate("TestArray", testArray, schemaValidateSimpleArray)).not.toThrow();
});
it("validates if the prop value items is not empty.", () => {
expect.assertions(1);
const testArray = [{ items: 123 }];
expect(() => EntitySchema.validate("TestArray", testArray, schemaValidateSimpleArray)).not.toThrow();
});
});
describe("::minItems", () => {
it("throws if the prop value is lesser than expected.", () => {
expect.assertions(1);
const testArray = [];
expect(() =>
EntitySchema.validate("TestArray", testArray, schemaValidateMinItemsArrayValue),
).toThrowEntityValidationError("minItems");
});
it("validates if the prop value length is above the minimum requirements.", () => {
expect.assertions(1);
const testArray = [{ items: 123 }];
expect(() => EntitySchema.validate("TestArray", testArray, schemaValidateMinItemsArrayValue)).not.toThrow();
});
});
});
});