Skip to content

Commit

Permalink
minor(vest): support custom message in test (#560)
Browse files Browse the repository at this point in the history
  • Loading branch information
ealush authored Jan 21, 2021
1 parent 553b45c commit 0cf5615
Show file tree
Hide file tree
Showing 11 changed files with 149 additions and 46 deletions.
1 change: 1 addition & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ on:
push:
branches:
- release
- release_dev

jobs:
build:
Expand Down
2 changes: 1 addition & 1 deletion packages/n4s/docs/_sidebar.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
- [Main](./)
- [List of Enforce Rules](./rules)
- [Schema validations](./coumpound)
- [Schema validations](./compound)
- [Templates and Composites](./template)
- [Custom Enforce Rules](./custom)
- [Consuming external rules](./external)
28 changes: 2 additions & 26 deletions packages/n4s/src/lib/__tests__/transformResult.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
import {
transformResult,
getDefaultResult,
formatResultMessage,
validateResult,
} from 'transformResult';

Expand Down Expand Up @@ -54,7 +53,7 @@ describe.each([true, false])('Test transform result', bool => {
transformResult(result, { rule: goodObjectRule, value: bool })
).toEqual({
pass: bool,
message: formatResultMessage(goodObjectRule, result.message),
message: result.message,
});
});

Expand Down Expand Up @@ -85,10 +84,7 @@ describe.each([true, false])('Test transform result', bool => {
})
).toEqual({
pass: bool,
message: formatResultMessage(
goodObjectMessageFunctionRule,
result.message()
),
message: result.message(),
});
});

Expand All @@ -106,23 +102,3 @@ describe.each([true, false])('Test transform result', bool => {
).toThrow(Error);
});
});

describe("Test transform result's message", () => {
[goodObjectMessageRule, goodObjectMessageRule, goodObjectRule].forEach(
rule => {
it('Should contain the library name', () => {
const result = rule(true);
expect(transformResult(result, { rule, value: true }).message).toMatch(
LIBRARY_NAME
);
});

it('Should contain the name of the rule', () => {
const result = rule(true);
expect(transformResult(result, { rule, value: true }).message).toMatch(
rule.name
);
});
}
);
});
13 changes: 3 additions & 10 deletions packages/n4s/src/lib/transformResult.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,12 @@ export function validateResult(result, rule) {
}

