functional-models 1.0.1 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +1 -0
- package/.github/workflows/feature.yml +26 -0
- package/.github/workflows/{ci.yml → ut.yml} +6 -7
- package/.prettierignore +1 -0
- package/README.md +4 -5
- package/features/model.feature +7 -0
- package/features/stepDefinitions/steps.js +87 -0
- package/features/validation.feature +12 -0
- package/package.json +10 -3
- package/src/fields.js +106 -0
- package/src/index.js +4 -4
- package/src/lazy.js +13 -10
- package/src/models.js +55 -0
- package/src/utils.js +1 -17
- package/src/validation.js +173 -0
- package/test/src/fields.test.js +160 -0
- package/test/src/lazy.test.js +9 -19
- package/test/src/models.test.js +97 -0
- package/test/src/utils.test.js +1 -10
- package/test/src/validation.test.js +318 -0
- package/src/dates.js +0 -13
- package/src/objects.js +0 -23
- package/src/properties.js +0 -31
- package/src/references.js +0 -38
- package/test/src/dates.test.js +0 -33
- package/test/src/objects.test.js +0 -50
- package/test/src/properties.test.js +0 -60
- package/test/src/references.test.js +0 -84
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
const assert = require('chai').assert
|
|
2
|
+
const {
|
|
3
|
+
uniqueId,
|
|
4
|
+
field,
|
|
5
|
+
dateField,
|
|
6
|
+
referenceField,
|
|
7
|
+
} = require('../../src/fields')
|
|
8
|
+
const { createModel } = require('../../src/models')
|
|
9
|
+
|
|
10
|
+
describe('/src/fields.js', () => {
|
|
11
|
+
describe('#field()', () => {
|
|
12
|
+
it('should throw an exception if config.valueSelector is not a function but is set', () => {
|
|
13
|
+
assert.throws(() => {
|
|
14
|
+
field({ valueSelector: 'blah' })
|
|
15
|
+
})
|
|
16
|
+
})
|
|
17
|
+
it('should not throw an exception if config.valueSelector is a function', () => {
|
|
18
|
+
assert.doesNotThrow(() => {
|
|
19
|
+
field({ valueSelector: () => ({}) })
|
|
20
|
+
})
|
|
21
|
+
})
|
|
22
|
+
describe('#createGetter()', () => {
|
|
23
|
+
it('should return a function even if config.value is set to a value', () => {
|
|
24
|
+
const instance = field({ value: 'my-value' })
|
|
25
|
+
const actual = instance.createGetter('not-my-value')
|
|
26
|
+
assert.isFunction(actual)
|
|
27
|
+
})
|
|
28
|
+
it('should return the value passed into config.value regardless of what is passed into the createGetter', async () => {
|
|
29
|
+
const instance = field({ value: 'my-value' })
|
|
30
|
+
const actual = await instance.createGetter('not-my-value')()
|
|
31
|
+
const expected = 'my-value'
|
|
32
|
+
assert.deepEqual(actual, expected)
|
|
33
|
+
})
|
|
34
|
+
it('should return the value passed into createGetter when config.value is not set', async () => {
|
|
35
|
+
const instance = field()
|
|
36
|
+
const actual = await instance.createGetter('my-value')()
|
|
37
|
+
const expected = 'my-value'
|
|
38
|
+
assert.deepEqual(actual, expected)
|
|
39
|
+
})
|
|
40
|
+
it('should return the value of the function passed into createGetter when config.value is not set', async () => {
|
|
41
|
+
const instance = field()
|
|
42
|
+
const actual = await instance.createGetter(() => 'my-value')()
|
|
43
|
+
const expected = 'my-value'
|
|
44
|
+
assert.deepEqual(actual, expected)
|
|
45
|
+
})
|
|
46
|
+
})
|
|
47
|
+
})
|
|
48
|
+
describe('#uniqueId()', () => {
|
|
49
|
+
describe('#createGetter()', () => {
|
|
50
|
+
it('should call createUuid only once even if called twice', async () => {
|
|
51
|
+
const uniqueField = uniqueId({})
|
|
52
|
+
const getter = uniqueField.createGetter()
|
|
53
|
+
const first = await getter()
|
|
54
|
+
const second = await getter()
|
|
55
|
+
assert.deepEqual(first, second)
|
|
56
|
+
})
|
|
57
|
+
it('should use the uuid passed in', async () => {
|
|
58
|
+
const uniqueField = uniqueId({})
|
|
59
|
+
const getter = uniqueField.createGetter('my-uuid')
|
|
60
|
+
const actual = await getter()
|
|
61
|
+
const expected = 'my-uuid'
|
|
62
|
+
assert.deepEqual(actual, expected)
|
|
63
|
+
})
|
|
64
|
+
})
|
|
65
|
+
})
|
|
66
|
+
describe('#dateField()', () => {
|
|
67
|
+
it('should create a new date once when config.autoNow=true and called multiple times', async () => {
|
|
68
|
+
const proto = dateField({ autoNow: true })
|
|
69
|
+
const instance = proto.createGetter()
|
|
70
|
+
const first = await instance()
|
|
71
|
+
const second = await instance()
|
|
72
|
+
const third = await instance()
|
|
73
|
+
assert.deepEqual(first, second)
|
|
74
|
+
assert.deepEqual(first, third)
|
|
75
|
+
})
|
|
76
|
+
it('should use the date passed in', async () => {
|
|
77
|
+
const proto = dateField({ autoNow: true })
|
|
78
|
+
const date = new Date()
|
|
79
|
+
const instance = proto.createGetter(date)
|
|
80
|
+
const actual = await instance()
|
|
81
|
+
const expected = date
|
|
82
|
+
assert.deepEqual(actual, expected)
|
|
83
|
+
})
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
describe('#referenceField()', () => {
|
|
87
|
+
describe('#createGetter()', () => {
|
|
88
|
+
it('should return "obj-id" when no fetcher is used', async () => {
|
|
89
|
+
const input = ['obj-id']
|
|
90
|
+
const actual = await referenceField({}).createGetter(...input)()
|
|
91
|
+
const expected = 'obj-id'
|
|
92
|
+
assert.equal(actual, expected)
|
|
93
|
+
})
|
|
94
|
+
it('should allow null as the input', async () => {
|
|
95
|
+
const input = [null]
|
|
96
|
+
const actual = await referenceField({}).createGetter(...input)()
|
|
97
|
+
const expected = null
|
|
98
|
+
assert.equal(actual, expected)
|
|
99
|
+
})
|
|
100
|
+
it('should return "obj-id" from {}.id when no fetcher is used', async () => {
|
|
101
|
+
const input = [{ id: 'obj-id' }]
|
|
102
|
+
const actual = await referenceField({}).createGetter(...input)()
|
|
103
|
+
const expected = 'obj-id'
|
|
104
|
+
assert.equal(actual, expected)
|
|
105
|
+
})
|
|
106
|
+
it('should return prop: "switch-a-roo" when switch-a-roo fetcher is used', async () => {
|
|
107
|
+
const input = ['obj-id']
|
|
108
|
+
const actual = await referenceField({
|
|
109
|
+
fetcher: () => ({ id: 'obj-id', prop: 'switch-a-roo' }),
|
|
110
|
+
}).createGetter(...input)()
|
|
111
|
+
const expected = 'switch-a-roo'
|
|
112
|
+
assert.deepEqual(actual.prop, expected)
|
|
113
|
+
})
|
|
114
|
+
it('should combine functions when switch-a-roo fetcher is used', async () => {
|
|
115
|
+
const input = ['obj-id']
|
|
116
|
+
const instance = await referenceField({
|
|
117
|
+
fetcher: () => ({
|
|
118
|
+
id: 'obj-id',
|
|
119
|
+
prop: 'switch-a-roo',
|
|
120
|
+
functions: { myfunc: 'ok' },
|
|
121
|
+
}),
|
|
122
|
+
}).createGetter(...input)()
|
|
123
|
+
const actual = instance.functions.myfunc
|
|
124
|
+
const expected = 'ok'
|
|
125
|
+
assert.deepEqual(actual, expected)
|
|
126
|
+
})
|
|
127
|
+
it('should take the smartObject as a value', async () => {
|
|
128
|
+
const proto = createModel({
|
|
129
|
+
id: uniqueId({ value: 'obj-id' }),
|
|
130
|
+
})
|
|
131
|
+
const input = [proto({ id: 'obj-id' })]
|
|
132
|
+
const instance = await referenceField({}).createGetter(...input)()
|
|
133
|
+
const actual = await instance.getId()
|
|
134
|
+
const expected = 'obj-id'
|
|
135
|
+
assert.deepEqual(actual, expected)
|
|
136
|
+
})
|
|
137
|
+
describe('#functions.toJson()', () => {
|
|
138
|
+
it('should use the getId of the smartObject passed in when toJson is called', async () => {
|
|
139
|
+
const proto = createModel({
|
|
140
|
+
id: uniqueId({ value: 'obj-id' }),
|
|
141
|
+
})
|
|
142
|
+
const input = [proto({ id: 'obj-id' })]
|
|
143
|
+
const instance = await referenceField({}).createGetter(...input)()
|
|
144
|
+
const actual = await instance.functions.toJson()
|
|
145
|
+
const expected = 'obj-id'
|
|
146
|
+
assert.deepEqual(actual, expected)
|
|
147
|
+
})
|
|
148
|
+
it('should return "obj-id" when switch-a-roo fetcher is used and toJson is called', async () => {
|
|
149
|
+
const input = ['obj-id']
|
|
150
|
+
const instance = await referenceField({
|
|
151
|
+
fetcher: () => ({ id: 'obj-id', prop: 'switch-a-roo' }),
|
|
152
|
+
}).createGetter(...input)()
|
|
153
|
+
const actual = await instance.functions.toJson()
|
|
154
|
+
const expected = 'obj-id'
|
|
155
|
+
assert.deepEqual(actual, expected)
|
|
156
|
+
})
|
|
157
|
+
})
|
|
158
|
+
})
|
|
159
|
+
})
|
|
160
|
+
})
|
package/test/src/lazy.test.js
CHANGED
|
@@ -1,25 +1,15 @@
|
|
|
1
1
|
const assert = require('chai').assert
|
|
2
|
-
const
|
|
2
|
+
const sinon = require('sinon')
|
|
3
|
+
const { lazyValue } = require('../../src/lazy')
|
|
3
4
|
|
|
4
5
|
describe('/src/lazy.js', () => {
|
|
5
|
-
describe('#
|
|
6
|
-
it('should call the
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const obj = lazyProperty(...inputs)
|
|
13
|
-
const actual = await obj.getLazy()
|
|
14
|
-
const expected = 'world'
|
|
15
|
-
assert.deepEqual(actual, expected)
|
|
16
|
-
})
|
|
17
|
-
it('should return the lazy value that is passed in', async () => {
|
|
18
|
-
const inputs = ['lazy', () => 'hello world']
|
|
19
|
-
const obj = lazyProperty(...inputs)
|
|
20
|
-
const actual = await obj.getLazy()
|
|
21
|
-
const expected = 'hello world'
|
|
22
|
-
assert.deepEqual(actual, expected)
|
|
6
|
+
describe('#lazyValue()', () => {
|
|
7
|
+
it('should only call the method passed in once even after two calls', async () => {
|
|
8
|
+
const method = sinon.stub().returns('hello-world')
|
|
9
|
+
const instance = lazyValue(method)
|
|
10
|
+
await instance()
|
|
11
|
+
await instance()
|
|
12
|
+
sinon.assert.calledOnce(method)
|
|
23
13
|
})
|
|
24
14
|
})
|
|
25
15
|
})
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
const assert = require('chai').assert
|
|
2
|
+
const { createModel } = require('../../src/models')
|
|
3
|
+
const { field } = require('../../src/fields')
|
|
4
|
+
|
|
5
|
+
describe('/src/models.js', () => {
|
|
6
|
+
describe('#createModel()', () => {
|
|
7
|
+
it('should return a function when called once with valid data', () => {
|
|
8
|
+
const actual = createModel({})
|
|
9
|
+
const expected = 'function'
|
|
10
|
+
assert.isFunction(actual)
|
|
11
|
+
})
|
|
12
|
+
describe('#()', () => {
|
|
13
|
+
it('should use the value passed in when field.defaultValue and field.value are not set', async () => {
|
|
14
|
+
const input = {
|
|
15
|
+
myField: field({ required: true }),
|
|
16
|
+
}
|
|
17
|
+
const model = createModel(input)
|
|
18
|
+
const instance = model({ myField: 'passed-in' })
|
|
19
|
+
const actual = await instance.getMyField()
|
|
20
|
+
const expected = 'passed-in'
|
|
21
|
+
assert.deepEqual(actual, expected)
|
|
22
|
+
})
|
|
23
|
+
it('should use the value for field.value when even if field.defaultValue is set and a value is passed in', async () => {
|
|
24
|
+
const input = {
|
|
25
|
+
myField: field({ value: 'value', defaultValue: 'default-value' }),
|
|
26
|
+
}
|
|
27
|
+
const model = createModel(input)
|
|
28
|
+
const instance = model({ myField: 'passed-in' })
|
|
29
|
+
const actual = await instance.getMyField()
|
|
30
|
+
const expected = 'value'
|
|
31
|
+
assert.deepEqual(actual, expected)
|
|
32
|
+
})
|
|
33
|
+
it('should use the value for field.value when even if field.defaultValue is not set and a value is passed in', async () => {
|
|
34
|
+
const input = {
|
|
35
|
+
myField: field({ value: 'value' }),
|
|
36
|
+
}
|
|
37
|
+
const model = createModel(input)
|
|
38
|
+
const instance = model({ myField: 'passed-in' })
|
|
39
|
+
const actual = await instance.getMyField()
|
|
40
|
+
const expected = 'value'
|
|
41
|
+
assert.deepEqual(actual, expected)
|
|
42
|
+
})
|
|
43
|
+
it('should use the value for field.defaultValue when field.value is not set and no value is passed in', async () => {
|
|
44
|
+
const input = {
|
|
45
|
+
myField: field({ defaultValue: 'defaultValue' }),
|
|
46
|
+
}
|
|
47
|
+
const model = createModel(input)
|
|
48
|
+
const instance = model({})
|
|
49
|
+
const actual = await instance.getMyField()
|
|
50
|
+
const expected = 'defaultValue'
|
|
51
|
+
assert.deepEqual(actual, expected)
|
|
52
|
+
})
|
|
53
|
+
it('should use the value for field.defaultValue when field.value is not set and null is passed as a value', async () => {
|
|
54
|
+
const input = {
|
|
55
|
+
myField: field({ defaultValue: 'defaultValue' }),
|
|
56
|
+
}
|
|
57
|
+
const model = createModel(input)
|
|
58
|
+
const instance = model({ myField: null })
|
|
59
|
+
const actual = await instance.getMyField()
|
|
60
|
+
const expected = 'defaultValue'
|
|
61
|
+
assert.deepEqual(actual, expected)
|
|
62
|
+
})
|
|
63
|
+
it('should return a model with getId and getType for the provided valid keyToField', () => {
|
|
64
|
+
const input = {
|
|
65
|
+
id: field({ required: true }),
|
|
66
|
+
type: field(),
|
|
67
|
+
}
|
|
68
|
+
const model = createModel(input)
|
|
69
|
+
const actual = model({ id: 'my-id', type: 'my-type' })
|
|
70
|
+
console.log(actual)
|
|
71
|
+
assert.isOk(actual.getId)
|
|
72
|
+
assert.isOk(actual.getType)
|
|
73
|
+
})
|
|
74
|
+
it('should return a model where validate returns one error for id', async () => {
|
|
75
|
+
const input = {
|
|
76
|
+
id: field({ required: true }),
|
|
77
|
+
type: field(),
|
|
78
|
+
}
|
|
79
|
+
const model = createModel(input)
|
|
80
|
+
const instance = model({ type: 'my-type' })
|
|
81
|
+
const actual = await instance.functions.validate.model()
|
|
82
|
+
const expected = 1
|
|
83
|
+
console.log(actual)
|
|
84
|
+
assert.equal(Object.values(actual).length, expected)
|
|
85
|
+
})
|
|
86
|
+
})
|
|
87
|
+
it('should return a function when called once with valid data', () => {
|
|
88
|
+
const actual = createModel({})
|
|
89
|
+
assert.isFunction(actual)
|
|
90
|
+
})
|
|
91
|
+
it('should throw an exception if a key "model" is passed in', () => {
|
|
92
|
+
assert.throws(() => {
|
|
93
|
+
createModel({ model: 'weeee' })
|
|
94
|
+
})
|
|
95
|
+
})
|
|
96
|
+
})
|
|
97
|
+
})
|
package/test/src/utils.test.js
CHANGED
|
@@ -1,18 +1,9 @@
|
|
|
1
1
|
const assert = require('chai').assert
|
|
2
2
|
const sinon = require('sinon')
|
|
3
3
|
const proxyquire = require('proxyquire')
|
|
4
|
-
const { loweredTitleCase, createUuid
|
|
4
|
+
const { loweredTitleCase, createUuid } = require('../../src/utils')
|
|
5
5
|
|
|
6
6
|
describe('/src/utils.js', () => {
|
|
7
|
-
describe('#lazyValue()', () => {
|
|
8
|
-
it('should only call the method passed in once even after two calls', async () => {
|
|
9
|
-
const method = sinon.stub().returns('hello-world')
|
|
10
|
-
const instance = lazyValue(method)
|
|
11
|
-
await instance()
|
|
12
|
-
await instance()
|
|
13
|
-
sinon.assert.calledOnce(method)
|
|
14
|
-
})
|
|
15
|
-
})
|
|
16
7
|
describe('#loweredTitleCase()', () => {
|
|
17
8
|
it('should turn TitleCase into titleCase', () => {
|
|
18
9
|
const actual = loweredTitleCase('TitleCase')
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
const assert = require('chai').assert
|
|
2
|
+
const sinon = require('sinon')
|
|
3
|
+
const {
|
|
4
|
+
isNumber,
|
|
5
|
+
isBoolean,
|
|
6
|
+
isInteger,
|
|
7
|
+
isString,
|
|
8
|
+
isRequired,
|
|
9
|
+
maxNumber,
|
|
10
|
+
minNumber,
|
|
11
|
+
choices,
|
|
12
|
+
maxTextLength,
|
|
13
|
+
minTextLength,
|
|
14
|
+
meetsRegex,
|
|
15
|
+
aggregateValidator,
|
|
16
|
+
emptyValidator,
|
|
17
|
+
createModelValidator,
|
|
18
|
+
createFieldValidator,
|
|
19
|
+
} = require('../../src/validation')
|
|
20
|
+
|
|
21
|
+
describe('/src/validation.js', () => {
|
|
22
|
+
describe('#isNumber()', () => {
|
|
23
|
+
it('should return an error when empty is passed', () => {
|
|
24
|
+
const actual = isNumber(null)
|
|
25
|
+
assert.isOk(actual)
|
|
26
|
+
})
|
|
27
|
+
it('should return an error when "asdf" is passed', () => {
|
|
28
|
+
const actual = isNumber('asdf')
|
|
29
|
+
assert.isOk(actual)
|
|
30
|
+
})
|
|
31
|
+
it('should return undefined when 1 is passed', () => {
|
|
32
|
+
const actual = isNumber(1)
|
|
33
|
+
assert.isUndefined(actual)
|
|
34
|
+
})
|
|
35
|
+
it('should return error when "1" is passed', () => {
|
|
36
|
+
const actual = isNumber('1')
|
|
37
|
+
assert.isOk(actual)
|
|
38
|
+
})
|
|
39
|
+
})
|
|
40
|
+
describe('#isString()', () => {
|
|
41
|
+
it('should return undefined when "1" is passed', () => {
|
|
42
|
+
const actual = isString('1')
|
|
43
|
+
assert.isUndefined(actual)
|
|
44
|
+
})
|
|
45
|
+
it('should return error when 1 is passed', () => {
|
|
46
|
+
const actual = isString(1)
|
|
47
|
+
assert.isOk(actual)
|
|
48
|
+
})
|
|
49
|
+
})
|
|
50
|
+
describe('#isRequired()', () => {
|
|
51
|
+
it('should return undefined when 1 is passed', () => {
|
|
52
|
+
const actual = isRequired(1)
|
|
53
|
+
assert.isUndefined(actual)
|
|
54
|
+
})
|
|
55
|
+
it('should return undefined when 0 is passed', () => {
|
|
56
|
+
const actual = isRequired(0)
|
|
57
|
+
assert.isUndefined(actual)
|
|
58
|
+
})
|
|
59
|
+
it('should return undefined when "something" is passed', () => {
|
|
60
|
+
const actual = isRequired('something')
|
|
61
|
+
assert.isUndefined(actual)
|
|
62
|
+
})
|
|
63
|
+
it('should return error when null is passed', () => {
|
|
64
|
+
const actual = isRequired(null)
|
|
65
|
+
assert.isOk(actual)
|
|
66
|
+
})
|
|
67
|
+
it('should return error when undefined is passed', () => {
|
|
68
|
+
const actual = isRequired(undefined)
|
|
69
|
+
assert.isOk(actual)
|
|
70
|
+
})
|
|
71
|
+
it('should return undefined when false is passed', () => {
|
|
72
|
+
const actual = isRequired(false)
|
|
73
|
+
assert.isUndefined(actual)
|
|
74
|
+
})
|
|
75
|
+
it('should return undefined when true is passed', () => {
|
|
76
|
+
const actual = isRequired(true)
|
|
77
|
+
assert.isUndefined(actual)
|
|
78
|
+
})
|
|
79
|
+
})
|
|
80
|
+
describe('#isBoolean()', () => {
|
|
81
|
+
it('should return error when "true" is passed"', () => {
|
|
82
|
+
const actual = isBoolean('true')
|
|
83
|
+
assert.isOk(actual)
|
|
84
|
+
})
|
|
85
|
+
it('should return an error when "false" is passed', () => {
|
|
86
|
+
const actual = isBoolean('false')
|
|
87
|
+
assert.isOk(actual)
|
|
88
|
+
})
|
|
89
|
+
it('should return undefined when true is passed"', () => {
|
|
90
|
+
const actual = isBoolean(true)
|
|
91
|
+
assert.isUndefined(actual)
|
|
92
|
+
})
|
|
93
|
+
it('should return undefined when false is passed', () => {
|
|
94
|
+
const actual = isBoolean(false)
|
|
95
|
+
assert.isUndefined(actual)
|
|
96
|
+
})
|
|
97
|
+
})
|
|
98
|
+
describe('#maxNumber()', () => {
|
|
99
|
+
it('should return error if max=5 and value="hello world"', () => {
|
|
100
|
+
const actual = maxNumber(5)('hello world')
|
|
101
|
+
assert.isOk(actual)
|
|
102
|
+
})
|
|
103
|
+
it('should return error if max=5 and value=6', () => {
|
|
104
|
+
const actual = maxNumber(5)(6)
|
|
105
|
+
assert.isOk(actual)
|
|
106
|
+
})
|
|
107
|
+
it('should return undefined if max=5 and value=5', () => {
|
|
108
|
+
const actual = maxNumber(5)(5)
|
|
109
|
+
assert.isUndefined(actual)
|
|
110
|
+
})
|
|
111
|
+
it('should return undefined if max=5 and value=4', () => {
|
|
112
|
+
const actual = maxNumber(5)(4)
|
|
113
|
+
assert.isUndefined(actual)
|
|
114
|
+
})
|
|
115
|
+
})
|
|
116
|
+
describe('#minNumber()', () => {
|
|
117
|
+
it('should return error if min=5 and value="hello world"', () => {
|
|
118
|
+
const actual = minNumber(5)('hello world')
|
|
119
|
+
assert.isOk(actual)
|
|
120
|
+
})
|
|
121
|
+
it('should return error if min=5 and value=4', () => {
|
|
122
|
+
const actual = minNumber(5)(4)
|
|
123
|
+
assert.isOk(actual)
|
|
124
|
+
})
|
|
125
|
+
it('should return undefined if min=5 and value=4', () => {
|
|
126
|
+
const actual = minNumber(5)(5)
|
|
127
|
+
assert.isUndefined(actual)
|
|
128
|
+
})
|
|
129
|
+
it('should return undefined if min=5 and value=6', () => {
|
|
130
|
+
const actual = minNumber(5)(6)
|
|
131
|
+
assert.isUndefined(actual)
|
|
132
|
+
})
|
|
133
|
+
})
|
|
134
|
+
describe('#choices()', () => {
|
|
135
|
+
it('should return an error if choices are [1,2,3] and value is 4', () => {
|
|
136
|
+
const actual = choices([1, 2, 3])(4)
|
|
137
|
+
assert.isOk(actual)
|
|
138
|
+
})
|
|
139
|
+
it('should return undefined if choices are [1,2,3] and value is 1', () => {
|
|
140
|
+
const actual = choices([1, 2, 3])(1)
|
|
141
|
+
assert.isUndefined(actual)
|
|
142
|
+
})
|
|
143
|
+
})
|
|
144
|
+
describe('#minTextLength()', () => {
|
|
145
|
+
it('should return error if min=5 and value=5', () => {
|
|
146
|
+
const actual = minTextLength(5)(5)
|
|
147
|
+
assert.isOk(actual)
|
|
148
|
+
})
|
|
149
|
+
it('should return error if length=5 and value="asdf"', () => {
|
|
150
|
+
const actual = minTextLength(5)('asdf')
|
|
151
|
+
assert.isOk(actual)
|
|
152
|
+
})
|
|
153
|
+
it('should return undefined if length=5 and value="hello"', () => {
|
|
154
|
+
const actual = minTextLength(5)('hello')
|
|
155
|
+
assert.isUndefined(actual)
|
|
156
|
+
})
|
|
157
|
+
it('should return undefined if length=5 and value="hello world"', () => {
|
|
158
|
+
const actual = minTextLength(5)('hello world')
|
|
159
|
+
assert.isUndefined(actual)
|
|
160
|
+
})
|
|
161
|
+
})
|
|
162
|
+
describe('#maxTextLength()', () => {
|
|
163
|
+
it('should return error if max=5 and value=5', () => {
|
|
164
|
+
const actual = maxTextLength(5)(5)
|
|
165
|
+
assert.isOk(actual)
|
|
166
|
+
})
|
|
167
|
+
it('should return error if length=5 and value="hello world"', () => {
|
|
168
|
+
const actual = maxTextLength(5)('hello world')
|
|
169
|
+
assert.isOk(actual)
|
|
170
|
+
})
|
|
171
|
+
it('should return undefined if length=5 and value="hello"', () => {
|
|
172
|
+
const actual = maxTextLength(5)('hello')
|
|
173
|
+
assert.isUndefined(actual)
|
|
174
|
+
})
|
|
175
|
+
it('should return undefined if length=5 and value="asdf"', () => {
|
|
176
|
+
const actual = maxTextLength(5)('asdf')
|
|
177
|
+
assert.isUndefined(actual)
|
|
178
|
+
})
|
|
179
|
+
})
|
|
180
|
+
describe('#meetsRegex()', () => {
|
|
181
|
+
it('should return an error with regex=/asdf/ flags="g" and value="hello world"', () => {
|
|
182
|
+
const actual = meetsRegex(/asdf/, 'g')('hello world')
|
|
183
|
+
assert.isOk(actual)
|
|
184
|
+
})
|
|
185
|
+
it('should return undefined with regex=/asdf/ flags="g" and value="hello asdf world"', () => {
|
|
186
|
+
const actual = meetsRegex(/asdf/, 'g')('asdf')
|
|
187
|
+
assert.isUndefined(actual)
|
|
188
|
+
})
|
|
189
|
+
})
|
|
190
|
+
describe('#aggregateValidator()', () => {
|
|
191
|
+
it('should return two errors when two validators are passed, and the value fails both', async () => {
|
|
192
|
+
const validators = [minTextLength(10), isNumber]
|
|
193
|
+
const value = 'asdf'
|
|
194
|
+
const actual = (await aggregateValidator(validators)('asdf')).length
|
|
195
|
+
const expected = 2
|
|
196
|
+
assert.equal(actual, expected)
|
|
197
|
+
})
|
|
198
|
+
it('should return one error when one validator is passed, and the value fails', async () => {
|
|
199
|
+
const validators = minTextLength(10)
|
|
200
|
+
const value = 'asdf'
|
|
201
|
+
const actual = (await aggregateValidator(validators)('asdf')).length
|
|
202
|
+
const expected = 1
|
|
203
|
+
assert.equal(actual, expected)
|
|
204
|
+
})
|
|
205
|
+
})
|
|
206
|
+
describe('#emptyValidator()', () => {
|
|
207
|
+
it('should return an empty array with a value of 1', () => {
|
|
208
|
+
const actual = emptyValidator(1).length
|
|
209
|
+
const expected = 0
|
|
210
|
+
assert.equal(actual, expected)
|
|
211
|
+
})
|
|
212
|
+
it('should return an empty array with a value of "1"', () => {
|
|
213
|
+
const actual = emptyValidator('1').length
|
|
214
|
+
const expected = 0
|
|
215
|
+
assert.equal(actual, expected)
|
|
216
|
+
})
|
|
217
|
+
it('should return an empty array with a value of true', () => {
|
|
218
|
+
const actual = emptyValidator(true).length
|
|
219
|
+
const expected = 0
|
|
220
|
+
assert.equal(actual, expected)
|
|
221
|
+
})
|
|
222
|
+
it('should return an empty array with a value of false', () => {
|
|
223
|
+
const actual = emptyValidator(false).length
|
|
224
|
+
const expected = 0
|
|
225
|
+
assert.equal(actual, expected)
|
|
226
|
+
})
|
|
227
|
+
it('should return an empty array with a value of undefined', () => {
|
|
228
|
+
const actual = emptyValidator(undefined).length
|
|
229
|
+
const expected = 0
|
|
230
|
+
assert.equal(actual, expected)
|
|
231
|
+
})
|
|
232
|
+
})
|
|
233
|
+
describe('#isInteger()', () => {
|
|
234
|
+
it('should return an error with a value of "1"', () => {
|
|
235
|
+
const actual = isInteger('1')
|
|
236
|
+
assert.isOk(actual)
|
|
237
|
+
})
|
|
238
|
+
it('should return undefined with a value of 1', () => {
|
|
239
|
+
const actual = isInteger(1)
|
|
240
|
+
assert.isUndefined(actual)
|
|
241
|
+
})
|
|
242
|
+
})
|
|
243
|
+
describe('#createModelValidator()', () => {
|
|
244
|
+
it('should use both functions.validate for two objects', async () => {
|
|
245
|
+
const fields = {
|
|
246
|
+
functions: {
|
|
247
|
+
validate: {
|
|
248
|
+
id: sinon.stub().returns(undefined),
|
|
249
|
+
type: sinon.stub().returns(undefined),
|
|
250
|
+
},
|
|
251
|
+
},
|
|
252
|
+
}
|
|
253
|
+
const validator = createModelValidator(fields)
|
|
254
|
+
await validator()
|
|
255
|
+
sinon.assert.calledOnce(fields.functions.validate.id)
|
|
256
|
+
sinon.assert.calledOnce(fields.functions.validate.type)
|
|
257
|
+
})
|
|
258
|
+
it('should combine results for both functions.validate for two objects that error', async () => {
|
|
259
|
+
const fields = {
|
|
260
|
+
functions: {
|
|
261
|
+
validate: {
|
|
262
|
+
id: sinon.stub().returns('error1'),
|
|
263
|
+
type: sinon.stub().returns('error2'),
|
|
264
|
+
},
|
|
265
|
+
},
|
|
266
|
+
}
|
|
267
|
+
const validator = createModelValidator(fields)
|
|
268
|
+
const actual = await validator()
|
|
269
|
+
const expected = {
|
|
270
|
+
id: 'error1',
|
|
271
|
+
type: 'error2',
|
|
272
|
+
}
|
|
273
|
+
assert.deepEqual(actual, expected)
|
|
274
|
+
})
|
|
275
|
+
it('should take the error of the one of two functions', async () => {
|
|
276
|
+
const fields = {
|
|
277
|
+
functions: {
|
|
278
|
+
validate: {
|
|
279
|
+
id: sinon.stub().returns(undefined),
|
|
280
|
+
type: sinon.stub().returns('error2'),
|
|
281
|
+
},
|
|
282
|
+
},
|
|
283
|
+
}
|
|
284
|
+
const validator = createModelValidator(fields)
|
|
285
|
+
const actual = await validator()
|
|
286
|
+
const expected = {
|
|
287
|
+
type: 'error2',
|
|
288
|
+
}
|
|
289
|
+
assert.deepEqual(actual, expected)
|
|
290
|
+
})
|
|
291
|
+
})
|
|
292
|
+
describe('#createFieldValidator()', () => {
|
|
293
|
+
it('should not include isRequired if required=false, returning []', async () => {
|
|
294
|
+
const validator = createFieldValidator({ required: false })
|
|
295
|
+
const actual = await validator(null)
|
|
296
|
+
const expected = []
|
|
297
|
+
assert.deepEqual(actual, expected)
|
|
298
|
+
})
|
|
299
|
+
it('should return [] if no configs are provided', async () => {
|
|
300
|
+
const validator = createFieldValidator({})
|
|
301
|
+
const actual = await validator(null)
|
|
302
|
+
const expected = []
|
|
303
|
+
assert.deepEqual(actual, expected)
|
|
304
|
+
})
|
|
305
|
+
it('should use isRequired if required=false, returning one error', async () => {
|
|
306
|
+
const validator = createFieldValidator({ required: true })
|
|
307
|
+
const actual = await validator(null)
|
|
308
|
+
const expected = 1
|
|
309
|
+
assert.equal(actual.length, expected)
|
|
310
|
+
})
|
|
311
|
+
it('should use validators.isRequired returning one error', async () => {
|
|
312
|
+
const validator = createFieldValidator({ validators: [isRequired] })
|
|
313
|
+
const actual = await validator(null)
|
|
314
|
+
const expected = 1
|
|
315
|
+
assert.equal(actual.length, expected)
|
|
316
|
+
})
|
|
317
|
+
})
|
|
318
|
+
})
|
package/src/dates.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
const { property } = require('./properties')
|
|
2
|
-
|
|
3
|
-
const _autonowDate = ({ key }) => (date = null, ...args) => {
|
|
4
|
-
const theDate = date ? date : new Date()
|
|
5
|
-
return property(key, theDate, ...args)
|
|
6
|
-
}
|
|
7
|
-
const lastModifiedProperty = _autonowDate({ key: 'lastModified' })
|
|
8
|
-
const lastUpdatedProperty = _autonowDate({ key: 'lastUpdated' })
|
|
9
|
-
|
|
10
|
-
module.exports = {
|
|
11
|
-
lastModifiedProperty,
|
|
12
|
-
lastUpdatedProperty,
|
|
13
|
-
}
|
package/src/objects.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
const { toJson } = require('./serialization')
|
|
2
|
-
|
|
3
|
-
const smartObject = (
|
|
4
|
-
internals,
|
|
5
|
-
{ metaProperties = {}, functions = {} } = {}
|
|
6
|
-
) => {
|
|
7
|
-
const realInternals = Array.isArray(internals)
|
|
8
|
-
? internals.reduce((acc, obj) => ({ ...acc, ...obj }), {})
|
|
9
|
-
: internals
|
|
10
|
-
|
|
11
|
-
return {
|
|
12
|
-
...(metaProperties ? { meta: { ...metaProperties } } : {}),
|
|
13
|
-
...realInternals,
|
|
14
|
-
functions: {
|
|
15
|
-
...functions,
|
|
16
|
-
toJson: toJson(realInternals),
|
|
17
|
-
},
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
module.exports = {
|
|
22
|
-
smartObject,
|
|
23
|
-
}
|