@truedat/core 8.3.0 → 8.3.2
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": "@truedat/core",
|
|
3
|
-
"version": "8.3.
|
|
3
|
+
"version": "8.3.2",
|
|
4
4
|
"description": "Truedat Web Core",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"module": "src/index.js",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"@testing-library/jest-dom": "^6.6.3",
|
|
49
49
|
"@testing-library/react": "^16.3.0",
|
|
50
50
|
"@testing-library/user-event": "^14.6.1",
|
|
51
|
-
"@truedat/test": "8.3.
|
|
51
|
+
"@truedat/test": "8.3.2",
|
|
52
52
|
"identity-obj-proxy": "^3.0.0",
|
|
53
53
|
"jest": "^29.7.0",
|
|
54
54
|
"redux-saga-test-plan": "^4.0.6"
|
|
@@ -85,5 +85,5 @@
|
|
|
85
85
|
"slate-react": "^0.22.10",
|
|
86
86
|
"swr": "^2.3.3"
|
|
87
87
|
},
|
|
88
|
-
"gitHead": "
|
|
88
|
+
"gitHead": "ed0c289882710d6df3483692fab5833747130cbf"
|
|
89
89
|
}
|
|
@@ -18,9 +18,7 @@ export const StatusPill = ({ status }) => (
|
|
|
18
18
|
])(status)}
|
|
19
19
|
size="small"
|
|
20
20
|
>
|
|
21
|
-
<FormattedMessage
|
|
22
|
-
id={`uploadJob.parser.event.status.${status}`}
|
|
23
|
-
/>
|
|
21
|
+
<FormattedMessage id={`uploadJob.parser.event.status.${status}`} />
|
|
24
22
|
</Label>
|
|
25
23
|
);
|
|
26
24
|
|
|
@@ -64,9 +62,8 @@ const SheetAndLine = ({ response }) => (
|
|
|
64
62
|
{response.row_number ? (
|
|
65
63
|
<span>
|
|
66
64
|
{" "}
|
|
67
|
-
-{" "}
|
|
68
|
-
|
|
69
|
-
: {response.row_number}
|
|
65
|
+
- <FormattedMessage id="uploadJob.parser.result.prop.row_number" />:{" "}
|
|
66
|
+
{response.row_number}
|
|
70
67
|
</span>
|
|
71
68
|
) : null}
|
|
72
69
|
</Label>
|
|
@@ -90,7 +87,7 @@ const externalIdDetailValue = (details) =>
|
|
|
90
87
|
external_id={details.external_id}
|
|
91
88
|
/>
|
|
92
89
|
) : (
|
|
93
|
-
details?.external_id ?? ""
|
|
90
|
+
(details?.external_id ?? "")
|
|
94
91
|
);
|
|
95
92
|
|
|
96
93
|
const ErrorDetail = ({ response }) => {
|
|
@@ -131,18 +128,20 @@ const ErrorDetail = ({ response }) => {
|
|
|
131
128
|
],
|
|
132
129
|
],
|
|
133
130
|
implementation_creation_error: (details) => {
|
|
134
|
-
return
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
131
|
+
return (
|
|
132
|
+
details?.map((detail) => {
|
|
133
|
+
if (_.isArray(detail)) {
|
|
134
|
+
const [field, [error]] = detail;
|
|
135
|
+
return [field, error];
|
|
136
|
+
}
|
|
139
137
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
138
|
+
if (_.isObject(detail)) {
|
|
139
|
+
return [detail.field, detail.message];
|
|
140
|
+
}
|
|
143
141
|
|
|
144
|
-
|
|
145
|
-
|
|
142
|
+
return detail;
|
|
143
|
+
}) || []
|
|
144
|
+
);
|
|
146
145
|
},
|
|
147
146
|
duplicate_field_names: (details) => [
|
|
148
147
|
[
|
|
@@ -152,41 +151,60 @@ const ErrorDetail = ({ response }) => {
|
|
|
152
151
|
],
|
|
153
152
|
pending_approval_conflict: (details) =>
|
|
154
153
|
[
|
|
155
|
-
[
|
|
156
|
-
|
|
154
|
+
[
|
|
155
|
+
formatMessage({ id: `${messagePrefix}.message` }),
|
|
156
|
+
details?.message ?? "",
|
|
157
|
+
],
|
|
158
|
+
[null, externalIdDetailValue(details)],
|
|
157
159
|
].filter(([, v]) => v !== undefined && v !== ""),
|
|
158
160
|
data_structure_not_found: (details) => [
|
|
159
|
-
[
|
|
160
|
-
],
|
|
161
|
-
template_not_found: (details) => [
|
|
162
|
-
[formatMessage({ id: `${messagePrefix}.externalId` }), externalIdDetailValue(details)],
|
|
163
|
-
],
|
|
164
|
-
unauthorized: (details) => [
|
|
165
|
-
[formatMessage({ id: `${messagePrefix}.externalId` }), externalIdDetailValue(details)],
|
|
161
|
+
[null, externalIdDetailValue(details)],
|
|
166
162
|
],
|
|
163
|
+
template_not_found: (details) => [[null, externalIdDetailValue(details)]],
|
|
164
|
+
unauthorized: (details) => [[null, externalIdDetailValue(details)]],
|
|
167
165
|
unreject_failed: (details) =>
|
|
168
166
|
[
|
|
169
|
-
[
|
|
170
|
-
|
|
167
|
+
[
|
|
168
|
+
formatMessage({ id: `${messagePrefix}.reason` }),
|
|
169
|
+
details?.reason ?? "",
|
|
170
|
+
],
|
|
171
|
+
[null, externalIdDetailValue(details)],
|
|
171
172
|
].filter(([, v]) => v !== undefined && v !== ""),
|
|
172
173
|
field_validation_error: (details) =>
|
|
173
174
|
details?.errors?.map((e) => [
|
|
174
175
|
e?.field ?? formatMessage({ id: `${messagePrefix}.message` }),
|
|
175
176
|
e?.message ?? "",
|
|
176
|
-
]) ?? [[
|
|
177
|
-
unprocessable_entity: (details) => [
|
|
178
|
-
[formatMessage({ id: `${messagePrefix}.externalId` }), externalIdDetailValue(details)],
|
|
179
|
-
],
|
|
177
|
+
]) ?? [[null, externalIdDetailValue(details)]],
|
|
178
|
+
unprocessable_entity: (details) => [[null, externalIdDetailValue(details)]],
|
|
180
179
|
structure_note_creation_error: (details) => {
|
|
180
|
+
const reason = details?.reason ?? details?.error;
|
|
181
|
+
|
|
182
|
+
const reasonMessageId =
|
|
183
|
+
reason != null
|
|
184
|
+
? `structures.uploadStructures.failed.note.${reason}`
|
|
185
|
+
: null;
|
|
186
|
+
|
|
181
187
|
const errorPairs = details?.errors?.length
|
|
182
188
|
? details.errors.map((e) => [
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
: [
|
|
189
|
+
e?.field ?? formatMessage({ id: `${messagePrefix}.message` }),
|
|
190
|
+
e?.message ?? "",
|
|
191
|
+
])
|
|
192
|
+
: [
|
|
193
|
+
[
|
|
194
|
+
formatMessage({ id: `${messagePrefix}.reason` }),
|
|
195
|
+
reasonMessageId
|
|
196
|
+
? formatMessage({
|
|
197
|
+
id: reasonMessageId,
|
|
198
|
+
defaultMessage: String(reason),
|
|
199
|
+
})
|
|
200
|
+
: String(reason ?? ""),
|
|
201
|
+
],
|
|
202
|
+
];
|
|
203
|
+
|
|
187
204
|
const externalIdPair = details?.external_id
|
|
188
|
-
? [[
|
|
205
|
+
? [[null, externalIdDetailValue(details)]]
|
|
189
206
|
: [];
|
|
207
|
+
|
|
190
208
|
return [...errorPairs, ...externalIdPair];
|
|
191
209
|
},
|
|
192
210
|
};
|
|
@@ -195,12 +213,20 @@ const ErrorDetail = ({ response }) => {
|
|
|
195
213
|
|
|
196
214
|
const details = _.cond([
|
|
197
215
|
[_.isNil, _.constant([])],
|
|
198
|
-
[
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
216
|
+
[
|
|
217
|
+
_.stubTrue,
|
|
218
|
+
(d) => {
|
|
219
|
+
const result = detailBuilder(d);
|
|
220
|
+
return _.isArray(result) ? result : [];
|
|
221
|
+
},
|
|
222
|
+
],
|
|
202
223
|
])(response.details);
|
|
203
224
|
|
|
225
|
+
const visibleDetails = _.filter(
|
|
226
|
+
([, value]) => value != null && value !== "",
|
|
227
|
+
details
|
|
228
|
+
);
|
|
229
|
+
|
|
204
230
|
return (
|
|
205
231
|
<div>
|
|
206
232
|
<CellHeader
|
|
@@ -208,25 +234,25 @@ const ErrorDetail = ({ response }) => {
|
|
|
208
234
|
response={response}
|
|
209
235
|
/>
|
|
210
236
|
|
|
211
|
-
{
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
237
|
+
{_.isEmpty(visibleDetails)
|
|
238
|
+
? null
|
|
239
|
+
: visibleDetails.map(([key, value], idx) => (
|
|
240
|
+
<div key={idx}>
|
|
241
|
+
{key != null && key !== "" ? (
|
|
242
|
+
<span
|
|
243
|
+
style={{
|
|
244
|
+
fontSize: "1em",
|
|
245
|
+
fontWeight: "bold",
|
|
246
|
+
paddingRight: "5px",
|
|
247
|
+
}}
|
|
248
|
+
>
|
|
249
|
+
{key}:
|
|
250
|
+
</span>
|
|
251
|
+
) : null}
|
|
225
252
|
{value}
|
|
226
253
|
</div>
|
|
227
|
-
))
|
|
228
|
-
|
|
229
|
-
</div >
|
|
254
|
+
))}
|
|
255
|
+
</div>
|
|
230
256
|
);
|
|
231
257
|
};
|
|
232
258
|
const summaryItems = [
|
|
@@ -268,36 +294,36 @@ const CompletedDetail = ({ response }) => {
|
|
|
268
294
|
);
|
|
269
295
|
}
|
|
270
296
|
return result;
|
|
271
|
-
}
|
|
297
|
+
},
|
|
272
298
|
])(summaryItems);
|
|
273
299
|
|
|
274
300
|
if (items.length === 0) return null;
|
|
275
301
|
|
|
276
|
-
return
|
|
277
|
-
<span> | {items} | </span>
|
|
278
|
-
);
|
|
302
|
+
return <span> | {items} | </span>;
|
|
279
303
|
};
|
|
280
304
|
|
|
281
|
-
|
|
282
305
|
const InfoDetail = ({ response }) =>
|
|
283
306
|
!response || !response.type ? null : (
|
|
284
307
|
<div>
|
|
285
308
|
<CellHeader
|
|
286
|
-
header={
|
|
309
|
+
header={
|
|
310
|
+
response.type === "unchanged" && response.details?.is_deprecated
|
|
311
|
+
? "uploadJob.parser.info.deprecated_implementation"
|
|
312
|
+
: `uploadJob.parser.info.${response.type}`
|
|
313
|
+
}
|
|
287
314
|
response={response}
|
|
288
315
|
/>
|
|
289
316
|
{response.details ? (
|
|
290
317
|
<div>
|
|
291
318
|
{response.details.implementation_key != null ? (
|
|
292
319
|
<RuleImplementationLink {...response.details} />
|
|
293
|
-
) :
|
|
294
|
-
response.details.external_id != null
|
|
320
|
+
) : response.details.data_structure_id != null ||
|
|
321
|
+
response.details.external_id != null ? (
|
|
295
322
|
<StructureNoteLink
|
|
296
323
|
data_structure_id={response.details.data_structure_id}
|
|
297
324
|
external_id={response.details.external_id}
|
|
298
325
|
/>
|
|
299
|
-
) : null}
|
|
300
|
-
{" "}
|
|
326
|
+
) : null}{" "}
|
|
301
327
|
</div>
|
|
302
328
|
) : null}
|
|
303
329
|
<ChangesDetail changes={response?.details?.changes} />
|
|
@@ -360,21 +386,21 @@ const ChangesDetail = ({
|
|
|
360
386
|
);
|
|
361
387
|
};
|
|
362
388
|
|
|
363
|
-
|
|
364
389
|
const formatValue = (value, key) => {
|
|
365
390
|
if (_.has("value")(value)) return formatValue(value.value, key);
|
|
366
391
|
if (_.isArray(value)) {
|
|
367
|
-
return _.flow(
|
|
392
|
+
return _.flow(
|
|
393
|
+
_.map((v) => formatValue(v, key)),
|
|
394
|
+
_.join(", ")
|
|
395
|
+
)(value);
|
|
368
396
|
}
|
|
369
397
|
if (_.isObject(value)) {
|
|
370
398
|
if (_.has("document")(value))
|
|
371
399
|
return <RichTextEditor readOnly value={value} />;
|
|
372
400
|
if (_.has("url_value")(value))
|
|
373
401
|
return `[${value.url_name}] (${value.url_value})`;
|
|
374
|
-
if (_.has("name")(value))
|
|
375
|
-
|
|
376
|
-
if (_.has("external_id")(value))
|
|
377
|
-
return value.external_id;
|
|
402
|
+
if (_.has("name")(value)) return value.name;
|
|
403
|
+
if (_.has("external_id")(value)) return value.external_id;
|
|
378
404
|
|
|
379
405
|
return _.flow(_.keys, _.join(", "))(value);
|
|
380
406
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import userEvent from "@testing-library/user-event";
|
|
1
2
|
import { render } from "@truedat/test/render";
|
|
2
3
|
import { StatusPill, ResponseCell } from "../UploadJobParser";
|
|
3
4
|
|
|
@@ -35,9 +36,7 @@ describe("<ResponseCell />", () => {
|
|
|
35
36
|
const rendered = render(
|
|
36
37
|
<ResponseCell response={response} status="FAILED" />
|
|
37
38
|
);
|
|
38
|
-
expect(
|
|
39
|
-
rendered.getByText(/missing_required_headers/i)
|
|
40
|
-
).toBeInTheDocument();
|
|
39
|
+
expect(rendered.getByText(/missing_required_headers/i)).toBeInTheDocument();
|
|
41
40
|
});
|
|
42
41
|
|
|
43
42
|
it("renders ERROR status with details", () => {
|
|
@@ -51,9 +50,7 @@ describe("<ResponseCell />", () => {
|
|
|
51
50
|
<ResponseCell response={response} status="ERROR" />
|
|
52
51
|
);
|
|
53
52
|
expect(
|
|
54
|
-
rendered.getByText(
|
|
55
|
-
/uploadJob.parser.error.missing_required_headers/i
|
|
56
|
-
)
|
|
53
|
+
rendered.getByText(/uploadJob.parser.error.missing_required_headers/i)
|
|
57
54
|
).toBeInTheDocument();
|
|
58
55
|
expect(rendered.getByText(/header1, header2/i)).toBeInTheDocument();
|
|
59
56
|
});
|
|
@@ -87,12 +84,22 @@ describe("<ResponseCell />", () => {
|
|
|
87
84
|
};
|
|
88
85
|
const rendered = render(<ResponseCell response={response} status="INFO" />);
|
|
89
86
|
expect(
|
|
90
|
-
rendered.getByText(
|
|
91
|
-
/uploadJob.parser.info.implementation_updated/i
|
|
92
|
-
)
|
|
87
|
+
rendered.getByText(/uploadJob.parser.info.implementation_updated/i)
|
|
93
88
|
).toBeInTheDocument();
|
|
94
89
|
});
|
|
95
90
|
|
|
91
|
+
it("renders INFO status with deprecated_implementation specifically when unchanged and deprecated", () => {
|
|
92
|
+
const response = {
|
|
93
|
+
type: "unchanged",
|
|
94
|
+
details: {
|
|
95
|
+
id: 123,
|
|
96
|
+
is_deprecated: true,
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
const rendered = render(<ResponseCell response={response} status="INFO" />);
|
|
100
|
+
expect(rendered.getByText(/uploadJob.parser.info.deprecated_implementation/i)).toBeInTheDocument();
|
|
101
|
+
});
|
|
102
|
+
|
|
96
103
|
it("renders default case for unknown status", () => {
|
|
97
104
|
const response = "some text";
|
|
98
105
|
const rendered = render(
|
|
@@ -100,4 +107,261 @@ describe("<ResponseCell />", () => {
|
|
|
100
107
|
);
|
|
101
108
|
expect(rendered.getByText(/some text/i)).toBeInTheDocument();
|
|
102
109
|
});
|
|
110
|
+
|
|
111
|
+
it("renders ERROR status with structure_note_creation_error and translated workflow reason", () => {
|
|
112
|
+
const response = {
|
|
113
|
+
type: "structure_note_creation_error",
|
|
114
|
+
details: {
|
|
115
|
+
reason: "content_unchanged",
|
|
116
|
+
external_id: "EXT-001",
|
|
117
|
+
data_structure_id: 123,
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
const renderOpts = {
|
|
121
|
+
messages: {
|
|
122
|
+
en: {
|
|
123
|
+
"uploadJob.parser.error.structure_note_creation_error":
|
|
124
|
+
"Structure note error",
|
|
125
|
+
"uploadJob.parser.detail.reason": "Reason",
|
|
126
|
+
"uploadJob.parser.detail.externalId": "External id",
|
|
127
|
+
"structures.uploadStructures.failed.note.content_unchanged":
|
|
128
|
+
"Content unchanged",
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
const rendered = render(
|
|
133
|
+
<ResponseCell response={response} status="ERROR" />,
|
|
134
|
+
renderOpts
|
|
135
|
+
);
|
|
136
|
+
expect(rendered.getByText(/structure note error/i)).toBeInTheDocument();
|
|
137
|
+
expect(rendered.getByText(/content unchanged/i)).toBeInTheDocument();
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it("returns null when ERROR response has no type", () => {
|
|
141
|
+
const response = { details: {} };
|
|
142
|
+
const rendered = render(
|
|
143
|
+
<ResponseCell response={response} status="ERROR" />
|
|
144
|
+
);
|
|
145
|
+
expect(rendered.container.firstChild).toBeNull();
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it("renders ERROR status with invalid_template_name details", () => {
|
|
149
|
+
const response = {
|
|
150
|
+
type: "invalid_template_name",
|
|
151
|
+
details: { template_name: "My Template" },
|
|
152
|
+
};
|
|
153
|
+
const rendered = render(
|
|
154
|
+
<ResponseCell response={response} status="ERROR" />
|
|
155
|
+
);
|
|
156
|
+
expect(
|
|
157
|
+
rendered.getByText(/uploadJob.parser.error.invalid_template_name/i)
|
|
158
|
+
).toBeInTheDocument();
|
|
159
|
+
expect(rendered.getByText(/My Template/i)).toBeInTheDocument();
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it("renders ERROR status with duplicate_field_names details", () => {
|
|
163
|
+
const response = {
|
|
164
|
+
type: "duplicate_field_names",
|
|
165
|
+
details: { duplicate_fields: ["col_a", "col_b"] },
|
|
166
|
+
};
|
|
167
|
+
const rendered = render(
|
|
168
|
+
<ResponseCell response={response} status="ERROR" />
|
|
169
|
+
);
|
|
170
|
+
expect(
|
|
171
|
+
rendered.getByText(/uploadJob.parser.error.duplicate_field_names/i)
|
|
172
|
+
).toBeInTheDocument();
|
|
173
|
+
expect(rendered.getByText(/col_a, col_b/i)).toBeInTheDocument();
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it("renders ERROR status with implementation_creation_error and array details", () => {
|
|
177
|
+
const response = {
|
|
178
|
+
type: "implementation_creation_error",
|
|
179
|
+
details: [
|
|
180
|
+
["name", ["Name is required"]],
|
|
181
|
+
["key", ["Key is invalid"]],
|
|
182
|
+
],
|
|
183
|
+
};
|
|
184
|
+
const rendered = render(
|
|
185
|
+
<ResponseCell response={response} status="ERROR" />
|
|
186
|
+
);
|
|
187
|
+
expect(
|
|
188
|
+
rendered.getByText(
|
|
189
|
+
/uploadJob.parser.error.implementation_creation_error/i
|
|
190
|
+
)
|
|
191
|
+
).toBeInTheDocument();
|
|
192
|
+
expect(rendered.getByText(/Name is required/i)).toBeInTheDocument();
|
|
193
|
+
expect(rendered.getByText(/Key is invalid/i)).toBeInTheDocument();
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it("renders ERROR status with implementation_creation_error and object details", () => {
|
|
197
|
+
const response = {
|
|
198
|
+
type: "implementation_creation_error",
|
|
199
|
+
details: [
|
|
200
|
+
{ field: "name", message: "Invalid" },
|
|
201
|
+
{ field: "key", message: "Duplicate" },
|
|
202
|
+
],
|
|
203
|
+
};
|
|
204
|
+
const rendered = render(
|
|
205
|
+
<ResponseCell response={response} status="ERROR" />
|
|
206
|
+
);
|
|
207
|
+
expect(rendered.getByText(/Invalid/i)).toBeInTheDocument();
|
|
208
|
+
expect(rendered.getByText(/Duplicate/i)).toBeInTheDocument();
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
it("renders ERROR status with field_validation_error details", () => {
|
|
212
|
+
const response = {
|
|
213
|
+
type: "field_validation_error",
|
|
214
|
+
details: {
|
|
215
|
+
errors: [
|
|
216
|
+
{ field: "name", message: "Required" },
|
|
217
|
+
{ field: "external_id", message: "Already exists" },
|
|
218
|
+
],
|
|
219
|
+
},
|
|
220
|
+
};
|
|
221
|
+
const rendered = render(
|
|
222
|
+
<ResponseCell response={response} status="ERROR" />
|
|
223
|
+
);
|
|
224
|
+
expect(
|
|
225
|
+
rendered.getByText(/uploadJob.parser.error.field_validation_error/i)
|
|
226
|
+
).toBeInTheDocument();
|
|
227
|
+
expect(rendered.getByText(/Required/i)).toBeInTheDocument();
|
|
228
|
+
expect(rendered.getByText(/Already exists/i)).toBeInTheDocument();
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
it("renders ERROR status with deprecated_implementation details", () => {
|
|
232
|
+
const response = {
|
|
233
|
+
type: "deprecated_implementation",
|
|
234
|
+
details: { implementation_key: "old_impl_key" },
|
|
235
|
+
};
|
|
236
|
+
const rendered = render(
|
|
237
|
+
<ResponseCell response={response} status="ERROR" />
|
|
238
|
+
);
|
|
239
|
+
expect(
|
|
240
|
+
rendered.getByText(/uploadJob.parser.error.deprecated_implementation/i)
|
|
241
|
+
).toBeInTheDocument();
|
|
242
|
+
expect(rendered.getByText(/old_impl_key/i)).toBeInTheDocument();
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
it("renders ERROR status with unreject_failed details", () => {
|
|
246
|
+
const response = {
|
|
247
|
+
type: "unreject_failed",
|
|
248
|
+
details: { reason: "Workflow in progress" },
|
|
249
|
+
};
|
|
250
|
+
const renderOpts = {
|
|
251
|
+
messages: {
|
|
252
|
+
en: {
|
|
253
|
+
"uploadJob.parser.error.unreject_failed": "Unreject failed",
|
|
254
|
+
"uploadJob.parser.detail.reason": "Reason",
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
};
|
|
258
|
+
const rendered = render(
|
|
259
|
+
<ResponseCell response={response} status="ERROR" />,
|
|
260
|
+
renderOpts
|
|
261
|
+
);
|
|
262
|
+
expect(rendered.getByText(/unreject failed/i)).toBeInTheDocument();
|
|
263
|
+
expect(rendered.getByText(/Workflow in progress/i)).toBeInTheDocument();
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
it("renders COMPLETED status with no summary when all counts are zero", () => {
|
|
267
|
+
const response = {
|
|
268
|
+
insert_count: 0,
|
|
269
|
+
update_count: 0,
|
|
270
|
+
unchanged_count: 0,
|
|
271
|
+
error_count: 0,
|
|
272
|
+
invalid_sheet_count: 0,
|
|
273
|
+
};
|
|
274
|
+
const rendered = render(
|
|
275
|
+
<ResponseCell response={response} status="COMPLETED" />
|
|
276
|
+
);
|
|
277
|
+
expect(
|
|
278
|
+
rendered.queryByText(/uploadJob.parser.result.summary.created/i)
|
|
279
|
+
).not.toBeInTheDocument();
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
it("renders default case with object response as JSON", () => {
|
|
283
|
+
const response = { code: "ERR_001", description: "Something failed" };
|
|
284
|
+
const rendered = render(
|
|
285
|
+
<ResponseCell response={response} status="UNKNOWN" />
|
|
286
|
+
);
|
|
287
|
+
expect(rendered.getByText(/"code":\s*"ERR_001"/i)).toBeInTheDocument();
|
|
288
|
+
expect(
|
|
289
|
+
rendered.getByText(/"description":\s*"Something failed"/i)
|
|
290
|
+
).toBeInTheDocument();
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
it("renders INFO status with details.changes and expandable ChangesDetail", async () => {
|
|
294
|
+
const response = {
|
|
295
|
+
type: "implementation_updated",
|
|
296
|
+
details: {
|
|
297
|
+
changes: {
|
|
298
|
+
name: "New Name",
|
|
299
|
+
description: "Updated description",
|
|
300
|
+
},
|
|
301
|
+
},
|
|
302
|
+
};
|
|
303
|
+
const user = userEvent.setup({ delay: null });
|
|
304
|
+
const rendered = render(<ResponseCell response={response} status="INFO" />);
|
|
305
|
+
expect(
|
|
306
|
+
rendered.getByText(/uploadJob.parser.info.implementation_updated/i)
|
|
307
|
+
).toBeInTheDocument();
|
|
308
|
+
expect(
|
|
309
|
+
rendered.getByText(/uploadJob.parser.result.prop.changes/i)
|
|
310
|
+
).toBeInTheDocument();
|
|
311
|
+
expect(rendered.getByText(/\(2\)/)).toBeInTheDocument();
|
|
312
|
+
await user.click(
|
|
313
|
+
rendered.getByText(/uploadJob.parser.result.prop.changes/i).closest("div")
|
|
314
|
+
);
|
|
315
|
+
expect(rendered.getByText(/New Name/i)).toBeInTheDocument();
|
|
316
|
+
expect(rendered.getByText(/Updated description/i)).toBeInTheDocument();
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
it("renders INFO status with nested df_content in changes", async () => {
|
|
320
|
+
const response = {
|
|
321
|
+
type: "implementation_updated",
|
|
322
|
+
details: {
|
|
323
|
+
changes: {
|
|
324
|
+
df_content: {
|
|
325
|
+
inner_key: "inner_value",
|
|
326
|
+
},
|
|
327
|
+
},
|
|
328
|
+
},
|
|
329
|
+
};
|
|
330
|
+
const user = userEvent.setup({ delay: null });
|
|
331
|
+
const rendered = render(<ResponseCell response={response} status="INFO" />);
|
|
332
|
+
const changesHeader = rendered.getByText(
|
|
333
|
+
/uploadJob.parser.result.prop.changes/i
|
|
334
|
+
);
|
|
335
|
+
await user.click(changesHeader.closest("div"));
|
|
336
|
+
expect(
|
|
337
|
+
rendered.getByText(/ruleImplementations.props.df_content/i)
|
|
338
|
+
).toBeInTheDocument();
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
it("renders ERROR with sheet and row_number in response", () => {
|
|
342
|
+
const response = {
|
|
343
|
+
type: "missing_required_headers",
|
|
344
|
+
sheet: "Sheet1",
|
|
345
|
+
row_number: 5,
|
|
346
|
+
details: { missing_headers: ["H1"] },
|
|
347
|
+
};
|
|
348
|
+
const rendered = render(
|
|
349
|
+
<ResponseCell response={response} status="ERROR" />
|
|
350
|
+
);
|
|
351
|
+
expect(rendered.getByText(/Sheet1/i)).toBeInTheDocument();
|
|
352
|
+
expect(rendered.getByText(/5/)).toBeInTheDocument();
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
it("renders INFO status with null details", () => {
|
|
356
|
+
const response = { type: "some_info" };
|
|
357
|
+
const rendered = render(<ResponseCell response={response} status="INFO" />);
|
|
358
|
+
expect(
|
|
359
|
+
rendered.getByText(/uploadJob.parser.info.some_info/i)
|
|
360
|
+
).toBeInTheDocument();
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
it("renders INFO status with null response as null", () => {
|
|
364
|
+
const rendered = render(<ResponseCell response={null} status="INFO" />);
|
|
365
|
+
expect(rendered.container.firstChild).toBeNull();
|
|
366
|
+
});
|
|
103
367
|
});
|