@defra-fish/business-rules-lib 1.48.0 → 1.49.0-rc.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@defra-fish/business-rules-lib",
3
- "version": "1.48.0",
3
+ "version": "1.49.0-rc.0",
4
4
  "description": "Shared business rules for the rod licensing digital services",
5
5
  "type": "module",
6
6
  "engines": {
@@ -37,5 +37,5 @@
37
37
  "moment": "^2.29.1",
38
38
  "uuid": "^8.3.2"
39
39
  },
40
- "gitHead": "8e068512dcdb2fb5b57ec4f361e51004599ef32c"
40
+ "gitHead": "7e16adc1d78e8619339261efe774e81a6f87d68c"
41
41
  }
@@ -0,0 +1,95 @@
1
+ import Joi from 'joi'
2
+ import * as dateValidation from '../date.validators.js'
3
+
4
+ describe('date validators', () => {
5
+ describe('dayValidator', () => {
6
+ it.each([1, 15, 31])('validates if %s is an integer between 1 and 31', async value => {
7
+ await expect(dateValidation.createDayValidator(Joi).validateAsync(value)).resolves.toEqual(value)
8
+ })
9
+
10
+ it.each([
11
+ ['less than 1', 0, 'must be greater than or equal to 1'],
12
+ ['greater than 31', 32, 'must be less than or equal to 31'],
13
+ ['a non-integer number', 1.5, 'must be an integer'],
14
+ ['a string', 'foo', 'must be a number'],
15
+ ['an empty string', '', 'must be a number'],
16
+ ['null', null, 'must be a number'],
17
+ ['undefined', undefined, 'is required']
18
+ ])('throws an error if the value is %s', async (_desc, value, message) => {
19
+ await expect(dateValidation.createDayValidator(Joi).validateAsync(value)).rejects.toThrow('"value" ' + message)
20
+ })
21
+ })
22
+
23
+ describe('monthValidator', () => {
24
+ it.each([1, 6, 12])('validates if %s is an integer between 1 and 12', async value => {
25
+ await expect(dateValidation.createMonthValidator(Joi).validateAsync(value)).resolves.toEqual(value)
26
+ })
27
+
28
+ it.each([
29
+ ['less than 1', 0, 'must be greater than or equal to 1'],
30
+ ['greater than 12', 13, 'must be less than or equal to 12'],
31
+ ['a non-integer number', 1.5, 'must be an integer'],
32
+ ['a string', 'foo', 'must be a number'],
33
+ ['an empty string', '', 'must be a number'],
34
+ ['null', null, 'must be a number'],
35
+ ['undefined', undefined, 'is required']
36
+ ])('throws an error if the value is %s', async (_desc, value, message) => {
37
+ await expect(dateValidation.createMonthValidator(Joi).validateAsync(value)).rejects.toThrow('"value" ' + message)
38
+ })
39
+ })
40
+
41
+ describe('yearValidator', () => {
42
+ it.each([
43
+ [1900, 1900, 2024],
44
+ [1991, 1950, 2000],
45
+ [2500, 1500, 2500]
46
+ ])('validates if %s is an integer between %s and %s', async (value, minYear, maxYear) => {
47
+ await expect(dateValidation.createYearValidator(Joi, minYear, maxYear).validateAsync(value)).resolves.toEqual(value)
48
+ })
49
+
50
+ it.each([
51
+ ['less than the minimum year', 1800, 'must be greater than or equal to 1900'],
52
+ ['greater than the maximum year', 2500, 'must be less than or equal to 2024'],
53
+ ['a non-integer number', 1950.5, 'must be an integer'],
54
+ ['a string', 'foo', 'must be a number'],
55
+ ['an empty string', '', 'must be a number'],
56
+ ['null', null, 'must be a number'],
57
+ ['undefined', undefined, 'is required']
58
+ ])('throws an error if the value is %s', async (_desc, value, message) => {
59
+ await expect(dateValidation.createYearValidator(Joi, 1900, 2024).validateAsync(value)).rejects.toThrow('"value" ' + message)
60
+ })
61
+ })
62
+
63
+ describe('createNumericCharacterValidator', () => {
64
+ it.each(['1', '99', '0'])('validates if %s is a string made of valid numeric characters', async value => {
65
+ await expect(dateValidation.createNumericCharacterValidator(Joi).validateAsync(value)).resolves.toEqual(value)
66
+ })
67
+
68
+ it.each(['foo', '1.5'])('throws an error if %s is not a string made of numeric characters', async value => {
69
+ await expect(dateValidation.createNumericCharacterValidator(Joi).validateAsync(value)).rejects.toThrow(
70
+ '"value" with value "' + value + '" fails to match the required pattern: /^\\d*$/'
71
+ )
72
+ })
73
+ })
74
+
75
+ describe('createRealDateValidator', () => {
76
+ it.each([
77
+ ['January 1st 2021', { year: 2021, month: 1, day: 1 }],
78
+ ['June 30th 2023', { year: 2023, month: 6, day: 30 }],
79
+ ['February 29th 2024', { year: 2024, month: 2, day: 29 }],
80
+ ['December 3rd 1950', { year: 1950, month: 12, day: 3 }]
81
+ ])('validates if %s is a real date', async (_desc, value) => {
82
+ await expect(dateValidation.createRealDateValidator(Joi).validateAsync(value)).resolves.toEqual(value)
83
+ })
84
+
85
+ it.each([
86
+ ['the day does not exist in that month', { year: 2021, month: 4, day: 31 }],
87
+ ['the 29th of February is given in a non-leap year', { year: 2023, month: 2, day: 29 }],
88
+ ['the month is too high', { year: 1950, month: 13, day: 31 }],
89
+ ['a field is not a valid number', { year: 'foo', month: 1, day: 1 }],
90
+ ['a field is not defined', { year: undefined, month: 1, day: 1 }]
91
+ ])('throws an error if %s', async (_desc, value) => {
92
+ await expect(dateValidation.createRealDateValidator(Joi).validateAsync(value)).rejects.toThrow('"value" must be a real date')
93
+ })
94
+ })
95
+ })
@@ -0,0 +1,30 @@
1
+ const MAX_DAY = 31
2
+ const MAX_MONTH = 12
3
+
4
+ export const createDayValidator = joi => joi.number().integer().min(1).max(MAX_DAY).required()
5
+
6
+ export const createMonthValidator = joi => joi.number().integer().min(1).max(MAX_MONTH).required()
7
+
8
+ export const createYearValidator = (joi, minYear, maxYear) => joi.number().integer().min(minYear).max(maxYear).required()
9
+
10
+ export const createNumericCharacterValidator = joi =>
11
+ joi.string().trim().pattern(/^\d*$/).description('A string of numeric characters only').example('31')
12
+
13
+ export const createRealDateValidator = joi =>
14
+ joi.object().extend({
15
+ type: 'date',
16
+ messages: {
17
+ 'date.real': '{{#label}} must be a real date'
18
+ },
19
+ validate (value, helpers) {
20
+ const enteredDate = [value.year, value.month - 1, value.day]
21
+ const constructedDate = new Date(Date.UTC(...enteredDate))
22
+ const deconstructedDate = [constructedDate.getFullYear(), constructedDate.getMonth(), constructedDate.getDate()]
23
+ for (let i = 0; i < enteredDate.length; i++) {
24
+ if (enteredDate[i] !== deconstructedDate[i]) {
25
+ return { value, errors: helpers.error('date.real') }
26
+ }
27
+ }
28
+ return { value }
29
+ }
30
+ })