Skip to content

Commit f0c4b59

Browse files
arszhlirantal
authored andcommitted
feat(opinion_scale): add average and median stats (#20)
1 parent c730b1c commit f0c4b59

File tree

5 files changed

+89
-0
lines changed

5 files changed

+89
-0
lines changed

__tests__/Form/__snapshots__/form.test.js.snap

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,9 @@ Object {
295295
},
296296
],
297297
},
298+
"average": 7,
298299
"id": "TIOUqoiyBSi81",
300+
"median": 7,
299301
"properties": Object {
300302
"labels": Object {
301303
"left": "Not knowledgeable",

__tests__/Form/adapters.test.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ const formResponseAnswersAdapters = require(path.resolve(
33
'./src/Form/Adapters/formResponsesAnswersAdapters'
44
))
55
const formFieldsAdapters = require(path.resolve('./src/Form/Adapters/formFieldsAdapters'))
6+
const questionStatisticsAdapters = require(path.resolve(
7+
'./src/Form/Adapters/questionStatisticsAdapters'
8+
))
69

710
describe('Adapters', () => {
811
describe('Forms fields', () => {
@@ -43,4 +46,35 @@ describe('Adapters', () => {
4346
expect(answerObject).toHaveProperty('answerData.data', mockAnswer.choice.other)
4447
})
4548
})
49+
50+
describe('Fields statistics', () => {
51+
it('Opinion scale calculates correct median and average', () => {
52+
const mockQuestion1 = {
53+
1: Array(6),
54+
2: Array(4),
55+
3: Array(2),
56+
4: Array(9)
57+
}
58+
59+
const mockQuestion2 = {
60+
1: Array(6),
61+
2: Array(12),
62+
3: Array(3),
63+
4: Array(6)
64+
}
65+
66+
const questionStatisticAdapter = questionStatisticsAdapters.get('opinion_scale')
67+
const adaptorResponse1 = questionStatisticAdapter(mockQuestion1)
68+
const adaptorResponse2 = questionStatisticAdapter(mockQuestion2)
69+
70+
expect(adaptorResponse1).toMatchObject({
71+
median: 3,
72+
average: 2.67
73+
})
74+
expect(adaptorResponse2).toMatchObject({
75+
median: 2,
76+
average: 2.33
77+
})
78+
})
79+
})
4680
})
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
'use strict'
2+
const mathUtils = require('../Utils/MathUtils')
3+
4+
const questionStatisticsAdapters = new Map()
5+
questionStatisticsAdapters.set('opinion_scale', answers => {
6+
const answersArr = Object.keys(answers).reduce((result, key) => {
7+
const amount = answers[key].length
8+
if (amount) {
9+
const number = parseInt(key)
10+
result = result.concat(Array(amount).fill(number))
11+
}
12+
return result
13+
}, [])
14+
15+
const median = mathUtils.median(answersArr)
16+
const average = mathUtils.average(answersArr)
17+
18+
return {
19+
median,
20+
average: mathUtils.roundTo(average, 2)
21+
}
22+
})
23+
24+
module.exports = questionStatisticsAdapters

src/Form/Form.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
const {createClient} = require('@typeform/api-client')
44
const formFieldAdapters = require('./Adapters/formFieldsAdapters')
55
const formResponseAnswersAdapters = require('./Adapters/formResponsesAnswersAdapters')
6+
const questionStatisticsAdapters = require('./Adapters/questionStatisticsAdapters')
67

78
module.exports = class Form {
89
constructor({apiKey} = {}) {
@@ -101,6 +102,17 @@ module.exports = class Form {
101102
}
102103
}
103104

105+
_fillStatistics(form) {
106+
const fields = Object.values(form.fields)
107+
for (const field of fields) {
108+
const questionStatisticAdapter = questionStatisticsAdapters.get(field.type)
109+
if (questionStatisticAdapter) {
110+
const adaptorResponse = questionStatisticAdapter(field.answers)
111+
Object.assign(field, adaptorResponse)
112+
}
113+
}
114+
}
115+
104116
async fetchFormResponses(formId) {
105117
const form = await this._fetchForm(formId)
106118
const {totalRespondents, submissionAnswers} = await this._fetchResponses(formId)
@@ -146,6 +158,7 @@ module.exports = class Form {
146158
}
147159
})
148160
})
161+
this._fillStatistics(form)
149162

150163
return form
151164
}

src/Form/Utils/MathUtils.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
'use strict'
2+
3+
const median = arr => {
4+
const mid = Math.floor(arr.length / 2)
5+
const nums = [...arr].sort()
6+
return arr.length % 2 !== 0 ? nums[mid] : (nums[mid - 1] + nums[mid]) / 2
7+
}
8+
const average = arr => arr.reduce((sum, current) => sum + current, 0) / arr.length
9+
10+
const roundTo = (number, precision) => Number(number.toFixed(precision))
11+
12+
module.exports = {
13+
median,
14+
average,
15+
roundTo
16+
}

0 commit comments

Comments
 (0)