Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redux logic errors #1954

Merged
merged 28 commits into from
Jan 31, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
4168920
Start migration updateProjectSource saga
joshling1919 Nov 13, 2019
c26af06
Update updateProjectSource
joshling1919 Nov 15, 2019
fe8d719
Use redux-logic for errors
joshling1919 Nov 16, 2019
9bf3a0d
Remove errors sagas unit tests
joshling1919 Nov 16, 2019
1227492
Reorganize errors logic
joshling1919 Dec 2, 2019
e40ff0f
Start validateProjectOnChange tests
joshling1919 Dec 3, 2019
982f9d4
Finish validateProjectOnChange specs
joshling1919 Dec 5, 2019
e429d3b
Write test for validateSource helper
joshling1919 Dec 6, 2019
7a6faef
Start validateCurrentProject test
joshling1919 Dec 7, 2019
4e4e64c
Finish validateProjectOnChange tests
joshling1919 Dec 10, 2019
adfd45b
Merge branch 'master' of https://github.com/popcodeorg/popcode into r…
joshling1919 Jan 9, 2020
9d7a55c
Refactor validateSource logic tests
joshling1919 Jan 13, 2020
1080acb
Lint validateCurrentProject and validateProjectOnChange
joshling1919 Jan 13, 2020
33eb932
Improve validateCurrentProject and validateProjectOnChange tests
joshling1919 Jan 13, 2020
80cf62f
Ensure that only current validations are dispatched
joshling1919 Jan 13, 2020
9a6a751
Merge branch 'master' of https://github.com/popcodeorg/popcode into r…
joshling1919 Jan 14, 2020
12b20a0
Merge branch 'master' of https://github.com/popcodeorg/popcode into r…
joshling1919 Jan 15, 2020
99c37ca
Lint errors logic
joshling1919 Jan 15, 2020
c2be8db
Merge branch 'master' of https://github.com/popcodeorg/popcode into r…
joshling1919 Jan 23, 2020
5520295
Start validateProject logic
joshling1919 Jan 23, 2020
23c2613
Refactor errors logic to use validateProject
joshling1919 Jan 25, 2020
c81b993
Merge branch 'master' of https://github.com/popcodeorg/popcode into r…
joshling1919 Jan 25, 2020
c12991d
Run lint
joshling1919 Jan 25, 2020
5a567a8
Merge branch 'master' into redux-logic-errors
outoftime Jan 25, 2020
3b666dd
Refactor validateProject
joshling1919 Jan 27, 2020
fbe3d0c
Merge branch 'redux-logic-errors' of https://github.com/joshling1919/…
joshling1919 Jan 27, 2020
8826d1e
Merge branch 'master' of https://github.com/popcodeorg/popcode into r…
joshling1919 Jan 27, 2020
43505c8
Merge branch 'master' into redux-logic-errors
outoftime Jan 31, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/logic/__tests__/helpers.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import noop from 'lodash-es/noop';
import reduce from 'lodash-es/reduce';
import {createLogicMiddleware} from 'redux-logic';
import configureStore from 'redux-mock-store';
import {first} from 'rxjs/operators';

import rootReducer from '../../reducers';