// for easier testing and mocking
export function getDefaultResult(value, rule) {
export function getDefaultResult(value) {
return {
message: formatResultMessage(rule, `invalid ${typeof value} value`),
message: new Error(`invalid ${typeof value} value`),
};
}

export function formatResultMessage(rule, msg) {
return `[${LIBRARY_NAME}]: "${rule.name}" ${msg}`;
}

/**
* Transform the result of a rule into a standard format
* @param {string} interfaceName to be used in the messages
Expand All @@ -47,10 +43,7 @@ export function transformResult(result, { rule, value }) {
} else {
defaultResult.pass = result.pass;
if (result.message) {
defaultResult.message = formatResultMessage(
rule,
optionalFunctionValue(result.message)
);
defaultResult.message = optionalFunctionValue(result.message);
}
return defaultResult;
}
Expand Down
26 changes: 22 additions & 4 deletions packages/n4s/src/runtime/__tests__/enforceRunner.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,28 @@ describe('Test runner', () => {
expect(() => enforceRunner(n => n === 2, 1)).toThrow(Error);
});

it('Should throw with verbose', () => {
expect(() =>
enforceRunner(() => ({ pass: false, message: 'Custom message' }))
).toThrow(Error);
describe('With custom message', () => {
it('Should throw with verbose', () => {
expect(() =>
enforceRunner(() => ({ pass: false, message: 'Custom message' }))
).toThrow('Custom message');
});

it('Should throw message string', () => {
let msg;
try {
enforceRunner(() => ({ pass: false, message: 'Custom message' }));
} catch (e) {
msg = e;
}
expect(typeof msg).toBe('string');
});
});

describe('Without custom message', () => {
it('Should throw an Error', () => {
expect(() => enforceRunner(() => ({ pass: false }))).toThrow(Error);
});
});
});

Expand Down
4 changes: 2 additions & 2 deletions packages/n4s/src/runtime/__tests__/extend.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ describe('enforce.extend', () => {

it('Should throw on failing custom rule in regular test', () => {
const t = () => enforce('The name is Snowball').endsWith('Snuffles');
expect(t).toThrow(Error);
expect(t).toThrow();
});

it('Should return silently for custom rule in regular test', () => {
Expand All @@ -40,7 +40,7 @@ describe('enforce.extend', () => {

it('Should use message from returned function result', () => {
expect(() => enforce('').failsWithFunction(2)).toThrow(
'[vest]: "failsWithFunction" Custom error with function'
'Custom error with function'
);
});
});
2 changes: 1 addition & 1 deletion packages/n4s/src/runtime/enforceRunner.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ function runner(rule, value, args = []) {
}

if (!result.pass) {
throw new Error(result.message);
throw result.message;
}
}

Expand Down
23 changes: 23 additions & 0 deletions packages/vest/docs/n4s/custom.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,26 @@ enforce.extend({
},
});
```

This is useful when combind with Vest tests, because vest test can use the string value as the test message:

```js
enforce.extend({
isChecked: value => {
return {
pass: !!value.checked,
message: () => 'value must be checked',
};
},
});

/*...*/

/*
tost = { checked: false }
*/

test('tos', () => {
enforce(tos).isChecked(); // will fail with the message: "value must be checked"
});
```
28 changes: 26 additions & 2 deletions packages/vest/docs/test.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ A test can either be synchronous or asynchronous, and it can either have a [seve

There are three ways to fail a test:

### Throwing an error inside your test body (using enforce)
### Throwing inside your test body (using enforce)

Just like in most unit testing frameworks, a validation fails whenever an error is thrown inside the test body. The [`enforce`](./enforce) function throws an error whenever the enforced value does not meet the specified criteria.
Just like in most unit testing frameworks, a validation fails whenever the test body throws an exception. [`Enforce`](./enforce) throws on failed validations.
When thrown with a string

```js
// const username = 'Gina.Vandervort';
Expand All @@ -31,6 +32,29 @@ test('password', 'Should be at least 6 characters long', () => {
}); // this test fails
```

Alternatively, you can also throw a string value to use it as your test message. To do that, you need to omit the test message, and throw a string, for example - when using enforce.extend.

```js
enforce.extend({
isChecked: value => {
return {
pass: !!value.checked,
message: () => 'value must be checked',
};
},
});

/*...*/

/*
tost = { checked: false }
*/

test('tos', () => {
enforce(tos).isChecked(); // will fail with the message: "value must be checked"
});
```

### Explicitly returning false

To make it easy to migrate your existing validation logic into Vest, it also supports validations explicitly returning `false` (and not any other falsy value) to represent failures.
Expand Down
63 changes: 63 additions & 0 deletions packages/vest/src/core/test/__tests__/test.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,69 @@ describe("Test Vest's `test` function", () => {
expect(testObject.failed).toBe(true);
expect(testObject == false).toBe(true); //eslint-disable-line
});

describe('Thrown with a message', () => {
enforce.extend({
fail: () => {
return {
pass: false,
message: () => 'I fail with a message',
};
},
});
describe('When field has a message', () => {
it("Should use field's own message", () => {
const res = create(() => {
test('field_with_message', 'some_field_message', () => {
enforce().fail();
});
test('warning_field_with_message', 'some_field_message', () => {
vest.warn();
enforce().fail();
});
})();

expect(res.getErrors('field_with_message')).toEqual([
'some_field_message',
]);
expect(res.tests['field_with_message'].errors).toEqual([
'some_field_message',
]);
expect(res.getWarnings('warning_field_with_message')).toEqual([
'some_field_message',
]);
expect(res.tests['warning_field_with_message'].warnings).toEqual([
'some_field_message',
]);
});
});
describe('When field does not have a message', () => {
it('Should use message from thrown error', () => {
const res = create(() => {
test('field_without_message', () => {
enforce().fail();
});
test('warning_field_without_message', () => {
vest.warn();
enforce().fail();
});
})();

expect(res.getErrors('field_without_message')).toEqual([
'I fail with a message',
]);
expect(res.tests['field_without_message'].errors).toEqual([
'I fail with a message',
]);
expect(res.getWarnings('warning_field_without_message')).toEqual([
'I fail with a message',
]);
expect(
res.tests['warning_field_without_message'].warnings
).toEqual(['I fail with a message']);
});
});
});
});

describe('async', () => {
Expand Down
5 changes: 5 additions & 0 deletions packages/vest/src/core/test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import context from 'ctx';
import { isExcluded } from 'exclusive';
import isFunction from 'isFunction';
import isPromise from 'isPromise';
import isStringValue from 'isStringValue';
import { isUndefined } from 'isUndefined';
import { setPending } from 'pending';
import runAsyncTest from 'runAsyncTest';
import bindTestEach from 'test.each';
Expand All @@ -22,6 +24,9 @@ const sync = testObject =>
try {
result = testObject.testFn();
} catch (e) {
if (isUndefined(testObject.statement) && isStringValue(e)) {
testObject.statement = e;
}
result = false;
}

Expand Down

0 comments on commit 0cf5615

Please sign in to comment.