@coorpacademy/app-review 0.2.4 → 0.2.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.
Files changed (97) hide show
  1. package/es/actions/api/post-answer.js +4 -2
  2. package/es/actions/api/test/fetch-correction.test.js +2 -1
  3. package/es/actions/api/test/fetch-skills.test.js +2 -1
  4. package/es/actions/api/test/fetch-slide.test.js +2 -1
  5. package/es/actions/api/test/post-answer.test.js +32 -10
  6. package/es/actions/api/test/post-progression.test.js +2 -1
  7. package/es/actions/data/test/token.test.js +2 -1
  8. package/es/actions/test/create-test-store.d.ts +1 -1
  9. package/es/actions/ui/answers.js +13 -6
  10. package/es/actions/ui/test/answers.test.js +17 -1
  11. package/es/actions/ui/test/slides.test.js +2 -1
  12. package/es/reducers/data/index.d.ts +4 -2
  13. package/es/reducers/data/index.js +2 -6
  14. package/es/reducers/index.d.ts +2 -1
  15. package/es/reducers/ui/index.d.ts +1 -1
  16. package/es/reducers/ui/slide.d.ts +3 -1
  17. package/es/reducers/ui/slide.js +5 -0
  18. package/es/reducers/ui/test/slide.test.js +12 -0
  19. package/es/types/slides.d.ts +1 -0
  20. package/es/views/skills/test/skills.test.js +4 -2
  21. package/es/views/slides/map-api-slide-to-ui.js +8 -7
  22. package/es/views/slides/test/fixtures/qcm-graphic.js +4 -2
  23. package/es/views/slides/test/fixtures/qcm.js +4 -4
  24. package/es/views/slides/test/index.test.js +20 -10
  25. package/es/views/slides/test/slide.free-text.on-change.test.d.ts +1 -0
  26. package/es/views/slides/test/slide.free-text.on-change.test.js +69 -0
  27. package/es/views/slides/test/slide.qcm-drag.on-click.test.d.ts +1 -0
  28. package/es/views/slides/test/slide.qcm-drag.on-click.test.js +69 -0
  29. package/es/views/slides/test/slide.qcm-graphic.on-click.test.d.ts +1 -0
  30. package/es/views/slides/test/slide.qcm-graphic.on-click.test.js +69 -0
  31. package/es/views/slides/test/slide.qcm.on-click.test.d.ts +1 -0
  32. package/es/views/slides/test/slide.qcm.on-click.test.js +71 -0
  33. package/es/views/slides/test/slide.slider.on-change.test.d.ts +1 -0
  34. package/es/views/slides/test/slide.slider.on-change.test.js +70 -0
  35. package/es/views/slides/test/slide.template.on-change.test.js +2 -1
  36. package/lib/actions/api/post-answer.js +9 -5
  37. package/lib/actions/api/test/fetch-correction.test.js +2 -1
  38. package/lib/actions/api/test/fetch-skills.test.js +2 -1
  39. package/lib/actions/api/test/fetch-slide.test.js +2 -1
  40. package/lib/actions/api/test/post-answer.test.js +45 -14
  41. package/lib/actions/api/test/post-progression.test.js +2 -1
  42. package/lib/actions/data/test/token.test.js +2 -1
  43. package/lib/actions/test/create-test-store.d.ts +1 -1
  44. package/lib/actions/ui/answers.js +13 -6
  45. package/lib/actions/ui/test/answers.test.js +43 -1
  46. package/lib/actions/ui/test/slides.test.js +2 -1
  47. package/lib/reducers/data/index.d.ts +4 -2
  48. package/lib/reducers/data/index.js +2 -6
  49. package/lib/reducers/index.d.ts +2 -1
  50. package/lib/reducers/ui/index.d.ts +1 -1
  51. package/lib/reducers/ui/slide.d.ts +3 -1
  52. package/lib/reducers/ui/slide.js +5 -0
  53. package/lib/reducers/ui/test/slide.test.js +12 -0
  54. package/lib/types/slides.d.ts +1 -0
  55. package/lib/views/skills/test/skills.test.js +4 -2
  56. package/lib/views/slides/map-api-slide-to-ui.js +8 -7
  57. package/lib/views/slides/test/fixtures/qcm-graphic.js +4 -2
  58. package/lib/views/slides/test/fixtures/qcm.js +4 -4
  59. package/lib/views/slides/test/index.test.js +20 -10
  60. package/lib/views/slides/test/slide.free-text.on-change.test.d.ts +1 -0
  61. package/lib/views/slides/test/slide.free-text.on-change.test.js +71 -0
  62. package/lib/views/slides/test/slide.qcm-drag.on-click.test.d.ts +1 -0
  63. package/lib/views/slides/test/slide.qcm-drag.on-click.test.js +71 -0
  64. package/lib/views/slides/test/slide.qcm-graphic.on-click.test.d.ts +1 -0
  65. package/lib/views/slides/test/slide.qcm-graphic.on-click.test.js +71 -0
  66. package/lib/views/slides/test/slide.qcm.on-click.test.d.ts +1 -0
  67. package/lib/views/slides/test/slide.qcm.on-click.test.js +73 -0
  68. package/lib/views/slides/test/slide.slider.on-change.test.d.ts +1 -0
  69. package/lib/views/slides/test/slide.slider.on-change.test.js +72 -0
  70. package/lib/views/slides/test/slide.template.on-change.test.js +2 -1
  71. package/package.json +3 -3
  72. package/src/actions/api/post-answer.ts +4 -2
  73. package/src/actions/api/test/fetch-correction.test.ts +2 -1
  74. package/src/actions/api/test/fetch-skills.test.ts +2 -1
  75. package/src/actions/api/test/fetch-slide.test.ts +2 -1
  76. package/src/actions/api/test/post-answer.test.ts +51 -10
  77. package/src/actions/api/test/post-progression.test.ts +2 -1
  78. package/src/actions/data/test/token.test.ts +2 -1
  79. package/src/actions/test/create-test-store.ts +1 -1
  80. package/src/actions/ui/answers.ts +15 -6
  81. package/src/actions/ui/test/answers.test.ts +33 -2
  82. package/src/actions/ui/test/slides.test.ts +2 -1
  83. package/src/reducers/data/index.ts +3 -7
  84. package/src/reducers/ui/slide.ts +7 -1
  85. package/src/reducers/ui/test/slide.test.ts +13 -0
  86. package/src/types/slides.ts +1 -0
  87. package/src/views/skills/test/skills.test.ts +4 -2
  88. package/src/views/slides/map-api-slide-to-ui.ts +8 -7
  89. package/src/views/slides/test/fixtures/qcm-graphic.ts +4 -2
  90. package/src/views/slides/test/fixtures/qcm.ts +5 -4
  91. package/src/views/slides/test/index.test.ts +20 -10
  92. package/src/views/slides/test/slide.free-text.on-change.test.ts +79 -0
  93. package/src/views/slides/test/slide.qcm-drag.on-click.test.ts +78 -0
  94. package/src/views/slides/test/slide.qcm-graphic.on-click.test.ts +79 -0
  95. package/src/views/slides/test/slide.qcm.on-click.test.ts +80 -0
  96. package/src/views/slides/test/slide.slider.on-change.test.ts +80 -0
  97. package/src/views/slides/test/slide.template.on-change.test.ts +2 -1
