@truedat/dd 5.2.9 → 5.3.1

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.
@@ -0,0 +1,86 @@
1
+ import React from "react";
2
+ import { waitFor } from "@testing-library/react";
3
+ import userEvent from "@testing-library/user-event";
4
+ import { render } from "@truedat/test/render";
5
+ import { REFERENCE_DATASETS_QUERY } from "../../api/queries";
6
+ import ReferenceDatasetFieldSelector from "../ReferenceDatasetFieldSelector";
7
+
8
+ const referenceDatasets = [
9
+ {
10
+ __typename: "ReferenceDataset",
11
+ id: "1",
12
+ name: "countries",
13
+ headers: ["CODE", "DESC_ES", "DESC_EN"],
14
+ rowCount: 9,
15
+ updatedAt: "2023-03-04T12:10:53.245332Z",
16
+ },
17
+ {
18
+ __typename: "ReferenceDataset",
19
+ id: "2",
20
+ name: "currencies",
21
+ headers: ["ENTITY", "Currency", "Alphabetic Code", "Numeric Code"],
22
+ rowCount: 5,
23
+ updatedAt: "2023-03-05T09:57:59.765822Z",
24
+ },
25
+ ];
26
+
27
+ const referenceDatasetsMock = {
28
+ request: {
29
+ query: REFERENCE_DATASETS_QUERY,
30
+ },
31
+ result: { data: { referenceDatasets } },
32
+ };
33
+
34
+ describe("<ReferenceDatasetFieldSelector />", () => {
35
+ it("selecting reference dataset fills fields dropdown; clicking a field calls onChange", async () => {
36
+ const onChange = jest.fn();
37
+ const renderOpts = {
38
+ mocks: [referenceDatasetsMock],
39
+ };
40
+ const { queryAllByText, getByRole } = render(
41
+ <ReferenceDatasetFieldSelector onChange={onChange} />,
42
+ renderOpts
43
+ );
44
+ const countriesOptionQuery = () =>
45
+ getByRole("option", { name: /countries/i });
46
+ await waitFor(() => {
47
+ // also matches "reference dataset field", get first
48
+ expect(queryAllByText(/Reference dataset/i)[0]).toBeInTheDocument();
49
+ // same text for label and dropdown, match the second one, the dropdown
50
+ expect(queryAllByText(/Reference dataset field/i)[1]).toBeInTheDocument();
51
+ expect(countriesOptionQuery()).toBeInTheDocument();
52
+ expect(getByRole("option", { name: /currencies/i })).toBeInTheDocument();
53
+ });
54
+
55
+ userEvent.click(countriesOptionQuery());
56
+
57
+ const optionQuery = () => getByRole("option", { name: /CODE/i });
58
+ await waitFor(() => {
59
+ expect(optionQuery()).toBeInTheDocument();
60
+ });
61
+ userEvent.click(optionQuery());
62
+ expect(onChange).toHaveBeenNthCalledWith(
63
+ 1,
64
+ null,
65
+ {
66
+ name: null,
67
+ referenceDataset: { id: "1" },
68
+ type: "reference_dataset_field",
69
+ },
70
+ null
71
+ );
72
+ expect(onChange).toHaveBeenNthCalledWith(
73
+ 2,
74
+ null,
75
+ {
76
+ name: "CODE",
77
+ referenceDataset: {
78
+ id: "1",
79
+ name: "countries",
80
+ },
81
+ type: "reference_dataset_field",
82
+ },
83
+ null
84
+ );
85
+ });
86
+ });
@@ -0,0 +1,138 @@
1
+ import React from "react";
2
+ import { waitFor } from "@testing-library/react";
3
+ import { render } from "@truedat/test/render";
4
+ import userEvent from "@testing-library/user-event";
5
+ import StructureStructureForm from "../StructureStructureForm";
6
+ import { linkStructureToStructure } from "../../routines";
7
+ import { LINK_LABELS_QUERY } from "../../api/queries";
8
+
9
+ const linkLabels = {
10
+ labels: [
11
+ {
12
+ id: "1",
13
+ name: "is_copy_from",
14
+ },
15
+ {
16
+ id: "2",
17
+ name: "reimu_ga_tsukutta",
18
+ },
19
+ {
20
+ id: "3",
21
+ name: "marisa_ga_tsukutta",
22
+ },
23
+ ],
24
+ };
25
+
26
+ const linkLabelsMock = {
27
+ request: { query: LINK_LABELS_QUERY },
28
+ result: { data: linkLabels },
29
+ };
30
+
31
+ describe("<StructureStructureForm />", () => {
32
+ const structure = {
33
+ alias: null,
34
+ confidential: false,
35
+ domain_ids: [1],
36
+ domains: [
37
+ {
38
+ external_id: "Acme",
39
+ id: 1,
40
+ name: "Acme",
41
+ parent_id: null,
42
+ parents: [],
43
+ updated_at: "2022-03-22 12:56:39.639127Z",
44
+ },
45
+ ],
46
+ external_id: "external_id",
47
+ id: 67583,
48
+ inserted_at: "2019-11-27T08:35:44.000000Z",
49
+ updated_at: "2021-06-10T12:01:17.343065Z",
50
+ class: null,
51
+ classes: null,
52
+ data_structure_link_count: 0,
53
+ data_structure_type: {
54
+ metadata_views: [],
55
+ template_id: 9,
56
+ translation: null,
57
+ },
58
+ degree: null,
59
+ deleted_at: null,
60
+ description: null,
61
+ grant: null,
62
+ grants: [],
63
+ group: "group",
64
+ implementation_count: 0,
65
+ metadata: {
66
+ database: "database",
67
+ host: "host",
68
+ },
69
+ name: "structure",
70
+ note: {},
71
+ siblings: [],
72
+ source: {
73
+ external_id: "oracle_meta_ds2",
74
+ id: 19,
75
+ },
76
+ system: {
77
+ id: 2,
78
+ name: "SYSTEM_1",
79
+ },
80
+ type: "Schema",
81
+ };
82
+
83
+ it("matches the latest snapshot", async () => {
84
+ const columns = ["name", "system", "group"].map((name) => ({ name }));
85
+ const structureActiveFilters = {};
86
+ const structuresRows = [{ id: 1 }, { id: 2 }];
87
+ const dispatch = jest.fn();
88
+
89
+ const props = {
90
+ linkStructureToStructure,
91
+ structuresRows,
92
+ columns,
93
+ onSelect: jest.fn(),
94
+ };
95
+
96
+ const renderOpts = {
97
+ mocks: [linkLabelsMock],
98
+ state: {
99
+ structure,
100
+ structures: [structure],
101
+ structureActiveFilters,
102
+ },
103
+ dispatch,
104
+ };
105
+
106
+ const { queryByText, findByText, getByRole } = render(
107
+ <StructureStructureForm {...props} />,
108
+ renderOpts
109
+ );
110
+ await waitFor(() =>
111
+ expect(queryByText(/loading/i)).not.toBeInTheDocument()
112
+ );
113
+ userEvent.click(await findByText("structure"));
114
+
115
+ const saveButton = getByRole("button", { name: "Save" });
116
+ await waitFor(() => {
117
+ expect(saveButton).toBeEnabled();
118
+ });
119
+
120
+ const label1 = getByRole("option", { name: "is_copy_from" });
121
+ const label2 = getByRole("option", { name: "reimu_ga_tsukutta" });
122
+
123
+ userEvent.click(label1);
124
+ userEvent.click(label2);
125
+
126
+ userEvent.click(saveButton);
127
+ await new Promise((r) => setTimeout(r, 200));
128
+
129
+ expect(dispatch).toHaveBeenCalledWith({
130
+ ...linkStructureToStructure(),
131
+ payload: {
132
+ sourceStructureId: 67583,
133
+ targetStructureId: 67583,
134
+ labelIds: ["1", "2"],
135
+ },
136
+ });
137
+ });
138
+ });
@@ -1,22 +1,27 @@
1
1
  import React from "react";
