Skip to content

Commit 5fe0ab3

Browse files
committed
Merge branch 'universal-redux' into fullstack
2 parents 0c3833a + 64af216 commit 5fe0ab3

File tree

4 files changed

+194
-0
lines changed

4 files changed

+194
-0
lines changed

src-clean/services/api/index.js

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import axios from 'axios'
2+
3+
const facade = {}
4+
5+
const api = axios.create({ baseURL: 'https://jsonplaceholder.typicode.com' })
6+
7+
facade.request = (config) => api.request(config)
8+
9+
;['delete', 'get', 'head'].forEach((method) => {
10+
facade[method] = (url, config) => facade.request({ ...config, method, url })
11+
})
12+
13+
;['post', 'put', 'patch'].forEach((method) => {
14+
facade[method] = (url, data, config) => facade.request({ ...config, method, url, data })
15+
})
16+
17+
export default facade

src-clean/services/api/index.test.js

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import axios from 'axios'
2+
import { stub, spy } from 'sinon'
3+
4+
const request = spy()
5+
6+
stub(axios, 'create', () => ({ request }))
7+
8+
const api = require('.').default
9+
10+
beforeEach(() => {
11+
request.reset()
12+
})
13+
14+
test('get', () => {
15+
expect(request.called).toBe(false)
16+
api.get('/test', { foo: 'bar' })
17+
expect(request.calledWith({
18+
method: 'get',
19+
url: '/test',
20+
foo: 'bar'
21+
})).toBe(true)
22+
})
23+
24+
test('post', () => {
25+
expect(request.called).toBe(false)
26+
api.post('/test', { title: 'test' }, { foo: 'bar' })
27+
expect(request.calledWith({
28+
method: 'post',
29+
url: '/test',
30+
foo: 'bar',
31+
data: { title: 'test' }
32+
})).toBe(true)
33+
})
+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import isEmail from 'validator/lib/isEmail'
2+
import isInt from 'validator/lib/isInt'
3+
import isIn from 'validator/lib/isIn'
4+
import isURL from 'validator/lib/isURL'
5+
6+
const isEmpty = (value) => value === undefined || value === null || value === ''
7+
const join = (rules) => (value, data) =>
8+
rules.map((rule) => rule(value, data)).filter((error) => !!error)[0]
9+
10+
export const email = (value) => !isEmpty(value) && !isEmail(value) &&
11+
'Invalid email address'
12+
13+
export const url = (value) => !isEmpty(value) && !isURL(value) &&
14+
'Invalid URL'
15+
16+
export const required = (value) => isEmpty(value) &&
17+
'Required field'
18+
19+
export const minLength = (min) => (value) => !isEmpty(value) && value.length < min &&
20+
`Must be at least ${min} characters`
21+
22+
export const maxLength = (max) => (value) => !isEmpty(value) && value.length > max &&
23+
`Must be no more than ${max} characters`
24+
25+
export const integer = (value) => !isInt(value) &&
26+
'Must be an integer'
27+
28+
export const oneOf = (values) => (value) => !isIn(value, values) &&
29+
`Must be one of: ${values.join(', ')}`
30+
31+
export const match = (field) => (value, data) => data && value !== data[field] &&
32+
'Must match'
33+
34+
export const createValidator = (rules) => (data = {}) => {
35+
const errors = {}
36+
Object.keys(rules).forEach((key) => {
37+
const rule = join([].concat(rules[key]))
38+
const error = rule(data[key], data)
39+
if (error) {
40+
errors[key] = error
41+
}
42+
})
43+
return errors
44+
}
+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import * as v from '.'
2+
3+
test('email', () => {
4+
expect(v.email('invalid')).toBeTruthy()
5+
expect(v.email('invalid@invalid')).toBeTruthy()
6+
expect(v.email('[email protected]')).toBeFalsy()
7+
})
8+
9+
test('url', () => {
10+
expect(v.url('invalid')).toBeTruthy()
11+
expect(v.url('valid.com')).toBeFalsy()
12+
expect(v.url('valid.com/test')).toBeFalsy()
13+
expect(v.url('http://valid.com')).toBeFalsy()
14+
})
15+
16+
test('required', () => {
17+
expect(v.required('')).toBeTruthy()
18+
expect(v.required(null)).toBeTruthy()
19+
expect(v.required(undefined)).toBeTruthy()
20+
expect(v.required('valid')).toBeFalsy()
21+
})
22+
23+
test('minLength', () => {
24+
expect(v.minLength(5)('1234')).toBeTruthy()
25+
expect(v.minLength(5)('12345')).toBeFalsy()
26+
})
27+
28+
test('maxLength', () => {
29+
expect(v.maxLength(5)('123456')).toBeTruthy()
30+
expect(v.maxLength(5)('12345')).toBeFalsy()
31+
})
32+
33+
test('integer', () => {
34+
expect(v.integer('invalid')).toBeTruthy()
35+
expect(v.integer('2.3')).toBeTruthy()
36+
expect(v.integer('.5')).toBeTruthy()
37+
expect(v.integer('1')).toBeFalsy()
38+
})
39+
40+
test('oneOf', () => {
41+
expect(v.oneOf(['valid', 'test'])('invalid')).toBeTruthy()
42+
expect(v.oneOf(['valid', 'test'])('valid')).toBeFalsy()
43+
expect(v.oneOf(['valid', 'test'])('test')).toBeFalsy()
44+
})
45+
46+
test('match', () => {
47+
expect(v.match('invalid')('123', { password: '321' })).toBeTruthy()
48+
expect(v.match('password')('123', { password: '321' })).toBeTruthy()
49+
expect(v.match('password')('321', { password: '321' })).toBeFalsy()
50+
})
51+
52+
test('createValidator', () => {
53+
const validator = v.createValidator({
54+
email: [v.required, v.email],
55+
password: [v.required, v.minLength(6)],
56+
passwordRepeat: [v.match('password'), v.required]
57+
})
58+
59+
expect(typeof validator).toBe('function')
60+
61+
expect(validator({
62+
email: '',
63+
password: '',
64+
passwordRepeat: null
65+
})).toEqual({
66+
email: v.required(''),
67+
password: v.required(''),
68+
passwordRepeat: v.match('a')('c', { a: 'b' })
69+
}, 'Expected to follow the validation order')
70+
71+
expect(Object.keys(validator({
72+
email: 'invalid',
73+
password: '12345',
74+
passwordRepeat: ''
75+
}))).toEqual(['email', 'password', 'passwordRepeat'])
76+
77+
expect(Object.keys(validator({
78+
79+
password: '12345',
80+
passwordRepeat: ''
81+
}))).toEqual(['password', 'passwordRepeat'])
82+
83+
expect(Object.keys(validator({
84+
85+
password: '123456',
86+
passwordRepeat: '654321'
87+
}))).toEqual(['passwordRepeat'])
88+
89+
expect(validator({
90+
91+
password: '123456',
92+
passwordRepeat: '123456'
93+
})).toEqual({})
94+
95+
expect(validator()).toEqual({
96+
email: v.required(''),
97+
password: v.required(''),
98+
passwordRepeat: v.required('')
99+
})
100+
})

0 commit comments

Comments
 (0)