project-booster-vue 8.119.2 → 8.119.3

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": "project-booster-vue",
3
- "version": "8.119.2",
3
+ "version": "8.119.3",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "test:unit": "vue-cli-service test:unit --forceExit --detectOpenHandles",
@@ -24,6 +24,7 @@
24
24
  "dist/*",
25
25
  "src/*",
26
26
  "public/*",
27
+ "scenario-validator/*",
27
28
  "*.json"
28
29
  ],
29
30
  "dependencies": {
@@ -0,0 +1,115 @@
1
+ const R = require('ramda');
2
+ const request = require('request');
3
+ const axios = require('axios');
4
+ const Ajv = require('ajv');
5
+ const {
6
+ getAllStepName,
7
+ hasTemplates,
8
+ hasNoTemplates,
9
+ createDirectGraphForJson,
10
+ getAllConfigurationForTemplateLiteral,
11
+ getPictures,
12
+ getStepComponent,
13
+ } = require('./jsonExplorer');
14
+
15
+ const getUrlStatusCode = (url) => {
16
+ return new Promise((resolve, reject) => {
17
+ const r = request(url);
18
+ r.on('response', (response) => {
19
+ r.abort();
20
+ resolve(response.statusCode);
21
+ });
22
+ r.on('error', function (err) {
23
+ reject(err);
24
+ });
25
+ });
26
+ };
27
+
28
+ const isOffline = process.env.OFFLINE;
29
+
30
+ const itOnline = isOffline ? it.skip : it;
31
+
32
+ const testImage = (url) => {
33
+ describe(url, () => {
34
+ itOnline('should exist', async () => {
35
+ const status = await getUrlStatusCode(url);
36
+ expect(status).toBe(200);
37
+ });
38
+ it('should not be on a subproject bucket', () => {
39
+ const bucketRegex = /^https:\/\/storage.googleapis.com\/budget-estimate-[^\/]+subproject-forms\/.*/;
40
+ expect(bucketRegex.test(url)).toBeFalsy();
41
+ });
42
+ });
43
+ };
44
+
45
+ const validateSchema = (rawJson) => {
46
+ itOnline('should be valid according to json schema', async () => {
47
+ const jsonSchema = (await axios.get('https://adeo.github.io/project-booster-vue/jsonSchema/scenario.json')).data;
48
+ const ajv = new Ajv({ allErrors: true });
49
+ const validate = ajv.compile(jsonSchema);
50
+ const valid = validate(rawJson);
51
+ if (!valid) {
52
+ console.error(validate.errors);
53
+ }
54
+ expect(valid).toBeTruthy();
55
+ });
56
+ };
57
+ const sharedScenarioTests = (json) => {
58
+ validateSchema(json);
59
+ it('should have a __START__ step', () => {
60
+ expect(json['__START__']).toBeDefined();
61
+ });
62
+ it('should have keys same as code', () => {
63
+ R.toPairs(json).forEach(([key, { code }]) => {
64
+ expect(key).toEqual(code);
65
+ });
66
+ });
67
+ describe('images', () => {
68
+ describe('static images', () => {
69
+ const images = getPictures(json).filter(hasNoTemplates);
70
+ for (let url of images) {
71
+ testImage(url);
72
+ }
73
+ });
74
+ describe('dynamic images', () => {
75
+ const images = getPictures(json)
76
+ .filter(hasTemplates)
77
+ .filter((v, i, a) => a.indexOf(v) === i);
78
+ for (let template of images) {
79
+ describe(template, () => {
80
+ for (let url of getAllConfigurationForTemplateLiteral(json, template)) {
81
+ testImage(url);
82
+ }
83
+ });
84
+ }
85
+ });
86
+ });
87
+ describe('steps', () => {
88
+ const graph = createDirectGraphForJson(json);
89
+ const allSteps = getAllStepName(json);
90
+ Object.entries(graph).map(([key, val]) => {
91
+ describe(key, () => {
92
+ it('should have valid destination', () => {
93
+ val.forEach((destination) => {
94
+ expect(allSteps.indexOf(destination)).toBeGreaterThanOrEqual(0);
95
+ });
96
+ });
97
+
98
+ const stepComponentName = getStepComponent(json[key]);
99
+
100
+ if (stepComponentName === 'PbSpaceInput' || stepComponentName === 'PbAmountInput') {
101
+ it('should have a value for going back for a numeric input', () => {
102
+ expect(json[key].payload.value).toBeDefined();
103
+ expect(typeof json[key].payload.value).toBe('object');
104
+ });
105
+ }
106
+ });
107
+ });
108
+ });
109
+ };
110
+
111
+ module.exports.sharedScenarioTests = sharedScenarioTests;
112
+ module.exports.validateSchema = validateSchema;
113
+ module.exports.testImage = testImage;
114
+ module.exports.getUrlStatusCode = getUrlStatusCode;
115
+ module.exports.getPictures = getPictures;
@@ -0,0 +1,165 @@
1
+ const R = require('ramda');
2
+
3
+ const getStepComponent = (step) => (step && step.component) || undefined;
4
+
5
+ const getTemplates = R.match(/(\${.*?})/g);
6
+
7
+ const hasTemplates = (string) => getTemplates(string).length > 0;
8
+ const hasNoTemplates = (string) => getTemplates(string).length === 0;
9
+
10
+ const getPictures = (json) => {
11
+ const polishArray = R.pipe(R.reject(R.isNil), R.flatten, R.reject(R.isNil), R.filter(R.reject(R.isNil)), R.uniq);
12
+ const getAnswersImages = R.pipe(
13
+ R.map(R.pipe(R.path(['payload', 'answers']), R.values, R.map(R.path(['viewModel', 'image'])))),
14
+ R.values,
15
+ );
16
+ const getStrips = R.pipe(R.values, R.map(R.path(['payload', 'viewModel', 'decoratorStripe'])));
17
+ const images = [...getStrips(json), ...getAnswersImages(json)];
18
+ return images.length > 0 ? polishArray(images) : images;
19
+ };
20
+
21
+ const getAllConfigurationForTemplateLiteral = (json, string) => {
22
+ const stepForString = R.pipe(
23
+ R.values,
24
+ R.filter(
25
+ R.compose(
26
+ R.includes(string),
27
+ R.pipe(R.path(['payload', 'answers']), R.values, R.map(R.path(['viewModel', 'image']))),
28
+ ),
29
+ ),
30
+ )(json)[0];
31
+
32
+ const defaultValuesData = R.path(['payload', 'defaultDecoratorValue'], stepForString);
33
+
34
+ const defaultValues = R.pipe(
35
+ R.match(/defaultValue\..+?[ }]/g),
36
+ R.map(
37
+ R.pipe(
38
+ R.split('.'),
39
+ R.nth(1),
40
+ (str) => str.substring(0, str.length - 1),
41
+ (val) => R.path([val], defaultValuesData),
42
+ ),
43
+ ),
44
+ );
45
+
46
+ const answersValues = R.pipe(
47
+ R.match(/(.+?)\[0]\.value/g),
48
+ R.map(
49
+ R.pipe(
50
+ R.split('.'),
51
+ R.nth(1),
52
+ R.split('['),
53
+ R.nth(0),
54
+ (val) => json[val],
55
+ R.path(['payload', 'answers']),
56
+ R.values,
57
+ R.map(R.path(['value'])),
58
+ R.flatten,
59
+ ),
60
+ ),
61
+ R.flatten,
62
+ );
63
+
64
+ const combinator = R.pipe(
65
+ getTemplates,
66
+ R.map((val) => R.concat(defaultValues(val), answersValues(val))),
67
+ );
68
+
69
+ let combined = combinator(string);
70
+
71
+ if (combined.length > 1) {
72
+ combined = R.reduce(R.xprod, [], combined);
73
+ } else {
74
+ combined = R.splitEvery(1, combined[0]);
75
+ }
76
+
77
+ const urls = R.map((pair) => {
78
+ const templates = getTemplates(string);
79
+ let newString = string;
80
+ pair.forEach((value, i) => {
81
+ newString = R.replace(templates[i], value, newString);
82
+ });
83
+ return newString;
84
+ }, combined);
85
+
86
+ return R.uniq(urls);
87
+ };
88
+
89
+ const isTypeScenario = R.propEq('type', 'SCENARIO');
90
+
91
+ const getDestinationFromScenario = (step) => {
92
+ const direction = R.prop('stepCode');
93
+
94
+ return R.filter(R.is(String))([direction(step)]);
95
+ };
96
+
97
+ const getDestinationFromStep = (step) => {
98
+ const forPayload = R.pipe(
99
+ R.path(['payload', 'multiSelect', 'actions', 'VALIDATE', 'nextStep', 'code']),
100
+ R.ifElse(
101
+ R.is(String),
102
+ (val) => [val],
103
+ () => [],
104
+ ),
105
+ );
106
+
107
+ const baseForStep = R.ifElse(
108
+ R.has('nextStep'),
109
+ R.pipe(
110
+ R.prop('nextStep'),
111
+ R.ifElse(
112
+ R.has('code'),
113
+ R.pipe(R.prop('code'), (val) => [val]),
114
+ R.ifElse(
115
+ R.has('conditionals'),
116
+ R.pipe(R.prop('conditionals'), R.map(R.path(['nextStep', 'code']))),
117
+ R.pipe(() => []),
118
+ ),
119
+ ),
120
+ (val) => val || [],
121
+ ),
122
+ () => [],
123
+ );
124
+
125
+ const stepsInside = R.pipe(
126
+ R.ifElse(
127
+ R.propEq('component', 'PbQuestion'),
128
+ R.pipe(R.path(['payload', 'answers']), R.values, R.map(R.path(['nextStep', 'code']))),
129
+ R.ifElse(
130
+ R.propEq('component', 'PbRestitution'),
131
+ R.pipe(
132
+ R.path(['payload', 'callToActions']),
133
+ R.values,
134
+ R.map(R.prop('action')),
135
+ R.filter(R.is(Object)),
136
+ R.map(R.prop('code')),
137
+ ),
138
+ () => R.init([]),
139
+ ),
140
+ ),
141
+ (val) => val || [],
142
+ );
143
+
144
+ const ret = R.filter(R.is(String))(R.concat(stepsInside(step), R.concat(baseForStep(step), forPayload(step))));
145
+
146
+ return ret || [];
147
+ };
148
+
149
+ const getAllStepName = R.keys;
150
+
151
+ const createDirectGraphForJson = (json) => {
152
+ const directGraph = R.pipe(
153
+ R.map(R.pipe(R.ifElse(isTypeScenario, getDestinationFromScenario, getDestinationFromStep), R.uniq())),
154
+ )(json);
155
+
156
+ return R.map(R.filter((val) => val !== 'null'))(directGraph);
157
+ };
158
+
159
+ module.exports.getPictures = getPictures;
160
+ module.exports.getAllStepName = getAllStepName;
161
+ module.exports.getStepComponent = getStepComponent;
162
+ module.exports.createDirectGraphForJson = createDirectGraphForJson;
163
+ module.exports.hasTemplates = hasTemplates;
164
+ module.exports.hasNoTemplates = hasNoTemplates;
165
+ module.exports.getAllConfigurationForTemplateLiteral = getAllConfigurationForTemplateLiteral;