@truedat/dq 4.43.0 → 4.43.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.
Files changed (52) hide show
  1. package/CHANGELOG.md +22 -3
  2. package/package.json +5 -5
  3. package/src/api.js +2 -0
  4. package/src/components/ConditionSummary.js +1 -0
  5. package/src/components/FieldSummary.js +86 -0
  6. package/src/components/ImplementationSummary.js +11 -1
  7. package/src/components/NewRemediation.js +27 -20
  8. package/src/components/NewRuleImplementation.js +42 -6
  9. package/src/components/RemediationPlan.js +47 -78
  10. package/src/components/RuleImplementationProperties.js +2 -1
  11. package/src/components/RuleImplementationResultTabs.js +113 -0
  12. package/src/components/RuleImplementationResults.js +1 -1
  13. package/src/components/RuleResult.js +108 -0
  14. package/src/components/{ExecutionDetails.js → RuleResultDetails.js} +4 -21
  15. package/src/components/RuleResultRemediationLoader.js +44 -0
  16. package/src/components/RuleResultRemediations.js +47 -0
  17. package/src/components/RuleResultRow.js +0 -3
  18. package/src/components/RuleResultSegmentRow.js +83 -0
  19. package/src/components/RuleResultSegments.js +102 -0
  20. package/src/components/RuleResultSegmentsLoader.js +34 -0
  21. package/src/components/RuleResultsRoutes.js +73 -0
  22. package/src/components/RuleRoutes.js +4 -14
  23. package/src/components/RuleSelector.js +5 -2
  24. package/src/components/__test_samples__/NewRuleImplementationProps.js +22 -2
  25. package/src/components/__tests__/ExecutionDetails.spec.js +5 -5
  26. package/src/components/__tests__/NewRuleImplementation.spec.js +27 -7
  27. package/src/components/__tests__/RuleResultSegmentsLoader.spec.js +32 -0
  28. package/src/components/__tests__/__snapshots__/ExecutionDetails.spec.js.snap +2 -30
  29. package/src/components/__tests__/__snapshots__/NewRuleImplementation.spec.js.snap +1211 -1217
  30. package/src/components/__tests__/__snapshots__/RuleImplementationProperties.spec.js.snap +1 -0
  31. package/src/components/index.js +2 -2
  32. package/src/components/ruleImplementationForm/DatasetForm.js +4 -1
  33. package/src/components/ruleImplementationForm/FieldsGrid.js +57 -0
  34. package/src/components/ruleImplementationForm/FieldsGroup.js +107 -0
  35. package/src/components/ruleImplementationForm/RuleImplementationForm.js +45 -0
  36. package/src/components/ruleImplementationForm/SegmentsForm.js +35 -0
  37. package/src/components/ruleImplementationForm/__tests__/DataSetForm.spec.js +0 -1
  38. package/src/components/ruleImplementationForm/__tests__/RuleImplementationForm.spec.js +27 -10
  39. package/src/components/ruleImplementationForm/__tests__/__snapshots__/RuleImplementationForm.spec.js.snap +315 -91
  40. package/src/messages/en.js +7 -0
  41. package/src/messages/es.js +7 -0
  42. package/src/reducers/__tests__/segmentResult.spec.js +46 -0
  43. package/src/reducers/index.js +2 -0
  44. package/src/reducers/ruleImplementation.js +1 -0
  45. package/src/reducers/segmentResults.js +19 -0
  46. package/src/routines.js +3 -0
  47. package/src/sagas/__tests__/fetchSegmentResults.spec.js +78 -0
  48. package/src/sagas/fetchSegmentResults.js +30 -0
  49. package/src/sagas/index.js +3 -0
  50. package/src/services/encodeRawContent.js +5 -5
  51. package/src/styles/remediationPlan.less +5 -0
  52. package/src/styles/ruleImplementationForm/DatasetForm.less +5 -0