@@ -0,0 +1,73 @@
1
+ var _a;
2
+ import test from 'ava';
3
+ import omit from 'lodash/fp/omit';
4
+ import get from 'lodash/fp/get';
5
+ import { mapStateToSlidesProps } from '..';
6
+ import { services } from '../../../test/util/services.mock';
7
+ import { createTestStore } from '../../../actions/test/create-test-store';
8
+ import { EDIT_QCM } from '../../../actions/ui/answers';
9
+ import { qcmSlide } from './fixtures/qcm';
10
+ var progression = {
11
+ _id: '123456789123',
12
+ content: { type: 'skill', ref: '_skill-ref' },
13
+ engine: {
14
+ ref: 'review'
15
+ },
16
+ state: {
17
+ allAnswers: [],
18
+ isCorrect: true,
19
+ nextContent: {
20
+ ref: qcmSlide._id,
21
+ type: 'slide'
22
+ },
23
+ pendingSlides: [],
24
+ slides: [],
25
+ step: {
26
+ current: 1
27
+ },
28
+ stars: 0
29
+ }
30
+ };
31
+ var initialState = {
32
+ data: {
33
+ progression: progression,
34
+ slides: (_a = {},
35
+ _a[qcmSlide._id] = qcmSlide,
36
+ _a),
37
+ skills: [],
38
+ token: '1234',
39
+ corrections: {}
40
+ },
41
+ ui: {
42
+ currentSlideRef: qcmSlide._id,
43
+ navigation: ['skills', 'slides'],
44
+ answers: [],
45
+ slide: {
46
+ validateButton: false
47
+ }
48
+ }
49
+ };
50
+ test('should dispatch EDIT_QCM action via the property onClick of a QCM slide', function (t) {
51
+ var _a;
52
+ t.plan(2);
53
+ var expectedActions = [
54
+ {
55
+ type: EDIT_QCM,
56
+ payload: [
57
+ "Pour chaque transaction il existe un pourcentage fixe déterminé par le droit d'auteur du pays où se tient la vente"
58
+ ]
59
+ }
60
+ ];
61
+ var _b = createTestStore(t, initialState, services, expectedActions), dispatch = _b.dispatch, getState = _b.getState;
62
+ var props = mapStateToSlidesProps(getState(), dispatch);
63
+ t.deepEqual(omit('answerUI', props.stack.slides['0']), {
64
+ hidden: false,
65
+ position: 0,
66
+ loading: false,
67
+ parentContentTitle: 'From "Developing the review app" course',
68
+ questionText: "Après la vente d'un NFT, son créateur peut-il toucher de l'argent ?"
69
+ });
70
+ var SlideProps = (_a = props.stack.slides['0'].answerUI) === null || _a === void 0 ? void 0 : _a.model;
71
+ var onClick = get(['1', 'onClick'], SlideProps.answers);
72
+ onClick();
73
+ });
@@ -0,0 +1,72 @@
1
+ var _a;
2
+ import test from 'ava';
3
+ import omit from 'lodash/fp/omit';
4
+ import get from 'lodash/fp/get';
5
+ import { mapStateToSlidesProps } from '..';
6
+ import { services } from '../../../test/util/services.mock';
7
+ import { createTestStore } from '../../../actions/test/create-test-store';
8
+ import { EDIT_SLIDER } from '../../../actions/ui/answers';
9
+ import { sliderSlide } from './fixtures/slider';
10
+ var progression = {
11
+ _id: '123456789123',
12
+ content: { type: 'skill', ref: '_skill-ref' },
13
+ engine: {
14
+ ref: 'review'
15
+ },
16
+ state: {
17
+ allAnswers: [],
18
+ isCorrect: true,
19
+ nextContent: {
20
+ ref: sliderSlide._id,
21
+ type: 'slide'
22
+ },
23
+ pendingSlides: [],
24
+ slides: [],
25
+ step: {
26
+ current: 1
27
+ },
28
+ stars: 0
29
+ }
30
+ };
31
+ var initialState = {
32
+ data: {
33
+ progression: progression,
34
+ slides: (_a = {},
35
+ _a[sliderSlide._id] = sliderSlide,
36
+ _a),
37
+ skills: [],
38
+ token: '1234',
39
+ corrections: {}
40
+ },
41
+ ui: {
42
+ currentSlideRef: sliderSlide._id,
43
+ navigation: ['skills', 'slides'],
44
+ answers: [],
45
+ slide: {
46
+ validateButton: false
47
+ }
48
+ }
49
+ };
50
+ test('should dispatch EDIT_SLIDER action via the property onChange of a Slider slide', function (t) {
51
+ var _a;
52
+ t.plan(2);
53
+ var expectedActions = [
54
+ {
55
+ type: EDIT_SLIDER,
56
+ payload: ['5']
57
+ }
58
+ ];
59
+ var _b = createTestStore(t, initialState, services, expectedActions), dispatch = _b.dispatch, getState = _b.getState;
60
+ var props = mapStateToSlidesProps(getState(), dispatch);
61
+ t.deepEqual(omit('answerUI', props.stack.slides['0']), {
62
+ hidden: false,
63
+ position: 0,
64
+ loading: false,
65
+ parentContentTitle: 'From "Developing the review app" course',
66
+ questionText: 'En combien d’années la communauté de communes du Thouarsais est-elle passée de zéro à un tiers d’énergies renouvelables ?'
67
+ });
68
+ var SlideProps = (_a = props.stack.slides['0'].answerUI) === null || _a === void 0 ? void 0 : _a.model;
69
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
70
+ var onChange = get('onChange', SlideProps);
71
+ onChange(0.29339261968085106);
72
+ });
@@ -35,7 +35,8 @@ var initialState = {
35
35
  _a[templateSlide._id] = templateSlide,
36
36
  _a),
