-
Notifications
You must be signed in to change notification settings - Fork 705
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
Extract authentication logic to redux state #517
Changes from all commits
d0a81c4
e46785f
261b70d
cc9279f
d19ecbe
19426c9
d1381d8
8c9e2e1
ae197d7
5a70881
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import { IAuthState } from "reducers/auth"; | ||
import configureMockStore from "redux-mock-store"; | ||
import thunk from "redux-thunk"; | ||
import { getType } from "typesafe-actions"; | ||
import actions from "."; | ||
import { Auth } from "../shared/Auth"; | ||
|
||
const mockStore = configureMockStore([thunk]); | ||
const token = "abcd"; | ||
const validationErrorMsg = "Validation error"; | ||
|
||
let store: any; | ||
|
||
beforeEach(() => { | ||
const state: IAuthState = { | ||
authenticated: false, | ||
authenticating: false, | ||
}; | ||
|
||
Auth.validateToken = jest.fn(); | ||
Auth.setAuthToken = jest.fn(); | ||
|
||
store = mockStore({ | ||
auth: { | ||
state, | ||
}, | ||
}); | ||
}); | ||
|
||
describe("authenticate", () => { | ||
it("dispatches authenticating and auth error if invalid", () => { | ||
Auth.validateToken = jest.fn().mockImplementationOnce(() => { | ||
throw new Error(validationErrorMsg); | ||
}); | ||
const expectedActions = [ | ||
{ | ||
type: getType(actions.auth.authenticating), | ||
}, | ||
{ | ||
errorMsg: `Error: ${validationErrorMsg}`, | ||
type: getType(actions.auth.authenticationError), | ||
}, | ||
]; | ||
|
||
return store.dispatch(actions.auth.authenticate(token)).then(() => { | ||
expect(store.getActions()).toEqual(expectedActions); | ||
}); | ||
}); | ||
|
||
it("dispatches authenticating and auth ok if valid", () => { | ||
const expectedActions = [ | ||
{ | ||
type: getType(actions.auth.authenticating), | ||
}, | ||
{ | ||
authenticated: true, | ||
type: getType(actions.auth.setAuthenticated), | ||
}, | ||
]; | ||
|
||
return store.dispatch(actions.auth.authenticate(token)).then(() => { | ||
expect(store.getActions()).toEqual(expectedActions); | ||
}); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
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. I think I don't fully understand the purpose of snapshots. It seems that it's something that you just replace with the current state when it fails. Apparently it's not a very useful test. Am I missing something? |
||
|
||
exports[`displays an error if the authenticate handler throws an error 1`] = ` | ||
exports[`displays an error if the authentication error is passed 1`] = ` | ||
<section | ||
className="LoginForm" | ||
> | ||
|
@@ -15,15 +15,6 @@ exports[`displays an error if the authenticate handler throws an error 1`] = ` | |
role="alert" | ||
> | ||
There was an error connecting to the Kubernetes API. Please check that your token is valid. | ||
<button | ||
className="alert__close" | ||
onClick={[Function]} | ||
> | ||
<X | ||
color="currentColor" | ||
size="24" | ||
/> | ||
</button> | ||
</div> | ||
</div> | ||
<div | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import { shallow } from "enzyme"; | ||
import { Location } from "history"; | ||
import * as React from "react"; | ||
import { IAuthState } from "reducers/auth"; | ||
import configureMockStore from "redux-mock-store"; | ||
import thunk from "redux-thunk"; | ||
import LoginForm from "./LoginFormContainer"; | ||
|
||
const mockStore = configureMockStore([thunk]); | ||
|
||
const makeStore = ( | ||
authenticated: boolean, | ||
authenticating: boolean, | ||
authenticationError: string, | ||
) => { | ||
const state: IAuthState = { | ||
authenticated, | ||
authenticating, | ||
authenticationError, | ||
}; | ||
return mockStore({ auth: state }); | ||
}; | ||
|
||
const emptyLocation: Location = { | ||
hash: "", | ||
pathname: "", | ||
search: "", | ||
state: "", | ||
}; | ||
|
||
describe("LoginFormContainer props", () => { | ||
it("maps authentication redux states to props", () => { | ||
const store = makeStore(true, true, "It's a trap"); | ||
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. why not just pass the IAuthState object directly? not sure why this helper is valuable, it's also not easy to read what the first two parameters relate to 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. also, shouldn't we test different variations? 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. I do not see much value on passing variations since the mapStateToProps just takes the values, there are not defaults or anything. |
||
const wrapper = shallow(<LoginForm store={store} location={emptyLocation} />); | ||
const form = wrapper.find("LoginForm"); | ||
expect(form).toHaveProp({ | ||
authenticated: true, | ||
authenticating: true, | ||
authenticationError: "It's a trap", | ||
}); | ||
}); | ||
}); |
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.
We should see if
Partial<IStoreState>
works here, if not we can try casting the mockStore thing to IStoreState