Comparing version 8.2.0 to 8.3.1
@@ -65,2 +65,3 @@ /* eslint-disable prettier/prettier */ | ||
function isRegExp(v) { return v instanceof RegExp; } | ||
function isError(v) { return v instanceof Error; } | ||
function isSymbol(v) { return typeof v === "symbol"; } | ||
@@ -114,2 +115,3 @@ function isAny() { return true; } | ||
isRegExp.desc = "regular expression" | ||
isError.desc = "error" | ||
isSymbol.desc = "symbol" | ||
@@ -193,2 +195,4 @@ isAny.desc = "any" | ||
"regexp": isRegExp, | ||
"err": isError, | ||
"error": isError, | ||
"symbol": isSymbol, | ||
@@ -195,0 +199,0 @@ |
@@ -21,3 +21,3 @@ const ValueError = require("../errors/ValueError"); | ||
// Throw either checker.error or error with standardised message. | ||
throwError(checker.error || error, `Must be ${checker.desc}`, value, prefix); | ||
throwError(checker.error || error, `${checker.prefix || "Must be"} ${checker.desc}`, value, prefix); | ||
} | ||
@@ -104,5 +104,5 @@ | ||
// Check args. | ||
runChecker(this.checkers.string, description, "check(): description", BlorkError); | ||
if (prefix) runChecker(this.checkers.string, prefix, "check(): prefix", BlorkError); | ||
if (error) runChecker(this.checkers.function, error, "check(): error", BlorkError); | ||
runChecker(this.checkers.string, description, "assert(): description", BlorkError); | ||
if (prefix) runChecker(this.checkers.string, prefix, "assert(): prefix", BlorkError); | ||
if (error) runChecker(this.checkers.function, error, "assert(): error", BlorkError); | ||
@@ -148,4 +148,4 @@ // Enforce assertion. | ||
runChecker(this.checkers.array, types, "args(): types", BlorkError); | ||
if (prefix) runChecker(this.checkers.string, prefix, "add(): prefix", BlorkError); | ||
if (error) runChecker(this.checkers.function, error, "add(): error", BlorkError); | ||
if (prefix) runChecker(this.checkers.string, prefix, "args(): prefix", BlorkError); | ||
if (error) runChecker(this.checkers.function, error, "args(): error", BlorkError); | ||
@@ -152,0 +152,0 @@ // Recurse into each type. |
@@ -32,5 +32,10 @@ const format = require("../helpers/format"); | ||
if (frame) { | ||
// Prepend the caller function name to the prefix, e.g. "name" → "MyClass.myFunc(): name" | ||
/* istanbul ignore else */ | ||
if (frame.function) prefix = prefix ? `${frame.function}: ${prefix}` : frame.function; | ||
// Was this not called by an anonymous function? | ||
if (frame.function) { | ||
// Prepend the calling function name to the prefix, e.g. "name" → "MyClass.myFunc(): name" | ||
if (!prefix) prefix = frame.function; | ||
else if (prefix.indexOf(": ") === -1) | ||
// Skip any prefixes that already have a ':' colon. | ||
prefix = `${frame.function}: ${prefix}`; | ||
} | ||
// Update file, line, column. | ||
@@ -37,0 +42,0 @@ this.fileName = frame.file; |
@@ -22,18 +22,28 @@ const destack = require("./destack"); | ||
// Loop through the frames (stop at end-minus-1 because we need there to be a next frame). | ||
for (let i = 0; i < frames.length - 2; i++) { | ||
// Remove this frame from the lines. | ||
const j = lines.indexOf(frames[i].original); | ||
/* istanbul ignore else */ | ||
if (j >= 0) lines.splice(j, 1); | ||
// Whether to return the next frame in the loop with a named function. | ||
let returnNextNamed = false; | ||
// Loop through the frames. | ||
for (let i = 0; i < frames.length; i++) { | ||
// Does the function name include "Blorker$" | ||
if (frames[i].function.indexOf("Blorker$") >= 0) { | ||
// Return NEXT frame (with a recombined stack property) | ||
return Object.assign({ stack: lines.join("\n") }, frames[i + 1]); | ||
// Return the next named function. | ||
returnNextNamed = true; | ||
} else if (returnNextNamed && frames[i].function) { | ||
// Return this frame (if the previous frame had a function named Blorker$etc and this frame has a named function). | ||
// Recreate the stack property ignoring all lines above this. | ||
frames[i].stack = lines.join("\n"); | ||
// Return this frame. | ||
return frames[i]; | ||
} | ||
// Remove this line from the stack. | ||
const j = lines.indexOf(frames[i].original); | ||
/* istanbul ignore else */ | ||
if (j >= 0) lines.splice(j, 1); | ||
} | ||
// Otherwise return the first frame. | ||
return Object.assign({ stack: stack }, frames[0]); | ||
frames[0].stack = stack; | ||
return frames[0]; | ||
} | ||
@@ -40,0 +50,0 @@ } |
@@ -376,2 +376,3 @@ const debug = require("../helpers/debug"); | ||
checker.desc = number.toString(); | ||
checker.string = number.toString(); | ||
@@ -433,3 +434,23 @@ // Return the checker. | ||
} | ||
}, | ||
// Return type. | ||
// Changes error message from e.g. "Must be string" to "Must return string" | ||
{ | ||
start: "return ", | ||
callback(type, find) { | ||
// Get normal checker. | ||
const valueChecker = find(type); | ||
// Create a checker. | ||
const checker = v => valueChecker(v); | ||
// Checker settings. | ||
checker.desc = valueChecker.desc; | ||
checker.prefix = "Must return"; | ||
// Return it. | ||
return checker; | ||
} | ||
} | ||
]; |
{ | ||
"name": "blork", | ||
"description": "Blork! Mini runtime type checking in Javascript", | ||
"version": "8.2.0", | ||
"version": "8.3.1", | ||
"license": "0BSD", | ||
@@ -25,2 +25,3 @@ "author": "Dave Houlbrooke <dave@shax.com>", | ||
"watch": "jest --watchAll", | ||
"jest": "jest --coverage", | ||
"test": "jest --coverage", | ||
@@ -27,0 +28,0 @@ "lint": "eslint ./", |
130
README.md
@@ -17,4 +17,39 @@ # Blork! Mini runtime type checking in Javascript | ||
## Usage | ||
## Canonical example | ||
The perfect use case for Blork is where you need to validate the input for a library function in a neat and clear way — with error messages that actually help developers fix the mistake! | ||
```js | ||
// findStrings.js | ||
import { check } from "blork"; | ||
// 1. Make a function that needs its arguments validated. | ||
function findStrings(haystack, needles, startIndex = 0, caseSensitive = false) { | ||
// Check the args. | ||
check(haystack, "str", "haystack"); // Must be string. | ||
check(needles, "str+|str+[]+", "needles"); // Must be non-empty string or non-empty array of non-empty strings. | ||
check(startIndex, "int{1,}", "startIndex"); // Must be integer greater than 1. | ||
check(caseSensitive, "bool", "caseSensitive"); // Must be boolean true or false. | ||
// ...etc | ||
return etc; | ||
} | ||
// 2. Call the function we made with valid arguments. | ||
const sentence = "These dogs and cats are the best."; | ||
const finds = findStrings(sentence, ["dogs", "cats", "best"], 6, true); | ||
// 3. Call the function with invalid arguments. | ||
// This will throw TypeError "findStrings(): haystack: Must be string (received 1234)" | ||
const nope1 = findStrings(1234); | ||
// This will throw TypeError "findStrings(): needles: Must be non-empty array containing non-empty string (received ["dogs", 1234])" | ||
const nope1 = findStrings("Nopes", ["dogs", 1234]); | ||
// This will throw TypeError "findStrings(): startIndex: Must be integer (minimum 1) (received 0)" | ||
const nope2 = findStrings("Nopes", ["dogs"], 0); | ||
// This will throw TypeError "findStrings(): caseSensitive: Must be boolean (received null)" | ||
const nope2 = findStrings("Nopes", ["dogs"], 0, null); | ||
``` | ||
## Usage guide | ||
### check(): Check individual values | ||
@@ -58,2 +93,3 @@ | ||
- Appending a `+` means non-empty (e.g. `arr+` `str+` means non-empty arrays and strings respectively). | ||
- ...and many more | ||
@@ -96,7 +132,7 @@ ```js | ||
check([1, "a"], "[int, str]"); // No error. | ||
check([1, false], "[int, str]"); // Throws ValueError "Must be plain array tuple containing integer, string (received [1, false])" | ||
check([1, false], "[int, str]"); // Throws ValueError "Must be plain array tuple like [integer, string] (received [1, false])" | ||
// Object types. | ||
check({ a: 1 }, "{ camel: integer }"); // No error. | ||
check({ "$": 1 }, "{ camel: integer }"); // Throws ValueError "Must be plain object with camelCase string keys containing integer (received { "$": 1 })" | ||
check({ "$": 1 }, "{ camel: integer }"); // Throws ValueError "Must be plain object like { camelCase string: integer } (received { "$": 1 })" | ||
@@ -428,2 +464,3 @@ // String literal types. | ||
| `regex`, `regexp` | Instances of **RegExp** (regular expressions) | ||
| `error`, `err` | Instances of **Error** | ||
| `symbol` | Value is **Symbol** (using **typeof**) | ||
@@ -454,2 +491,4 @@ | `empty` | Value is empty (e.g. **v.length === 0** (string/array), **v.size === 0** (Map/Set), `Object.keys(v) === 0` (objects), or `!v` (anything else) | ||
### String modifiers - array type | ||
Any string type can be made into an array of that type by appending `[]` brackets to the type reference. This means the check looks for a plain array whose contents only include the specified type. | ||
@@ -465,7 +504,9 @@ | ||
// Fail. | ||
check([1, 2], "str[]"); // Throws ValueError "Must be plain array containing: string (received [1, 2])" | ||
check(["a"], "int[]"); // Throws ValueError "Must be plain array containing: integer (received ["a"])" | ||
check([], "int[]+"); // Throws ValueError "Must be non-empty plain array containing: integer (received [])" | ||
check([1, 2], "str[]"); // Throws ValueError "Must be plain array containing string (received [1, 2])" | ||
check(["a"], "int[]"); // Throws ValueError "Must be plain array containing integer (received ["a"])" | ||
check([], "int[]+"); // Throws ValueError "Must be non-empty plain array containing integer (received [])" | ||
``` | ||
### String modifiers - tuple type | ||
Array tuples can be specified by surrounding types in `[]` brackets. | ||
@@ -480,30 +521,63 @@ | ||
// Fail. | ||
check([true, true], "[str, str]") // Throws ValueError "Must be plain array tuple containing: string, string (received [true, true])" | ||
check([true], "[bool, bool]") // Throws ValueError "Must be plain array tuple containing: boolean, boolean (received [true])" | ||
check(["a", "b", "c"], "[str, str]") // Throws ValueError "Must be plain array tuple containing: string, string (received ["a", "b", "c"])" | ||
check([true, true], "[str, str]") // Throws ValueError "Must be plain array tuple like [string, string] (received [true, true])" | ||
check([true], "[bool, bool]") // Throws ValueError "Must be plain array tuple like [boolean, boolean] (received [true])" | ||
check(["a", "b", "c"], "[str, str]") // Throws ValueError "Must be plain array tuple like [string, string] (received ["a", "b", "c"])" | ||
``` | ||
Check for objects only containing strings of a specified type by surrounding the type in `{}` braces. This means the check looks for a plain object whose contents only include the specified type (whitespace is optional). | ||
### String modifiers - object type | ||
Check for objects only containing strings of a specified type by surrounding the type in `{}` braces. This means the check looks for a plain object whose contents only include the specified type (whitespace is optional). If you specify multiple props (separated by commas) they are treated like `OR` conditions. | ||
```js | ||
// Pass. | ||
check({ a: "a", b: "b" }, "{str}"); // No error. | ||
check({ a: 1, b: 2 }, "{int}"); // No error. | ||
check({ a: 1, b: 2 }, "{ int }"); // No error. | ||
check({}, "{int}"); // No error (empty is fine). | ||
check({ a: 1 }, "{int}+"); // No error (non-empty). | ||
check({ a: 1, b: "B" }, "{ int, str }"); // No error (integers or strings are fine). | ||
// Fail. | ||
check({ a: 1, b: 2 }, "{str}"); // Throws ValueError "Must be plain object containing: string (received [1, 2])" | ||
check({ a: "a" }, "{int}"); // Throws ValueError "Must be plain object containing: integer (received ["a"])" | ||
check({}, "{int}+"); // Throws ValueError "Must be non-empty plain object containing: integer (received [])" | ||
check({ a: 1, b: 2 }, "{str}"); // Throws ValueError "Must be plain object like { string: string } (received { a: 1, b: 2 })" | ||
check({ a: "a" }, "{ int }"); // Throws ValueError "Must be plain object like { string: integer } (received { a: "a" })" | ||
check({}, "{int}+"); // Throws ValueError "Must be non-empty plain object like { string: integer } (received {})" | ||
``` | ||
A type for the keys can also be specified by using `{ key: value }` format. | ||
A type for the keys can also be specified by using `{ key: value }` format. Again multiple props can be specified separated by commas. | ||
```js | ||
// Pass. | ||
check({ myVar: 123 }, "{ camel: integer }"); | ||
check({ "my-var": 123 }, "{ kebab: integer }"); | ||
check({ myVar: 123 }, "{ camel: int }"); // No error (key is camelCase). | ||
check({ "my-var": 123 }, "{ kebab: int }"); // No error (key is kebab-case). | ||
check({ "YAS": 123 }, "{ upper: bool }"); // No error (key is UPPERCASE). | ||
check({ a: 1, B: true }, "{ lower: int, upper: bool }"); // No error (a is lowercase and integer, B is UPPERCASE and boolean). | ||
// Fail. | ||
check({ "myVar": 123 }, "{ kebab: int }"); // Throws ValueError "Must be plain object like { kebab-case string: integer } (received { "myVar": 123 })" | ||
check({ "nope": true }, "{ upper: bool }"); // Throws ValueError "Must be plain object like { UPPERCASE string: boolean } (received { "nope": true })" | ||
``` | ||
Exact props can be specified by wrapping the key string in quotes (single or double). | ||
```js | ||
// Pass. | ||
check({ name: "Dave" }, '{ "name": str }'); | ||
check({ name: "Dave", age: 48 }, '{ "name": str, "age": int }'); | ||
// Fail. | ||
check({ name: 123 }, '{ "name": str }'); // Throws ValueError "Must be plain object like { "name": string } (received etc)"... | ||
check({ name: "Dave", age: "123" }, '{ "name": str, "age": int }'); // Throws ValueError "Must be plain object like { "name": string, "age": integer } (received etc)" | ||
``` | ||
Exact prop checkers and normal checkers can be mixed in the same string type. If an exact key is specified it will be favoured. | ||
```js | ||
// Pass. | ||
check({ name: "Dave", a: 1, b: 2 }, '{ "name": str, lower: int }'); | ||
// Fail. | ||
check({ name: "Dave", a: 1, b: false }, '{ "name": str, lower: int }'); // Throws ValueError "Must be plain object like { "name": string, lowercase string: integer } (received etc)" | ||
``` | ||
### String modifiers - optional type | ||
Any string type can be made optional by appending a `?` question mark to the type reference. This means the check will also accept `undefined` in addition to the specified type. | ||
@@ -523,2 +597,4 @@ | ||
### String modifiers - non-empty type | ||
Any type can be made non-empty by appending a `+` plus sign to the type reference. This means the check will only pass if the value is non-empty. Specifically this works as follows: | ||
@@ -545,2 +621,4 @@ | ||
### String modifiers - size type | ||
To specify a size for the type, you can prepend minimum/maximum with e.g. `{12}`, `{4,8}`, `{4,}` or `{,8}` (e.g. RegExp style quantifiers). This allows you to specify e.g. a string with 12 characters, an array with between 10 and 20 items, or an integer with a minimum value of 4. | ||
@@ -562,2 +640,4 @@ | ||
### String modifiers - inverted type | ||
Any string type can inverted by prepending a `!` exclamation mark to the type reference. This means the check will only pass if the _inverse_ of its type is true. | ||
@@ -578,2 +658,4 @@ | ||
### String modifiers - OR and AND combined types and grouped types | ||
You can use `&` and `|` to join string types together, to form AND and OR chains of allowed types. This allows you to compose together more complex types like `number | string` or `date | number | null` or `string && custom-checker` | ||
@@ -610,3 +692,3 @@ | ||
`()` parentheses can be used to create a 'grouped type'. This is useful to specify an array that allows several types, to make an invert/optional type of several types, or to state an explicit precence order for `&` and `|`. | ||
`()` parentheses can be used to create a 'grouped type' which is useful to specify an array that allows several types, to make an invert/optional type of several types, or to state an explicit precence order for `&` and `|`. | ||
@@ -778,3 +860,3 @@ ```js | ||
Similarly, to check the format of tuples, pass an array with two or more items as the type. _If two or more types are in an type array, it is considered a tuple type and will be rejected if it does not conform exactly to the tuple._ | ||
Similarly to check the format of tuples pass an array with two or more items as the type. _If two or more types are in an type array, it is considered a tuple type and will be rejected if it does not conform exactly to the tuple._ | ||
@@ -796,8 +878,14 @@ ```js | ||
## Roadmap | ||
## Roadmap and ideas | ||
- [ ] Support `@decorator` syntax for class methods (PRs welcome) | ||
- [ ] Support `@decorator` syntax for class methods | ||
- [ ] Allow `args()` to accept a string type e.g. in the format `"str, num, bool"` | ||
## Changelog | ||
- 8.3.0 | ||
- Add an error string checker, e.g. `check(new TypeError(), "error")` | ||
- When ValueError auto-prefixes the name of the calling function, it skips anonymous functions in the stack | ||
- When ValueError auto-prefixes the name of the calling function, it doesn't if the prefix already includes a ': ' colon space. | ||
- Add return string type modifier, e.g. `check(123, `return num`)` (changes error message to e.g. `Must return X`) | ||
- 8.2.0 | ||
@@ -804,0 +892,0 @@ - Add string string type, e.g. `"abc"` |
@@ -91,2 +91,4 @@ const checkers = require("../../lib/checkers/checkers"); | ||
expect(mockCheck(/[abc]+/g, "regex")).toBe(undefined); | ||
expect(mockCheck(new Error("abc"), "err")).toBe(undefined); | ||
expect(mockCheck(new TypeError("abc"), "error")).toBe(undefined); | ||
expect(mockCheck(Symbol(), "symbol")).toBe(undefined); | ||
@@ -189,2 +191,4 @@ | ||
expect(() => mockCheck("/[abc]+/g", "regex")).toThrow(TypeError); | ||
expect(() => mockCheck("abc", "err")).toThrow(TypeError); | ||
expect(() => mockCheck(false, "error")).toThrow(TypeError); | ||
expect(() => mockCheck("symbol", "symbol")).toThrow(TypeError); | ||
@@ -191,0 +195,0 @@ |
@@ -442,2 +442,16 @@ const BlorkError = require("../../lib/errors/BlorkError"); | ||
}); | ||
describe("Return types", () => { | ||
test("Return types pass correctly", () => { | ||
expect(check("a", "return string")).toBe(undefined); | ||
expect(check(123, "return number")).toBe(undefined); | ||
}); | ||
test("Return types fail correctly", () => { | ||
expect(() => check(123, "return string")).toThrow(TypeError); | ||
expect(() => check("a", "return number")).toThrow(TypeError); | ||
}); | ||
test("Correct error message", () => { | ||
expect(() => check(123, "return string")).toThrow(/Must return string/); | ||
expect(() => check("a", "return number")).toThrow(/Must return finite number/); | ||
}); | ||
}); | ||
}); |
@@ -5,61 +5,107 @@ const { ValueError, EMPTY } = require("../../lib/exports"); | ||
describe("ValueError()", () => { | ||
test("Return correct error with default message", () => { | ||
expect(new ValueError()).toHaveProperty("name", "ValueError"); | ||
expect(new ValueError()).toHaveProperty("message", "Object.test(): Invalid value"); | ||
expect(new ValueError()).toHaveProperty("prefix", "Object.test()"); | ||
expect(new ValueError()).toHaveProperty("reason", "Invalid value"); | ||
expect(new ValueError()).not.toHaveProperty("value"); | ||
describe("Default reason", () => { | ||
test("Return correct error with default reason (named function)", () => { | ||
function abc() { | ||
const e = new ValueError(); | ||
expect(e).toHaveProperty("name", "ValueError"); | ||
expect(e).toHaveProperty("message", "abc(): Invalid value"); | ||
expect(e).toHaveProperty("prefix", "abc()"); | ||
expect(e).toHaveProperty("reason", "Invalid value"); | ||
expect(e).not.toHaveProperty("value"); | ||
} | ||
abc(); | ||
}); | ||
test("Return correct error with default reason (named function)", () => { | ||
(() => { | ||
const e = new ValueError(); | ||
expect(e).toHaveProperty("name", "ValueError"); | ||
expect(e).toHaveProperty("message", "Invalid value"); | ||
expect(e).toHaveProperty("prefix", ""); | ||
expect(e).toHaveProperty("reason", "Invalid value"); | ||
expect(e).not.toHaveProperty("value"); | ||
})(); | ||
}); | ||
}); | ||
test("Return correct error with message only", () => { | ||
expect(new ValueError("Message")).toHaveProperty("name", "ValueError"); | ||
expect(new ValueError("Message")).toHaveProperty("message", "Object.test(): Message"); | ||
expect(new ValueError("Message")).toHaveProperty("prefix", "Object.test()"); | ||
expect(new ValueError("Message")).toHaveProperty("reason", "Message"); | ||
expect(new ValueError("Message")).not.toHaveProperty("value"); | ||
function abc() { | ||
return new ValueError("Message"); | ||
} | ||
expect(abc()).toHaveProperty("name", "ValueError"); | ||
expect(abc()).toHaveProperty("message", "abc(): Message"); | ||
expect(abc()).toHaveProperty("prefix", "abc()"); | ||
expect(abc()).toHaveProperty("reason", "Message"); | ||
expect(abc()).not.toHaveProperty("value"); | ||
describe("Reason", () => { | ||
test("Return correct error with reason only (named function)", () => { | ||
function abc() { | ||
const e = new ValueError("Reason"); | ||
expect(e).toHaveProperty("name", "ValueError"); | ||
expect(e).toHaveProperty("message", "abc(): Reason"); | ||
expect(e).toHaveProperty("prefix", "abc()"); | ||
expect(e).toHaveProperty("reason", "Reason"); | ||
expect(e).not.toHaveProperty("value"); | ||
} | ||
abc(); | ||
}); | ||
test("Return correct error with reason only (named function)", () => { | ||
(() => { | ||
const e = new ValueError("Reason"); | ||
expect(e).toHaveProperty("name", "ValueError"); | ||
expect(e).toHaveProperty("message", "Reason"); | ||
expect(e).toHaveProperty("prefix", ""); | ||
expect(e).toHaveProperty("reason", "Reason"); | ||
expect(e).not.toHaveProperty("value"); | ||
})(); | ||
}); | ||
}); | ||
test("Return correct error with message and value", () => { | ||
expect(new ValueError("Message", 123)).toHaveProperty("name", "ValueError"); | ||
expect(new ValueError("Message", 123)).toHaveProperty("message", "Object.test(): Message (received 123)"); | ||
expect(new ValueError("Message", 123)).toHaveProperty("prefix", "Object.test()"); | ||
expect(new ValueError("Message", 123)).toHaveProperty("reason", "Message"); | ||
expect(new ValueError("Message", 123)).toHaveProperty("value", 123); | ||
function abc() { | ||
return new ValueError("Message", 123); | ||
} | ||
expect(abc()).toHaveProperty("name", "ValueError"); | ||
expect(abc()).toHaveProperty("message", "abc(): Message (received 123)"); | ||
expect(abc()).toHaveProperty("prefix", "abc()"); | ||
expect(abc()).toHaveProperty("reason", "Message"); | ||
expect(abc()).toHaveProperty("value", 123); | ||
describe("Value", () => { | ||
test("Return correct error with reason and value (named function)", () => { | ||
function abc() { | ||
const e = new ValueError("Reason", 123); | ||
expect(e).toHaveProperty("name", "ValueError"); | ||
expect(e).toHaveProperty("message", "abc(): Reason (received 123)"); | ||
expect(e).toHaveProperty("prefix", "abc()"); | ||
expect(e).toHaveProperty("reason", "Reason"); | ||
expect(e).toHaveProperty("value", 123); | ||
} | ||
abc(); | ||
}); | ||
test("Return correct error with reason and value (anonymous function)", () => { | ||
(() => { | ||
const e = new ValueError("Reason", 123); | ||
expect(e).toHaveProperty("message", "Reason (received 123)"); | ||
expect(e).toHaveProperty("prefix", ""); | ||
expect(e).toHaveProperty("reason", "Reason"); | ||
expect(e).toHaveProperty("value", 123); | ||
})(); | ||
}); | ||
}); | ||
test("Return correct error with message, value, and prefix", () => { | ||
expect(new ValueError("Message", 123, "Prefix")).toHaveProperty("name", "ValueError"); | ||
expect(new ValueError("Message", 123, "Prefix")).toHaveProperty( | ||
"message", | ||
"Object.test(): Prefix: Message (received 123)" | ||
); | ||
expect(new ValueError("Message", 123, "Prefix")).toHaveProperty("prefix", "Object.test(): Prefix"); | ||
expect(new ValueError("Message", 123, "Prefix")).toHaveProperty("reason", "Message"); | ||
expect(new ValueError("Message", 123, "Prefix")).toHaveProperty("value", 123); | ||
function abc() { | ||
return new ValueError("Message", 123, "Prefix"); | ||
} | ||
expect(abc()).toHaveProperty("name", "ValueError"); | ||
expect(abc()).toHaveProperty("message", "abc(): Prefix: Message (received 123)"); | ||
expect(abc()).toHaveProperty("prefix", "abc(): Prefix"); | ||
expect(abc()).toHaveProperty("reason", "Message"); | ||
expect(abc()).toHaveProperty("value", 123); | ||
describe("Prefix", () => { | ||
test("Return correct error with reason, value, and prefix (named function)", () => { | ||
function abc() { | ||
const e = new ValueError("Reason", 123, "Prefix"); | ||
expect(e).toHaveProperty("name", "ValueError"); | ||
expect(e).toHaveProperty("message", "abc(): Prefix: Reason (received 123)"); | ||
expect(e).toHaveProperty("prefix", "abc(): Prefix"); | ||
expect(e).toHaveProperty("reason", "Reason"); | ||
expect(e).toHaveProperty("value", 123); | ||
} | ||
abc(); | ||
}); | ||
test("Return correct error with reason, value, and prefix (named function but with prefix including ': ' colon space)", () => { | ||
function abc() { | ||
const e = new ValueError("Reason", 123, "myFunc(): Prefix"); | ||
expect(e).toHaveProperty("name", "ValueError"); | ||
expect(e).toHaveProperty("message", "myFunc(): Prefix: Reason (received 123)"); | ||
expect(e).toHaveProperty("prefix", "myFunc(): Prefix"); | ||
expect(e).toHaveProperty("reason", "Reason"); | ||
expect(e).toHaveProperty("value", 123); | ||
} | ||
abc(); | ||
}); | ||
test("Return correct error with reason, value, and prefix (anonymous function)", () => { | ||
(() => { | ||
const e = new ValueError("Reason", 123, "Prefix"); | ||
expect(e).toHaveProperty("message", "Prefix: Reason (received 123)"); | ||
expect(e).toHaveProperty("prefix", "Prefix"); | ||
expect(e).toHaveProperty("reason", "Reason"); | ||
expect(e).toHaveProperty("value", 123); | ||
})(); | ||
}); | ||
}); | ||
test("Does not show value in message if value is EMPTY", () => { | ||
expect(new ValueError("Message", EMPTY).hasOwnProperty("value")).toBe(false); | ||
expect(new ValueError("Message", EMPTY).message).not.toMatch(/received/); | ||
expect(new ValueError("Reason", EMPTY).hasOwnProperty("value")).toBe(false); | ||
expect(new ValueError("Reason", EMPTY).message).not.toMatch(/received/); | ||
}); | ||
}); |
@@ -5,72 +5,127 @@ const cause = require("../../lib/helpers/cause"); | ||
describe("cause()", () => { | ||
test("Correct frame is returned (Chrome, Node, IE, Edge)", () => { | ||
// Full stack from a random Blork error. | ||
const stack = [ | ||
"ValueError: Must be finite string (received 123)", | ||
" at throwError (classes/Blorker.js:41:83)", | ||
" at runChecker (classes/Blorker.js:21:77)", | ||
" at Blorker._check (classes/Blorker.js:261:109)", | ||
" at Blorker$check (classes/Blorker.js:118:31)", | ||
" at MyClass.name (MyClass.js:8:4)", | ||
" at myFunc (helpers/myFunc.js:129:432)" | ||
]; | ||
describe("Chrome, Node, IE, Edge", () => { | ||
test("Correct frame is returned", () => { | ||
// Full stack from a random Blork error. | ||
const stack = [ | ||
"ValueError: Must be finite string (received 123)", | ||
" at throwError (classes/Blorker.js:41:83)", | ||
" at runChecker (classes/Blorker.js:21:77)", | ||
" at Blorker._check (classes/Blorker.js:261:109)", | ||
" at Blorker$check (classes/Blorker.js:118:31)", | ||
" at MyClass.name (MyClass.js:8:4)", | ||
" at myFunc (helpers/myFunc.js:129:432)" | ||
]; | ||
// Get the cause stack frame from the frames. | ||
expect(cause(stack.join("\n"))).toEqual({ | ||
function: "MyClass.name()", | ||
file: "MyClass.js", | ||
line: 8, | ||
column: 4, | ||
original: " at MyClass.name (MyClass.js:8:4)", | ||
stack: [ | ||
// Get the cause stack frame from the frames. | ||
const c = cause(stack.join("\n")); | ||
expect(c.function).toBe("MyClass.name()"); | ||
expect(c.file).toBe("MyClass.js"); | ||
expect(c.line).toBe(8); | ||
expect(c.column).toBe(4); | ||
expect(c.original).toBe(" at MyClass.name (MyClass.js:8:4)"); | ||
expect(c.stack).toBe( | ||
[ | ||
"ValueError: Must be finite string (received 123)", | ||
" at MyClass.name (MyClass.js:8:4)", | ||
" at myFunc (helpers/myFunc.js:129:432)" | ||
].join("\n") | ||
); | ||
}); | ||
test("Anonymous functions are skipped over", () => { | ||
// Full stack from a random Blork error. | ||
const stack = [ | ||
"ValueError: Must be finite string (received 123)", | ||
" at throwError (classes/Blorker.js:41:83)", | ||
" at runChecker (classes/Blorker.js:21:77)", | ||
" at Blorker._check (classes/Blorker.js:261:109)", | ||
" at Blorker$check (classes/Blorker.js:118:31)", | ||
" at <anonymous>:1:3", // Anonymous. | ||
" at <anonymous>:1", // Anonymous. | ||
" at <anonymous>", // Anonymous. | ||
" at MyClass.name (MyClass.js:8:4)", | ||
" at myFunc (helpers/myFunc.js:129:432)" | ||
].join("\n") | ||
]; | ||
// Get the cause stack frame from the frames. | ||
const c = cause(stack.join("\n")); | ||
expect(c.function).toBe("MyClass.name()"); | ||
expect(c.file).toBe("MyClass.js"); | ||
expect(c.line).toBe(8); | ||
expect(c.column).toBe(4); | ||
expect(c.original).toBe(" at MyClass.name (MyClass.js:8:4)"); | ||
expect(c.stack).toBe( | ||
[ | ||
"ValueError: Must be finite string (received 123)", | ||
" at MyClass.name (MyClass.js:8:4)", | ||
" at myFunc (helpers/myFunc.js:129:432)" | ||
].join("\n") | ||
); | ||
}); | ||
}); | ||
test("Correct frame is returned (Firefox, Safari)", () => { | ||
// Full stack from a random Blork error. | ||
const stack = [ | ||
"throwError@classes/Blorker.js:41:83", | ||
"runChecker@classes/Blorker.js:21:77", | ||
"Blorker._check@classes/Blorker.js:261:109", | ||
"Blorker$check@classes/Blorker.js:118:31", | ||
"MyClass.name@MyClass.js:8:4", | ||
"myFunc@helpers/myFunc.js:129:432" | ||
]; | ||
test("First frame is returned if no Blorker call is in the stack", () => { | ||
// Full stack from a random Blork error. | ||
const stack = [ | ||
"Error", | ||
" at Object.test (functions/cause.test.js:8:4)", | ||
" at Object.asyncFn (node_modules/jest-jasmine2/build/jasmine_async.js:129:432)", | ||
" at resolve (node_modules/jest-jasmine2/build/queue_runner.js:51:12)", | ||
" at new Promise (<anonymous>)", | ||
" at mapper (node_modules/jest-jasmine2/build/queue_runner.js:40:274)", | ||
" at promise.then (node_modules/jest-jasmine2/build/queue_runner.js:83:39)", | ||
" at <anonymous>", | ||
" at process._tickCallback (internal/process/next_tick.js:182:7)" | ||
]; | ||
// Get the cause stack frame from the frames. | ||
expect(cause(stack.join("\n"))).toEqual({ | ||
function: "MyClass.name()", | ||
file: "MyClass.js", | ||
line: 8, | ||
column: 4, | ||
original: "MyClass.name@MyClass.js:8:4", | ||
stack: ["MyClass.name@MyClass.js:8:4", "myFunc@helpers/myFunc.js:129:432"].join("\n") | ||
// Get the cause stack frame from the frames. | ||
const c = cause(stack.join("\n")); | ||
expect(c.function).toBe("Object.test()"); | ||
expect(c.file).toBe("functions/cause.test.js"); | ||
expect(c.line).toBe(8); | ||
expect(c.column).toBe(4); | ||
expect(c.original).toBe(" at Object.test (functions/cause.test.js:8:4)"); | ||
expect(c.stack).toBe(stack.join("\n")); | ||
}); | ||
}); | ||
test("First frame is returned if no Blorker call is in the stack", () => { | ||
// Full stack from a random Blork error. | ||
const stack = [ | ||
"Error", | ||
" at Object.test (functions/cause.test.js:8:4)", | ||
" at Object.asyncFn (node_modules/jest-jasmine2/build/jasmine_async.js:129:432)", | ||
" at resolve (node_modules/jest-jasmine2/build/queue_runner.js:51:12)", | ||
" at new Promise (<anonymous>)", | ||
" at mapper (node_modules/jest-jasmine2/build/queue_runner.js:40:274)", | ||
" at promise.then (node_modules/jest-jasmine2/build/queue_runner.js:83:39)", | ||
" at <anonymous>", | ||
" at process._tickCallback (internal/process/next_tick.js:182:7)" | ||
]; | ||
describe("Firefox, Safari", () => { | ||
test("Correct frame is returned", () => { | ||
// Full stack from a random Blork error. | ||
const stack = [ | ||
"throwError@classes/Blorker.js:41:83", | ||
"runChecker@classes/Blorker.js:21:77", | ||
"Blorker._check@classes/Blorker.js:261:109", | ||
"Blorker$check@classes/Blorker.js:118:31", | ||
"MyClass.name@MyClass.js:8:4", | ||
"myFunc@helpers/myFunc.js:129:432" | ||
]; | ||
// Get the cause stack frame from the frames. | ||
expect(cause(stack.join("\n"))).toEqual({ | ||
function: "Object.test()", | ||
file: "functions/cause.test.js", | ||
line: 8, | ||
column: 4, | ||
original: " at Object.test (functions/cause.test.js:8:4)", | ||
stack: stack.join("\n") | ||
// Get the cause stack frame from the frames. | ||
const c = cause(stack.join("\n")); | ||
expect(c.function).toBe("MyClass.name()"); | ||
expect(c.file).toBe("MyClass.js"); | ||
expect(c.line).toBe(8); | ||
expect(c.column).toBe(4); | ||
expect(c.original).toBe("MyClass.name@MyClass.js:8:4"); | ||
expect(c.stack).toBe(["MyClass.name@MyClass.js:8:4", "myFunc@helpers/myFunc.js:129:432"].join("\n")); | ||
}); | ||
test("Anonymous functions are skipped over", () => { | ||
// Full stack from a random Blork error. | ||
const stack = [ | ||
"throwError@classes/Blorker.js:41:83", | ||
"runChecker@classes/Blorker.js:21:77", | ||
"Blorker._check@classes/Blorker.js:261:109", | ||
"Blorker$check@classes/Blorker.js:118:31", | ||
"@file:///C:/example.html:16:13", // Anonymous. | ||
"@debugger eval code:21:9", // Anonymous. | ||
"MyClass.name@MyClass.js:8:4", | ||
"myFunc@helpers/myFunc.js:129:432" | ||
]; | ||
// Get the cause stack frame from the frames. | ||
const c = cause(stack.join("\n")); | ||
expect(c.function).toBe("MyClass.name()"); | ||
expect(c.file).toBe("MyClass.js"); | ||
expect(c.line).toBe(8); | ||
expect(c.column).toBe(4); | ||
expect(c.original).toBe("MyClass.name@MyClass.js:8:4"); | ||
expect(c.stack).toBe(["MyClass.name@MyClass.js:8:4", "myFunc@helpers/myFunc.js:129:432"].join("\n")); | ||
}); | ||
}); | ||
@@ -77,0 +132,0 @@ test("Undefined is returned if stack is not valid", () => { |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
211004
3872
943
0