37
37
  skills: [],
38
- token: '1234'
38
+ token: '1234',
39
+ corrections: {}
39
40
  },
40
41
  ui: {
41
42
  currentSlideRef: templateSlide._id,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coorpacademy/app-review",
3
- "version": "0.2.4",
3
+ "version": "0.2.5",
4
4
  "description": "",
5
5
  "engines": {
6
6
  "node": ">=16.15.0"
@@ -41,7 +41,7 @@
41
41
  "./package.json": "./package.json"
42
42
  },
43
43
  "dependencies": {
44
- "@coorpacademy/components": "10.22.19",
44
+ "@coorpacademy/components": "10.22.20",
45
45
  "@coorpacademy/redux-task": "^1.1.5",
46
46
  "cross-fetch": "^3.1.5",
47
47
  "jwt-decode": "^3.1.2",
@@ -78,5 +78,5 @@
78
78
  "ts-node": "^10.9.1",
79
79
  "typescript": "^4.7.4"
80
80
  },
81
- "gitHead": "0a46b77df8a358538d52121666f2dc3a8f1e22c5"
81
+ "gitHead": "4b6111dabb768f900ef6d35f16d40844e74336dd"
82
82
  }
@@ -3,6 +3,7 @@ import buildTask from '@coorpacademy/redux-task';
3
3
  import get from 'lodash/fp/get';
