Skip to content

Commit

Permalink
add(vest): suite.resetField (#777)
Browse files Browse the repository at this point in the history
  • Loading branch information
ealush authored Jan 21, 2022
1 parent d9a5831 commit c1e31f3
Show file tree
Hide file tree
Showing 8 changed files with 111 additions and 6 deletions.
8 changes: 8 additions & 0 deletions packages/vest/src/core/state/stateHooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,11 @@ export function useTestsFlat(): VestTest[] {

return flatCache([current], () => nestedArray.flatten(current));
}

export function useEachTestObject(
handler: (testObject: VestTest) => void
): void {
const testObjects = useTestsFlat();

testObjects.forEach(handler);
}
69 changes: 69 additions & 0 deletions packages/vest/src/core/suite/__tests__/resetField.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { create, test } from 'vest';

describe('suite.resetField', () => {
let suite;

beforeEach(() => {
suite = create(() => {
test('field1', 'f1 error', () => false);
test('field2', 'f2 error', () => false);
});
suite();
});

it('Should reset the validity state of a field', () => {
expect(suite.get().hasErrors('field1')).toBe(true);
expect(suite.get().hasErrors('field2')).toBe(true);
expect(suite.get().getErrors('field1')).toEqual(['f1 error']);
expect(suite.get().getErrors('field2')).toEqual(['f2 error']);
suite.resetField('field1');
expect(suite.get().hasErrors('field1')).toBe(false);
expect(suite.get().hasErrors('field2')).toBe(true);
expect(suite.get().getErrors('field1')).toEqual([]);
expect(suite.get().getErrors('field2')).toEqual(['f2 error']);
suite.resetField('field2');
expect(suite.get().hasErrors('field1')).toBe(false);
expect(suite.get().hasErrors('field2')).toBe(false);
expect(suite.get().getErrors('field1')).toEqual([]);
expect(suite.get().getErrors('field2')).toEqual([]);
});

it('Should refresh the suite result', () => {
const res = suite.get();
expect(res).toBe(suite.get());
suite.resetField('field1');
expect(res).not.toBe(suite.get());
});

it('Should allow the field to keep updating (no final status)', () => {
suite.resetField('field1');
expect(suite.get().hasErrors('field1')).toBe(false);
expect(suite.get().hasErrors('field2')).toBe(true);
suite();
expect(suite.get().hasErrors('field1')).toBe(true);
expect(suite.get().hasErrors('field2')).toBe(true);
});

it('sanity', () => {
expect(suite.get().tests).toMatchInlineSnapshot(`
Object {
"field1": Object {
"errorCount": 1,
"errors": Array [
"f1 error",
],
"testCount": 1,
"warnCount": 0,
},
"field2": Object {
"errorCount": 1,
"errors": Array [
"f2 error",
],
"testCount": 1,
"warnCount": 0,
},
}
`);
});
});
7 changes: 6 additions & 1 deletion packages/vest/src/core/suite/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { initBus, Events } from 'vestBus';
type CreateProperties = {
get: () => TDraftResult;
reset: () => void;
resetField: (fieldName: string) => void;
remove: (fieldName: string) => void;
};

Expand Down Expand Up @@ -64,6 +65,7 @@ function create<T extends CB>(

get: () => TDraftResult;
reset: () => void;
resetField: (fieldName: string) => void;
remove: (fieldName: string) => void;
}

Expand Down Expand Up @@ -91,10 +93,13 @@ function create<T extends CB>(
}),
{
get: context.bind(ctxRef, produceDraft),
reset: state.reset,
remove: context.bind(ctxRef, (fieldName: string) => {
bus.emit(Events.REMOVE_FIELD, fieldName);
}),
reset: state.reset,
resetField: context.bind(ctxRef, (fieldName: string) => {
bus.emit(Events.RESET_FIELD, fieldName);
}),
}
);

Expand Down
5 changes: 5 additions & 0 deletions packages/vest/src/core/test/VestTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,11 @@ export default class VestTest {
useRefreshTestObjects();
}