@@ -1,100 +1,324 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
3
  exports[`<RuleImplementationForm /> matches the latest snapshot 1`] = `
4
- <GridColumn>
5
- <GridRow
6
- stretched={true}
7
- textAlign="center"
4
+ <div>
5
+ <div
6
+ class="column"
8
7
  >
9
- <StepGroup
10
- size="small"
8
+ <div
9
+ class="stretched center aligned row"
11
10
  >
12
- <RuleImplementationStep
13
- activeStep="information"
14
- icon={
15
- Object {
16
- "name": "info",
17
- }
18
- }
19
- key="0"
20
- name="information"
11
+ <div
12
+ class="ui small steps"
13
+ >
14
+ <div
15
+ class="active step"
16
+ >
17
+ <i
18
+ aria-hidden="true"
19
+ class="info icon"
20
+ />
21
+ <div
22
+ class="content"
23
+ >
24
+ <div
25
+ class="title"
26
+ >
27
+ ruleImplementationForm.step.information
28
+ </div>
29
+ </div>
30
+ </div>
31
+ <div
32
+ class="step"
33
+ >
34
+ <i
35
+ aria-hidden="true"
36
+ class="database icon"
37
+ />
38
+ <div
39
+ class="content"
40
+ >
41
+ <div
42
+ class="title"
43
+ >
44
+ ruleImplementationForm.step.dataset
45
+ </div>
46
+ </div>
47
+ </div>
48
+ <div
49
+ class="step"
50
+ >
51
+ <i
52
+ aria-hidden="true"
53
+ class="user icon"
54
+ />
55
+ <div
56
+ class="content"
57
+ >
58
+ <div
59
+ class="title"
60
+ >
61
+ ruleImplementationForm.step.populations
62
+ </div>
63
+ </div>
64
+ </div>
65
+ <div
66
+ class="step"
67
+ >
68
+ <i
69
+ aria-hidden="true"
70
+ class="setting icon"
71
+ />
72
+ <div
73
+ class="content"
74
+ >
75
+ <div
76
+ class="title"
77
+ >
78
+ ruleImplementationForm.step.validations
79
+ </div>
80
+ </div>
81
+ </div>
82
+ <div
83
+ class="step"
84
+ >
85
+ <i
86
+ aria-hidden="true"
87
+ class="grid layout icon"
88
+ />
89
+ <div
90
+ class="content"
91
+ >
92
+ <div
93
+ class="title"
94
+ >
95
+ ruleImplementationForm.step.segments
96
+ </div>
97
+ </div>
98
+ </div>
99
+ </div>
100
+ <div
101
+ class="ui fitted hidden divider"
21
102
  />
22
- <RuleImplementationStep
23
- activeStep="information"
24
- icon={
25
- Object {
26
- "name": "database",
27
- }
28
- }
29
- key="1"
30
- name="dataset"
31
- />
32
- <RuleImplementationStep
33
- activeStep="information"
34
- icon={
35
- Object {
36
- "name": "user",
37
- }
38
- }
39
- key="2"
40
- name="populations"
41
- />
42
- <RuleImplementationStep
43
- activeStep="information"
44
- icon={
45
- Object {
46
- "name": "setting",
47
- }
48
- }
49
- key="3"
50
- name="validations"
51
- />
52
- </StepGroup>
53
- <Divider
54
- fitted={true}
55
- hidden={true}
56
- />
57
- </GridRow>
58
- <GridRow
59
- className="rule-impl-form-row"
60
- stretched={true}
61
- >
62
- <Form
63
- as="form"
103
+ </div>
104
+ <div
105
+ class="stretched row rule-impl-form-row"
64
106
  >
65
- <Connect(InformationForm)
66
- ruleImplementation={
67
- Object {
68
- "executable": true,
69
- "implementationKey": "foo",
70
- }
71
- }
72
- />
73
- </Form>
74
- </GridRow>
75
- <Divider
76
- hidden={true}
77
- />
78
- <GridRow
79
- stretched={true}
80
- >
81
- <Button
82
- as="button"
83
- content="actions.next"
84
- disabled={true}
85
- floated="right"
86
- loading={false}
87
- onClick={[Function]}
88
- primary={true}
89
- type="submit"
107
+ <form
108
+ class="ui form"
109
+ >
110
+ <div
111
+ class="field"
112
+ >
113
+ <div
114
+ class="ui checked toggle checkbox"
115
+ >
116
+ <input
117
+ checked=""
118
+ class="hidden"
119
+ name="executable"
120
+ readonly=""
121
+ tabindex="0"
122
+ type="radio"
123
+ value=""
124
+ />
125
+ <label>
126
+ ruleImplementation.props.executable
127
+ </label>
128
+ </div>
129
+ </div>
130
+ <div
131
+ class="field"
132
+ >
133
+ <label>
134
+ ruleImplementation.props.name
135
+ <i
136
+ aria-hidden="true"
137
+ class="question circle outline icon rule-form-popup"
138
+ />
139
+ </label>
140
+ <div
141
+ class="field"
142
+ >
143
+ <div
144
+ class="ui input"
145
+ >
146
+ <input
147
+ autocomplete="off"
148
+ name="implementation_key"
149
+ placeholder="ruleImplementation.props.name.placeholder"
150
+ type="text"
151
+ value="foo"
152
+ />
153
+ </div>
154
+ </div>
155
+ </div>
156
+ <div
157
+ class="ui segment"
158
+ >
159
+ <div
160
+ class="field"
161
+ >
162
+ <label
163
+ class="rule-form-label"
164
+ >
165
+ ruleImplementations.props.result_type
166
+ <span>
167
+ *
168
+ </span>
169
+ <i
170
+ aria-hidden="true"
171
+ class="question circle outline icon rule-form-popup"
172
+ />
173
+ </label>
174
+ <div
175
+ class="inline fields"
176
+ >
177
+ <div
178
+ class="field"
179
+ >
180
+ <div
181
+ class="ui checked radio checkbox"
182
+ >
183
+ <input
184
+ checked=""
185
+ class="hidden"
186
+ name="result_type"
187
+ readonly=""
188
+ tabindex="0"
189
+ type="radio"
190
+ value="percentage"
191
+ />
192
+ <label>
193
+ ruleImplementations.props.result_type.percentage
194
+ </label>
195
+ </div>
196
+ </div>
197
+ <div
198
+ class="field"
199
+ >
200
+ <div
201
+ class="ui radio checkbox"
202
+ >
203
+ <input
204
+ class="hidden"
205
+ name="result_type"
206
+ readonly=""
207
+ tabindex="0"
208
+ type="radio"
209
+ value="deviation"
210
+ />
211
+ <label>
212
+ ruleImplementations.props.result_type.deviation
213
+ </label>
214
+ </div>
215
+ </div>
216
+ <div
217
+ class="field"
218
+ >
219
+ <div
220
+ class="ui radio checkbox"
221
+ >
222
+ <input
223
+ class="hidden"
224
+ name="result_type"
225
+ readonly=""
226
+ tabindex="0"
227
+ type="radio"
228
+ value="errors_number"
229
+ />
230
+ <label>
231
+ ruleImplementations.props.result_type.errors_number
232
+ </label>
233
+ </div>
234
+ </div>
235
+ </div>
236
+ </div>
237
+ <div
238
+ class="field"
239
+ >
240
+ <label
241
+ class="rule-form-label"
242
+ >
243
+ ruleImplementations.props.minimum
244
+ <span>
245
+ *
246
+ </span>
247
+ <i
248
+ aria-hidden="true"
249
+ class="question circle outline icon rule-form-popup"
250
+ />
251
+ </label>
252
+ <div
253
+ class="field"
254
+ >
255
+ <div
256
+ class="ui input"
257
+ >
258
+ <input
259
+ autocomplete="off"
260
+ name="minimum"
261
+ placeholder="ruleImplementations.props.minimum.placeholder"
262
+ type="text"
263
+ value="10"
264
+ />
265
+ </div>
266
+ </div>
267
+ </div>
268
+ <div
269
+ class="field"
270
+ >
271
+ <label
272
+ class="rule-form-label"
273
+ >
274
+ ruleImplementations.props.goal
275
+ <span>
276
+ *
277
+ </span>
278
+ <i
279
+ aria-hidden="true"
280
+ class="question circle outline icon rule-form-popup"
281
+ />
282
+ </label>
283
+ <div
284
+ class="field"
285
+ >
286
+ <div
287
+ class="ui input"
288
+ >
289
+ <input
290
+ autocomplete="off"
291
+ name="goal"
292
+ placeholder="ruleImplementations.props.goal.placeholder"
293
+ type="text"
294
+ value="20"
295
+ />
296
+ </div>
297
+ </div>
298
+ </div>
299
+ </div>
300
+ </form>
301
+ </div>
302
+ <div
303
+ class="ui hidden divider"
90
304
  />
91
- <Button
92
- as="button"
93
- content="actions.cancel"
94
- floated="right"
95
- onClick={[Function]}
96
- secondary={true}
97
- />
98
- </GridRow>
99
- </GridColumn>
305
+ <div
306
+ class="stretched row"
307
+ >
308
+ <button
309
+ class="ui loading primary disabled right floated button"
310
+ disabled=""
311
+ tabindex="-1"
312
+ type="submit"
313
+ >
314
+ actions.next
315
+ </button>
316
+ <button
317
+ class="ui secondary right floated button"
318
+ >
319
+ actions.cancel
320
+ </button>
321
+ </div>
322
+ </div>
323
+ </div>
100
324
  `;
