typedrest 0.5.0 → 0.6.0
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/README.md +41 -5
- package/endpoints/{CachingEndpoint.ts → CachingEndpoint.d.ts} +0 -1
- package/endpoints/Endpoint.d.ts +121 -0
- package/endpoints/Endpoint.js +1 -1
- package/endpoints/{EntryEndpoint.ts → EntryEndpoint.d.ts} +7 -27
- package/endpoints/generic/{CollectionEndpoint.ts → CollectionEndpoint.d.ts} +2 -5
- package/endpoints/generic/{ETagEndpointBase.ts → ETagEndpointBase.d.ts} +7 -38
- package/endpoints/generic/{ElementEndpoint.ts → ElementEndpoint.d.ts} +12 -70
- package/endpoints/generic/{GenericCollectionEndpoint.ts → GenericCollectionEndpoint.d.ts} +21 -106
- package/endpoints/generic/{IndexerEndpoint.ts → IndexerEndpoint.d.ts} +4 -11
- package/endpoints/generic/PartialResponse.d.ts +19 -0
- package/endpoints/{index.ts → index.d.ts} +1 -2
- package/endpoints/raw/{BlobEndpoint.ts → BlobEndpoint.d.ts} +9 -29
- package/endpoints/raw/{UploadEndpoint.ts → UploadEndpoint.d.ts} +4 -18
- package/endpoints/reactive/Delay.d.ts +7 -0
- package/endpoints/reactive/GenericStreamingCollectionEndpoint.d.ts +32 -0
- package/endpoints/reactive/{PollingEndpoint.ts → PollingEndpoint.d.ts} +7 -34
- package/endpoints/reactive/SseStreamingEndpoint.d.ts +50 -0
- package/endpoints/reactive/{StreamingCollectionEndpoint.ts → StreamingCollectionEndpoint.d.ts} +2 -5
- package/endpoints/reactive/{StreamingEndpoint.ts → StreamingEndpoint.d.ts} +5 -27
- package/endpoints/rpc/{ActionEndpoint.ts → ActionEndpoint.d.ts} +3 -10
- package/endpoints/rpc/{ConsumerEndpoint.ts → ConsumerEndpoint.d.ts} +3 -12
- package/endpoints/rpc/{FunctionEndpoint.ts → FunctionEndpoint.d.ts} +3 -14
- package/endpoints/rpc/{ProducerEndpoint.ts → ProducerEndpoint.d.ts} +3 -11
- package/endpoints/rpc/{RpcEndpointBase.ts → RpcEndpointBase.d.ts} +4 -12
- package/errors/DefaultErrorHandler.d.ts +21 -0
- package/errors/{Errors.ts → Errors.d.ts} +20 -21
- package/http/EntityStream.d.ts +10 -0
- package/http/FetchHttpClient.d.ts +15 -0
- package/http/FetchHttpClient.js +1 -1
- package/http/{HttpClient.ts → HttpClient.d.ts} +1 -3
- package/http/HttpContentRange.d.ts +23 -0
- package/http/{HttpHeader.ts → HttpHeader.d.ts} +1 -1
- package/http/{HttpMethod.ts → HttpMethod.d.ts} +1 -1
- package/http/{HttpStatusCode.ts → HttpStatusCode.d.ts} +1 -1
- package/http/ResponseCache.d.ts +19 -0
- package/http/RetryAfter.d.ts +6 -0
- package/http/ServerSentEvents.d.ts +50 -0
- package/links/AggregateLinkExtractor.d.ts +17 -0
- package/links/HalLinkExtractor.d.ts +13 -0
- package/links/HeaderLinkExtractor.d.ts +13 -0
- package/links/{Link.ts → Link.d.ts} +6 -2
- package/links/{LinkExtractor.ts → LinkExtractor.d.ts} +0 -1
- package/package.json +64 -14
- package/serializers/JsonSerializer.d.ts +18 -0
- package/serializers/{Serializer.ts → Serializer.d.ts} +0 -2
- package/endpoints/Endpoint.test.ts +0 -300
- package/endpoints/Endpoint.ts +0 -247
- package/endpoints/generic/CollectionEndpoint.test.ts +0 -215
- package/endpoints/generic/ElementEndpoint.test.ts +0 -262
- package/endpoints/generic/GenericCollectionEndpoint.test.ts +0 -123
- package/endpoints/generic/IndexerEndpoint.test.ts +0 -12
- package/endpoints/generic/PartialResponse.ts +0 -28
- package/endpoints/raw/BlobEndpoint.test.ts +0 -52
- package/endpoints/raw/UploadEndpoint.test.ts +0 -47
- package/endpoints/reactive/Delay.ts +0 -26
- package/endpoints/reactive/GenericStreamingCollectionEndpoint.ts +0 -73
- package/endpoints/reactive/PollingEndpoint.test.ts +0 -84
- package/endpoints/reactive/SseStreamingEndpoint.test.ts +0 -169
- package/endpoints/reactive/SseStreamingEndpoint.ts +0 -115
- package/endpoints/reactive/StreamingCollectionEndpoint.test.ts +0 -110
- package/endpoints/reactive/StreamingEndpoint.test.ts +0 -130
- package/endpoints/rpc/ActionEndpoint.test.ts +0 -36
- package/endpoints/rpc/ConsumerEndpoint.test.ts +0 -29
- package/endpoints/rpc/FunctionEndpoint.test.ts +0 -29
- package/endpoints/rpc/ProducerEndpoint.test.ts +0 -32
- package/errors/DefaultErrorHandler.ts +0 -65
- package/http/EntityStream.ts +0 -40
- package/http/FetchHttpClient.ts +0 -26
- package/http/HttpContentRange.ts +0 -41
- package/http/ResponseCache.ts +0 -25
- package/http/RetryAfter.ts +0 -19
- package/http/ServerSentEvents.ts +0 -145
- package/jest.config.js +0 -12
- package/links/AggregateLinkExtractor.ts +0 -28
- package/links/HalLinkExtractor.ts +0 -45
- package/links/HeaderLinkExtractor.ts +0 -56
- package/serializers/JsonSerializer.ts +0 -25
- /package/endpoints/generic/{index.ts → index.d.ts} +0 -0
- /package/endpoints/raw/{index.ts → index.d.ts} +0 -0
- /package/endpoints/reactive/{index.ts → index.d.ts} +0 -0
- /package/endpoints/rpc/{index.ts → index.d.ts} +0 -0
- /package/errors/{ErrorHandler.ts → ErrorHandler.d.ts} +0 -0
- /package/errors/{index.ts → index.d.ts} +0 -0
- /package/http/{index.ts → index.d.ts} +0 -0
- /package/{index.ts → index.d.ts} +0 -0
- /package/links/{index.ts → index.d.ts} +0 -0
- /package/serializers/{index.ts → index.d.ts} +0 -0
|
@@ -1,215 +0,0 @@
|
|
|
1
|
-
import fetchMock from 'jest-fetch-mock';
|
|
2
|
-
import { CollectionEndpoint } from '.';
|
|
3
|
-
import { EntryEndpoint } from '..';
|
|
4
|
-
import { HttpHeader, HttpStatusCode, HttpMethod } from '../../http';
|
|
5
|
-
|
|
6
|
-
class MockEntity {
|
|
7
|
-
constructor(public id: number, public name: string) { }
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
fetchMock.enableMocks();
|
|
11
|
-
let endpoint: CollectionEndpoint<MockEntity>;
|
|
12
|
-
|
|
13
|
-
beforeEach(() => {
|
|
14
|
-
fetchMock.resetMocks();
|
|
15
|
-
endpoint = new CollectionEndpoint(new EntryEndpoint('http://localhost/'), 'endpoint');
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
test('getById', () => {
|
|
19
|
-
expect(endpoint.get('x/y').uri).toEqual(new URL('http://localhost/endpoint/x%2Fy'));
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
test('getByIdWithLinkHeaderRelative', async () => {
|
|
23
|
-
fetchMock.mockOnceIf(
|
|
24
|
-
'http://localhost/endpoint',
|
|
25
|
-
'[]',
|
|
26
|
-
{
|
|
27
|
-
headers: {
|
|
28
|
-
[HttpHeader.Link]: '<children{?id}>; rel=child; templated=true'
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
);
|
|
32
|
-
await endpoint.readAll();
|
|
33
|
-
|
|
34
|
-
expect(endpoint.get('1').uri).toEqual(new URL('http://localhost/children?id=1'));
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
test('getByIdWithLinkHeaderAbsolute', async () => {
|
|
38
|
-
fetchMock.mockOnceIf(
|
|
39
|
-
'http://localhost/endpoint',
|
|
40
|
-
'[]',
|
|
41
|
-
{
|
|
42
|
-
headers: {
|
|
43
|
-
[HttpHeader.Link]: '<http://localhost/children{?id}>; rel=child; templated=true'
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
);
|
|
47
|
-
await endpoint.readAll();
|
|
48
|
-
|
|
49
|
-
expect(endpoint.get('1').uri).toEqual(new URL('http://localhost/children?id=1'));
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
test('getByEntity', () => {
|
|
53
|
-
expect(endpoint.get(new MockEntity(1, 'test')).uri).toEqual(new URL('http://localhost/endpoint/1'));
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
test('getByEntityWithLinkHeaderRelative', async () => {
|
|
57
|
-
fetchMock.mockOnceIf(
|
|
58
|
-
'http://localhost/endpoint',
|
|
59
|
-
'[]',
|
|
60
|
-
{
|
|
61
|
-
headers: {
|
|
62
|
-
[HttpHeader.Link]: '<children/{id}>; rel=child; templated=true'
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
);
|
|
66
|
-
await endpoint.readAll();
|
|
67
|
-
|
|
68
|
-
expect(endpoint.get('1').uri).toEqual(new URL('http://localhost/children/1'));
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
test('getByEntityWithLinkHeaderAbsolute', async () => {
|
|
72
|
-
fetchMock.mockOnceIf(
|
|
73
|
-
'http://localhost/endpoint',
|
|
74
|
-
'[]',
|
|
75
|
-
{
|
|
76
|
-
headers: {
|
|
77
|
-
[HttpHeader.Link]: '<http://localhost/children/{id}>; rel=child; templated=true'
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
);
|
|
81
|
-
await endpoint.readAll();
|
|
82
|
-
|
|
83
|
-
expect(endpoint.get('1').uri).toEqual(new URL('http://localhost/children/1'));
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
test('readAll', async () => {
|
|
87
|
-
fetchMock.mockOnceIf(
|
|
88
|
-
'http://localhost/endpoint',
|
|
89
|
-
'[{"id":5,"name":"test1"}, {"id":6,"name":"test2"}]'
|
|
90
|
-
);
|
|
91
|
-
|
|
92
|
-
const result = await endpoint.readAll();
|
|
93
|
-
expect(result).toEqual([new MockEntity(5, 'test1'), new MockEntity(6, 'test2')]);
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
test('readAllCache', async () => {
|
|
97
|
-
fetchMock.mockOnceIf(
|
|
98
|
-
'http://localhost/endpoint',
|
|
99
|
-
'[{"id":5,"name":"test1"}, {"id":6,"name":"test2"}]',
|
|
100
|
-
{
|
|
101
|
-
headers: {
|
|
102
|
-
[HttpHeader.ETag]: '"123abc"'
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
);
|
|
106
|
-
const result1 = await endpoint.readAll();
|
|
107
|
-
expect(result1).toEqual([new MockEntity(5, 'test1'), new MockEntity(6, 'test2')]);
|
|
108
|
-
|
|
109
|
-
fetchMock.mockOnceIf(
|
|
110
|
-
'http://localhost/endpoint',
|
|
111
|
-
async req => {
|
|
112
|
-
expect(req.headers.get(HttpHeader.IfNoneMatch)).toBe('"123abc"');
|
|
113
|
-
return { status: HttpStatusCode.NotModified };
|
|
114
|
-
}
|
|
115
|
-
);
|
|
116
|
-
const result2 = await endpoint.readAll();
|
|
117
|
-
expect(result2).toEqual([new MockEntity(5, 'test1'), new MockEntity(6, 'test2')]);
|
|
118
|
-
|
|
119
|
-
expect(result2).not.toBe(result1); // Should cache response, not deserialized object
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
test('create', async () => {
|
|
123
|
-
fetchMock.mockOnceIf(
|
|
124
|
-
req => req.method === HttpMethod.Post && req.url === 'http://localhost/endpoint',
|
|
125
|
-
async req => {
|
|
126
|
-
expect(req.headers.get(HttpHeader.ContentType)).toBe('application/json');
|
|
127
|
-
expect(await req.text()).toBe('{"id":0,"name":"test"}');
|
|
128
|
-
return { body: '{"id":5,"name":"test"}' };
|
|
129
|
-
}
|
|
130
|
-
);
|
|
131
|
-
|
|
132
|
-
const element = (await endpoint.create(new MockEntity(0, 'test')))!;
|
|
133
|
-
expect(element!.response).toEqual(new MockEntity(5, 'test'));
|
|
134
|
-
expect(element.uri).toEqual(new URL('http://localhost/endpoint/5'));
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
test('createLocation', async () => {
|
|
138
|
-
fetchMock.mockOnceIf(
|
|
139
|
-
req => req.method === HttpMethod.Post && req.url === 'http://localhost/endpoint',
|
|
140
|
-
async req => {
|
|
141
|
-
expect(req.headers.get(HttpHeader.ContentType)).toBe('application/json');
|
|
142
|
-
expect(await req.text()).toBe('{"id":0,"name":"test"}');
|
|
143
|
-
return {
|
|
144
|
-
body: '{"id":5,"name":"test"}',
|
|
145
|
-
headers: {
|
|
146
|
-
[HttpHeader.Location]: '/endpoint/new'
|
|
147
|
-
}
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
);
|
|
151
|
-
|
|
152
|
-
const element = (await endpoint.create(new MockEntity(0, 'test')))!;
|
|
153
|
-
expect(element.response).toEqual(new MockEntity(5, 'test'));
|
|
154
|
-
expect(element.uri).toEqual(new URL('http://localhost/endpoint/new'));
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
test('createUndefined', async () => {
|
|
158
|
-
fetchMock.mockOnceIf(
|
|
159
|
-
req => req.method === HttpMethod.Post && req.url === 'http://localhost/endpoint',
|
|
160
|
-
async req => {
|
|
161
|
-
expect(req.headers.get(HttpHeader.ContentType)).toBe('application/json');
|
|
162
|
-
expect(await req.text()).toBe('{"id":0,"name":"test"}');
|
|
163
|
-
return { status: HttpStatusCode.Accepted };
|
|
164
|
-
}
|
|
165
|
-
);
|
|
166
|
-
|
|
167
|
-
const element = (await endpoint.create(new MockEntity(0, 'test')));
|
|
168
|
-
expect(element).toBeUndefined();
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
test('createAll', async () => {
|
|
172
|
-
fetchMock.mockOnceIf(
|
|
173
|
-
req => req.method === HttpMethod.Patch && req.url === 'http://localhost/endpoint',
|
|
174
|
-
async req => {
|
|
175
|
-
expect(req.headers.get(HttpHeader.ContentType)).toBe('application/json');
|
|
176
|
-
expect(await req.text()).toBe('[{"id":5,"name":"test1"},{"id":6,"name":"test2"}]');
|
|
177
|
-
return {};
|
|
178
|
-
}
|
|
179
|
-
);
|
|
180
|
-
|
|
181
|
-
await endpoint.createAll([new MockEntity(5, 'test1'), new MockEntity(6, 'test2')]);
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
test('setAll', async () => {
|
|
185
|
-
fetchMock.mockOnceIf(
|
|
186
|
-
req => req.method === HttpMethod.Put && req.url === 'http://localhost/endpoint',
|
|
187
|
-
async req => {
|
|
188
|
-
expect(req.headers.get(HttpHeader.ContentType)).toBe('application/json');
|
|
189
|
-
expect(await req.text()).toBe('[{"id":5,"name":"test1"},{"id":6,"name":"test2"}]');
|
|
190
|
-
return {};
|
|
191
|
-
}
|
|
192
|
-
);
|
|
193
|
-
|
|
194
|
-
await endpoint.setAll([new MockEntity(5, 'test1'), new MockEntity(6, 'test2')]);
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
test('setAllETag', async () => {
|
|
198
|
-
fetchMock.mockOnceIf(
|
|
199
|
-
'http://localhost/endpoint',
|
|
200
|
-
'[{"id":5,"name":"test1"}, {"id":6,"name":"test2"}]',
|
|
201
|
-
{
|
|
202
|
-
headers: { [HttpHeader.ETag]: '"123abc"' }
|
|
203
|
-
});
|
|
204
|
-
const result = await endpoint.readAll();
|
|
205
|
-
|
|
206
|
-
fetchMock.mockOnceIf(
|
|
207
|
-
req => req.method === HttpMethod.Put && req.url === 'http://localhost/endpoint',
|
|
208
|
-
async req => {
|
|
209
|
-
expect(req.headers.get(HttpHeader.IfMatch)).toBe('"123abc"');
|
|
210
|
-
expect(await req.text()).toBe('[{"id":5,"name":"test1"},{"id":6,"name":"test2"}]');
|
|
211
|
-
return {};
|
|
212
|
-
}
|
|
213
|
-
);
|
|
214
|
-
await endpoint.setAll(result);
|
|
215
|
-
});
|
|
@@ -1,262 +0,0 @@
|
|
|
1
|
-
import fetchMock from 'jest-fetch-mock';
|
|
2
|
-
import { ElementEndpoint } from '.';
|
|
3
|
-
import { EntryEndpoint } from '..';
|
|
4
|
-
import { HttpStatusCode, HttpMethod, HttpHeader } from '../../http';
|
|
5
|
-
import { ConcurrencyError } from '../../errors';
|
|
6
|
-
|
|
7
|
-
class MockEntity {
|
|
8
|
-
constructor(public id: number, public name: string) { }
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
fetchMock.enableMocks();
|
|
12
|
-
let endpoint: ElementEndpoint<MockEntity>;
|
|
13
|
-
|
|
14
|
-
beforeEach(() => {
|
|
15
|
-
fetchMock.resetMocks();
|
|
16
|
-
endpoint = new ElementEndpoint(new EntryEndpoint('http://localhost/'), 'endpoint');
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
test('read', async () => {
|
|
20
|
-
fetchMock.mockOnceIf(
|
|
21
|
-
'http://localhost/endpoint',
|
|
22
|
-
'{"id":5,"name":"test"}',
|
|
23
|
-
{
|
|
24
|
-
headers: { [HttpHeader.ContentType]: 'application/json' }
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
const result = await endpoint.read();
|
|
28
|
-
expect(result).toEqual(new MockEntity(5, 'test'));
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
test('readCache', async () => {
|
|
32
|
-
fetchMock.mockOnceIf(
|
|
33
|
-
'http://localhost/endpoint',
|
|
34
|
-
'{"id":5,"name":"test"}',
|
|
35
|
-
{
|
|
36
|
-
headers: {
|
|
37
|
-
[HttpHeader.ContentType]: 'application/json',
|
|
38
|
-
[HttpHeader.ETag]: '"123abc"'
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
);
|
|
42
|
-
const result1 = await endpoint.read();
|
|
43
|
-
expect(result1).toEqual(new MockEntity(5, 'test'));
|
|
44
|
-
|
|
45
|
-
fetchMock.mockOnceIf(
|
|
46
|
-
'http://localhost/endpoint',
|
|
47
|
-
async req => {
|
|
48
|
-
expect(req.headers.get('If-None-Match')).toBe('"123abc"');
|
|
49
|
-
return { status: HttpStatusCode.NotModified };
|
|
50
|
-
}
|
|
51
|
-
);
|
|
52
|
-
const result2 = await endpoint.read();
|
|
53
|
-
expect(result2).toEqual(new MockEntity(5, 'test'));
|
|
54
|
-
|
|
55
|
-
expect(result2).not.toBe(result1); // Should cache response, not deserialized object
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
test('existsTrue', async () => {
|
|
59
|
-
fetchMock.mockOnceIf(req => req.method === HttpMethod.Head && req.url === 'http://localhost/endpoint');
|
|
60
|
-
|
|
61
|
-
const result = await endpoint.exists();
|
|
62
|
-
expect(result).toBe(true);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
test('existsFalse', async () => {
|
|
66
|
-
fetchMock.mockOnceIf(
|
|
67
|
-
req => req.method === HttpMethod.Head && req.url === 'http://localhost/endpoint',
|
|
68
|
-
async () => {
|
|
69
|
-
return { status: HttpStatusCode.NotFound };
|
|
70
|
-
}
|
|
71
|
-
);
|
|
72
|
-
|
|
73
|
-
const result = await endpoint.exists();
|
|
74
|
-
expect(result).toBe(false);
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
test('setResult', async () => {
|
|
78
|
-
fetchMock.mockOnceIf(
|
|
79
|
-
req => req.method === HttpMethod.Put && req.url === 'http://localhost/endpoint',
|
|
80
|
-
async req => {
|
|
81
|
-
expect(req.headers.get(HttpHeader.ContentType)).toBe('application/json');
|
|
82
|
-
expect(await req.text()).toBe('{"id":5,"name":"test"}');
|
|
83
|
-
return {
|
|
84
|
-
headers: { [HttpHeader.ContentType]: 'application/json' },
|
|
85
|
-
body: '{"id":5,"name":"testXXX"}'
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
);
|
|
89
|
-
|
|
90
|
-
const result = await endpoint.set(new MockEntity(5, 'test'));
|
|
91
|
-
expect(result).toEqual(new MockEntity(5, 'testXXX'));
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
test('setNoResult', async () => {
|
|
95
|
-
fetchMock.mockOnceIf(
|
|
96
|
-
req => req.method === HttpMethod.Put && req.url === 'http://localhost/endpoint',
|
|
97
|
-
async req => {
|
|
98
|
-
expect(req.headers.get(HttpHeader.ContentType)).toBe('application/json');
|
|
99
|
-
expect(await req.text()).toBe('{"id":5,"name":"test"}');
|
|
100
|
-
return {};
|
|
101
|
-
}
|
|
102
|
-
);
|
|
103
|
-
|
|
104
|
-
const result = await endpoint.set(new MockEntity(5, 'test'));
|
|
105
|
-
expect(result).toBeUndefined();
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
test('setETag', async () => {
|
|
109
|
-
fetchMock.mockOnceIf(
|
|
110
|
-
'http://localhost/endpoint',
|
|
111
|
-
'{"id":5,"name":"test"}',
|
|
112
|
-
{
|
|
113
|
-
headers: {
|
|
114
|
-
[HttpHeader.ContentType]: 'application/json',
|
|
115
|
-
[HttpHeader.ETag]: '"123abc"'
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
);
|
|
119
|
-
const result = await endpoint.read();
|
|
120
|
-
|
|
121
|
-
fetchMock.mockOnceIf(
|
|
122
|
-
req => req.method === HttpMethod.Put && req.url === 'http://localhost/endpoint',
|
|
123
|
-
async req => {
|
|
124
|
-
expect(req.headers.get(HttpHeader.IfMatch)).toBe('"123abc"');
|
|
125
|
-
expect(await req.text()).toBe('{"id":5,"name":"test"}');
|
|
126
|
-
return {};
|
|
127
|
-
|
|
128
|
-
}
|
|
129
|
-
);
|
|
130
|
-
await endpoint.set(result);
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
test('updateRetry', async () => {
|
|
134
|
-
fetchMock.mockOnceIf(
|
|
135
|
-
req => req.method === HttpMethod.Get && req.url === 'http://localhost/endpoint',
|
|
136
|
-
async req => {
|
|
137
|
-
return {
|
|
138
|
-
headers: {
|
|
139
|
-
[HttpHeader.ContentType]: 'application/json',
|
|
140
|
-
[HttpHeader.ETag]: '"1"'
|
|
141
|
-
},
|
|
142
|
-
body: '{"id":5,"name":"test1"}'
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
).mockOnceIf(
|
|
146
|
-
req => req.method === HttpMethod.Put && req.url === 'http://localhost/endpoint',
|
|
147
|
-
async req => {
|
|
148
|
-
expect(req.headers.get(HttpHeader.IfMatch)).toBe('"1"');
|
|
149
|
-
expect(await req.text()).toBe('{"id":5,"name":"testX"}');
|
|
150
|
-
return { status: HttpStatusCode.PreconditionFailed };
|
|
151
|
-
}
|
|
152
|
-
).mockOnceIf(
|
|
153
|
-
req => req.method === HttpMethod.Get && req.url === 'http://localhost/endpoint',
|
|
154
|
-
async req => {
|
|
155
|
-
return {
|
|
156
|
-
headers: {
|
|
157
|
-
[HttpHeader.ContentType]: 'application/json',
|
|
158
|
-
[HttpHeader.ETag]: '"2"'
|
|
159
|
-
},
|
|
160
|
-
body: '{"id":5,"name":"test2"}'
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
).mockOnceIf(
|
|
164
|
-
req => req.method === HttpMethod.Put && req.url === 'http://localhost/endpoint',
|
|
165
|
-
async req => {
|
|
166
|
-
expect(req.headers.get(HttpHeader.IfMatch)).toBe('"2"');
|
|
167
|
-
expect(await req.text()).toBe('{"id":5,"name":"testX"}');
|
|
168
|
-
return {
|
|
169
|
-
headers: { [HttpHeader.ContentType]: 'application/json' },
|
|
170
|
-
body: '{"id":5,"name":"testX"}'
|
|
171
|
-
};
|
|
172
|
-
}
|
|
173
|
-
);
|
|
174
|
-
|
|
175
|
-
await endpoint.update(x => x.name = 'testX');
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
test('updateFail', async () => {
|
|
179
|
-
fetchMock.mockOnceIf(
|
|
180
|
-
req => req.method === HttpMethod.Get && req.url === 'http://localhost/endpoint',
|
|
181
|
-
'{"id":5,"name":"test1"}',
|
|
182
|
-
{
|
|
183
|
-
headers: {
|
|
184
|
-
[HttpHeader.ContentType]: 'application/json',
|
|
185
|
-
[HttpHeader.ETag]: '"1"'
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
);
|
|
189
|
-
fetchMock.mockOnceIf(
|
|
190
|
-
req => req.method === HttpMethod.Put && req.url === 'http://localhost/endpoint',
|
|
191
|
-
async req => {
|
|
192
|
-
expect(req.headers.get(HttpHeader.IfMatch)).toBe('"1"');
|
|
193
|
-
expect(await req.text()).toBe('{"id":5,"name":"testX"}');
|
|
194
|
-
return { status: HttpStatusCode.PreconditionFailed };
|
|
195
|
-
}
|
|
196
|
-
);
|
|
197
|
-
|
|
198
|
-
let errorThrown = false;
|
|
199
|
-
try {
|
|
200
|
-
await endpoint.update(x => x.name = 'testX', 0);
|
|
201
|
-
} catch (err) {
|
|
202
|
-
errorThrown = err instanceof ConcurrencyError;
|
|
203
|
-
}
|
|
204
|
-
expect(errorThrown).toBe(true);
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
test('mergeResult', async () => {
|
|
208
|
-
fetchMock.mockOnceIf(
|
|
209
|
-
req => req.method === HttpMethod.Patch && req.url === 'http://localhost/endpoint',
|
|
210
|
-
async req => {
|
|
211
|
-
expect(await req.text()).toBe('{"id":5,"name":"test"}');
|
|
212
|
-
return {
|
|
213
|
-
headers: { [HttpHeader.ContentType]: 'application/json' },
|
|
214
|
-
body: '{"id":5,"name":"testXXX"}'
|
|
215
|
-
};
|
|
216
|
-
}
|
|
217
|
-
);
|
|
218
|
-
|
|
219
|
-
const result = await endpoint.merge(new MockEntity(5, 'test'));
|
|
220
|
-
expect(result).toEqual(new MockEntity(5, 'testXXX'));
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
test('mergeNoResult', async () => {
|
|
224
|
-
fetchMock.mockOnceIf(
|
|
225
|
-
req => req.method === HttpMethod.Patch && req.url === 'http://localhost/endpoint',
|
|
226
|
-
async req => {
|
|
227
|
-
expect(await req.text()).toBe('{"id":5,"name":"test"}');
|
|
228
|
-
return {};
|
|
229
|
-
}
|
|
230
|
-
);
|
|
231
|
-
|
|
232
|
-
const result = await endpoint.merge(new MockEntity(5, 'test'));
|
|
233
|
-
expect(result).toBeUndefined();
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
test('delete', async () => {
|
|
237
|
-
fetchMock.mockOnceIf(req => req.method === HttpMethod.Delete && req.url === 'http://localhost/endpoint');
|
|
238
|
-
await endpoint.delete();
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
test('deleteETag', async () => {
|
|
242
|
-
fetchMock.mockOnceIf(
|
|
243
|
-
'http://localhost/endpoint',
|
|
244
|
-
'{"id":5,"name":"test"}',
|
|
245
|
-
{
|
|
246
|
-
headers: {
|
|
247
|
-
[HttpHeader.ContentType]: 'application/json',
|
|
248
|
-
[HttpHeader.ETag]: '"123abc"'
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
);
|
|
252
|
-
await endpoint.read();
|
|
253
|
-
|
|
254
|
-
fetchMock.mockOnceIf(
|
|
255
|
-
req => req.method === HttpMethod.Delete && req.url === 'http://localhost/endpoint',
|
|
256
|
-
async req => {
|
|
257
|
-
expect(req.headers.get(HttpHeader.IfMatch)).toBe('"123abc"');
|
|
258
|
-
return {};
|
|
259
|
-
}
|
|
260
|
-
);
|
|
261
|
-
await endpoint.delete();
|
|
262
|
-
});
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* NOTE: The jsdom environment strips the "Range" request header, so these tests need the node environment.
|
|
3
|
-
* @jest-environment node
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import fetchMock from 'jest-fetch-mock';
|
|
7
|
-
import { CollectionEndpoint } from '.';
|
|
8
|
-
import { EntryEndpoint } from '..';
|
|
9
|
-
import { HttpHeader, HttpStatusCode, HttpContentRange } from '../../http';
|
|
10
|
-
import { RangeNotSatisfiableError } from '../../errors';
|
|
11
|
-
|
|
12
|
-
class MockEntity {
|
|
13
|
-
constructor(public id: number, public name: string) { }
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
fetchMock.enableMocks();
|
|
17
|
-
let endpoint: CollectionEndpoint<MockEntity>;
|
|
18
|
-
|
|
19
|
-
beforeEach(() => {
|
|
20
|
-
fetchMock.resetMocks();
|
|
21
|
-
endpoint = new CollectionEndpoint(new EntryEndpoint('http://localhost/'), 'endpoint');
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
test('readRange', async () => {
|
|
25
|
-
fetchMock.mockOnceIf(
|
|
26
|
-
'http://localhost/endpoint',
|
|
27
|
-
async req => {
|
|
28
|
-
expect(req.headers.get(HttpHeader.Range)).toBe('elements=1-2');
|
|
29
|
-
return {
|
|
30
|
-
body: '[{"id":6,"name":"test2"}, {"id":7,"name":"test3"}]',
|
|
31
|
-
status: HttpStatusCode.PartialContent,
|
|
32
|
-
headers: {
|
|
33
|
-
[HttpHeader.ContentRange]: 'elements 1-2/3'
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
const result = await endpoint.readRange(1, 2);
|
|
40
|
-
expect(result.elements).toEqual([new MockEntity(6, 'test2'), new MockEntity(7, 'test3')]);
|
|
41
|
-
expect(result.range).toEqual(new HttpContentRange('elements', 1, 2, 3));
|
|
42
|
-
expect(result.endReached).toBe(true);
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
test('readRangeOffset', async () => {
|
|
46
|
-
fetchMock.mockOnceIf(
|
|
47
|
-
'http://localhost/endpoint',
|
|
48
|
-
async req => {
|
|
49
|
-
expect(req.headers.get(HttpHeader.Range)).toBe('elements=1-');
|
|
50
|
-
return {
|
|
51
|
-
body: '[{"id":6,"name":"test2"}]',
|
|
52
|
-
status: HttpStatusCode.PartialContent,
|
|
53
|
-
headers: {
|
|
54
|
-
[HttpHeader.ContentRange]: 'elements 1-1/*'
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
);
|
|
59
|
-
|
|
60
|
-
const result = await endpoint.readRange(1);
|
|
61
|
-
expect(result.elements).toEqual([new MockEntity(6, 'test2')]);
|
|
62
|
-
expect(result.range).toEqual(new HttpContentRange('elements', 1, 1, undefined));
|
|
63
|
-
expect(result.endReached).toBe(false);
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
test('readRangeTail', async () => {
|
|
67
|
-
fetchMock.mockOnceIf(
|
|
68
|
-
'http://localhost/endpoint',
|
|
69
|
-
async req => {
|
|
70
|
-
expect(req.headers.get(HttpHeader.Range)).toBe('elements=-1');
|
|
71
|
-
return {
|
|
72
|
-
body: '[{"id":6,"name":"test2"}]',
|
|
73
|
-
status: HttpStatusCode.PartialContent
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
);
|
|
77
|
-
|
|
78
|
-
const result = await endpoint.readRange(undefined, 1);
|
|
79
|
-
expect(result.elements).toEqual([new MockEntity(6, 'test2')]);
|
|
80
|
-
expect(result.range).toBeUndefined();
|
|
81
|
-
expect(result.endReached).toBe(true);
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
test('readRangeNotSatisfiable', async () => {
|
|
85
|
-
fetchMock.mockOnceIf(
|
|
86
|
-
'http://localhost/endpoint',
|
|
87
|
-
async () => ({ status: HttpStatusCode.RangeNotSatisfiable })
|
|
88
|
-
);
|
|
89
|
-
|
|
90
|
-
await expect(endpoint.readRange(1)).rejects.toThrow(RangeNotSatisfiableError);
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
test('readRangeAllowed', async () => {
|
|
94
|
-
expect(endpoint.readRangeAllowed).toBeUndefined();
|
|
95
|
-
|
|
96
|
-
fetchMock.mockOnceIf(
|
|
97
|
-
'http://localhost/endpoint',
|
|
98
|
-
'[]',
|
|
99
|
-
{
|
|
100
|
-
headers: {
|
|
101
|
-
[HttpHeader.AcceptRanges]: 'elements'
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
);
|
|
105
|
-
await endpoint.readAll();
|
|
106
|
-
|
|
107
|
-
expect(endpoint.readRangeAllowed).toBe(true);
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
test('readRangeNotAllowed', async () => {
|
|
111
|
-
fetchMock.mockOnceIf(
|
|
112
|
-
'http://localhost/endpoint',
|
|
113
|
-
'[]',
|
|
114
|
-
{
|
|
115
|
-
headers: {
|
|
116
|
-
[HttpHeader.AcceptRanges]: 'none'
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
);
|
|
120
|
-
await endpoint.readAll();
|
|
121
|
-
|
|
122
|
-
expect(endpoint.readRangeAllowed).toBe(false);
|
|
123
|
-
});
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { IndexerEndpoint, ElementEndpoint } from '.';
|
|
2
|
-
import { EntryEndpoint } from '..';
|
|
3
|
-
|
|
4
|
-
let endpoint: IndexerEndpoint<ElementEndpoint<{}>>;
|
|
5
|
-
|
|
6
|
-
beforeEach(() => {
|
|
7
|
-
endpoint = new IndexerEndpoint<ElementEndpoint<{}>>(new EntryEndpoint('http://localhost/'), 'endpoint', ElementEndpoint);
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
test('getById', () => {
|
|
11
|
-
expect(endpoint.get('x/y').uri).toEqual(new URL('http://localhost/endpoint/x%2Fy'));
|
|
12
|
-
});
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { HttpContentRange } from "../../http";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Represents a subset of a set of elements.
|
|
5
|
-
* @typeParam TEntity The type of element the response contains.
|
|
6
|
-
*/
|
|
7
|
-
export class PartialResponse<TEntity> {
|
|
8
|
-
/**
|
|
9
|
-
* Creates a new partial response.
|
|
10
|
-
* @param elements The returned elements.
|
|
11
|
-
* @param range The range the `elements` come from.
|
|
12
|
-
*/
|
|
13
|
-
constructor(public readonly elements: TEntity[], public readonly range?: HttpContentRange) {
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Indicates whether the response reaches the end of the elements available on the server.
|
|
18
|
-
*/
|
|
19
|
-
get endReached(): boolean {
|
|
20
|
-
// No range specified, must be complete response
|
|
21
|
-
if (this.range?.to === undefined) return true;
|
|
22
|
-
|
|
23
|
-
// No length specified, can't be the end
|
|
24
|
-
if (this.range.length === undefined) return false;
|
|
25
|
-
|
|
26
|
-
return this.range.to === this.range.length - 1;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import fetchMock from 'jest-fetch-mock';
|
|
2
|
-
import { BlobEndpoint } from '.';
|
|
3
|
-
import { EntryEndpoint } from '..';
|
|
4
|
-
import { HttpMethod, HttpHeader } from '../../http';
|
|
5
|
-
|
|
6
|
-
fetchMock.enableMocks();
|
|
7
|
-
let endpoint: BlobEndpoint;
|
|
8
|
-
|
|
9
|
-
beforeEach(() => {
|
|
10
|
-
fetchMock.resetMocks();
|
|
11
|
-
endpoint = new BlobEndpoint(new EntryEndpoint('http://localhost/'), 'endpoint');
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
test('probe', async () => {
|
|
15
|
-
fetchMock.mockOnceIf(
|
|
16
|
-
req => req.method === HttpMethod.Options && req.url === 'http://localhost/endpoint',
|
|
17
|
-
async () => {
|
|
18
|
-
return {
|
|
19
|
-
headers: {
|
|
20
|
-
[HttpHeader.Allow]: HttpMethod.Put
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
);
|
|
25
|
-
await endpoint.probe();
|
|
26
|
-
|
|
27
|
-
expect(endpoint.downloadAllowed).toBe(false);
|
|
28
|
-
expect(endpoint.uploadAllowed).toBe(true);
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
test('download', async () => {
|
|
32
|
-
fetchMock.mockOnceIf(
|
|
33
|
-
req => req.method === HttpMethod.Get && req.url === 'http://localhost/endpoint',
|
|
34
|
-
'data'
|
|
35
|
-
);
|
|
36
|
-
|
|
37
|
-
await endpoint.download();
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
test('uploadFrom', async () => {
|
|
41
|
-
const data = new Blob([new Uint8Array([1, 2, 3])], { type: 'mock/type' });
|
|
42
|
-
|
|
43
|
-
fetchMock.mockOnceIf(
|
|
44
|
-
req => req.method === HttpMethod.Put && req.url === 'http://localhost/endpoint',
|
|
45
|
-
async req => {
|
|
46
|
-
expect(req.headers.get(HttpHeader.ContentType)).toBe('mock/type');
|
|
47
|
-
return {};
|
|
48
|
-
}
|
|
49
|
-
);
|
|
50
|
-
|
|
51
|
-
await endpoint.uploadFrom(data);
|
|
52
|
-
});
|