Skip to content

Commit

Permalink
added: promisify utility (#261)
Browse files Browse the repository at this point in the history
  • Loading branch information
adife committed Aug 8, 2020
1 parent fe5784d commit f9f1d39
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 0 deletions.
65 changes: 65 additions & 0 deletions packages/vest/docs/utilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,68 @@ vest.create('Checkout', () => {
);
});
```

## `promisify()`

Promisify is a function that enables you to run your async validations as a [Javascript Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).
This can be useful when running async validations on the server, or when you do not need the partial validation results.

!> **NOTE** The Promise is resolved when all tests finish running.

### Usage

`promisify()` accepts a validation suite declaration, and returns a function that when called, returns a Promise.

```js
import vest from 'vest';
import promisify from 'vest/promisify';

const validate = promisify(
vest.create('CreateNewUser', data => {
test('email', 'The email already exists', () => doesEmailExist(data.email));
test('username', 'The username already exists', () =>
doesUsernameExist(data.username)
);
})
);

validate(data).then(res => {
if (res.hasErrors('email')) {
/* ... */
}

if (res.hasErrors('usename')) {
/* ... */
}
});
```

```js
// validation.js
import vest, { test } from 'vest';

const validate = vest.create('CreateNewUser', data => {
test('email', 'The email already exists', () => doesEmailExist(data.email));
test('username', 'The username already exists', () =>
doesUsernameExist(data.username)
);
});

export default validate;
```

```js
// Form.js
import promisify from 'vest/promisify';
import validate from './validation.js';

const validateAsync = promisify(validate(data));

async function handler(data) {
const result = await validateAsync(data);

if (result.hasErrors('email')) {
// Do stuff here
}
}
```
5 changes: 5 additions & 0 deletions packages/vest/src/utilities/promisify.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
declare function promisify(
validatorFn: (...args: any[]) => IVestResult
): Promise<DraftResult>;

export default promisify;
7 changes: 7 additions & 0 deletions packages/vest/src/utilities/promisify.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const promisify = validatorFn => (...args) => {
if (typeof validatorFn !== 'function') {
throw new Error('[vest/promisify]: Expected validatorFn to be a function.');
}

return new Promise(resolve => validatorFn(...args).done(resolve));
};
82 changes: 82 additions & 0 deletions packages/vest/src/utilities/tests/promisify.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import faker from 'faker';
import vest from '../..';
import { dummyTest } from '../../../testUtils/testDummy';
import { promisify } from '../promisify';

describe('Utility: promisify', () => {
let validatorFn;
let validateAsync;

beforeEach(() => {
validatorFn = jest.fn(() => vest.validate('test-promisify', jest.fn()));
validateAsync = promisify(validatorFn);
});

describe('Test arguments', () => {
it('Should throw an error', () => {
const invalidValidateAsync = promisify('invalid');
expect(() => invalidValidateAsync()).toThrow();
});
});

describe('Return value', () => {
it('should be a function', () => {
expect(typeof promisify(jest.fn())).toBe('function');
});

it('should be a promise', () =>
new Promise(done => {
const res = validateAsync();
expect(typeof res?.then).toBe('function');
res.then(() => done());
}));
});

describe('When returned function is invoked', () => {
it('Calls `validatorFn` argument', () =>
new Promise(done => {
const validateAsync = promisify(() =>
vest.validate('test-promisify', () => done())
);
validateAsync();
}));

it('Passes all arguments over to tests callback', async () => {
const params = [
1,
{ [faker.random.word()]: [1, 2, 3] },
false,
[faker.random.word()],
];

await validateAsync(...params);
expect(validatorFn).toHaveBeenCalledWith(...params);
});
});

describe('Initial run', () => {
it('Produces correct validation', () =>
new Promise(done => {
const validate = vest.create('test-promisify', () => {
dummyTest.failing('field_0');
dummyTest.failingAsync('field_1');
});

const validateAsync = promisify(validate);

const promise = validateAsync();
const res = vest.get('test-promisify');

expect(res.hasErrors('field_0')).toBe(true);
expect(res.hasErrors('field_1')).toBe(false);

promise.then(result => {
expect(result.hasErrors('field_0')).toBe(true);
expect(result.hasErrors('field_1')).toBe(true);
expect(result).not.toBe(res);
expect(result).not.isDeepCopyOf(res);
done();
});
}));
});
});

0 comments on commit f9f1d39

Please sign in to comment.