@@ -456,6 +456,7 @@ export default {
456
456
  "ruleImplementationForm.step.information": "Information",
457
457
  "ruleImplementationForm.step.dataset": "Data Set",
458
458
  "ruleImplementationForm.step.populations": "Populations",
459
+ "ruleImplementationForm.step.segments": "Segments",
459
460
  "ruleImplementationForm.step.validations": "Validations",
460
461
  "ruleImplementationRawForm.props.database": "Database",
461
462
  "ruleImplementationRawForm.props.database.placeholder": "Select database",
@@ -528,6 +529,7 @@ export default {
528
529
  "ruleImplementations.summary.headers.implementation": "Rule Implementation",
529
530
  "ruleImplementations.summary.headers.population": "Population",
530
531
  "ruleImplementations.summary.headers.populations": "Populations",
532
+ "ruleImplementations.summary.headers.segments": "Segments",
531
533
  "ruleImplementations.summary.headers.validations": "Validation",
532
534
  "ruleImplementations.upload.success.errors":
533
535
  "Error in {implementation_key} attribute: {key} message: {message} ",
@@ -551,6 +553,7 @@ export default {
551
553
  "ruleResult.props.errors": "Errors",
552
554
  "ruleResult.props.quality": "Quality",
553
555
  "ruleResult.props.records": "Records",
556
+ "ruleResultSegment.props.name": "Name",
554
557
  "ruleSubscription.actions.remove": "Eliminar",
555
558
  "rule_result.actions.delete.confirmation.content":
556
559
  "This rule result will be deleted. Are you sure?",
@@ -578,6 +581,7 @@ export default {
578
581
  "Error uploading file. No rules have been created.",
579
582
  "rules.upload.failed.misssing_required_columns":
580
583
  "Missing required columns. Expected [{expected}]. Found [{found}].",
584
+ "segmentsForm.add.text": "Add Segment",
581
585
  "structureSelector.union.criteria": "Union criteria",
582
586
  "structureFields.dropdown.label": "Select Field",
583
587
  "structureFields.dropdown.placeholder": "Fields",
@@ -591,6 +595,9 @@ export default {
591
595
  "tabs.dq.ruleImplementation.details": "Details",
592
596
  "tabs.dq.ruleImplementation.results": "Results",
593
597
  "tabs.dq.ruleImplementations": "Implementations",
598
+ "tabs.dq.ruleImplementationResult.info": "Information",
599
+ "tabs.dq.ruleImplementationResult.segmentResult": "Segments Results",
600
+ "tabs.dq.ruleImplementationResult.remediationPlan": "Remedy Plan",
594
601
  "tabs.qualityRules": "Quality Rules",
595
602
  "updateRuleImplementation.error.implementation_key.duplicated":
596
603
  "Duplicated implementation key",
@@ -471,6 +471,7 @@ export default {
471
471
  "ruleImplementationForm.step.dataset": "Datos",
472
472
  "ruleImplementationForm.step.information": "Información",
473
473
  "ruleImplementationForm.step.populations": "Poblaciones",
474
+ "ruleImplementationForm.step.segments": "Segmentos",
474
475
  "ruleImplementationForm.step.validations": "Validaciones",
475
476
  "ruleImplementationRawForm.props.database.placeholder":
476
477
  "Seleccionar base de datos",
@@ -551,6 +552,7 @@ export default {
551
552
  "Implementación de una Regla",
552
553
  "ruleImplementations.summary.headers.population": "Población",
553
554
  "ruleImplementations.summary.headers.populations": "Poblaciones",
555
+ "ruleImplementations.summary.headers.segments": "Segmentos",
554
556
  "ruleImplementations.summary.headers.validations": "Validaciones",
555
557
  "ruleImplementations.upload.success.errors":
556
558
  "Error en {name} atributo: {key} mensaje: {message} ",
@@ -575,6 +577,7 @@ export default {
575
577
  "ruleResult.props.header.information": "Información",
576
578
  "ruleResult.props.quality": "Calidad",
577
579
  "ruleResult.props.records": "Registros",
580
+ "ruleResultSegment.props.name": "Nombre",
578
581
  "rules.actions.activate_execution": "Activar ejecución",
579
582
  "rules.actions.create": "Nueva regla de calidad",
580
583
  "rules.actions.delete.confirmation.content":
@@ -605,6 +608,7 @@ export default {
605
608
  "rules.upload.failed.misssing_required_columns":
606
609
  "Faltan columnas obligatorias en el fichero. Esperado [{expected}]. Recibido [{found}].",
607
610
  "ruleSubscription.actions.remove": "Eliminar",
611
+ "segmentsForm.add.text": "Añadir segmentación",
608
612
  "structureSelector.union.criteria": "Criterio de unión",
609
613
  "structureFields.dropdown.label": "Seleccionar Campo",
610
614
  "structureFields.dropdown.placeholder": "Campos",
@@ -618,6 +622,9 @@ export default {
618
622
  "tabs.dq.ruleImplementation.results": "Resultados",
619
623
  "tabs.dq.ruleImplementation": "Implementación",
620
624
  "tabs.dq.ruleImplementations": "Implementaciones",
625
+ "tabs.dq.ruleImplementationResult.info": "Información",
626
+ "tabs.dq.ruleImplementationResult.segmentResult": "Resultados de Segmentación",
627
+ "tabs.dq.ruleImplementationResult.remediationPlan": "Plan de remediación",
621
628
  "tabs.qualityRules": "Reglas de Calidad",
622
629
  "updateRule.error.domain_id.required": "El dominio es requerido",
623
630
  "updateRuleImplementation.error.implementation_key.duplicated":
@@ -0,0 +1,46 @@
1
+ import { fetchSegmentResults, clearSegmentResults } from "../../routines";
2
+ import { segmentResults } from "../segmentResults";
3
+
4
+ const fooState = { foo: "bar" };
5
+
6
+ describe("reducers: segmentResults", () => {
7
+ const initialState = {};
8
+
9
+ it("should provide the initial state", () => {
10
+ expect(segmentResults(undefined, {})).toEqual(initialState);
11
+ });
12
+
13
+ it("should handle the fetchSegmentResults.TRIGGER action", () => {
14
+ expect(
15
+ segmentResults(fooState, { type: fetchSegmentResults.TRIGGER })
16
+ ).toEqual(initialState);
17
+ });
18
+
19
+ it("should handle the fetchSegmentResults.SUCCESS action", () => {
20
+ const segmentResult = {
21
+ id: 2,
22
+ errors: 2,
23
+ records: 10,
24
+ result: "80.0",
25
+ params: "foo=bar",
26
+ };
27
+ const payload = { data: segmentResult };
28
+
29
+ expect(
30
+ segmentResults(fooState, {
31
+ type: fetchSegmentResults.SUCCESS,
32
+ payload,
33
+ })
34
+ ).toMatchObject(segmentResult);
35
+ });
36
+
37
+ it("should handle the clearSegmentResults.TRIGGER action", () => {
38
+ expect(
39
+ segmentResults(fooState, { type: clearSegmentResults.TRIGGER })
40
+ ).toEqual(initialState);
41
+ });
42
+
43
+ it("should ignore unknown actions", () => {
44
+ expect(segmentResults(fooState, { type: "FOO" })).toBe(fooState);
45
+ });
46
+ });
@@ -44,6 +44,7 @@ import { ruleUpdating } from "./ruleUpdating";
44
44
  import { rules } from "./rules";
45
45
  import { rulesLoading } from "./rulesLoading";
46
46
  import { rulesPageSize } from "./rulesPageSize";
47
+ import { segmentResults } from "./segmentResults";
47
48
  import { uploadingImplementationsFile } from "./uploadingImplementationsFile";
48
49
  import { uploadingRulesFile } from "./uploadingRulesFile";
49
50
  import { userImplementationsPermissions } from "./userImplementationsPermissions";
@@ -97,6 +98,7 @@ export {
97
98
  rules,
98
99
  rulesLoading,
99
100
  rulesPageSize,
101
+ segmentResults,
100
102
  uploadingImplementationsFile,
101
103
  uploadingRulesFile,
102
104
  userImplementationsPermissions,
@@ -17,6 +17,7 @@ const pickFields = _.pick([
17
17
  "implementation_key",
18
18
  "implementation_type",
19
19
  "populations",
20
+ "segments",
20
21
  "raw_content",
21
22
  "results",
22
23
  "rule_id",
@@ -0,0 +1,19 @@
1
+ import _ from "lodash/fp";
2
+ import { fetchSegmentResults, clearSegmentResults } from "../routines";
3
+
4
+ const initialState = {};
5
+
6
+ const segmentResults = (state = initialState, { type, payload }) => {
7
+ switch (type) {
8
+ case fetchSegmentResults.TRIGGER:
9
+ return initialState;
10
+ case fetchSegmentResults.SUCCESS:
11
+ return _.prop("data")(payload);
12
+ case clearSegmentResults.TRIGGER:
13
+ return initialState;
14
+ default:
15
+ return state;
16
+ }
17
+ };
18
+
19
+ export { segmentResults };
package/src/routines.js CHANGED
@@ -59,6 +59,9 @@ export const searchRuleImplementations = createRoutine(
59
59
 
60
60
  export const deleteRuleResult = createRoutine("DELETE_RULE_RESULT");
61
61
 
62
+ export const fetchSegmentResults = createRoutine("FETCH_SEGMENT_RESULTS");
63
+ export const clearSegmentResults = createRoutine("CLEAR_SEGMENT_RESULTS");
64
+
62
65
  export const clearImplementationFilters = createRoutine(
63
66
  "CLEAR_IMPLEMENTATION_FILTERS"
64
67
  );
@@ -0,0 +1,78 @@
1
+ import { compile } from "path-to-regexp";
2
+ import { testSaga } from "redux-saga-test-plan";
3
+ import { apiJson, JSON_OPTS } from "@truedat/core/services/api";
4
+ import {
5
+ fetchSegmentResultsRequestSaga,
6
+ fetchSegmentResultsSaga,
7
+ } from "../fetchSegmentResults";
8
+ import { fetchSegmentResults } from "../../routines";
9
+ import { API_SEGMENT_RESULTS } from "../../api";
10
+
11
+ describe("sagas: fetchSegmentResultsRequestSaga", () => {
12
+ it("should invoke fetchSegmentResultsSaga on trigger", () => {
13
+ expect(() => {
14
+ testSaga(fetchSegmentResultsRequestSaga)
15
+ .next()
16
+ .takeLatest(fetchSegmentResults.TRIGGER, fetchSegmentResultsSaga)
17
+ .finish()
18
+ .isDone();
19
+ }).not.toThrow();
20
+ });
21
+
22
+ it("should throw exception if an unhandled action is received", () => {
23
+ expect(() => {
24
+ testSaga(fetchSegmentResultsRequestSaga)
25
+ .next()
26
+ .takeLatest("FOO", fetchSegmentResultsSaga);
27
+ }).toThrow();
28
+ });
29
+ });
30
+
31
+ describe("sagas: fetchRemediaitonSaga", () => {
32
+ it("should put a success action when a response is returned", () => {
33
+ const ruleResultId = 1;
34
+ const url = compile(API_SEGMENT_RESULTS)({ rule_result_id: ruleResultId });
35
+ const payload = { rule_result_id: ruleResultId };
36
+ const data = {
37
+ id: 1,
38
+ df_name: "remediation_template",
39
+ df_content: { text: "some_text" },
40
+ };
41
+
42
+ expect(() => {
43
+ testSaga(fetchSegmentResultsSaga, { payload })
44
+ .next()
45
+ .put(fetchSegmentResults.request())
46
+ .next()
47
+ .call(apiJson, url, JSON_OPTS)
48
+ .next({ data })
49
+ .put(fetchSegmentResults.success(data))
50
+ .next()
51
+ .put(fetchSegmentResults.fulfill())
52
+ .next()
53
+ .isDone();
54
+ }).not.toThrow();
55
+ });
56
+
57
+ it("should put a failure action when the call returns an error", () => {
58
+ const message = "Request failed";
59
+ const error = { message };
60
+ const ruleResultId = 1;
61
+ const url = compile(API_SEGMENT_RESULTS)({ rule_result_id: ruleResultId });
62
+ const payload = { rule_result_id: ruleResultId };
63
+
64
+ expect(() => {
65
+ testSaga(fetchSegmentResultsSaga, { payload })
66
+ .next()
67
+ .put(fetchSegmentResults.request())
68
+ .next()
69
+ .call(apiJson, url, JSON_OPTS)
70
+ .throw(error)
71
+ .put(fetchSegmentResults.failure(message))
72
+ .next()
73
+ .put(fetchSegmentResults.fulfill())
74
+ .next()
75
+ .isDone();
76
+ }).not.toThrow();
77
+ });
78
+ });