2
2
  import { render } from "@truedat/test/render";
3
3
  import { waitFor } from "@testing-library/react";
4
- import { useParams } from "react-router-dom";
4
+ import userEvent from "@testing-library/user-event";
5
5
  import { STRUCTURE_STRUCTURE_LINKS_QUERY } from "../../api/queries";
6
+ import { deleteStructureStructureLink } from "../../routines";
6
7
  import StructureStructureLinks from "../StructureStructureLinks";
7
8
 
8
9
  jest.mock("react-router-dom", () => ({
9
10
  ...jest.requireActual("react-router-dom"),
10
- useParams: jest.fn(),
11
+ useParams: () => ({ id: 60217 }),
11
12
  }));
12
13
 
13
14
  const dataStructureWithLinks = {
14
15
  currentVersion: {
15
16
  id: "212416",
16
- name: "CMESANO",
17
+ name: "STRUCTURE_1",
17
18
  },
18
19
  dataStructureLinks: [
19
20
  {
21
+ _actions: {
22
+ delete_struct_to_struct_link: true,
23
+ },
24
+ id: "1",
20
25
  labels: [
21
26
  {
22
27
  name: "copy",
@@ -24,54 +29,58 @@ const dataStructureWithLinks = {
24
29
  ],
25
30
  source: {
26
31
  currentVersion: {
27
- name: "CMESANO",
32
+ name: "STRUCTURE_1",
28
33
  pathWithIds: [
29
34
  {
30
35
  data_structure_id: "114207",
31
- name: "SRV_DS2P.PRO.SANTALUCIA.ES",
36
+ name: "UNO",
32
37
  },
33
38
  {
34
39
  data_structure_id: "58050",
35
- name: "SIISDS2",
40
+ name: "DOS",
36
41
  },
37
42
  {
38
43
  data_structure_id: "58045",
39
- name: "INPAHEM_SINIEPAGO",
44
+ name: "TRES",
40
45
  },
41
46
  ],
42
47
  },
43
48
  id: "60217",
44
49
  system: {
45
50
  id: "2",
46
- name: "Oracle producción solvencia",
51
+ name: "SYSTEM_1",
47
52
  },
48
53
  },
49
54
  target: {
50
55
  currentVersion: {
51
- name: "NIDSINIE",
56
+ name: "STRUCTURE_2",
52
57
  pathWithIds: [
53
58
  {
54
59
  data_structure_id: "114207",
55
- name: "SRV_DS2P.PRO.SANTALUCIA.ES",
60
+ name: "UNO",
56
61
  },
57
62
  {
58
63
  data_structure_id: "58050",
59
- name: "SIISDS2",
64
+ name: "DOS",
60
65
  },
61
66
  {
62
67
  data_structure_id: "58045",
63
- name: "INPAHEM_SINIEPAGO",
68
+ name: "TRES",
64
69
  },
65
70
  ],
66
71
  },
67
72
  id: "60218",
68
73
  system: {
69
74
  id: "2",
70
- name: "Oracle producción solvencia",
75
+ name: "SYSTEM_1",
71
76
  },
72
77
  },
73
78
  },
74
79
  {
80
+ _actions: {
81
+ delete_struct_to_struct_link: true,
82
+ },
83
+ id: "2",
75
84
  labels: [
76
85
  {
77
86
  name: "label_1_1",
@@ -82,46 +91,46 @@ const dataStructureWithLinks = {
82
91
  ],
83
92
  source: {
84
93
  currentVersion: {
85
- name: "ivalindm",
94
+ name: "STRUCTURE_3",
86
95
  pathWithIds: [
87
96
  {
88
97
  data_structure_id: "147587",
89
- name: "bdrs",
98
+ name: "UNO",
90
99
  },
91
100
  {
92
101
  data_structure_id: "151648",
93
- name: "inpahem_siniepago",
102
+ name: "DOS",
94
103
  },
95
104
  ],
96
105
  },
97
106
  id: "151674",
98
107
  system: {
99
108
  id: "11",
100
- name: "Azure Databricks",
109
+ name: "SYSTEM_2",
101
110
  },
102
111
  },
103
112
  target: {
104
113
  currentVersion: {
105
- name: "CMESANO",
114
+ name: "STRUCTURE_1",
106
115
  pathWithIds: [
107
116
  {
108
117
  data_structure_id: "114207",
109
- name: "SRV_DS2P.PRO.SANTALUCIA.ES",
118
+ name: "UNO",
110
119
  },
111
120
  {
112
121
  data_structure_id: "58050",
113
- name: "SIISDS2",
122
+ name: "DOS",
114
123
  },
115
124
  {
116
125
  data_structure_id: "58045",
117
- name: "INPAHEM_SINIEPAGO",
126
+ name: "TRES",
118
127
  },
119
128
  ],
120
129
  },
121
130
  id: "60217",
122
131
  system: {
123
132
  id: "2",
124
- name: "Oracle producción solvencia",
133
+ name: "SYSTEM_1",
125
134
  },
126
135
  },
127
136
  },
@@ -138,24 +147,89 @@ const linksMock = {
138
147
  };
139
148
 
140
149
  describe("<StructureStructureLinks />", () => {
141
- const props = { dataStructureWithLinks };
150
+ const props = {
151
+ dataStructureWithLinks,
152
+ };
153
+
154
+ const structureActions = {
155
+ create_struct_to_struct_link: {
156
+ href: "/some/url",
157
+ method: "POST",
158
+ },
159
+ };
160
+
161
+ const renderOpts = {
162
+ routes: ["/structures/60217/structureLinks"],
163
+ mocks: [linksMock],
164
+ };
165
+
166
+ it("shows structure to structure links", async () => {
167
+ const { getByRole } = render(<StructureStructureLinks {...props} />, {
168
+ ...renderOpts,
169
+ state: { structureActions },
170
+ });
171
+ await waitFor(() => {
172
+ expect(getByRole("link", { name: /STRUCTURE_2/i })).toBeInTheDocument();
173
+ expect(getByRole("link", { name: /STRUCTURE_3/i })).toBeInTheDocument();
174
+ });
175
+ await waitFor(() => {
176
+ expect(getByRole("button", { name: /Add link/i })).toBeInTheDocument();
177
+ });
178
+ expect(
179
+ document.getElementById("delete-link-60217-60218")
180
+ ).toBeInTheDocument();
181
+ expect(
182
+ document.getElementById("delete-link-151674-60217")
183
+ ).toBeInTheDocument();
184
+ });
142
185
 
143
- it("matches the latest snapshot", async () => {
144
- const renderOpts = {
145
- routes: ["/structures/60217/structureLinks"],
146
- mocks: [linksMock],
147
- };
148
- useParams.mockImplementation(() => ({
149
- id: 60217,
150
- }));
151
- const { container, findByText, getByRole, queryByText, debug } = render(
186
+ it("hides the 'add link' and delete link buttons if there are no permissions", async () => {
187
+ const { getByRole, queryByRole } = render(
152
188
  <StructureStructureLinks {...props} />,
153
189
  renderOpts
154
190
  );
155
191
  await waitFor(() => {
156
- expect(getByRole("link", { name: /NIDSINIE/i })).toBeInTheDocument();
157
- expect(getByRole("link", { name: /ivalindm/i })).toBeInTheDocument();
192
+ expect(getByRole("link", { name: /STRUCTURE_2/i })).toBeInTheDocument();
193
+ expect(getByRole("link", { name: /STRUCTURE_3/i })).toBeInTheDocument();
194
+ });
195
+ expect(
196
+ queryByRole("button", { name: /Add link/i })
197
+ ).not.toBeInTheDocument();
198
+ expect(document.getElementById("delete-link-60217-60218")).toBeNull();
199
+ expect(document.getElementById("delete-link-151674-60217")).toBeNull();
200
+ });
201
+
202
+ it("deletes link", async () => {
203
+ const dispatch = jest.fn();
204
+ const { getByText, getByRole } = render(
205
+ <StructureStructureLinks {...props} />,
206
+ {
207
+ ...renderOpts,
208
+ state: { structureActions },
209
+ dispatch,
210
+ }
211
+ );
212
+ await waitFor(() => {
213
+ expect(getByRole("link", { name: /STRUCTURE_2/i })).toBeInTheDocument();
214
+ expect(getByRole("link", { name: /STRUCTURE_3/i })).toBeInTheDocument();
215
+ });
216
+ await waitFor(() => {
217
+ expect(getByRole("button", { name: /Add link/i })).toBeInTheDocument();
218
+ });
219
+
220
+ const deleteButton = document.getElementById("delete-link-60217-60218");
221
+ userEvent.click(deleteButton);
222
+ expect(getByText("Delete link")).toBeInTheDocument();
223
+ const yesButton = getByRole("button", { name: /Yes/i });
224
+ userEvent.click(yesButton);
225
+
226
+ expect(dispatch).toHaveBeenCalledWith({
227
+ ...deleteStructureStructureLink(),
228
+ payload: {
229
+ dataStructureLinkId: "1",
230
+ sourceStructureId: "60217",
231
+ targetStructureId: "60218",
232
+ },
158
233
  });
159
- expect(container).toMatchSnapshot();
160
234
  });
161
235
  });
@@ -424,6 +424,8 @@ export default {
424
424
  "structureLink.currentStructure": "Current structure",
425
425
  "structureLink.label": "Relation label",
426
426
  "structureLink.relatedStructure": "Related structure",
427
+ "structureLink.selector.label": "Relation label",
428
+ "structureLink.selector.placeholder": "Select a relation label...",
427
429
  "structureSelector.union.criteria": "Union criteria",
428
430
  "structureSelector.union.type": "Union type",
429
431
  "structureTag.comment": "Comments",
@@ -433,6 +433,9 @@ export default {
433
433
  "structureLink.currentStructure": "Estructura actual",
434
434
  "structureLink.label": "Etiqueta de relación",
435
435
  "structureLink.relatedStructure": "Estructura relacionada",
436
+ "structureLink.selector.label": "Etiqueta de relación",
437
+ "structureLink.selector.placeholder":
438
+ "Seleccione una etiqueta de relación...",
436
439
  "structureSelector.union.criteria": "Criterio de unión",
437
440
  "structureSelector.union.type": "Tipo de unión",
438
441
  "structureTag.comment": "Comentario",
@@ -8,6 +8,7 @@ import {
8
8
  STRUCTURE_TAGS,
9
9
  STRUCTURE_TYPES,
10
10
  STRUCTURES,
11
+ STRUCTURE_STRUCTURE_LINKS,
11
12
  linkTo,
12
13
  } from "@truedat/core/routes";
13
14
  import {
@@ -24,6 +25,7 @@ import {
24
25
  deleteStructure,
25
26
  deleteTag,
26
27
  doStructureNoteAction,
28
+ linkStructureToStructure,
27
29
  updateGrantApprovalRule,
28
30
  updateReferenceDataset,
29
31
  updateStructure,
@@ -50,6 +52,10 @@ export const structureRedirect = (
50
52
  const id = _.path("data.id")(payload);
51
53
  return linkTo.SYSTEM_STRUCTURES({ id });
52
54
  }
55
+ case linkStructureToStructure.SUCCESS:
56
+ return linkTo.STRUCTURE_STRUCTURE_LINKS({
57
+ id: payload.sourceStructureId,
58
+ });
53
59
  case updateSystem.SUCCESS: {
54
60
  const id = _.path("data.id")(payload);
55
61
  return linkTo.SYSTEM_STRUCTURES({ id });
package/src/routines.js CHANGED
@@ -51,6 +51,7 @@ export const deleteGrantApprovalRule = createRoutine("DELETE_GRANT_APPROVAL_RULE
51
51
  export const deleteReferenceDataset = createRoutine("DELETE_REFERENCE_DATASET");
52
52
  export const deleteStructureTag = createRoutine("DELETE_STRUCTURE_TAG");
53
53
  export const deleteStructure = createRoutine("DELETE_STRUCTURE");
54
+ export const deleteStructureStructureLink = createRoutine("DELETE_STRUCTURE_STRUCTURE_LINK");
54
55
  export const deleteTag = createRoutine("DELETE_TAG");
55
56
  export const deleteUserSearchFilter = createRoutine("DELETE_USER_SEARCH_FILTER");
56
57
  export const doStructureNoteAction = createRoutine("DO_STRUCTURE_NOTE_ACTION");
@@ -86,7 +87,7 @@ export const fetchUserSearchFilters = createRoutine("FETCH_USER_SEARCH_FILTERS")
86
87
  export const filterStructures = createRoutine("FILTER_STRUCTURES");
87
88
  export const hoverNode = createRoutine("HOVER_NODE");
88
89
  export const initSvg = createRoutine("INIT_SVG");
89
- export const tagStructure = createRoutine("TAG_STRUCTURE");
90
+ export const linkStructureToStructure = createRoutine("LINK_STRUCTURE_TO_STRUCTURE");
90
91
  export const loadLineageEvents = createRoutine("LOAD_LINEAGE_EVENTS");
91
92
  export const openGrantFilter = createRoutine("OPEN_GRANT_FILTER");
92
93
  export const openStructureFilter = createRoutine("OPEN_STRUCTURE_FILTER");
@@ -113,6 +114,7 @@ export const setGrantChangeRequestCart = createRoutine("SET_GRANT_CHANGE_REQUEST
113
114
  export const setGrantRequestsQuery = createRoutine("SET_GRANT_REQUESTS_QUERY");
114
115
  export const sortGrants = createRoutine("SORT_GRANTS");
115
116
  export const sortStructures = createRoutine("SORT_STRUCTURES");
117
+ export const tagStructure = createRoutine("TAG_STRUCTURE");
116
118
  export const toggleGrantDateFilter = createRoutine("TOGGLE_GRANT_DATE_FILTER");
117
119
  export const toggleGrantFilterValue = createRoutine("TOGGLE_GRANT_FILTER_VALUE");
118
120
  export const toggleStructureDateFilter = createRoutine("TOGGLE_STRUCTURE_DATE_FILTER");
@@ -0,0 +1,101 @@
1
+ import _ from "lodash/fp";
2
+ import { compile } from "path-to-regexp";
3
+ import { testSaga } from "redux-saga-test-plan";
4
+ import { apiJsonDelete, JSON_OPTS } from "@truedat/core/services/api";
5
+ import {
6
+ deleteStructureStructureLinkSaga,
7
+ deleteStructureStructureLinkRequestSaga,
8
+ } from "../deleteStructureStructureLink";
9
+ import { deleteStructureStructureLink } from "../../routines";
10
+ import { API_STRUCTURE_TO_STRUCTURE_LINK } from "../../api";
11
+
12
+ describe("sagas: deleteStructureStructureRequestSaga", () => {
13
+ it("should invoke deleteStructureStructureSaga on deleteStructureStructureLink.TRIGGER", () => {
14
+ expect(() => {
15
+ testSaga(deleteStructureStructureLinkRequestSaga)
16
+ .next()
17
+ .takeLatest(
18
+ deleteStructureStructureLink.TRIGGER,
19
+ deleteStructureStructureLinkSaga
20
+ )
21
+ .finish()
22
+ .isDone();
23
+ }).not.toThrow();
24
+ });
25
+
26
+ it("should throw exception if an unhandled action is received", () => {
27
+ expect(() => {
28
+ testSaga(deleteStructureStructureLinkRequestSaga)
29
+ .next()
30
+ .takeLatest("FOO", deleteStructureStructureLinkSaga);
31
+ }).toThrow();
32
+ });
33
+ });
34
+
35
+ describe("sagas: deleteStructureStructureLinkSaga", () => {
36
+ const sourceStructureId = 1;
37
+ const targetStructureId = 2;
38
+ const dataStructureLinkId = 1;
39
+ const receivedPayload = {
40
+ sourceStructureId,
41
+ targetStructureId,
42
+ dataStructureLinkId,
43
+ };
44
+
45
+ const deletePayload = {
46
+ sourceStructureId,
47
+ targetStructureId,
48
+ };
49
+
50
+ const url = compile(API_STRUCTURE_TO_STRUCTURE_LINK)({
51
+ sourceStructureId,
52
+ targetStructureId,
53
+ });
54
+
55
+ const client = {
56
+ cache: {
57
+ identify: jest.fn(),
58
+ evict: jest.fn(),
59
+ gc: jest.fn(),
60
+ },
61
+ };
62
+
63
+ it("should put a success action when a response is returned", () => {
64
+ expect(() => {
65
+ testSaga(deleteStructureStructureLinkSaga, { payload: receivedPayload })
66
+ .next()
67
+ .getContext("client")
68
+ .next(client)
69
+ .put(deleteStructureStructureLink.request(deletePayload))
70
+ .next(client)
71
+ .call(apiJsonDelete, url, JSON_OPTS)
72
+ .next({ data: deletePayload })
73
+ .put(deleteStructureStructureLink.success(deletePayload))
74
+ .next()
75
+ .put(deleteStructureStructureLink.fulfill())
76
+ .next()
77
+ .isDone();
78
+ }).not.toThrow();
79
+ });
80
+
81
+ it("should put a failure action when a call returns an error", () => {
82
+ const message = "Request failed";
83
+ const error = { message };
84
+
85
+ expect(() => {
86
+ testSaga(deleteStructureStructureLinkSaga, { payload: receivedPayload })
87
+ .next()
88
+ .getContext("client")
89
+ .next(client)
90
+ .put(deleteStructureStructureLink.request(deletePayload))
91
+ .next(client)
92
+ .call(apiJsonDelete, url, JSON_OPTS)
93
+ .throw(error)
94
+ .put(deleteStructureStructureLink.failure(message))
95
+ .next()
96
+ .put(deleteStructureStructureLink.fulfill())
97
+ .next()
98
+ .isDone();
99
+ }).not.toThrow();
100
+ });
101
+ });