CommunitySolidServer/test/unit/storage/patch/ConvertingPatcher.test.ts
Joachim Van Herwegen b3da9c9fcf refactor: Restructure source code folder
This way the location of certain classes should make more sense
2021-10-12 12:51:02 +02:00

130 lines
5.2 KiB
TypeScript

import { BasicRepresentation } from '../../../../src/http/representation/BasicRepresentation';
import type { Patch } from '../../../../src/http/representation/Patch';
import type { ResourceIdentifier } from '../../../../src/http/representation/ResourceIdentifier';
import type {
RepresentationConverter,
RepresentationConverterArgs,
} from '../../../../src/storage/conversion/RepresentationConverter';
import { ConvertingPatcher } from '../../../../src/storage/patch/ConvertingPatcher';
import type {
RepresentationPatcher,
RepresentationPatcherInput,
} from '../../../../src/storage/patch/RepresentationPatcher';
describe('A ConvertingPatcher', (): void => {
const intermediateType = 'internal/quads';
const defaultType = 'text/turtle';
const identifier: ResourceIdentifier = { path: 'http://test.com/foo' };
const patch: Patch = new BasicRepresentation([], 'type/patch');
const representation = new BasicRepresentation([], 'application/trig');
const patchResult = new BasicRepresentation([], 'internal/quads');
let args: RepresentationPatcherInput;
let converter: jest.Mocked<RepresentationConverter>;
let patcher: jest.Mocked<RepresentationPatcher>;
let convertingPatcher: ConvertingPatcher;
beforeEach(async(): Promise<void> => {
args = { patch, identifier, representation };
converter = {
canHandle: jest.fn(),
handle: jest.fn(async({ preferences }: RepresentationConverterArgs): Promise<any> =>
new BasicRepresentation('converted', Object.keys(preferences.type!)[0])),
} as any;
patcher = {
canHandle: jest.fn(),
handle: jest.fn().mockResolvedValue(patchResult),
} as any;
convertingPatcher = new ConvertingPatcher(patcher, converter, intermediateType, defaultType);
});
it('rejects requests the converter cannot handle.', async(): Promise<void> => {
converter.canHandle.mockRejectedValueOnce(new Error('unsupported type'));
await expect(convertingPatcher.canHandle(args)).rejects.toThrow('unsupported type');
});
it('checks if the patcher can handle the input if there is no representation.', async(): Promise<void> => {
delete args.representation;
await expect(convertingPatcher.canHandle(args)).resolves.toBeUndefined();
patcher.canHandle.mockRejectedValueOnce(new Error('unsupported patch'));
await expect(convertingPatcher.canHandle(args)).rejects.toThrow('unsupported patch');
});
it('sends a mock representation with the correct type to the patcher to check support.', async(): Promise<void> => {
await expect(convertingPatcher.canHandle(args)).resolves.toBeUndefined();
expect(patcher.canHandle).toHaveBeenCalledTimes(1);
expect(patcher.canHandle.mock.calls[0][0].representation?.metadata.contentType).toBe(intermediateType);
});
it('converts the representation before calling the patcher.', async(): Promise<void> => {
const result = await convertingPatcher.handle(args);
expect(result.metadata.contentType).toBe('application/trig');
// Convert input
expect(converter.handle).toHaveBeenCalledTimes(2);
expect(converter.handle).toHaveBeenCalledWith({
representation,
identifier,
preferences: { type: { [intermediateType]: 1 }},
});
// Patch
expect(patcher.handle).toHaveBeenCalledTimes(1);
expect(patcher.handle)
.toHaveBeenLastCalledWith({ ...args, representation: await converter.handle.mock.results[0].value });
// Convert back
expect(converter.handle).toHaveBeenLastCalledWith({
representation: patchResult,
identifier,
preferences: { type: { 'application/trig': 1 }},
});
});
it('expects the patcher to create a new representation if there is none.', async(): Promise<void> => {
delete args.representation;
const result = await convertingPatcher.handle(args);
expect(result.metadata.contentType).toBe(defaultType);
// Patch
expect(patcher.handle).toHaveBeenCalledTimes(1);
expect(patcher.handle).toHaveBeenLastCalledWith(args);
// Convert new Representation to default type
expect(converter.handle).toHaveBeenCalledTimes(1);
expect(converter.handle).toHaveBeenLastCalledWith({
representation: patchResult,
identifier,
preferences: { type: { [defaultType]: 1 }},
});
});
it('does no conversion if there is no intermediate type.', async(): Promise<void> => {
convertingPatcher = new ConvertingPatcher(patcher, converter);
const result = await convertingPatcher.handle(args);
expect(result.metadata.contentType).toBe(patchResult.metadata.contentType);
// Patch
expect(converter.handle).toHaveBeenCalledTimes(0);
expect(patcher.handle).toHaveBeenCalledTimes(1);
expect(patcher.handle).toHaveBeenLastCalledWith(args);
});
it('does not convert to a default type if there is none.', async(): Promise<void> => {
delete args.representation;
convertingPatcher = new ConvertingPatcher(patcher, converter);
const result = await convertingPatcher.handle(args);
expect(result.metadata.contentType).toBe(patchResult.metadata.contentType);
// Patch
expect(converter.handle).toHaveBeenCalledTimes(0);
expect(patcher.handle).toHaveBeenCalledTimes(1);
expect(patcher.handle).toHaveBeenLastCalledWith(args);
});
});