export function makeTestLogic(logic) {
return async (action, {state = {}, afterDispatch = noop} = {}) => {
const logicMiddleware = createLogicMiddleware([logic]);
Expand All @@ -25,3 +28,11 @@ export function makeTestLogic(logic) {
return dispatch;
};
}

export function applyActions(...actions) {
return reduce(
actions,
(state, action) => rootReducer(state, action),
undefined,
);
}
13 changes: 1 addition & 12 deletions src/logic/__tests__/startAccountMigration.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import reduce from 'lodash-es/reduce';

import {
accountMigrationComplete,
accountMigrationError,
Expand All @@ -10,11 +8,10 @@ import {
userAuthenticated,
} from '../../actions/user';
import {migrateAccount} from '../../clients/firebase';
import rootReducer from '../../reducers';
import {bugsnagClient} from '../../util/bugsnag';
import startAccountMigration from '../startAccountMigration';

import {makeTestLogic} from './helpers';
import {applyActions, makeTestLogic} from './helpers';

import {
credentialFactory,
Expand Down Expand Up @@ -111,11 +108,3 @@ describe('startAccountMigration', () => {
expect(migrateAccount).not.toHaveBeenCalledWith(mockCredential);
});
});

function applyActions(...actions) {
return reduce(
actions,
(state, action) => rootReducer(state, action),
undefined,
);
}
78 changes: 78 additions & 0 deletions src/logic/__tests__/validateProject.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import {
projectRestoredFromLastSession as projectRestoredFromLastSessionAction,
snapshotImported as snapshotImportedAction,
} from '../../actions/clients';
import {validatedSource} from '../../actions/errors';
import {
changeCurrentProject as changeCurrentProjectAction,
gistImported as gistImportedAction,
toggleLibrary as toggleLibraryAction,
updateProjectSource as updateProjectSourceAction,
} from '../../actions/projects';
import validateProject from '../validateProject';

import {applyActions, makeTestLogic} from './helpers';

import {firebaseProjectFactory} from '@factories/data/firebase';
import {consoleErrorFactory} from '@factories/validations/errors';

jest.mock('../../analyzers');

const mockCssValidationErrors = [
consoleErrorFactory.build({
text: 'You have a starting { but no ending } to go with it.',
}),
];

const mockHtmlValidationErrors = [
consoleErrorFactory.build({
text: 'Closing tag missing',
}),
];

jest.mock('../../validations', () => ({
css: jest.fn(() => mockCssValidationErrors),
html: jest.fn(() => mockHtmlValidationErrors),
javascript: jest.fn(() => []),
}));

const testLogic = makeTestLogic(validateProject);
for (const action of [
changeCurrentProjectAction,
gistImportedAction,
snapshotImportedAction,
projectRestoredFromLastSessionAction,
toggleLibraryAction,
]) {
test(`validates current project on ${action}`, async () => {
const mockProject = firebaseProjectFactory.build();
const state = applyActions(
projectRestoredFromLastSessionAction(mockProject),
);

const dispatch = await testLogic(action(mockProject.projectKey), {
state,
});

expect(dispatch).toHaveBeenCalledWith(
validatedSource('html', mockHtmlValidationErrors),
);
expect(dispatch).toHaveBeenCalledWith(
validatedSource('css', mockCssValidationErrors),
);
});
}

test('UPDATE_PROJECT_SOURCE should validate newSource', async () => {
const mockProject = firebaseProjectFactory.build();
const state = applyActions(projectRestoredFromLastSessionAction(mockProject));

const dispatch = await testLogic(
updateProjectSourceAction(mockProject.projectKey, 'css', 'div {'),
{state},
);

expect(dispatch).toHaveBeenCalledWith(
validatedSource('css', mockCssValidationErrors),
);
});
6 changes: 4 additions & 2 deletions src/logic/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@ import projectSuccessfullySaved from './projectSuccessfullySaved';
import saveProject from './saveProject';
import startAccountMigration from './startAccountMigration';
import unlinkGithubIdentity from './unlinkGithubIdentity';
import validateProject from './validateProject';

export default [
instrumentApplicationLoaded,
instrumentEnvironmentReady,
linkGithubIdentity,
logout,
startAccountMigration,
unlinkGithubIdentity,
projectSuccessfullySaved,
saveProject,
startAccountMigration,
unlinkGithubIdentity,
validateProject,
];
79 changes: 79 additions & 0 deletions src/logic/validateProject.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import map from 'lodash-es/map';
import {createLogic} from 'redux-logic';

import {validatedSource} from '../actions/errors';
import Analyzer from '../analyzers';
import {getCurrentProject} from '../selectors';
import retryingFailedImports from '../util/retryingFailedImports';

function importValidations() {
return retryingFailedImports(() =>
import(
/* webpackChunkName: "mainAsync" */
'../validations'
),
);
}

async function validateSource({language, source, projectAttributes}, dispatch) {
const validations = await importValidations();
const validate = validations[language];
const validationErrors = await validate(source, projectAttributes);
dispatch(validatedSource(language, validationErrors));
}

async function validateSources({sources, projectAttributes}, dispatch) {
const validatePromises = map(Reflect.ownKeys(sources), language =>
Copy link
Contributor

Choose a reason for hiding this comment

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

Definitely not going to block on this, but a minor improvement here would be to map over sources itself, which would give you (source, language) as the arguments to the iterator.

validateSource(
{
language,
source: sources[language],
projectAttributes,
},
dispatch,
),
);

await Promise.all(validatePromises);
}

export default createLogic({
type: [
'CHANGE_CURRENT_PROJECT',
'GIST_IMPORTED',
'SNAPSHOT_IMPORTED',
'PROJECT_RESTORED_FROM_LAST_SESSION',
'TOGGLE_LIBRARY',
'UPDATE_PROJECT_SOURCE',
],
latest: true,
async process(
{
getState,
action: {
type,
payload: {language, newValue},
},
},
dispatch,
done,
) {
const state = getState();
const currentProject = getCurrentProject(state);
const projectAttributes = new Analyzer(currentProject);

if (type === 'UPDATE_PROJECT_SOURCE') {
await validateSource(
{language, source: newValue, projectAttributes},
dispatch,
);
} else {
await validateSources(
{sources: currentProject.sources, projectAttributes},
dispatch,
);
}

done();
},
});
80 changes: 0 additions & 80 deletions src/sagas/errors.js

This file was deleted.

2 changes: 0 additions & 2 deletions src/sagas/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {all} from 'redux-saga/effects';

import manageUserState from './manageUserState';
import watchErrors from './errors';
import watchProjects from './projects';
import watchUi from './ui';
import watchClients from './clients';
Expand All @@ -10,7 +9,6 @@ import watchCompiledProjects from './compiledProjects';
export default function* rootSaga() {
yield all([
manageUserState(),
watchErrors(),
watchProjects(),
watchUi(),
watchClients(),
Expand Down
Loading