Add captcha to main site, fix tests of styled-components
This commit is contained in:
parent
262ba2c2af
commit
c27e66a8e2
@ -13,5 +13,6 @@ module.exports = {
|
|||||||
'jsx',
|
'jsx',
|
||||||
],
|
],
|
||||||
setupFiles: ['<rootDir>/jest.setup.js'],
|
setupFiles: ['<rootDir>/jest.setup.js'],
|
||||||
|
setupFilesAfterEnv: ['<rootDir>/src/jest.env.ts'],
|
||||||
verbose: false,
|
verbose: false,
|
||||||
}
|
}
|
||||||
|
|||||||
3
packages/client/src/jest.env.ts
Normal file
3
packages/client/src/jest.env.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import { TestUtils } from '@rondo.dev/react-test'
|
||||||
|
import { theme } from './theme'
|
||||||
|
TestUtils.defaultTheme = theme
|
||||||
@ -36,7 +36,7 @@ export class LoginActions {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
register = (profile: NewUser) => {
|
register = (profile: NewUser & { captcha: string }) => {
|
||||||
return createPendingAction(
|
return createPendingAction(
|
||||||
this.http.post('/auth/register', profile),
|
this.http.post('/auth/register', profile),
|
||||||
'LOGIN_REGISTER',
|
'LOGIN_REGISTER',
|
||||||
|
|||||||
@ -5,12 +5,14 @@ import { Link } from 'react-router-dom'
|
|||||||
import { Input } from '../components/Input'
|
import { Input } from '../components/Input'
|
||||||
import { Redirect } from '../components/Redirect'
|
import { Redirect } from '../components/Redirect'
|
||||||
import { Button } from '../components'
|
import { Button } from '../components'
|
||||||
|
import { Captcha } from '@rondo.dev/react-captcha'
|
||||||
|
|
||||||
export interface RegisterFormProps {
|
export interface RegisterFormProps {
|
||||||
|
baseUrl: string
|
||||||
error?: string
|
error?: string
|
||||||
onSubmit: () => void
|
onSubmit: () => void
|
||||||
onChange: (name: string, value: string) => void
|
onChange: (name: string, value: string) => void
|
||||||
data: NewUser
|
data: NewUser & { captcha: string }
|
||||||
user?: UserProfile
|
user?: UserProfile
|
||||||
redirectTo: string
|
redirectTo: string
|
||||||
}
|
}
|
||||||
@ -74,6 +76,19 @@ export class RegisterForm extends React.PureComponent<RegisterFormProps> {
|
|||||||
value={this.props.data.lastName}
|
value={this.props.data.lastName}
|
||||||
placeholder='Last name'
|
placeholder='Last name'
|
||||||
/>
|
/>
|
||||||
|
<Captcha
|
||||||
|
imageUrl={this.props.baseUrl + '/api/auth/captcha.svg'}
|
||||||
|
audioUrl={this.props.baseUrl + '/api/auth/captcha.wav'}
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
Icon={undefined}
|
||||||
|
label='Captcha'
|
||||||
|
name='captcha'
|
||||||
|
type='text'
|
||||||
|
onChange={this.props.onChange}
|
||||||
|
value={this.props.data.captcha}
|
||||||
|
placeholder='Captcha'
|
||||||
|
/>
|
||||||
<div className='text-center'>
|
<div className='text-center'>
|
||||||
<Button name='submit' type='submit'>
|
<Button name='submit' type='submit'>
|
||||||
Register
|
Register
|
||||||
|
|||||||
@ -20,7 +20,7 @@ describe('configureRegister', () => {
|
|||||||
select: state => state.Login,
|
select: state => state.Login,
|
||||||
})
|
})
|
||||||
.withComponent(
|
.withComponent(
|
||||||
select => configureRegister(select, loginActions),
|
select => configureRegister(select, loginActions, '/app'),
|
||||||
)
|
)
|
||||||
.withJSX((Component, props) =>
|
.withJSX((Component, props) =>
|
||||||
<MemoryRouter><Component {...props} /></MemoryRouter>,
|
<MemoryRouter><Component {...props} /></MemoryRouter>,
|
||||||
@ -41,6 +41,7 @@ describe('configureRegister', () => {
|
|||||||
password: 'pass',
|
password: 'pass',
|
||||||
firstName: '',
|
firstName: '',
|
||||||
lastName: '',
|
lastName: '',
|
||||||
|
captcha: '',
|
||||||
}
|
}
|
||||||
const onSuccess = jest.fn()
|
const onSuccess = jest.fn()
|
||||||
let node: Element
|
let node: Element
|
||||||
|
|||||||
@ -6,16 +6,18 @@ import { LoginState } from './LoginReducer'
|
|||||||
import { RegisterForm } from './RegisterForm'
|
import { RegisterForm } from './RegisterForm'
|
||||||
import { withForm } from './withForm'
|
import { withForm } from './withForm'
|
||||||
|
|
||||||
const defaultCredentials: NewUser = {
|
const defaultCredentials: NewUser & { captcha: string }= {
|
||||||
username: '',
|
username: '',
|
||||||
password: '',
|
password: '',
|
||||||
firstName: '',
|
firstName: '',
|
||||||
lastName: '',
|
lastName: '',
|
||||||
|
captcha: '',
|
||||||
}
|
}
|
||||||
|
|
||||||
export function configureRegister<State>(
|
export function configureRegister<State>(
|
||||||
getLocalState: SelectState<State, LoginState>,
|
getLocalState: SelectState<State, LoginState>,
|
||||||
loginActions: LoginActions,
|
loginActions: LoginActions,
|
||||||
|
baseUrl: string,
|
||||||
) {
|
) {
|
||||||
return pack(
|
return pack(
|
||||||
getLocalState,
|
getLocalState,
|
||||||
@ -25,6 +27,7 @@ export function configureRegister<State>(
|
|||||||
redirectTo: state.redirectTo,
|
redirectTo: state.redirectTo,
|
||||||
}),
|
}),
|
||||||
dispatch => ({
|
dispatch => ({
|
||||||
|
baseUrl,
|
||||||
onSubmit: bindActionCreators(loginActions.register, dispatch),
|
onSubmit: bindActionCreators(loginActions.register, dispatch),
|
||||||
clearOnSuccess: true,
|
clearOnSuccess: true,
|
||||||
}),
|
}),
|
||||||
|
|||||||
@ -10,7 +10,7 @@ export interface APIDef {
|
|||||||
}
|
}
|
||||||
'/auth/register': {
|
'/auth/register': {
|
||||||
'post': {
|
'post': {
|
||||||
body: NewUser
|
body: NewUser & { captcha: string }
|
||||||
response: UserProfile
|
response: UserProfile
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,9 +13,6 @@ export interface CaptchaState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class Captcha extends React.PureComponent<CaptchaProps, CaptchaState> {
|
export class Captcha extends React.PureComponent<CaptchaProps, CaptchaState> {
|
||||||
static defaultProps = {
|
|
||||||
name: 'captcha',
|
|
||||||
}
|
|
||||||
state: CaptchaState = {
|
state: CaptchaState = {
|
||||||
type: 'image',
|
type: 'image',
|
||||||
attempt: 1,
|
attempt: 1,
|
||||||
@ -46,7 +43,7 @@ export class Captcha extends React.PureComponent<CaptchaProps, CaptchaState> {
|
|||||||
</a>
|
</a>
|
||||||
{this.props.audioUrl && (
|
{this.props.audioUrl && (
|
||||||
<a className='action-audio' onClick={this.changeToAudio}>
|
<a className='action-audio' onClick={this.changeToAudio}>
|
||||||
Click here for image version
|
Click here for audio version
|
||||||
</a>
|
</a>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
@ -58,7 +55,7 @@ export class Captcha extends React.PureComponent<CaptchaProps, CaptchaState> {
|
|||||||
Refresh
|
Refresh
|
||||||
</a>
|
</a>
|
||||||
<a className='action-image' onClick={this.changeToImage}>
|
<a className='action-image' onClick={this.changeToImage}>
|
||||||
Click here for audio version
|
Click here for image version
|
||||||
</a>
|
</a>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -2,8 +2,10 @@
|
|||||||
import { createStore, SelectState, WaitMiddleware } from '@rondo.dev/redux'
|
import { createStore, SelectState, WaitMiddleware } from '@rondo.dev/redux'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import ReactDOM from 'react-dom'
|
import ReactDOM from 'react-dom'
|
||||||
|
import T from 'react-dom/test-utils'
|
||||||
import { Provider } from 'react-redux'
|
import { Provider } from 'react-redux'
|
||||||
import { Action, AnyAction, combineReducers, Reducer, ReducersMapObject } from 'redux'
|
import { Action, AnyAction, combineReducers, Reducer, ReducersMapObject } from 'redux'
|
||||||
|
import { ThemeProvider, DefaultTheme } from 'styled-components'
|
||||||
|
|
||||||
interface RenderParams<State, LocalState> {
|
interface RenderParams<State, LocalState> {
|
||||||
reducers: ReducersMapObject<State, any>
|
reducers: ReducersMapObject<State, any>
|
||||||
@ -18,15 +20,24 @@ export class TestContainer extends React.Component<{}> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class TestUtils {
|
export class TestUtils {
|
||||||
|
static defaultTheme?: DefaultTheme
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a redux store
|
* Create a redux store
|
||||||
*/
|
*/
|
||||||
readonly createStore = createStore
|
readonly createStore = createStore
|
||||||
|
readonly Utils = T
|
||||||
|
|
||||||
render(jsx: JSX.Element) {
|
render(jsx: JSX.Element) {
|
||||||
const $div = document.createElement('div')
|
const $div = document.createElement('div')
|
||||||
const component = ReactDOM.render(
|
const component = ReactDOM.render(
|
||||||
<TestContainer>{jsx}</TestContainer>, $div) as unknown as TestContainer
|
<TestContainer>
|
||||||
|
<ThemeProvider theme={TestUtils.defaultTheme}>
|
||||||
|
{jsx}
|
||||||
|
</ThemeProvider>
|
||||||
|
</TestContainer>,
|
||||||
|
$div,
|
||||||
|
) as unknown as TestContainer
|
||||||
const node = component.ref.current!.children[0]
|
const node = component.ref.current!.children[0]
|
||||||
return {
|
return {
|
||||||
component,
|
component,
|
||||||
|
|||||||
@ -13,4 +13,5 @@ module.exports = {
|
|||||||
'jsx',
|
'jsx',
|
||||||
],
|
],
|
||||||
setupFiles: ['<rootDir>/jest.setup.js'],
|
setupFiles: ['<rootDir>/jest.setup.js'],
|
||||||
|
setupFilesAfterEnv: ['<rootDir>/src/jest.env.ts'],
|
||||||
}
|
}
|
||||||
|
|||||||
0
packages/scripts/template/src/jest.env.ts
Normal file
0
packages/scripts/template/src/jest.env.ts
Normal file
Loading…
x
Reference in New Issue
Block a user