This repository has been archived by the owner on Jun 17, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 154
Redux saga for easy testing and extending #97
Closed
mik639
wants to merge
16
commits into
joshwcomeau:master
from
mik639:redux-saga-for-easy-testing-and-extending
Closed
Changes from 4 commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
d720976
Tests for dependencies reducer
mik639 821dd0a
replace toMatchShapshot with toMatchInlineSnapshot, update jest
mik639 d3fe14e
replace dependency middleware with redux-saga and tests for it
mik639 8c3a3c5
Merge branch 'master' into redux-saga-for-easy-testing-and-extending
mik639 876e102
Fix html display in dependency search, and styling tweaks for results…
melanieseltzer 977a96b
Issue templates (#94)
joshwcomeau 90d4517
Switch to individual issue templates (#99)
joshwcomeau 0fb299a
add license and code of conduct (#98)
superhawk610 1f1889a
Update .gitignore (#101)
bennygenel befbcab
order of selectors arguments was changed (#104)
mik639 1a9cd1e
Bi directional communication (#100)
joshwcomeau 1097e19
Remove JS validation for VS Code users (#108)
joshwcomeau 6f1bdb0
Tests for dependencies reducer
mik639 6326c22
replace toMatchShapshot with toMatchInlineSnapshot, update jest
mik639 cc03c9d
replace dependency middleware with redux-saga and tests for it
mik639 121b078
Merge with master
mik639 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
import { select, call, put, takeEvery } from 'redux-saga/effects'; | ||
import { getPathForProjectId } from '../reducers/paths.reducer'; | ||
import { | ||
installDependency, | ||
uninstallDependency, | ||
} from '../services/dependencies.service'; | ||
import { loadProjectDependency } from '../services/read-from-disk.service'; | ||
import { | ||
ADD_DEPENDENCY_START, | ||
UPDATE_DEPENDENCY_START, | ||
DELETE_DEPENDENCY_START, | ||
addDependencyFinish, | ||
addDependencyError, | ||
updateDependencyFinish, | ||
updateDependencyError, | ||
deleteDependencyFinish, | ||
deleteDependencyError, | ||
} from '../actions'; | ||
|
||
/** | ||
* Trying to install new dependency, if success dispatching "finish" action | ||
* if not - dispatching "error" ection | ||
*/ | ||
export function* addDependency({ projectId, dependencyName, version }) { | ||
const projectPath = yield select(getPathForProjectId, projectId); | ||
try { | ||
yield call(installDependency, projectPath, dependencyName, version); | ||
const dependency = yield call( | ||
loadProjectDependency, | ||
projectPath, | ||
dependencyName | ||
); | ||
yield put(addDependencyFinish(projectId, dependency)); | ||
} catch (err) { | ||
yield call([console, 'error'], 'Failed to install dependency', err); | ||
yield put(addDependencyError(projectId, dependencyName)); | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These look great 👍 |
||
|
||
/** | ||
* Trying to update existing dependency, if success dispatching "finish" action, | ||
* if not - dispatching "error" action | ||
*/ | ||
export function* updateDependency({ | ||
projectId, | ||
dependencyName, | ||
latestVersion, | ||
}) { | ||
const projectPath = yield select(getPathForProjectId, projectId); | ||
try { | ||
yield call(installDependency, projectPath, dependencyName, latestVersion); | ||
yield put(updateDependencyFinish(projectId, dependencyName, latestVersion)); | ||
} catch (err) { | ||
yield call([console, 'error'], 'Failed to update dependency', err); | ||
yield put(updateDependencyError(projectId, dependencyName)); | ||
} | ||
} | ||
|
||
/** | ||
* Trying to delete dependency, if success dispatching "finish" action, | ||
* if not - dispatching "error" action | ||
*/ | ||
export function* deleteDependency({ projectId, dependencyName }) { | ||
const projectPath = yield select(getPathForProjectId, projectId); | ||
try { | ||
yield call(uninstallDependency, projectPath, dependencyName); | ||
yield put(deleteDependencyFinish(projectId, dependencyName)); | ||
} catch (err) { | ||
yield call([console, 'error'], 'Failed to delete dependency', err); | ||
yield put(deleteDependencyError(projectId, dependencyName)); | ||
} | ||
} | ||
|
||
/** | ||
* Root dependencies saga, watching for "start" actions | ||
*/ | ||
export default function* rootSaga() { | ||
yield takeEvery(ADD_DEPENDENCY_START, addDependency); | ||
yield takeEvery(UPDATE_DEPENDENCY_START, updateDependency); | ||
yield takeEvery(DELETE_DEPENDENCY_START, deleteDependency); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import { select, call, put } from 'redux-saga/effects'; | ||
import { addDependency } from './dependency.saga'; | ||
import { getPathForProjectId } from '../reducers/paths.reducer'; | ||
import { installDependency } from '../services/dependencies.service'; | ||
import { loadProjectDependency } from '../services/read-from-disk.service'; | ||
import { addDependencyFinish, addDependencyError } from '../actions'; | ||
|
||
jest.mock('../services/read-from-disk.service'); | ||
|
||
describe('Dependency sagas', () => { | ||
describe('addDependency saga', () => { | ||
const startAction = { | ||
projectId: 'foo', | ||
dependencyName: 'redux', | ||
version: '2.3', | ||
}; | ||
const dependency = { | ||
name: 'redux', | ||
version: '2.3', | ||
}; | ||
it('should install new dependency', () => { | ||
const saga = addDependency(startAction); | ||
expect(saga.next().value).toEqual(select(getPathForProjectId, 'foo')); | ||
expect(saga.next('/path/to/project/').value).toEqual( | ||
call(installDependency, '/path/to/project/', 'redux', '2.3') | ||
); | ||
expect(saga.next().value).toEqual( | ||
call(loadProjectDependency, '/path/to/project/', 'redux') | ||
); | ||
expect(saga.next(dependency).value).toEqual( | ||
put(addDependencyFinish('foo', dependency)) | ||
); | ||
expect(saga.next().done).toBe(true); | ||
}); | ||
|
||
it('should handle error', () => { | ||
const error = new Error('something wrong'); | ||
const saga = addDependency(startAction); | ||
expect(saga.next().value).toEqual(select(getPathForProjectId, 'foo')); | ||
expect(saga.next('/path/to/project/').value).toEqual( | ||
call(installDependency, '/path/to/project/', 'redux', '2.3') | ||
); | ||
expect(saga.throw(error).value).toEqual( | ||
call([console, 'error'], 'Failed to install dependency', error) | ||
); | ||
expect(saga.next().value).toEqual( | ||
put(addDependencyError('foo', 'redux')) | ||
); | ||
expect(saga.next().done).toBe(true); | ||
}); | ||
}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tests look great! Maybe just add a TODO comment for the other "branches"? Unless you plan on doing them as part of this PR, and were just waiting to see if I approved of sagas before spending the time? |
||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import { all } from 'redux-saga/effects'; | ||
import dependencySaga from './dependency.saga'; | ||
|
||
export default function*() { | ||
yield all([dependencySaga()]); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7691,6 +7691,10 @@ [email protected]: | |
prop-types "^15.5.7" | ||
redux-devtools-instrument "^1.0.1" | ||
|
||
redux-saga@^0.16.0: | ||
version "0.16.0" | ||
resolved "https://registry.yarnpkg.com/redux-saga/-/redux-saga-0.16.0.tgz#0a231db0a1489301dd980f6f2f88d8ced418f724" | ||
|
||
[email protected]: | ||
version "2.2.0" | ||
resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.2.0.tgz#e615a16e16b47a19a515766133d1e3e99b7852e5" | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, makes sense that we'd need to change the selectors to be state-first, for redux-saga
select
(it also just seems much more obvious, in retrospect, that this order makes more sense, since it matches how reducers work + allows for optional args afterwards).I think we should try to update all selectors to follow this pattern, though, since I wouldn't want it to be inconsistent from reducer to reducer.
It might even make sense as a separate preliminary PR, to update all selectors (and their callsites) to be state-first... but I'm OK if we do it as part of this PR if that's too much git-juggling, haha.