arxiv-api-wrapper 2.0.0 → 2.0.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.
package/tests/oai.test.ts CHANGED
@@ -1,248 +1,296 @@
1
- /**
2
- * Unit tests for OAI-PMH URL builder and XML parser (no network).
3
- * Pagination helpers (oaiListRecordsAll, etc.) are covered by integration tests.
4
- */
5
- import { describe, it, expect } from 'vitest';
6
- import { buildOaiUrl, normalizeOaiIdentifier } from '../src/oaiClient.js';
7
- import {
8
- parseIdentify,
9
- parseListMetadataFormats,
10
- parseListSets,
11
- parseGetRecord,
12
- parseListIdentifiers,
13
- parseListRecords,
14
- parseOaiResponse,
15
- } from '../src/oaiParser.js';
16
- import { OaiError } from '../src/oaiTypes.js';
17
-
18
- const OAI_BASE = 'https://oaipmh.arxiv.org/oai';
19
-
20
- describe('buildOaiUrl', () => {
21
- it('includes verb only for Identify', () => {
22
- const url = buildOaiUrl('Identify', {});
23
- expect(url).toBe(`${OAI_BASE}?verb=Identify`);
24
- });
25
-
26
- it('encodes identifier and metadataPrefix for GetRecord', () => {
27
- const url = buildOaiUrl('GetRecord', {
28
- identifier: 'oai:arXiv.org:cs/0112017',
29
- metadataPrefix: 'oai_dc',
30
- });
31
- expect(url).toContain('verb=GetRecord');
32
- expect(url).toContain('identifier=' + encodeURIComponent('oai:arXiv.org:cs/0112017'));
33
- expect(url).toContain('metadataPrefix=oai_dc');
34
- });
35
-
36
- it('includes from, until, set for ListRecords', () => {
37
- const url = buildOaiUrl('ListRecords', {
38
- metadataPrefix: 'oai_dc',
39
- from: '2024-01-01',
40
- until: '2024-01-31',
41
- set: 'cs:cs.AI',
42
- });
43
- expect(url).toContain('verb=ListRecords');
44
- expect(url).toContain('metadataPrefix=oai_dc');
45
- expect(url).toContain('from=2024-01-01');
46
- expect(url).toContain('until=2024-01-31');
47
- expect(url).toContain('set=cs%3Acs.AI');
48
- });
49
-
50
- it('encodes resumptionToken', () => {
51
- const token = 'token/with/slashes?and=chars';
52
- const url = buildOaiUrl('ListIdentifiers', { metadataPrefix: 'oai_dc', resumptionToken: token });
53
- expect(url).toContain('resumptionToken=' + encodeURIComponent(token));
54
- });
55
- });
56
-
57
- describe('normalizeOaiIdentifier', () => {
58
- it('returns full form unchanged', () => {
59
- expect(normalizeOaiIdentifier('oai:arXiv.org:cs/0112017')).toBe('oai:arXiv.org:cs/0112017');
60
- });
61
-
62
- it('prefixes short form', () => {
63
- expect(normalizeOaiIdentifier('cs/0112017')).toBe('oai:arXiv.org:cs/0112017');
64
- expect(normalizeOaiIdentifier('2101.01234')).toBe('oai:arXiv.org:2101.01234');
65
- });
66
- });
67
-
68
- function wrapOaiRoot(inner: string): string {
69
- return `<?xml version="1.0" encoding="UTF-8"?>
70
- <OAI-PMH xmlns="http://www.openarchives.org/OAI/2.0/">
71
- <responseDate>2024-01-15T12:00:00Z</responseDate>
72
- <request verb="Identify">${OAI_BASE}</request>
73
- ${inner}
74
- </OAI-PMH>`;
75
- }
76
-
77
- describe('parseIdentify', () => {
78
- it('parses Identify response', () => {
79
- const xml = wrapOaiRoot(`
80
- <Identify>
81
- <repositoryName>arXiv</repositoryName>
82
- <baseURL>https://oaipmh.arxiv.org/oai</baseURL>
83
- <protocolVersion>2.0</protocolVersion>
84
- <adminEmail>help@arxiv.org</adminEmail>
85
- <earliestDatestamp>2005-09-16</earliestDatestamp>
86
- <deletedRecord>persistent</deletedRecord>
87
- <granularity>YYYY-MM-DD</granularity>
88
- </Identify>`);
89
- const out = parseIdentify(xml);
90
- expect(out.repositoryName).toBe('arXiv');
91
- expect(out.baseURL).toBe('https://oaipmh.arxiv.org/oai');
92
- expect(out.protocolVersion).toBe('2.0');
93
- expect(out.adminEmail).toEqual(['help@arxiv.org']);
94
- expect(out.earliestDatestamp).toBe('2005-09-16');
95
- expect(out.deletedRecord).toBe('persistent');
96
- expect(out.granularity).toBe('YYYY-MM-DD');
97
- });
98
- });
99
-
100
- describe('parseListMetadataFormats', () => {
101
- it('parses ListMetadataFormats response', () => {
102
- const inner = `
103
- <ListMetadataFormats>
104
- <metadataFormat>
105
- <metadataPrefix>oai_dc</metadataPrefix>
106
- <schema>http://www.openarchives.org/OAI/2.0/oai_dc.xsd</schema>
107
- <metadataNamespace>http://www.openarchives.org/OAI/2.0/oai_dc/</metadataNamespace>
108
- </metadataFormat>
109
- <metadataFormat>
110
- <metadataPrefix>arXiv</metadataPrefix>
111
- <schema>https://arxiv.org/schemas/arXiv.xsd</schema>
112
- <metadataNamespace>http://arxiv.org/schemas/arXiv/</metadataNamespace>
113
- </metadataFormat>
114
- </ListMetadataFormats>`;
115
- const xml = wrapOaiRoot(inner).replace('<request verb="Identify">', '<request verb="ListMetadataFormats">');
116
- const out = parseListMetadataFormats(xml);
117
- expect(out).toHaveLength(2);
118
- expect(out[0].metadataPrefix).toBe('oai_dc');
119
- expect(out[1].metadataPrefix).toBe('arXiv');
120
- });
121
- });
122
-
123
- describe('parseListSets', () => {
124
- it('parses sets and resumptionToken', () => {
125
- const inner = `
126
- <ListSets>
127
- <set>
128
- <setSpec>cs</setSpec>
129
- <setName>Computer Science</setName>
130
- </set>
131
- <set>
132
- <setSpec>physics</setSpec>
133
- <setName>Physics</setName>
134
- </set>
135
- <resumptionToken expirationDate="2024-01-16T00:00:00Z" completeListSize="42" cursor="2">next-token</resumptionToken>
136
- </ListSets>`;
137
- const xml = wrapOaiRoot(inner).replace('<request verb="Identify">', '<request verb="ListSets">');
138
- const out = parseListSets(xml);
139
- expect(out.sets).toHaveLength(2);
140
- expect(out.sets[0].setSpec).toBe('cs');
141
- expect(out.sets[0].setName).toBe('Computer Science');
142
- expect(out.resumptionToken?.value).toBe('next-token');
143
- expect(out.resumptionToken?.expirationDate).toBe('2024-01-16T00:00:00Z');
144
- expect(out.resumptionToken?.completeListSize).toBe(42);
145
- expect(out.resumptionToken?.cursor).toBe(2);
146
- });
147
- });
148
-
149
- describe('parseGetRecord', () => {
150
- it('parses GetRecord with header and metadata', () => {
151
- const inner = `
152
- <GetRecord>
153
- <record>
154
- <header>
155
- <identifier>oai:arXiv.org:cs/0112017</identifier>
156
- <datestamp>2001-12-14</datestamp>
157
- <setSpec>cs</setSpec>
158
- <setSpec>math</setSpec>
159
- </header>
160
- <metadata>
161
- <dc xmlns:dc="http://purl.org/dc/elements/1.1/">
162
- <dc:title>Using Structural Metadata to Localize Experience of Digital Content</dc:title>
163
- <dc:creator>Dushay, Naomi</dc:creator>
164
- <dc:date>2001-12-14</dc:date>
165
- </dc>
166
- </metadata>
167
- </record>
168
- </GetRecord>`;
169
- const xml = wrapOaiRoot(inner).replace('<request verb="Identify">', '<request verb="GetRecord" identifier="oai:arXiv.org:cs/0112017" metadataPrefix="oai_dc">');
170
- const out = parseGetRecord(xml);
171
- expect(out.header.identifier).toBe('oai:arXiv.org:cs/0112017');
172
- expect(out.header.datestamp).toBe('2001-12-14');
173
- expect(out.header.setSpec).toEqual(['cs', 'math']);
174
- expect(out.metadata).toBeDefined();
175
- expect(Object.keys(out.metadata!).length).toBeGreaterThan(0);
176
- });
177
- });
178
-
179
- describe('parseListIdentifiers', () => {
180
- it('parses headers', () => {
181
- const inner = `
182
- <ListIdentifiers>
183
- <header>
184
- <identifier>oai:arXiv.org:hep-th/9901001</identifier>
185
- <datestamp>1999-12-25</datestamp>
186
- <setSpec>physics:hep-th</setSpec>
187
- </header>
188
- <header>
189
- <identifier>oai:arXiv.org:hep-th/9901002</identifier>
190
- <datestamp>1999-12-26</datestamp>
191
- </header>
192
- </ListIdentifiers>`;
193
- const xml = wrapOaiRoot(inner).replace('<request verb="Identify">', '<request verb="ListIdentifiers" metadataPrefix="oai_dc">');
194
- const out = parseListIdentifiers(xml);
195
- expect(out.headers).toHaveLength(2);
196
- expect(out.headers[0].identifier).toBe('oai:arXiv.org:hep-th/9901001');
197
- expect(out.headers[0].setSpec).toEqual(['physics:hep-th']);
198
- });
199
- });
200
-
201
- describe('parseListRecords', () => {
202
- it('parses records and resumptionToken', () => {
203
- const inner = `
204
- <ListRecords>
205
- <record>
206
- <header>
207
- <identifier>oai:arXiv.org:cs/0112017</identifier>
208
- <datestamp>2001-12-14</datestamp>
209
- <setSpec>cs</setSpec>
210
- </header>
211
- <metadata>
212
- <dc><dc:title>Test Paper</dc:title></dc>
213
- </metadata>
214
- </record>
215
- <resumptionToken cursor="1">resume-123</resumptionToken>
216
- </ListRecords>`;
217
- const xml = wrapOaiRoot(inner).replace('<request verb="Identify">', '<request verb="ListRecords" metadataPrefix="oai_dc">');
218
- const out = parseListRecords(xml);
219
- expect(out.records).toHaveLength(1);
220
- expect(out.records[0].header.identifier).toBe('oai:arXiv.org:cs/0112017');
221
- expect(out.resumptionToken?.value).toBe('resume-123');
222
- expect(out.resumptionToken?.cursor).toBe(1);
223
- });
224
- });
225
-
226
- describe('OAI error handling', () => {
227
- it('throws OaiError with code and message on error element', () => {
228
- const xml = wrapOaiRoot(`<error code="idDoesNotExist">No matching identifier in arXiv</error>`);
229
- expect(() => parseOaiResponse(xml)).toThrow(OaiError);
230
- try {
231
- parseOaiResponse(xml);
232
- } catch (e) {
233
- expect(e).toBeInstanceOf(OaiError);
234
- expect((e as OaiError).code).toBe('idDoesNotExist');
235
- expect((e as OaiError).messageText).toContain('No matching identifier');
236
- }
237
- });
238
-
239
- it('throws OaiError for noRecordsMatch', () => {
240
- const xml = wrapOaiRoot(`<error code="noRecordsMatch"/>`);
241
- expect(() => parseIdentify(xml)).toThrow(OaiError);
242
- try {
243
- parseOaiResponse(xml);
244
- } catch (e) {
245
- expect((e as OaiError).code).toBe('noRecordsMatch');
246
- }
247
- });
248
- });
1
+ /**
2
+ * Unit tests for OAI-PMH URL builder and XML parser (no network).
3
+ * Pagination helpers (oaiListRecordsAll, etc.) are covered by integration tests.
4
+ */
5
+ import { describe, it, expect } from 'vitest';
6
+ import {
7
+ buildOaiUrl,
8
+ normalizeOaiIdentifier,
9
+ oaiListIdentifiers,
10
+ oaiListRecords,
11
+ } from '../src/oaiClient.js';
12
+ import {
13
+ parseIdentify,
14
+ parseListMetadataFormats,
15
+ parseListSets,
16
+ parseGetRecord,
17
+ parseListIdentifiers,
18
+ parseListRecords,
19
+ parseOaiResponse,
20
+ } from '../src/oaiParser.js';
21
+ import { OaiError } from '../src/oaiTypes.js';
22
+
23
+ const OAI_BASE = 'https://oaipmh.arxiv.org/oai';
24
+
25
+ describe('buildOaiUrl', () => {
26
+ it('includes verb only for Identify', () => {
27
+ const url = buildOaiUrl('Identify', {});
28
+ expect(url).toBe(`${OAI_BASE}?verb=Identify`);
29
+ });
30
+
31
+ it('encodes identifier and metadataPrefix for GetRecord', () => {
32
+ const url = buildOaiUrl('GetRecord', {
33
+ identifier: 'oai:arXiv.org:cs/0112017',
34
+ metadataPrefix: 'oai_dc',
35
+ });
36
+ expect(url).toContain('verb=GetRecord');
37
+ expect(url).toContain('identifier=' + encodeURIComponent('oai:arXiv.org:cs/0112017'));
38
+ expect(url).toContain('metadataPrefix=oai_dc');
39
+ });
40
+
41
+ it('includes from, until, set for ListRecords', () => {
42
+ const url = buildOaiUrl('ListRecords', {
43
+ metadataPrefix: 'oai_dc',
44
+ from: '2024-01-01',
45
+ until: '2024-01-31',
46
+ set: 'cs:cs.AI',
47
+ });
48
+ expect(url).toContain('verb=ListRecords');
49
+ expect(url).toContain('metadataPrefix=oai_dc');
50
+ expect(url).toContain('from=2024-01-01');
51
+ expect(url).toContain('until=2024-01-31');
52
+ expect(url).toContain('set=cs%3Acs.AI');
53
+ });
54
+
55
+ it('encodes resumptionToken', () => {
56
+ const token = 'token/with/slashes?and=chars';
57
+ const url = buildOaiUrl('ListIdentifiers', { resumptionToken: token });
58
+ expect(url).toContain('resumptionToken=' + encodeURIComponent(token));
59
+ });
60
+
61
+ it('throws for resumptionToken combined with other params', () => {
62
+ expect(() =>
63
+ buildOaiUrl('ListRecords', {
64
+ metadataPrefix: 'oai_dc',
65
+ from: '2024-01-01',
66
+ resumptionToken: 'next-token',
67
+ })
68
+ ).toThrow(OaiError);
69
+ });
70
+ });
71
+
72
+ describe('normalizeOaiIdentifier', () => {
73
+ it('returns full form unchanged', () => {
74
+ expect(normalizeOaiIdentifier('oai:arXiv.org:cs/0112017')).toBe('oai:arXiv.org:cs/0112017');
75
+ });
76
+
77
+ it('prefixes short form', () => {
78
+ expect(normalizeOaiIdentifier('cs/0112017')).toBe('oai:arXiv.org:cs/0112017');
79
+ expect(normalizeOaiIdentifier('2101.01234')).toBe('oai:arXiv.org:2101.01234');
80
+ });
81
+ });
82
+
83
+ function wrapOaiRoot(inner: string): string {
84
+ return `<?xml version="1.0" encoding="UTF-8"?>
85
+ <OAI-PMH xmlns="http://www.openarchives.org/OAI/2.0/">
86
+ <responseDate>2024-01-15T12:00:00Z</responseDate>
87
+ <request verb="Identify">${OAI_BASE}</request>
88
+ ${inner}
89
+ </OAI-PMH>`;
90
+ }
91
+
92
+ describe('parseIdentify', () => {
93
+ it('parses Identify response', () => {
94
+ const xml = wrapOaiRoot(`
95
+ <Identify>
96
+ <repositoryName>arXiv</repositoryName>
97
+ <baseURL>https://oaipmh.arxiv.org/oai</baseURL>
98
+ <protocolVersion>2.0</protocolVersion>
99
+ <adminEmail>help@arxiv.org</adminEmail>
100
+ <earliestDatestamp>2005-09-16</earliestDatestamp>
101
+ <deletedRecord>persistent</deletedRecord>
102
+ <granularity>YYYY-MM-DD</granularity>
103
+ </Identify>`);
104
+ const out = parseIdentify(xml);
105
+ expect(out.repositoryName).toBe('arXiv');
106
+ expect(out.baseURL).toBe('https://oaipmh.arxiv.org/oai');
107
+ expect(out.protocolVersion).toBe('2.0');
108
+ expect(out.adminEmail).toEqual(['help@arxiv.org']);
109
+ expect(out.earliestDatestamp).toBe('2005-09-16');
110
+ expect(out.deletedRecord).toBe('persistent');
111
+ expect(out.granularity).toBe('YYYY-MM-DD');
112
+ });
113
+ });
114
+
115
+ describe('parseListMetadataFormats', () => {
116
+ it('parses ListMetadataFormats response', () => {
117
+ const inner = `
118
+ <ListMetadataFormats>
119
+ <metadataFormat>
120
+ <metadataPrefix>oai_dc</metadataPrefix>
121
+ <schema>http://www.openarchives.org/OAI/2.0/oai_dc.xsd</schema>
122
+ <metadataNamespace>http://www.openarchives.org/OAI/2.0/oai_dc/</metadataNamespace>
123
+ </metadataFormat>
124
+ <metadataFormat>
125
+ <metadataPrefix>arXiv</metadataPrefix>
126
+ <schema>https://arxiv.org/schemas/arXiv.xsd</schema>
127
+ <metadataNamespace>http://arxiv.org/schemas/arXiv/</metadataNamespace>
128
+ </metadataFormat>
129
+ </ListMetadataFormats>`;
130
+ const xml = wrapOaiRoot(inner).replace('<request verb="Identify">', '<request verb="ListMetadataFormats">');
131
+ const out = parseListMetadataFormats(xml);
132
+ expect(out).toHaveLength(2);
133
+ expect(out[0].metadataPrefix).toBe('oai_dc');
134
+ expect(out[1].metadataPrefix).toBe('arXiv');
135
+ });
136
+ });
137
+
138
+ describe('parseListSets', () => {
139
+ it('parses sets and resumptionToken', () => {
140
+ const inner = `
141
+ <ListSets>
142
+ <set>
143
+ <setSpec>cs</setSpec>
144
+ <setName>Computer Science</setName>
145
+ </set>
146
+ <set>
147
+ <setSpec>physics</setSpec>
148
+ <setName>Physics</setName>
149
+ </set>
150
+ <resumptionToken expirationDate="2024-01-16T00:00:00Z" completeListSize="42" cursor="2">next-token</resumptionToken>
151
+ </ListSets>`;
152
+ const xml = wrapOaiRoot(inner).replace('<request verb="Identify">', '<request verb="ListSets">');
153
+ const out = parseListSets(xml);
154
+ expect(out.sets).toHaveLength(2);
155
+ expect(out.sets[0].setSpec).toBe('cs');
156
+ expect(out.sets[0].setName).toBe('Computer Science');
157
+ expect(out.resumptionToken?.value).toBe('next-token');
158
+ expect(out.resumptionToken?.expirationDate).toBe('2024-01-16T00:00:00Z');
159
+ expect(out.resumptionToken?.completeListSize).toBe(42);
160
+ expect(out.resumptionToken?.cursor).toBe(2);
161
+ });
162
+ });
163
+
164
+ describe('parseGetRecord', () => {
165
+ it('parses GetRecord with header and metadata', () => {
166
+ const inner = `
167
+ <GetRecord>
168
+ <record>
169
+ <header>
170
+ <identifier>oai:arXiv.org:cs/0112017</identifier>
171
+ <datestamp>2001-12-14</datestamp>
172
+ <setSpec>cs</setSpec>
173
+ <setSpec>math</setSpec>
174
+ </header>
175
+ <metadata>
176
+ <dc xmlns:dc="http://purl.org/dc/elements/1.1/">
177
+ <dc:title>Using Structural Metadata to Localize Experience of Digital Content</dc:title>
178
+ <dc:creator>Dushay, Naomi</dc:creator>
179
+ <dc:date>2001-12-14</dc:date>
180
+ </dc>
181
+ </metadata>
182
+ </record>
183
+ </GetRecord>`;
184
+ const xml = wrapOaiRoot(inner).replace('<request verb="Identify">', '<request verb="GetRecord" identifier="oai:arXiv.org:cs/0112017" metadataPrefix="oai_dc">');
185
+ const out = parseGetRecord(xml);
186
+ expect(out.header.identifier).toBe('oai:arXiv.org:cs/0112017');
187
+ expect(out.header.datestamp).toBe('2001-12-14');
188
+ expect(out.header.setSpec).toEqual(['cs', 'math']);
189
+ expect(out.metadata).toBeDefined();
190
+ expect(Object.keys(out.metadata!).length).toBeGreaterThan(0);
191
+ });
192
+ });
193
+
194
+ describe('parseListIdentifiers', () => {
195
+ it('parses headers', () => {
196
+ const inner = `
197
+ <ListIdentifiers>
198
+ <header>
199
+ <identifier>oai:arXiv.org:hep-th/9901001</identifier>
200
+ <datestamp>1999-12-25</datestamp>
201
+ <setSpec>physics:hep-th</setSpec>
202
+ </header>
203
+ <header>
204
+ <identifier>oai:arXiv.org:hep-th/9901002</identifier>
205
+ <datestamp>1999-12-26</datestamp>
206
+ </header>
207
+ </ListIdentifiers>`;
208
+ const xml = wrapOaiRoot(inner).replace('<request verb="Identify">', '<request verb="ListIdentifiers" metadataPrefix="oai_dc">');
209
+ const out = parseListIdentifiers(xml);
210
+ expect(out.headers).toHaveLength(2);
211
+ expect(out.headers[0].identifier).toBe('oai:arXiv.org:hep-th/9901001');
212
+ expect(out.headers[0].setSpec).toEqual(['physics:hep-th']);
213
+ });
214
+ });
215
+
216
+ describe('parseListRecords', () => {
217
+ it('parses records and resumptionToken', () => {
218
+ const inner = `
219
+ <ListRecords>
220
+ <record>
221
+ <header>
222
+ <identifier>oai:arXiv.org:cs/0112017</identifier>
223
+ <datestamp>2001-12-14</datestamp>
224
+ <setSpec>cs</setSpec>
225
+ </header>
226
+ <metadata>
227
+ <dc><dc:title>Test Paper</dc:title></dc>
228
+ </metadata>
229
+ </record>
230
+ <resumptionToken cursor="1">resume-123</resumptionToken>
231
+ </ListRecords>`;
232
+ const xml = wrapOaiRoot(inner).replace('<request verb="Identify">', '<request verb="ListRecords" metadataPrefix="oai_dc">');
233
+ const out = parseListRecords(xml);
234
+ expect(out.records).toHaveLength(1);
235
+ expect(out.records[0].header.identifier).toBe('oai:arXiv.org:cs/0112017');
236
+ expect(out.resumptionToken?.value).toBe('resume-123');
237
+ expect(out.resumptionToken?.cursor).toBe(1);
238
+ });
239
+ });
240
+
241
+ describe('OAI error handling', () => {
242
+ it('throws OaiError with code and message on error element', () => {
243
+ const xml = wrapOaiRoot(`<error code="idDoesNotExist">No matching identifier in arXiv</error>`);
244
+ expect(() => parseOaiResponse(xml)).toThrow(OaiError);
245
+ try {
246
+ parseOaiResponse(xml);
247
+ } catch (e) {
248
+ expect(e).toBeInstanceOf(OaiError);
249
+ expect((e as OaiError).code).toBe('idDoesNotExist');
250
+ expect((e as OaiError).messageText).toContain('No matching identifier');
251
+ }
252
+ });
253
+
254
+ it('throws OaiError for noRecordsMatch', () => {
255
+ const xml = wrapOaiRoot(`<error code="noRecordsMatch"/>`);
256
+ expect(() => parseIdentify(xml)).toThrow(OaiError);
257
+ try {
258
+ parseOaiResponse(xml);
259
+ } catch (e) {
260
+ expect((e as OaiError).code).toBe('noRecordsMatch');
261
+ }
262
+ });
263
+ });
264
+
265
+ describe('resumptionToken validation', () => {
266
+ it('throws a local OaiError when resumptionToken is combined with from in oaiListRecords', async () => {
267
+ const invalidOptions = {
268
+ from: '2024-01-01',
269
+ resumptionToken: 'resume-token',
270
+ } as unknown as Parameters<typeof oaiListRecords>[1];
271
+
272
+ await expect(
273
+ oaiListRecords('oai_dc', invalidOptions)
274
+ ).rejects.toMatchObject({
275
+ name: 'OaiError',
276
+ code: 'badArgument',
277
+ });
278
+ await expect(oaiListRecords('oai_dc', invalidOptions)).rejects.toThrow(
279
+ 'resumptionToken must be used by itself'
280
+ );
281
+ });
282
+
283
+ it('throws a local OaiError when resumptionToken is combined with set in oaiListIdentifiers', async () => {
284
+ const invalidOptions = {
285
+ set: 'cs:cs:AI',
286
+ resumptionToken: 'resume-token',
287
+ } as unknown as Parameters<typeof oaiListIdentifiers>[1];
288
+
289
+ await expect(
290
+ oaiListIdentifiers('oai_dc', invalidOptions)
291
+ ).rejects.toMatchObject({
292
+ name: 'OaiError',
293
+ code: 'badArgument',
294
+ });
295
+ });
296
+ });