4
4
  import type {Options, ProgressionFromAPI} from '../../types/common';
5
5
  import type {StoreState} from '../../reducers';
6
+ import {fetchCorrection} from './fetch-correction';
6
7
  import {fetchSlide} from './fetch-slide';
7
8
 
8
9
  export const POST_ANSWER_REQUEST = '@@answer/POST_REQUEST' as const;
@@ -26,8 +27,8 @@ export const postAnswer = async (
26
27
  const state = getState();
27
28
  const token = get(['data', 'token'], state);
28
29
  const answer = get(['ui', 'answers'], state);
29
- const progression = state.data.progression;
30
- if (!progression) throw new Error('cannot answer question of inexisting progression');
30
+ const progression = get(['data', 'progression'], state);
31
+ if (!progression) throw new Error('Cannot answer a question of an inexistent progression');
31
32
 
32
33
  const action = buildTask({
33
34
  types: [POST_ANSWER_REQUEST, POST_ANSWER_SUCCESS, POST_ANSWER_FAILURE],
@@ -38,5 +39,6 @@ export const postAnswer = async (
38
39
  const updatedProgression = response.payload;
39
40
  const slideRef = updatedProgression.state.nextContent.ref;
40
41
  await dispatch(fetchSlide(slideRef));
42
+ await dispatch(fetchCorrection);
41
43
  }
42
44
  };
@@ -28,7 +28,8 @@ const initialState: StoreState = {
28
28
  [qcmSlide.universalRef]: qcmSlide
29
29
  },
30
30
  skills: [{skillRef, custom: false, name: skillRef, slidesToReview: 5}],
31
- token: '1234'
31
+ token: '1234',
32
+ corrections: {}
32
33
  },
33
34
  ui: {
34
35
  currentSlideRef: freeTextSlide._id,
@@ -15,7 +15,8 @@ const initialState: StoreState = {
15
15
  progression: null,
16
16
  slides: {},
17
17
  skills: [],
18
- token: '1234'
18
+ token: '1234',
19
+ corrections: {}
19
20
  },
20
21
  ui: {
21
22
  currentSlideRef: '',
@@ -17,7 +17,8 @@ const initialState: StoreState = {
17
17
  progression: null,
18
18
  slides: {},
19
19
  skills: [],
20
- token: '1234'
20
+ token: '1234',
21
+ corrections: {}
21
22
  },
22
23
  ui: {
23
24
  currentSlideRef: '',
@@ -1,6 +1,11 @@
1
1
  import test from 'ava';
2
+ import {AnyAction} from 'redux';
2
3
  import {createTestStore} from '../../test/create-test-store';
3
- import {postAnswerResponses, services} from '../../../test/util/services.mock';
4
+ import {
5
+ getChoicesCorrection,
6
+ postAnswerResponses,
7
+ services
8
+ } from '../../../test/util/services.mock';
4
9
  import {
5
10
  postAnswer,
6
11
  POST_ANSWER_FAILURE,
@@ -8,10 +13,10 @@ import {
8
13
  POST_ANSWER_SUCCESS
9
14
  } from '../post-answer';
10
15
  import type {StoreState} from '../../../reducers';
16
+ import {freeTextSlide} from '../../../views/slides/test/fixtures/free-text';
17
+ import {CORRECTION_FETCH_REQUEST, CORRECTION_FETCH_SUCCESS} from '../fetch-correction';
11
18
  import {SLIDE_FETCH_REQUEST, SLIDE_FETCH_SUCCESS} from '../fetch-slide';
12
19
  import {qcmGraphicSlide} from '../../../views/slides/test/fixtures/qcm-graphic';
13
- import {freeTextSlide} from '../../../views/slides/test/fixtures/free-text';
14
- import {SET_CURRENT_SLIDE} from '../../ui/slides';
15
20
 
16
21
  const progressionId = '123456789123';
17
22
  const skillRef = '_skill-ref';
@@ -44,7 +49,8 @@ const initialState: StoreState = {
44
49
  [freeTextSlide._id]: freeTextSlide
45
50
  },
46
51
  skills: [{skillRef, custom: false, name: skillRef, slidesToReview: 5}],
47
- token: '1234'
52
+ token: '1234',
53
+ corrections: {}
48
54
  },
49
55
  ui: {
50
56
  currentSlideRef: freeTextSlide._id,
@@ -56,26 +62,43 @@ const initialState: StoreState = {
56
62
  }
57
63
  };
58
64
 
59
- test('should dispatch POST_ANSWER_REQUEST, then POST_ANSWER_SUCCESS when the updated progression is returned', async t => {
60
- t.plan(4);
65
+ test('should dispatch post-answer, fetch-slide and fetch-correction actions when the answer is submitted', async t => {
66
+ t.plan(8);
61
67
  const expectedActions = [
62
68
  {type: POST_ANSWER_REQUEST},
63
69
  {
64
70
  type: POST_ANSWER_SUCCESS,
65
71
  payload: postAnswerResponses[freeTextSlide._id]
66
72
  },
67
- {type: SLIDE_FETCH_REQUEST, meta: {slideRef: qcmGraphicSlide._id}},
73
+ {
74
+ type: SLIDE_FETCH_REQUEST,
75
+ meta: {
76
+ slideRef: qcmGraphicSlide._id
77
+ }
78
+ },
68
79
  {
69
80
  type: SLIDE_FETCH_SUCCESS,
70
- meta: {slideRef: qcmGraphicSlide._id},
81
+ meta: {
82
+ slideRef: qcmGraphicSlide._id
83
+ },
71
84
  payload: qcmGraphicSlide
72
85
  },
73
- {type: SET_CURRENT_SLIDE, payload: qcmGraphicSlide}
86
+ {type: CORRECTION_FETCH_REQUEST, meta: {slideRef: freeTextSlide._id}},
87
+ {
88
+ type: CORRECTION_FETCH_SUCCESS,
89
+ meta: {slideRef: freeTextSlide._id},
90
+ payload: getChoicesCorrection(freeTextSlide._id)
91
+ }
74
92
  ];
75
93
 
76
- const {dispatch} = createTestStore(t, initialState, services, expectedActions);
94
+ const {dispatch, getState} = createTestStore(t, initialState, services, expectedActions);
77
95
 
78
96
  await dispatch(postAnswer);
97
+
98
+ const state = getState();
99
+
100
+ t.false(state.ui.slide.validateButton);
101
+ t.true(state.ui.slide.animateCorrectionPopin);
79
102
  });
80
103
 
81
104
  test('should dispatch POST_ANSWER_REQUEST, then POST_ANSWER_FAILURE on error', async t => {
@@ -104,3 +127,21 @@ test('should dispatch POST_ANSWER_REQUEST, then POST_ANSWER_FAILURE on error', a
104
127
 
105
128
  await dispatch(postAnswer);
106
129
  });
130
+
131
+ test('should not dispatch any action && throw an error if progression does not exist', async t => {
132
+ t.plan(1);
133
+ const expectedActions: AnyAction[] = [];
134
+
135
+ const {dispatch} = createTestStore(
136
+ t,
137
+ {...initialState, data: {...initialState.data, progression: null}},
138
+ services,
139
+ expectedActions
140
+ );
141
+
142
+ await t.throwsAsync(
143
+ () => dispatch(postAnswer),
144
+ undefined,
145
+ 'Cannot answer a question of an inexistent progression'
146
+ );
147
+ });
@@ -18,7 +18,8 @@ const initialState: StoreState = {
18
18
  progression: null,
19
19
  slides: {},
20
20
  skills: [],
21
- token: '1234'
21
+ token: '1234',
22
+ corrections: {}
22
23
  },
23
24
  ui: {
24
25
  currentSlideRef: '',
@@ -9,7 +9,8 @@ const initialState: StoreState = {
9
9
  progression: null,
10
10
  slides: {},
11
11
  skills: [],
12
- token: '1234'
12
+ token: '1234',
13
+ corrections: {}
13
14
  },
14
15
  ui: {
15
16
  currentSlideRef: '',
@@ -18,7 +18,7 @@ export const createTestStore = (
18
18
  initialState: StoreState,
19
19
  services: Services,
20
20
  actions: AnyAction[]
21
- ): Store => {
21
+ ): Store<StoreState, AnyAction> => {
22
22
  const thunkMiddleware = thunk.withExtraArgument({services});
23
23
  const enhancer = compose(applyMiddleware(thunkMiddleware, assertActionsMiddleware(t, actions)));
24
24
  return createStore(rootReducer, initialState, enhancer);
@@ -1,5 +1,8 @@
1
+ import flatten from 'lodash/fp/flatten';
2
+ import get from 'lodash/fp/get';
3
+ import includes from 'lodash/fp/includes';
4
+ import pull from 'lodash/fp/pull';
1
5
  import {Dispatch} from 'redux';
2
- import {flatten, get, includes, pull} from 'lodash/fp';
3
6
  import type {StoreState} from '../../reducers';
4
7
 
5
8
  export const EDIT_QCM = '@@answer/EDIT_QCM' as const;
@@ -43,7 +46,7 @@ const buildAnswer = (userAnswers: string[], questionType: string, newValue: stri
43
46
  case 'slider':
44
47
  case 'template':
45
48
  return newValue;
46
- default:
49
+ /* istanbul ignore next */ default:
47
50
  return [];
48
51
  }
49
52
  };
@@ -52,12 +55,18 @@ export const editAnswer =
52
55
  (answer: string[]) =>
53
56
  (dispatch: Dispatch, getState: () => StoreState): EditAnswerAction => {
54
57
  const state = getState();
55
- const currentSlideRef = get(['ui', 'currentSlideRef'])(state);
56
- const userAnswers = get(['ui', 'answers'])(state);
57
- const slide = get(['data', 'slides', currentSlideRef])(state);
58
- const questionType = get(['question', 'type'])(slide);
58
+ const currentSlideRef = get(['ui', 'currentSlideRef'], state);
59
+ const userAnswers = get(['ui', 'answers'], state);
60
+ const slide = get(['data', 'slides', currentSlideRef], state);
61
+
62
+ if (!slide) throw new Error('No slide was found');
63
+
64
+ const questionType = get(['question', 'type'], slide);
65
+
59
66
  const type = get(questionType, ANSWER_EDIT);
60
67
 
68
+ if (!type) throw new Error(`Question type ${questionType} is not supported`);
69
+
61
70
  return dispatch({
62
71
  type,
63
72
  payload: buildAnswer(userAnswers, questionType, answer)
@@ -1,7 +1,8 @@
1
1
  import test from 'ava';
2
2
  import pipe from 'lodash/fp/pipe';
3
3
  import set from 'lodash/fp/set';
4
- import {SlideFromAPI} from '../../../types/common';
4
+ import omit from 'lodash/fp/omit';
5
+ import {Question, SlideFromAPI} from '../../../types/common';
5
6
  import {createTestStore} from '../../test/create-test-store';
6
7
  import {services} from '../../../test/util/services.mock';
7
8
  import {freeTextSlide} from '../../../views/slides/test/fixtures/free-text';
@@ -42,7 +43,8 @@ const initialState: StoreState = {
42
43
  },
43
44
  slides: {},
44
45
  skills: [],
45
- token: '1234'
46
+ token: '1234',
47
+ corrections: {}
46
48
  },
47
49
  ui: {
48
50
  currentSlideRef: '',
@@ -62,6 +64,35 @@ const buildInitialState = (state: StoreState, question: SlideFromAPI): StoreStat
62
64
  )(state);
63
65
  };
64
66
 
67
+ test('editAnswer should throw an Error if the slide is not found', async t => {
68
+ const state = buildInitialState(initialState, freeTextSlide);
69
+ const expectedActions = [{type: undefined, payload: []}];
70
+ const {dispatch} = createTestStore(
71
+ t,
72
+ omit(['data', 'slides'], state) as StoreState,
73
+ services,
74
+ expectedActions
75
+ );
76
+ await t.throws(
77
+ () => dispatch(editAnswer(['Some kind of answer'])),
78
+ undefined,
79
+ 'No slide was found or questionType was not found'
80
+ );
81
+ });
82
+
83
+ test('editAnswer should throw an Error for unsupported questions', async t => {
84
+ const state = buildInitialState(initialState, {
85
+ ...freeTextSlide,
86
+ question: {...freeTextSlide.question, type: 'unsupportedType'} as unknown as Question
87
+ });
88
+ const {dispatch} = createTestStore(t, state, services, []);
89
+ await t.throws(
90
+ () => dispatch(editAnswer(['Some kind of answer'])),
91
+ undefined,
92
+ 'Question type unsupportedType is not supported'
93
+ );
94
+ });
95
+
65
96
  test('should dispatch EDIT_BASIC action when editAnswer is called', async t => {
66
97
  const state = buildInitialState(initialState, freeTextSlide);
67
98
  const expectedActions = [{type: ANSWER_EDIT.basic, payload: ['My Answer']}];
@@ -10,7 +10,8 @@ const initialState: StoreState = {
10
10
  progression: null,
11
11
  slides: {},
12
12
  skills: [],
13
- token: '1234'
13
+ token: '1234',
14
+ corrections: {}
14
15
  },
15
16
  ui: {
16
17
  currentSlideRef: '',
@@ -1,21 +1,17 @@
1
1
  import {combineReducers} from 'redux';
2
2
 
3
+ import corrections, {CorrectionsState} from './corrections';
3
4
  import progression, {ProgressionState} from './progression';
4
5
  import skills, {SkillsState} from './skills';
5
6
  import slides, {SlidesState} from './slides';
6
7
  import token, {TokenState} from './token';
7
8
 
8
9
  export type DataState = {
9
- isFetching?: boolean;
10
+ corrections: CorrectionsState;
10
11
  progression: ProgressionState;
11
12
  skills: SkillsState;
12
13
  slides: SlidesState;
13
14
  token: TokenState;
14
15
  };
15
16
 
16
- export default combineReducers({
17
- progression,
18
- skills,
19
- slides,
20
- token
21
- });
17
+ export default combineReducers({corrections, progression, skills, slides, token});
@@ -1,6 +1,7 @@
1
1
  import compact from 'lodash/fp/compact';
2
2
  import isEmpty from 'lodash/fp/isEmpty';
3
3
  import pipe from 'lodash/fp/pipe';
4
+ import set from 'lodash/fp/set';
4
5
  import {
5
6
  EditAnswerAction,
6
7
  EDIT_BASIC,
@@ -11,9 +12,11 @@ import {
11
12
  EDIT_TEMPLATE
12
13
  } from '../../actions/ui/answers';
13
14
  import {PostAnswerRequestAction, POST_ANSWER_REQUEST} from '../../actions/api/post-answer';
15
+ import {CORRECTION_FETCH_SUCCESS, ReceivedCorrection} from '../../actions/api/fetch-correction';
14
16
 
15
17
  export type UISlideState = {
16
18
  validateButton: boolean;
19
+ animateCorrectionPopin?: boolean;
17
20
  };
18
21
 
19
22
  export const initialState: UISlideState = {validateButton: false};
@@ -21,7 +24,7 @@ export const initialState: UISlideState = {validateButton: false};
21
24
  const reducer = (
22
25
  // eslint-disable-next-line default-param-last
23
26
  state: UISlideState = initialState,
24
- action: PostAnswerRequestAction | EditAnswerAction
27
+ action: PostAnswerRequestAction | EditAnswerAction | ReceivedCorrection
25
28
  ): UISlideState => {
26
29
  switch (action.type) {
27
30
  case EDIT_QCM:
@@ -35,6 +38,9 @@ const reducer = (
35
38
  case POST_ANSWER_REQUEST: {
36
39
  return initialState;
37
40
  }
41
+ case CORRECTION_FETCH_SUCCESS: {
42
+ return set(['animateCorrectionPopin'], true, state);
43
+ }
38
44
  default:
39
45
  return state;
40
46
  }
@@ -2,11 +2,24 @@ import test from 'ava';
2
2
  import reducer, {initialState} from '../slide';
3
3
  import {EDIT_BASIC} from '../../../actions/ui/answers';
4
4
  import {PostAnswerRequestAction} from '../../../actions/api/post-answer';
5
+ import {CORRECTION_FETCH_SUCCESS} from '../../../actions/api/fetch-correction';
5
6
 
6
7
  test('should use initial state if no answers are found when an EditAnswerAction is received', t => {
7
8
  const state = reducer(undefined, {type: EDIT_BASIC, payload: ['']});
8
9
  t.truthy(state);
9
10
  t.false(state.validateButton);
11
+ t.falsy(state.animateCorrectionPopin);
12
+ });
13
+
14
+ test('should set animateCorrectionPopin to true if CORRECTION_FETCH_SUCCESS is received', t => {
15
+ const state = reducer(undefined, {
16
+ type: CORRECTION_FETCH_SUCCESS,
17
+ payload: undefined,
18
+ meta: {slideRef: '1234'}
19
+ });
20
+ t.truthy(state);
21
+ t.false(state.validateButton);
22
+ t.true(state.animateCorrectionPopin);
10
23
  });
11
24
 
12
25
  test('should return state directly when there is no corresponding action handler + have an initial state', t => {
@@ -5,6 +5,7 @@ export type Choice = {
5
5
  help?: string;
6
6
  onClick: Function;
7
7
  ariaLabel?: string;
8
+ 'aria-label'?: string;
8
9
  };
9
10
 
10
11
  export type QcmDrag = {
@@ -10,7 +10,8 @@ test('should create initial props when there are no skills on the state', t => {
10
10
  progression: null,
11
11
  skills: [],
12
12
  slides: {},
13
- token: '1234'
13
+ token: '1234',
14
+ corrections: {}
14
15
  },
15
16
  ui: {
16
17
  currentSlideRef: '',
@@ -54,7 +55,8 @@ test('should create initial props when skills on the state', t => {
54
55
  }
55
56
  ],
56
57
  slides: {},
57
- token: '1234'
58
+ token: '1234',
59
+ corrections: {}
58
60
  },
59
61
  ui: {
60
62
  currentSlideRef: '',
@@ -52,14 +52,14 @@ const qcmProps =
52
52
  return {
53
53
  type: 'qcm',
54
54
  answers: map(choice => {
55
- const label = choice.label || '';
55
+ const label = getOr('', 'label', choice);
56
56
  return {
57
57
  title: label,
58
58
  selected: includes(label, answers),
59
59
  onClick: (): void => {
60
60
  dispatch(editAnswer([label]));
61
61
  },
62
- ariaLabel: choice.label
62
+ 'aria-label': label
63
63
  };
64
64
  }, question.content.choices)
65
65
  };
@@ -71,7 +71,7 @@ const qcmDragProps =
71
71
  return {
72
72
  type: 'qcmDrag',
73
73
  answers: map(choice => {
74
- const label = choice.label || '';
74
+ const label = getOr('', 'label', choice);
75
75
  const indexInAnswer = indexOf(label, answers);
76
76
  return {
77
77
  title: label,
@@ -91,14 +91,15 @@ const qcmGraphicProps =
91
91
  return {
92
92
  type: 'qcmGraphic',
93
93
  answers: map(choice => {
94
- const label = choice.label || '';
94
+ const label = getOr('', 'label', choice);
95
95
  return {
96
96
  title: label,
97
97
  image: get('media.src.0.url', choice),
98
98
  selected: includes(label, answers),
99
99
  onClick: (): void => {
100
100
  dispatch(editAnswer([label]));
101
- }
101
+ },
102
+ ariaLabel: label
102
103
  };
103
104
  }, question.content.choices)
104
105
  };
@@ -189,8 +190,8 @@ const basicProps =
189
190
  (answers: string[], question: BasicQuestion): FreeText => {
190
191
  return {
191
192
  type: 'freeText',
192
- placeholder: question.content.placeholder || '',
193
- value: answers[0] || '',
193
+ placeholder: getOr('', 'content.placeholder', question),
194
+ value: getOr('', '0', answers),
194
195
  onChange: (text: string): void => {
195
196
  dispatch(editAnswer([text]));
196
197
  }