Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Step 13.6: Split AuthScreen into SignInForm and SignUpForm
- Loading branch information
Showing
6 changed files
with
688 additions
and
138 deletions.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
import { createMemoryHistory } from 'history'; | ||
import React from 'react'; | ||
import { ApolloProvider } from '@apollo/react-hooks'; | ||
import { | ||
act, | ||
cleanup, | ||
render, | ||
fireEvent, | ||
waitFor, | ||
} from '@testing-library/react'; | ||
import SignInForm from './SignInForm'; | ||
import { SignInDocument } from '../../graphql/types'; | ||
import { mockApolloClient } from '../../test-helpers'; | ||
|
||
describe('SignInForm', () => { | ||
afterEach(cleanup); | ||
|
||
it('enables sign-in button when filled in', async () => { | ||
const history = createMemoryHistory(); | ||
const client = mockApolloClient(); | ||
|
||
let getByTestId: any = null; | ||
|
||
act(() => { | ||
getByTestId = render( | ||
<ApolloProvider client={client}> | ||
<SignInForm history={history} /> | ||
</ApolloProvider> | ||
).getByTestId; | ||
}); | ||
|
||
const signInButton = await waitFor( | ||
() => getByTestId('sign-in-button') as HTMLButtonElement | ||
); | ||
const usernameInput = await waitFor(() => | ||
getByTestId('username-input').querySelector('input') | ||
); | ||
const passwordInput = await waitFor(() => | ||
getByTestId('password-input').querySelector('input') | ||
); | ||
|
||
expect(signInButton.disabled).toEqual(true); | ||
|
||
act(() => { | ||
fireEvent.change(usernameInput, { target: { value: 'username' } }); | ||
fireEvent.change(passwordInput, { target: { value: 'password' } }); | ||
}); | ||
|
||
await waitFor(() => expect(signInButton.disabled).toEqual(false)); | ||
}); | ||
|
||
it('prints server error if input was wrong', async () => { | ||
const history = createMemoryHistory(); | ||
|
||
const client = mockApolloClient([ | ||
{ | ||
request: { | ||
query: SignInDocument, | ||
variables: { | ||
username: 'username', | ||
password: 'password', | ||
}, | ||
}, | ||
get result() { | ||
throw Error('sign-in failed'); | ||
}, | ||
}, | ||
]); | ||
|
||
let getByTestId: any = null; | ||
|
||
act(() => { | ||
getByTestId = render( | ||
<ApolloProvider client={client}> | ||
<SignInForm history={history} /> | ||
</ApolloProvider> | ||
).getByTestId; | ||
}); | ||
|
||
const signInButton = await waitFor( | ||
() => getByTestId('sign-in-button') as HTMLButtonElement | ||
); | ||
const usernameInput = await waitFor(() => | ||
getByTestId('username-input').querySelector('input') | ||
); | ||
const passwordInput = await waitFor(() => | ||
getByTestId('password-input').querySelector('input') | ||
); | ||
|
||
act(() => { | ||
fireEvent.change(usernameInput, { target: { value: 'username' } }); | ||
fireEvent.change(passwordInput, { target: { value: 'password' } }); | ||
}); | ||
|
||
await waitFor(() => expect(usernameInput.value).toEqual('username')); | ||
|
||
await waitFor(() => expect(passwordInput.value).toEqual('password')); | ||
|
||
act(() => { | ||
fireEvent.click(signInButton); | ||
}); | ||
|
||
const errorMessage = await waitFor(() => getByTestId('error-message')); | ||
|
||
await waitFor(() => | ||
expect(errorMessage.innerHTML).toContain('sign-in failed') | ||
); | ||
}); | ||
|
||
it('navigates to /chats if everything went right', async () => { | ||
const history = createMemoryHistory(); | ||
|
||
const client = mockApolloClient([ | ||
{ | ||
request: { | ||
query: SignInDocument, | ||
variables: { | ||
username: 'username', | ||
password: 'password', | ||
}, | ||
}, | ||
result: { data: {} }, | ||
}, | ||
]); | ||
|
||
let getByTestId: any = null; | ||
|
||
act(() => { | ||
getByTestId = render( | ||
<ApolloProvider client={client}> | ||
<SignInForm history={history} /> | ||
</ApolloProvider> | ||
).getByTestId; | ||
}); | ||
|
||
const usernameInput = await waitFor(() => | ||
getByTestId('username-input').querySelector('input') | ||
); | ||
const passwordInput = await waitFor(() => | ||
getByTestId('password-input').querySelector('input') | ||
); | ||
const signInButton = await waitFor( | ||
() => getByTestId('sign-in-button') as HTMLButtonElement | ||
); | ||
|
||
act(() => { | ||
fireEvent.change(usernameInput, { target: { value: 'username' } }); | ||
fireEvent.change(passwordInput, { target: { value: 'password' } }); | ||
}); | ||
|
||
await waitFor(() => expect(usernameInput.value).toEqual('username')); | ||
|
||
await waitFor(() => expect(passwordInput.value).toEqual('password')); | ||
|
||
act(() => { | ||
fireEvent.click(signInButton); | ||
}); | ||
|
||
await waitFor(() => expect(history.location.pathname).toEqual('/chats')); | ||
}); | ||
}); |
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,83 @@ | ||
import React from 'react'; | ||
import { useCallback, useState } from 'react'; | ||
import { useSignIn } from '../../services/auth.service'; | ||
import { | ||
SignForm, | ||
ActualForm, | ||
Legend, | ||
Section, | ||
TextField, | ||
Button, | ||
ErrorMessage, | ||
} from './form-components'; | ||
import { RouteComponentProps } from 'react-router-dom'; | ||
|
||
const SignInForm: React.FC<RouteComponentProps<any>> = ({ history }) => { | ||
const [username, setUsername] = useState(''); | ||
const [password, setPassword] = useState(''); | ||
const [error, setError] = useState(''); | ||
const [signIn] = useSignIn(); | ||
|
||
const onUsernameChange = useCallback(({ target }) => { | ||
setError(''); | ||
setUsername(target.value); | ||
}, []); | ||
|
||
const onPasswordChange = useCallback(({ target }) => { | ||
setError(''); | ||
setPassword(target.value); | ||
}, []); | ||
|
||
const maySignIn = useCallback(() => { | ||
return !!(username && password); | ||
}, [username, password]); | ||
|
||
const handleSignIn = useCallback(() => { | ||
signIn({ variables: { username, password } }) | ||
.then(() => { | ||
history.replace('/chats'); | ||
}) | ||
.catch((error) => { | ||
setError(error.message || error); | ||
}); | ||
}, [username, password, history, signIn]); | ||
|
||
return ( | ||
<SignForm> | ||
<ActualForm> | ||
<Legend>Sign in</Legend> | ||
<Section style={{ width: '100%' }}> | ||
<TextField | ||
data-testid="username-input" | ||
label="Username" | ||
value={username} | ||
onChange={onUsernameChange} | ||
margin="normal" | ||
placeholder="Enter your username" | ||
/> | ||
<TextField | ||
data-testid="password-input" | ||
label="Password" | ||
type="password" | ||
value={password} | ||
onChange={onPasswordChange} | ||
margin="normal" | ||
placeholder="Enter your password" | ||
/> | ||
</Section> | ||
<Button | ||
data-testid="sign-in-button" | ||
type="button" | ||
color="secondary" | ||
variant="contained" | ||
disabled={!maySignIn()} | ||
onClick={handleSignIn}> | ||
Sign in | ||
</Button> | ||
<ErrorMessage data-testid="error-message">{error}</ErrorMessage> | ||
</ActualForm> | ||
</SignForm> | ||
); | ||
}; | ||
|
||
export default SignInForm; |
Oops, something went wrong.