Skip to content

Commit

Permalink
patch: regorganize Context and Suite State (#413)
Browse files Browse the repository at this point in the history
Use Context package
  • Loading branch information
ealush committed Sep 26, 2020
1 parent bb81ffe commit b20aa66
Show file tree
Hide file tree
Showing 48 changed files with 388 additions and 681 deletions.
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"babel-eslint": "^10.1.0",
"babel-jest": "^26.3.0",
"babel-plugin-add-module-exports": "^1.0.4",
"context": "^0.1.0",
"cross-env": "^7.0.2",
"date-fns": "^2.16.1",
"eslint": "^7.9.0",
Expand Down Expand Up @@ -57,5 +58,8 @@
"prettier": {
"arrowParens": "avoid",
"singleQuote": true
},
"jest": {
"testEnvironment": "node"
}
}
2 changes: 1 addition & 1 deletion packages/vest/src/core/context/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import createContext from 'context';
import {
EXCLUSION_ITEM_TYPE_TESTS,
EXCLUSION_ITEM_TYPE_GROUPS,
} from '../../hooks/exclusive/constants';
import createContext from '../../lib/createContext';

export default createContext((ctxRef, parentContext) =>
parentContext
Expand Down
4 changes: 2 additions & 2 deletions packages/vest/src/core/produce/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import createCache from '../../lib/cache';
import copy from '../../lib/copy';
import hasRemainingTests from '../suite/hasRemainingTests';
import patch from '../suite/patch';
import * as suiteState from '../suite/suiteState';
import {
SEVERITY_GROUP_ERROR,
SEVERITY_GROUP_WARN,
Expand Down Expand Up @@ -46,7 +46,7 @@ const done = (state, ...args) => {
return output;
}

patch(state.suiteId, state => {
suiteState.patch(state.suiteId, state => {
if (fieldName) {
state.fieldCallbacks[fieldName] = [].concat(
...(state.fieldCallbacks[fieldName] || []),
Expand Down
43 changes: 22 additions & 21 deletions packages/vest/src/core/produce/spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ import runRegisterSuite from '../../../testUtils/runRegisterSuite';
import suiteIdByName from '../../../testUtils/suiteIdByName';
import testDummy from '../../../testUtils/testDummy';
import group from '../../hooks/group';
import getState from '../suite/getState';
import hasRemainingTests from '../suite/hasRemainingTests';
import patch from '../suite/patch';
import * as suiteState from '../suite/suiteState';
import {
SEVERITY_COUNT_ERROR,
SEVERITY_COUNT_WARN,
Expand Down Expand Up @@ -67,7 +66,7 @@ describe('module: produce', () => {
suiteName = `suite_${counter()}`;
resetState();
runCreateSuite(suiteName);
state = getState(suiteId);
state = suiteState.getCurrentState(suiteId);
testKeys = [
...new Set(state.testObjects.map(({ fieldName }) => fieldName)),
];
Expand All @@ -85,9 +84,9 @@ describe('module: produce', () => {
});

it('Should create a deep copy of subset of the state', () => {
expect(_.pick(getState(suiteId), KEPT_PROPERTIES)).isDeepCopyOf(
_.pick(produced, KEPT_PROPERTIES)
);
expect(
_.pick(suiteState.getCurrentState(suiteId), KEPT_PROPERTIES)
).isDeepCopyOf(_.pick(produced, KEPT_PROPERTIES));
});

it.each(GENERATED_METHODS)(
Expand Down Expand Up @@ -129,7 +128,7 @@ describe('module: produce', () => {
it('Should return all statement messages for failed field', () => {
errors.forEach(field => {
expect(produced.getErrors(field)).toEqual(
produce(getState(suiteId)).tests[field].errors
produce(suiteState.getCurrentState(suiteId)).tests[field].errors
);
});
});
Expand All @@ -139,7 +138,8 @@ describe('module: produce', () => {
const failures = errors.reduce(
(failures, key) =>
Object.assign(failures, {
[key]: produce(getState(suiteId)).tests[key].errors,
[key]: produce(suiteState.getCurrentState(suiteId)).tests[key]
.errors,
}),
{}
);
Expand All @@ -159,7 +159,7 @@ describe('module: produce', () => {
it('Should return all statement messages for failed field', () => {
warnings.forEach(field => {
expect(produced.getWarnings(field)).toEqual(
produce(getState(suiteId)).tests[field].warnings
produce(suiteState.getCurrentState(suiteId)).tests[field].warnings
);
});
});
Expand All @@ -169,7 +169,8 @@ describe('module: produce', () => {
const failures = warnings.reduce(
(failures, key) =>
Object.assign(failures, {
[key]: produce(getState(suiteId)).tests[key].warnings,
[key]: produce(suiteState.getCurrentState(suiteId)).tests[key]
.warnings,
}),
{}
);
Expand All @@ -182,15 +183,15 @@ describe('module: produce', () => {
it('Should return the error count of the field', () => {
testKeys.forEach(key => {
expect(produced.hasErrors(key)).toBe(
!!produce(getState(suiteId)).tests[key].errorCount
!!produce(suiteState.getCurrentState(suiteId)).tests[key].errorCount
);
});
});
});
describe('When invoked without field name', () => {
it('Should return the error count of the whole suite', () => {
expect(produced.hasErrors()).toBe(
!!produce(getState(suiteId)).errorCount
!!produce(suiteState.getCurrentState(suiteId)).errorCount
);
});
});
Expand All @@ -200,15 +201,15 @@ describe('module: produce', () => {
it('Should return the warning count of the field', () => {
testKeys.forEach(key => {
expect(produced.hasWarnings(key)).toBe(
!!produce(getState(suiteId)).tests[key].warnCount
!!produce(suiteState.getCurrentState(suiteId)).tests[key].warnCount
);
});
});
});
describe('When invoked without field name', () => {
it('Should return the warn count of the whole suite', () => {
expect(produced.hasWarnings()).toBe(
!!produce(getState(suiteId)).warnCount
!!produce(suiteState.getCurrentState(suiteId)).warnCount
);
});
});
Expand Down Expand Up @@ -423,7 +424,7 @@ describe('module: produce', () => {
describe('When no async tests', () => {
it('Sanity', () => {
runRegisterSuite({ name: suiteId });
const state = getState(suiteId);
const state = suiteState.getCurrentState(suiteId);
expect(hasRemainingTests(state)).toBe(false);
});

Expand Down Expand Up @@ -490,7 +491,7 @@ describe('module: produce', () => {

describe('When async (has remaining tests)', () => {
beforeEach(() => {
state = patch(suiteId, state => ({
state = suiteState.patch(suiteId, state => ({
...state,
pending: state.pending.concat({ fieldName: 'field_1' }),
isAsync: true,
Expand Down Expand Up @@ -519,7 +520,7 @@ describe('module: produce', () => {
// that in produce().done() we wrap the callback - so we don't have
// access to it. Instead what we do here is only allow the test to
// finish if the callback runs.
getState(suiteId).doneCallbacks[0]();
suiteState.getCurrentState(suiteId).doneCallbacks[0]();
}));
});

Expand All @@ -542,14 +543,14 @@ describe('module: produce', () => {
new Promise(done => {
const produced = runCreateSuite();
expect(
getState(suiteName).fieldCallbacks['field_1']
suiteState.getCurrentState(suiteName).fieldCallbacks['field_1']
).toBeUndefined();

// The test will pass only when done gets called.
produced.done('field_1', done);

expect(
getState(suiteName).fieldCallbacks['field_1']
suiteState.getCurrentState(suiteName).fieldCallbacks['field_1']
).not.toBeUndefined();
}));
});
Expand All @@ -559,12 +560,12 @@ describe('module: produce', () => {
const produced = runCreateSuite();
suiteId = suiteIdByName(suiteName);
expect(
getState(suiteId).fieldCallbacks['sync_field_2']
suiteState.getCurrentState(suiteId).fieldCallbacks['sync_field_2']
).toBeUndefined();
produced.done('sync_field_2', doneCallback_2);
expect(doneCallback_2).toHaveBeenCalled();
expect(
getState(suiteId).fieldCallbacks['sync_field_2']
suiteState.getCurrentState(suiteId).fieldCallbacks['sync_field_2']
).toBeUndefined();
});
});
Expand Down
61 changes: 5 additions & 56 deletions packages/vest/src/core/state/index.js
Original file line number Diff line number Diff line change
@@ -1,58 +1,7 @@
import createStore from '../../lib/createStorage';
import { KEY_CANCELED, KEY_SUITES } from './constants';

export const { get, set, register } = (() => {
const storage = {
state: {
[KEY_SUITES]: {},
[KEY_CANCELED]: {},
},
};

/**
* Retrieves the state object or a portion of it.
*/
const get = () => storage.state;

/**
* Updates the state with the value return from the setter callback.
* @param {Function} setter setter function.
* @returns {Object} updated state.
*/
const set = setter => {
storage.state = setter(get());

return get();
};

const register = () =>
set(
state =>
state ?? {
[KEY_SUITES]: {},
[KEY_CANCELED]: {},
}
);

register();

return { get, set, register };
})();

/**
* Updates the state with the output of the setter callback.
* @param {Function} setter
* @returns {Object} all the suites in the state.
*/
export const setSuites = setter => {
set(state => {
state[KEY_SUITES] = setter(state[KEY_SUITES]);
return state;
});
return get()[KEY_SUITES];
};

/**
* @param {string} suiteId.
* @returns {Object} Suite from state.
*/
export const getSuite = suiteId => get()[KEY_SUITES][suiteId];
export default createStore(() => ({
[KEY_SUITES]: {},
[KEY_CANCELED]: {},
}));
2 changes: 1 addition & 1 deletion packages/vest/src/core/state/spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import _ from 'lodash';
import resetState from '../../../testUtils/resetState';
import * as state from '.';
import state from '.';

describe('Module: state', () => {
beforeEach(() => {
Expand Down
7 changes: 3 additions & 4 deletions packages/vest/src/core/suite/cleanupCompleted/index.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import getState from '../getState';
import hasRemainingTests from '../hasRemainingTests';
import remove from '../remove';
import * as suiteState from '../suiteState';
/**
* Removes completed "stateless" suite from state storage.
* @param {string} suiteId
*/
const cleanupCompleted = suiteId => {
const state = getState(suiteId);
const state = suiteState.getCurrentState(suiteId);

if (hasRemainingTests(state)) {
return;
}
remove(suiteId);
suiteState.remove(suiteId);
};

export default cleanupCompleted;
2 changes: 1 addition & 1 deletion packages/vest/src/core/suite/cleanupCompleted/spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
OPERATION_MODE_STATEFUL,
OPERATION_MODE_STATELESS,
} from '../../../constants';
import * as state from '../../state';
import state from '../../state';
import { KEY_SUITES } from '../../state/constants';
import cleanupCompleted from '.';

Expand Down
17 changes: 7 additions & 10 deletions packages/vest/src/core/suite/create/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,8 @@ import { get } from '../../../hooks';
import validateSuiteParams from '../../../lib/validateSuiteParams';
import context from '../../context';
import produce from '../../produce';
import { getSuite } from '../../state';
import mergeExcludedTests from '../../test/lib/mergeExcludedTests';
import getState from '../getState';
import register from '../register';
import reset from '../reset';
import * as suiteState from '../suiteState';

/**
* Initializes a validation suite, creates a validation context.
Expand All @@ -34,23 +31,23 @@ const createSuite = (name, tests) => {
*/
if (
ctxRef.operationMode === OPERATION_MODE_STATEFUL &&
!getSuite(ctxRef.suiteId)
!suiteState.getSuite(ctxRef.suiteId)
) {
context.run(ctxRef, register);
context.run({ ...ctxRef }, suiteState.register);
}

// returns validator function
// and sets the function name
// to the name of the suite
return Object.defineProperties(
(...args) => {
const output = context.run(ctxRef, context => {
register();
const output = context.run({ ...ctxRef }, context => {
suiteState.register();
const { suiteId } = context;
tests.apply(null, args);
mergeExcludedTests(suiteId);

return produce(getState(suiteId));
return produce(suiteState.getCurrentState(suiteId));
});
return output;
},
Expand All @@ -62,7 +59,7 @@ const createSuite = (name, tests) => {
value: () => get(name),
},
reset: {
value: () => reset(name),
value: () => suiteState.reset(ctxRef.suiteId, ctxRef.operationMode),
},
}
);
Expand Down
Loading

0 comments on commit b20aa66

Please sign in to comment.