CommunitySolidServer/test/unit/util/FetchUtil.test.ts
Thomas Dupont ce754c119f
fix: Add content-negotiation when fetching dataset from url
* Solution works but tests don't

* refactor(FetchUtil): use arrayifyStream

* refactor(FetchUtil): split fetchDataset into 2 separate functions

* style(FetchUtil): onelining instead of declaring new local var

* test: trying to mock rdfDereferencer

* refactor: promise can't have async function as arg

* test(FetchUtil): pass Quad array to mockDereference instead

* test: all tests should pass now and coverage is back to 100%

* style: comment typo

* chore: make package.json and package-lock.json compatible with main

* chore: fix package.json double entries

* chore: updated package.json to be alfabetical again

* refactor(AgentGroupAccessChecker): Remove converter from contructor and config

* refactor(TokenOwnerShipValidator): Remove converter from constructor and config

* refactor(FetchUtil): Return BadRequestHttpError instead of generic Error

* test(FetchUtil): return Response object instead of mocking fetch

* style: typos and newlines
2022-02-15 13:44:03 +01:00

82 lines
3.2 KiB
TypeScript

import { Readable } from 'stream';
import type { Quad } from '@rdfjs/types';
import arrayifyStream from 'arrayify-stream';
import type { Response } from 'cross-fetch';
import { DataFactory } from 'n3';
import rdfDereferencer from 'rdf-dereference';
import { RdfToQuadConverter } from '../../../src/storage/conversion/RdfToQuadConverter';
import { fetchDataset, responseToDataset } from '../../../src/util/FetchUtil';
const { namedNode, quad } = DataFactory;
jest.mock('rdf-dereference', (): any => ({
dereference: jest.fn<string, any>(),
}));
describe('FetchUtil', (): void => {
const url = 'http://test.com/foo';
function mockResponse(body: string, contentType: string | null, status = 200): Response {
return ({
text: (): any => body,
url,
status,
headers: { get: (): any => contentType },
}) as any;
}
describe('#fetchDataset', (): void => {
const rdfDereferenceMock: jest.Mocked<typeof rdfDereferencer> = rdfDereferencer as any;
function mockDereference(quads?: Quad[]): any {
rdfDereferenceMock.dereference.mockImplementation((uri: string): any => {
if (!quads) {
throw new Error('Throws error because url does not exist');
}
return {
uri,
quads: Readable.from(quads),
exists: true,
};
});
}
it('errors if the URL does not exist.', async(): Promise<void> => {
mockDereference();
await expect(fetchDataset(url)).rejects.toThrow(`Could not parse resource at URL (${url})!`);
expect(rdfDereferenceMock.dereference).toHaveBeenCalledWith(url);
});
it('returns a Representation with quads.', async(): Promise<void> => {
const quads = [ quad(namedNode('http://test.com/s'), namedNode('http://test.com/p'), namedNode('http://test.com/o')) ];
mockDereference(quads);
const representation = await fetchDataset(url);
await expect(arrayifyStream(representation.data)).resolves.toEqual([
quad(namedNode('http://test.com/s'), namedNode('http://test.com/p'), namedNode('http://test.com/o')),
]);
});
});
describe('#responseToDataset', (): void => {
const converter = new RdfToQuadConverter();
it('accepts Response objects as input.', async(): Promise<void> => {
const response = mockResponse('<http://test.com/s> <http://test.com/p> <http://test.com/o>.', 'text/turtle');
const body = await response.text();
const representation = await responseToDataset(response, converter, body);
await expect(arrayifyStream(representation.data)).resolves.toEqual([
quad(namedNode('http://test.com/s'), namedNode('http://test.com/p'), namedNode('http://test.com/o')),
]);
});
it('errors if the status code is not 200.', async(): Promise<void> => {
const response = mockResponse('Incorrect status!', null, 400);
await expect(responseToDataset(response, converter)).rejects.toThrow(`Unable to access data at ${url}`);
});
it('errors if there is no content-type.', async(): Promise<void> => {
const response = mockResponse('No content-type!', null);
await expect(responseToDataset(response, converter)).rejects.toThrow(`Unable to access data at ${url}`);
});
});
});