Skip to content

Commit cef2c57

Browse files
fix problem+json context resolving while expanding violation list (#553)
* add jest-fetch-mock * violation list expanding test cases * problem+json context resolving fix * yarn upgrade * Remove commented import. * proto typo * lock rever
1 parent 551ba4c commit cef2c57

3 files changed

Lines changed: 111 additions & 6 deletions

File tree

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
"eslint-plugin-tree-shaking": "^1.10.0",
6767
"jest": "^29.0.0",
6868
"jest-environment-jsdom": "^29.0.0",
69+
"jest-fetch-mock": "^3.0.3",
6970
"node-fetch": "^3.2.10",
7071
"playwright": "^1.42.1",
7172
"prettier": "^3.0.0",

src/hydra/fetchHydra.test.ts

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import type { HttpError } from 'react-admin';
2+
import fetchMock from 'jest-fetch-mock';
3+
import fetchHydra from './fetchHydra.js';
4+
import schemaAnalyzer from './schemaAnalyzer.js';
5+
6+
fetchMock.enableMocks();
7+
8+
const headers = {
9+
'Content-Type': 'application/ld+json; charset=utf-8',
10+
Link: '<http://localhost/docs.jsonld>; rel="http://www.w3.org/ns/hydra/core#apiDocumentation"',
11+
};
12+
13+
test.each([
14+
[
15+
'ld+json',
16+
{
17+
'@context': '/contexts/ConstraintViolationList',
18+
'@type': 'ConstraintViolationList',
19+
'hydra:title': 'An error occurred',
20+
'hydra:description':
21+
'plainPassword: Password must be at least 6 characters long.',
22+
violations: [
23+
{
24+
propertyPath: 'plainPassword',
25+
message: 'Password must be at least 6 characters long.',
26+
},
27+
],
28+
},
29+
{ plainPassword: 'Password must be at least 6 characters long.' },
30+
],
31+
[
32+
'problem+json',
33+
{
34+
'@id': '\\/validation_errors\\/6b3befbc-2f01-4ddf-be21-b57898905284',
35+
'@type': 'ConstraintViolationList',
36+
status: 422,
37+
violations: [
38+
{
39+
propertyPath: 'entitlements',
40+
message:
41+
'At least one product must be selected if policy is restricted.',
42+
code: '6b3befbc-2f01-4ddf-be21-b57898905284',
43+
},
44+
],
45+
detail:
46+
'entitlements: At least one product must be selected if policy is restricted.',
47+
'hydra:title': 'An error occurred',
48+
'hydra:description':
49+
'entitlements: At least one product must be selected if policy is restricted.',
50+
type: '\\/validation_errors\\/6b3befbc-2f01-4ddf-be21-b57898905284',
51+
title: 'An error occurred',
52+
},
53+
{
54+
entitlements:
55+
'At least one product must be selected if policy is restricted.',
56+
},
57+
],
58+
])(
59+
'%s violation list expanding',
60+
async (format: string, resBody: object, expected: object) => {
61+
fetchMock.mockResponses(
62+
[
63+
JSON.stringify(resBody),
64+
{
65+
status: 422,
66+
statusText: '422 Unprocessable Content',
67+
headers: {
68+
...headers,
69+
'Content-Type': `application/${format}; charset=utf-8`,
70+
},
71+
},
72+
],
73+
[
74+
JSON.stringify({
75+
'@context': {
76+
'@vocab': 'http://localhost/docs.jsonld#',
77+
hydra: 'http://www.w3.org/ns/hydra/core#',
78+
},
79+
}),
80+
{
81+
status: 200,
82+
statusText: 'OK',
83+
headers,
84+
},
85+
],
86+
);
87+
88+
let violations;
89+
try {
90+
await fetchHydra(new URL('http://localhost/users'));
91+
} catch (error) {
92+
violations = schemaAnalyzer().getSubmissionErrors(error as HttpError);
93+
}
94+
expect(violations).toStrictEqual(expected);
95+
},
96+
);

src/hydra/fetchHydra.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {
44
getDocumentationUrlFromHeaders,
55
} from '@api-platform/api-doc-parser';
66
import jsonld from 'jsonld';
7-
import type { NodeObject } from 'jsonld';
7+
import type { ContextDefinition, NodeObject } from 'jsonld';
88
import type { JsonLdObj } from 'jsonld/jsonld-spec';
99
import type { HttpClientOptions, HydraHttpClientResponse } from '../types.js';
1010

@@ -54,12 +54,20 @@ function fetchHydra(
5454
return response;
5555
});
5656
};
57+
const base = getDocumentationUrlFromHeaders(headers);
5758

58-
return jsonld
59-
.expand(body, {
60-
base: getDocumentationUrlFromHeaders(headers),
61-
documentLoader,
62-
})
59+
return (
60+
'@context' in body
61+
? jsonld.expand(body, {
62+
base,
63+
documentLoader,
64+
})
65+
: documentLoader(base).then((response) =>
66+
jsonld.expand(body, {
67+
expandContext: response.document as ContextDefinition,
68+
}),
69+
)
70+
)
6371
.then((json) =>
6472
Promise.reject(
6573
new HttpError(

0 commit comments

Comments
 (0)