reset(): void {
this.status = STATUS_UNTESTED;
useRefreshTestObjects();
}

omit(): void {
this.setStatus(STATUS_OMITTED);
}
Expand Down
17 changes: 13 additions & 4 deletions packages/vest/src/core/vestBus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ import matchingFieldName from 'matchingFieldName';
import omitOptionalTests from 'omitOptionalTests';
import removeTestFromState from 'removeTestFromState';
import { runFieldCallbacks, runDoneCallbacks } from 'runCallbacks';
import { useTestsFlat } from 'stateHooks';
import { useEachTestObject } from 'stateHooks';

// eslint-disable-next-line max-lines-per-function
export function initBus() {
const bus = createBus();

Expand All @@ -34,16 +35,23 @@ export function initBus() {

// Removes a certain field from the state.
bus.on(Events.REMOVE_FIELD, (fieldName: string) => {
const testObjects = useTestsFlat();

testObjects.forEach(testObject => {
useEachTestObject(testObject => {
if (matchingFieldName(testObject, fieldName)) {
testObject.cancel();
removeTestFromState(testObject);
}
});
});

// Resets a certain field in the state.
bus.on(Events.RESET_FIELD, (fieldName: string) => {
useEachTestObject(testObject => {
if (matchingFieldName(testObject, fieldName)) {
testObject.reset();
}
});
});

return bus;
}

Expand All @@ -60,5 +68,6 @@ export function useBus() {
export enum Events {
TEST_COMPLETED = 'test_completed',
REMOVE_FIELD = 'remove_field',
RESET_FIELD = 'reset_field',
SUITE_COMPLETED = 'suite_completed',
}
1 change: 1 addition & 0 deletions website/docs/api_reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Below is a list of all the API functions exposed by Vest.
- [suite.get](./writing_your_suite/vests_suite.md#using-suiteget) - Returns the current validation state of the suite.
- [suite.remove](./writing_your_suite/vests_suite.md##removing-a-single-field-from-the-suite-state) - Removes a single field from the suite.
- [suite.reset](./writing_your_suite/vests_suite.md#cleaning-up-our-validation-state) - Resets the suite to its initial state.
- [suite.resetField](./writing_your_suite/vests_suite.md#cleaning-up-our-validation-state) - Resets a single field to an untested state.

- [test](./writing_tests/using_the_test_function.md) - A single validation test inside your suite.

Expand Down
2 changes: 1 addition & 1 deletion website/docs/understanding_state.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ In some cases, such as form reset, you want to discard of previous validation re

### Usage:

`.rese()` Is a property on your validation suite. Calling it will remove your suite's state.
`.reset()` Is a property on your validation suite. Calling it will remove your suite's state.

```js
import { create } from 'vest';
Expand Down
8 changes: 8 additions & 0 deletions website/docs/writing_your_suite/vests_suite.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,14 @@ This method is especially useful if we want to access our suite state from withi

When you want to clean up the suite state, for example, when the user clears the form, or when you want to navigate out of the page in an SPA - but the user might return to it later on, you can call `suite.reset()`. This will reset the suite state and cancel any pending async validations that may still be running.

## Resetting a single field

Sometimes you wish to only reset the validity of a single field, for example - if you want to to reset the validity as the user starts typing again and you only run the validation on blur.

Simply call `suite.resetField(fieldName)` and that field will be reset to its untested state.

## Removing a single field from the suite state

Note: You rarely need to use `suite.remove`, and this is mostly useful for external libraries validating on your behalf. Most users are fine using `reset` and `omitWhen`.

Sometimes we want to remove a certain field from the suite state. For example, when the user removed a dynamically added field. In this case, we can call `suite.remove(fieldName)`. This will remove the field from the suite state and cancel any pending async validations that may still be running.

1 comment on commit c1e31f3

@vercel
Copy link

@vercel vercel bot commented on c1e31f3 Jan 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

vest-next – ./website

vest-next-ealush.vercel.app
vest-website.vercel.app
vest-next-git-latest-ealush.vercel.app
vest-next.vercel.app

Please sign in to comment.