Add Media.tsx

This commit is contained in:
Jerko Steiner 2019-11-16 20:53:09 -03:00
parent 6fd6a4edf3
commit 22380ea381
2 changed files with 181 additions and 0 deletions

View File

@ -0,0 +1,81 @@
import React from 'react'
import ReactDOM from 'react-dom'
import TestUtils from 'react-dom/test-utils'
import { Provider } from 'react-redux'
import { createStore, Store } from '../store'
import { Media } from './Media'
import { MEDIA_ENUMERATE } from '../constants'
describe('Media', () => {
const onSave = jest.fn()
beforeEach(() => {
jest.resetAllMocks()
store = createStore()
store.dispatch({
type: MEDIA_ENUMERATE,
status: 'resolved',
payload: [{
id: '123',
name: 'Audio Input',
type: 'audioinput',
}, {
id: '456',
label: 'Video Input',
name: 'videoinput',
}],
})
})
let store: Store
async function render() {
const div = document.createElement('div')
const node = await new Promise<HTMLDivElement>(resolve => {
ReactDOM.render(
<div ref={div => resolve(div!)}>
<Provider store={store}>
<Media onSave={onSave} />
</Provider>
</div>,
div,
)
})
return node.children[0]
}
describe('submit', () => {
it('calls onSave', async () => {
const node = await render()
expect(node.tagName).toBe('FORM')
TestUtils.Simulate.submit(node)
expect(onSave.mock.calls.length).toBe(1)
})
})
describe('onVideoChange', () => {
it('calls onSetVideoConstraint', async () => {
const node = await render()
const select = node.querySelector('select.media-video')!
TestUtils.Simulate.change(select, {
target: {
value: '{"deviceId":123}',
} as any,
})
expect(store.getState().media.video).toEqual({ deviceId: 123 })
})
})
describe('onAudioChange', () => {
it('calls onSetAudioConstraint', async () => {
const node = await render()
const select = node.querySelector('select.media-audio')!
TestUtils.Simulate.change(select, {
target: {
value: '{"deviceId":456}',
} as any,
})
expect(store.getState().media.audio).toEqual({ deviceId: 456 })
})
})
})

View File

@ -0,0 +1,100 @@
import React from 'react'
import { connect } from 'react-redux'
import { AudioConstraint, MediaDevice, setAudioConstraint, setVideoConstraint, VideoConstraint } from '../actions/MediaActions'
import { MediaState } from '../reducers/media'
import { State } from '../store'
export type MediaProps = MediaState & {
onSetVideoConstraint: typeof setVideoConstraint
onSetAudioConstraint: typeof setAudioConstraint
onSave: () => void
}
function getId(constraint: VideoConstraint | AudioConstraint) {
return typeof constraint === 'object' && 'deviceId' in constraint
? constraint.deviceId
: ''
}
function mapStateToProps(state: State) {
return {
...state.media,
}
}
const mapDispatchToProps = {
onSetVideoConstraint: setVideoConstraint,
onSetAudioConstraint: setAudioConstraint,
}
const c = connect(mapStateToProps, mapDispatchToProps)
export const Media = c(React.memo(function Media(props: MediaProps) {
function onSave(event: React.FormEvent<HTMLFormElement>) {
event.preventDefault()
props.onSave()
}
function onVideoChange(event: React.ChangeEvent<HTMLSelectElement>) {
const constraint: VideoConstraint = JSON.parse(event.target.value)
props.onSetVideoConstraint(constraint)
}
function onAudioChange(event: React.ChangeEvent<HTMLSelectElement>) {
const constraint: AudioConstraint = JSON.parse(event.target.value)
props.onSetAudioConstraint(constraint)
}
const videoId = getId(props.video)
const audioId = getId(props.audio)
return (
<form className='media' onSubmit={onSave}>
<select className='media-video' onChange={onVideoChange} value={videoId}>
<Options
devices={props.devices}
default='{"facingMode":"user"}'
type='videoinput'
/>
</select>
<select className='media-audio' onChange={onAudioChange} value={audioId}>
<Options
devices={props.devices}
default='true'
type='audioinput'
/>
</select>
<button type='submit'>
Save
</button>
</form>
)
}))
interface OptionsProps {
devices: MediaDevice[]
type: 'audioinput' | 'videoinput'
default: string
}
function Options(props: OptionsProps) {
return (
<React.Fragment>
<option value='false'>Disabled</option>
<option value={props.default}>Default</option>
{
props.devices
.filter(device => device.type === props.type)
.map(device =>
<option
key={device.id}
value={JSON.stringify({deviceId: device.id})}>{device.name}
</option>,
)
}
</React.Fragment>
)
}