refactor: Enable stricter test linting

This commit is contained in:
Joachim Van Herwegen
2023-10-27 15:53:52 +02:00
parent 6248ed0938
commit 7a007dc466
48 changed files with 179 additions and 155 deletions

View File

@@ -80,7 +80,7 @@ describe('A BinarySliceResourceStore', (): void => {
});
it('closes the source stream if there was an error creating the SliceStream.', async(): Promise<void> => {
representation.data.destroy = jest.fn();
jest.spyOn(representation.data, 'destroy').mockImplementation();
await expect(store.getRepresentation(identifier, { range: { unit: 'bytes', parts: [{ start: -5 }]}}))
.rejects.toThrow(RangeNotSatisfiedHttpError);
expect(representation.data.destroy).toHaveBeenCalledTimes(1);

View File

@@ -147,7 +147,7 @@ describe('A DataAccessorBasedStore', (): void => {
accessor.data[resourceID.path] = representation;
const result = await store.getRepresentation(resourceID);
expect(result).toMatchObject({ binary: true });
expect(await arrayifyStream(result.data)).toEqual([ resourceData ]);
await expect(arrayifyStream(result.data)).resolves.toEqual([ resourceData ]);
expect(result.metadata.contentType).toBe('text/plain');
expect(result.metadata.get(namedNode('AUXILIARY'))?.value)
.toBe(auxiliaryStrategy.getAuxiliaryIdentifier(resourceID).path);
@@ -163,7 +163,7 @@ describe('A DataAccessorBasedStore', (): void => {
await auxiliaryStrategy.addMetadata(metaMirror);
const result = await store.getRepresentation(resourceID);
expect(result).toMatchObject({ binary: false });
expect(await arrayifyStream(result.data)).toBeRdfIsomorphic(metaMirror.quads());
await expect(arrayifyStream(result.data)).resolves.toBeRdfIsomorphic(metaMirror.quads());
expect(result.metadata.contentType).toEqual(INTERNAL_QUADS);
expect(result.metadata.get(namedNode('AUXILIARY'))?.value)
.toBe(auxiliaryStrategy.getAuxiliaryIdentifier(resourceID).path);
@@ -451,7 +451,7 @@ describe('A DataAccessorBasedStore', (): void => {
it('errors when trying to create an auxiliary resource with invalid data.', async(): Promise<void> => {
const resourceID = { path: `${root}resource.dummy` };
auxiliaryStrategy.validate = jest.fn().mockRejectedValue(new Error('bad data!'));
jest.spyOn(auxiliaryStrategy, 'validate').mockRejectedValue(new Error('bad data!'));
await expect(store.setRepresentation(resourceID, representation)).rejects.toThrow('bad data!');
});
@@ -703,7 +703,7 @@ describe('A DataAccessorBasedStore', (): void => {
});
it('re-throws the error if something goes wrong accessing the metadata.', async(): Promise<void> => {
accessor.getMetadata = jest.fn(async(): Promise<any> => {
jest.spyOn(accessor, 'getMetadata').mockImplementation(async(): Promise<any> => {
throw new Error('error');
});
@@ -738,7 +738,7 @@ describe('A DataAccessorBasedStore', (): void => {
storageMetadata.add(RDF.terms.type, PIM.terms.Storage);
accessor.data[`${root}container/`] = new BasicRepresentation(representation.data, storageMetadata);
accessor.data[`${root}container/.dummy`] = representation;
auxiliaryStrategy.isRequiredInRoot = jest.fn().mockReturnValue(true);
jest.spyOn(auxiliaryStrategy, 'isRequiredInRoot').mockReturnValue(true);
const result = store.deleteResource({ path: `${root}container/.dummy` });
await expect(result).rejects.toThrow(MethodNotAllowedHttpError);
await expect(result).rejects.toThrow(
@@ -787,7 +787,7 @@ describe('A DataAccessorBasedStore', (): void => {
const storageMetadata = new RepresentationMetadata(representation.metadata);
accessor.data[resourceID.path] = new BasicRepresentation(representation.data, storageMetadata);
accessor.data[auxResourceID.path] = representation;
auxiliaryStrategy.isRequiredInRoot = jest.fn().mockReturnValue(true);
jest.spyOn(auxiliaryStrategy, 'isRequiredInRoot').mockReturnValue(true);
const result = await store.deleteResource(auxResourceID);
expect(result.size).toBe(2);
expect(result.get(resourceID)?.get(SOLID_AS.terms.activity)).toEqual(AS.terms.Remove);
@@ -816,14 +816,15 @@ describe('A DataAccessorBasedStore', (): void => {
accessor.data[resourceID.path] = representation;
accessor.data[auxResourceID.path] = representation;
const deleteFn = accessor.deleteResource;
accessor.deleteResource = jest.fn(async(identifier: ResourceIdentifier): Promise<void> => {
if (auxiliaryStrategy.isAuxiliaryIdentifier(identifier)) {
throw new Error('auxiliary error!');
}
await deleteFn.call(accessor, identifier);
});
jest.spyOn(accessor, 'deleteResource')
.mockImplementation(async(identifier: ResourceIdentifier): Promise<void> => {
if (auxiliaryStrategy.isAuxiliaryIdentifier(identifier)) {
throw new Error('auxiliary error!');
}
await deleteFn.call(accessor, identifier);
});
const { logger } = store as any;
logger.error = jest.fn();
jest.spyOn(logger, 'error').mockImplementation();
const result = await store.deleteResource(resourceID);
expect(result.size).toBe(2);
expect(result.get({ path: root })?.get(SOLID_AS.terms.activity)).toEqual(AS.terms.Remove);
@@ -858,7 +859,7 @@ describe('A DataAccessorBasedStore', (): void => {
it('should rethrow any unexpected errors from validateIdentifier.', async(): Promise<void> => {
const resourceID = { path: `${root}resource` };
const originalMetaData = accessor.getMetadata;
accessor.getMetadata = jest.fn(async(): Promise<any> => {
jest.spyOn(accessor, 'getMetadata').mockImplementation(async(): Promise<any> => {
throw new Error('error');
});
await expect(store.hasResource(resourceID)).rejects.toThrow('error');

View File

@@ -34,7 +34,7 @@ describe('A LockingResourceStore', (): void => {
const readable = guardedStreamFrom([ 1, 2, 3 ]);
const { destroy } = readable;
readable.destroy = jest.fn((error): any => destroy.call(readable, error));
jest.spyOn(readable, 'destroy').mockImplementation((error): any => destroy.call(readable, error));
source = {
getRepresentation: jest.fn((): any => addOrder('getRepresentation', { data: readable } as Representation)),
addResource: jest.fn((): any => addOrder('addResource')),
@@ -272,7 +272,7 @@ describe('A LockingResourceStore', (): void => {
});
it('throws an error if a timeout happens before getting a resource.', async(): Promise<void> => {
source.getRepresentation = jest.fn(async(): Promise<any> => {
jest.spyOn(source, 'getRepresentation').mockImplementation(async(): Promise<any> => {
order.push('useless get');
// This will never resolve
return new Promise(emptyFn);

View File

@@ -160,7 +160,7 @@ describe('A MonitoringStore', (): void => {
});
it('should not emit an event when the Activity is not a valid AS value.', async(): Promise<void> => {
source.addResource = jest.fn().mockResolvedValue(new IdentifierMap([
jest.spyOn(source, 'addResource').mockResolvedValue(new IdentifierMap([
[{ path: 'http://example.org/path' }, new RepresentationMetadata({ [SOLID_AS.activity]: 'SomethingRandom' }) ],
]));

View File

@@ -28,7 +28,7 @@ describe('A PatchingStore', (): void => {
});
it('calls its patcher if modifyResource is not implemented.', async(): Promise<void> => {
source.modifyResource = jest.fn(async(): Promise<any> => {
jest.spyOn(source, 'modifyResource').mockImplementation(async(): Promise<any> => {
throw new NotImplementedHttpError();
});
await expect(store.modifyResource({ path: 'modifyPath' }, {} as Patch)).resolves.toBe('patcher');
@@ -40,7 +40,7 @@ describe('A PatchingStore', (): void => {
});
it('rethrows source modifyResource errors.', async(): Promise<void> => {
source.modifyResource = jest.fn(async(): Promise<any> => {
jest.spyOn(source, 'modifyResource').mockImplementation(async(): Promise<any> => {
throw new Error('dummy');
});
await expect(store.modifyResource({ path: 'modifyPath' }, {} as Patch)).rejects.toThrow('dummy');

View File

@@ -56,31 +56,31 @@ describe('AtomicFileDataAccessor', (): void => {
});
it('should throw an error when writing the data goes wrong.', async(): Promise<void> => {
data.read = jest.fn((): any => {
jest.spyOn(data, 'read').mockImplementation((): any => {
data.emit('error', new Error('error'));
return null;
});
jest.requireMock('fs-extra').stat = jest.fn((): any => ({
jest.spyOn(jest.requireMock('fs-extra'), 'stat').mockImplementation((): any => ({
isFile: (): boolean => false,
}));
await expect(accessor.writeDocument({ path: `${base}res.ttl` }, data, metadata)).rejects.toThrow('error');
});
it('should throw when renaming / moving the file goes wrong.', async(): Promise<void> => {
jest.requireMock('fs-extra').rename = jest.fn((): any => {
jest.spyOn(jest.requireMock('fs-extra'), 'rename').mockImplementation((): any => {
throw new Error('error');
});
jest.requireMock('fs-extra').stat = jest.fn((): any => ({
jest.spyOn(jest.requireMock('fs-extra'), 'stat').mockImplementation((): any => ({
isFile: (): boolean => true,
}));
await expect(accessor.writeDocument({ path: `${base}res.ttl` }, data, metadata)).rejects.toThrow('error');
});
it('should (on error) not unlink the temp file if it does not exist.', async(): Promise<void> => {
jest.requireMock('fs-extra').rename = jest.fn((): any => {
jest.spyOn(jest.requireMock('fs-extra'), 'rename').mockImplementation((): any => {
throw new Error('error');
});
jest.requireMock('fs-extra').stat = jest.fn((): any => ({
jest.spyOn(jest.requireMock('fs-extra'), 'stat').mockImplementation((): any => ({
isFile: (): boolean => false,
}));
await expect(accessor.writeDocument({ path: `${base}res.ttl` }, data, metadata)).rejects.toThrow('error');
@@ -88,10 +88,10 @@ describe('AtomicFileDataAccessor', (): void => {
it('should throw when renaming / moving the file goes wrong and the temp file does not exist.',
async(): Promise<void> => {
jest.requireMock('fs-extra').rename = jest.fn((): any => {
jest.spyOn(jest.requireMock('fs-extra'), 'rename').mockImplementation((): any => {
throw new Error('error');
});
jest.requireMock('fs-extra').stat = jest.fn();
jest.spyOn(jest.requireMock('fs-extra'), 'stat').mockImplementation();
await expect(accessor.writeDocument({ path: `${base}res.ttl` }, data, metadata)).rejects.toThrow('error');
});
});

View File

@@ -260,7 +260,8 @@ describe('A FileDataAccessor', (): void => {
it('throws an error if there is a problem with the internal metadata.', async(): Promise<void> => {
cache.data = { resource: 'data', 'resource.meta': 'invalid metadata!.' };
await expect(accessor.getMetadata({ path: `${base}resource` })).rejects.toThrow();
await expect(accessor.getMetadata({ path: `${base}resource` }))
.rejects.toThrow('Unexpected "invalid" on line 1.');
});
});
@@ -465,7 +466,7 @@ describe('A FileDataAccessor', (): void => {
jest.requireMock('fs-extra').remove = (): any => {
throw new Error('error');
};
await expect(accessor.deleteResource({ path: `${base}resource` })).rejects.toThrow();
await expect(accessor.deleteResource({ path: `${base}resource` })).rejects.toThrow('error');
});
it('removes the corresponding folder for containers.', async(): Promise<void> => {

View File

@@ -13,10 +13,10 @@ describe('FilterMetadataDataAccessor', (): void => {
beforeEach(async(): Promise<void> => {
jest.clearAllMocks();
childAccessor = {
getChildren: jest.fn(),
writeDocument: jest.fn(),
writeContainer: jest.fn(),
} as any;
childAccessor.getChildren = jest.fn();
});
it('removes only the matching metadata properties when calling writeDocument.', async(): Promise<void> => {

View File

@@ -160,7 +160,8 @@ describe('An InMemoryDataAccessor', (): void => {
await expect(accessor.getMetadata({ path: `${base}container/resource` }))
.resolves.toBeInstanceOf(RepresentationMetadata);
expect(await readableToString(await accessor.getData({ path: `${base}container/resource` }))).toBe('data');
await expect(readableToString(await accessor.getData({ path: `${base}container/resource` })))
.resolves.toBe('data');
});
it('can write to the root container without overriding its children.', async(): Promise<void> => {
@@ -187,7 +188,7 @@ describe('An InMemoryDataAccessor', (): void => {
await expect(accessor.getMetadata({ path: `${base}resource` }))
.resolves.toBeInstanceOf(RepresentationMetadata);
expect(await readableToString(await accessor.getData({ path: `${base}resource` }))).toBe('data');
await expect(readableToString(await accessor.getData({ path: `${base}resource` }))).resolves.toBe('data');
});
it('errors when writing to an invalid container path.', async(): Promise<void> => {

View File

@@ -25,7 +25,7 @@ describe('ValidatingDataAccessor', (): void => {
getMetadata: jest.fn(),
writeMetadata: jest.fn(),
};
childAccessor.getChildren = jest.fn();
jest.spyOn(childAccessor, 'getChildren').mockImplementation();
passthrough = new PassthroughDataAccessor(childAccessor);
});

View File

@@ -19,10 +19,10 @@ describe('ValidatingDataAccessor', (): void => {
beforeEach(async(): Promise<void> => {
jest.clearAllMocks();
childAccessor = {
getChildren: jest.fn(),
writeDocument: jest.fn(),
writeContainer: jest.fn(),
} as any;
childAccessor.getChildren = jest.fn();
validator = {
handleSafe: jest.fn(async(input: ValidatorInput): Promise<Representation> => input.representation),
} as any;

View File

@@ -114,7 +114,7 @@ describe('A ConstantConverter', (): void => {
expect(createReadStream).toHaveBeenCalledWith('abc/def/index.html', 'utf8');
expect(converted.metadata.contentType).toBe('text/html');
expect(await arrayifyStream(converted.data)).toEqual([ 'file contents' ]);
await expect(arrayifyStream(converted.data)).resolves.toEqual([ 'file contents' ]);
});
it('defaults to the most permissive options.', async(): Promise<void> => {

View File

@@ -16,7 +16,7 @@ describe('A ContainerToTemplateConverter', (): void => {
beforeEach(async(): Promise<void> => {
templateEngine = {
handleSafe: jest.fn().mockReturnValue(Promise.resolve('<html>')),
handleSafe: jest.fn().mockResolvedValue('<html>'),
} as any;
converter = new ContainerToTemplateConverter(templateEngine, 'text/html', identifierStrategy);
});

View File

@@ -33,7 +33,7 @@ describe('A DynamicJsonToTemplateConverter', (): void => {
input = { identifier, representation, preferences };
templateEngine = {
handleSafe: jest.fn().mockReturnValue(Promise.resolve('<html>')),
handleSafe: jest.fn().mockResolvedValue('<html>'),
} as any;
converter = new DynamicJsonToTemplateConverter(templateEngine);
});

View File

@@ -20,7 +20,7 @@ describe('An ErrorToTemplateConverter', (): void => {
beforeEach(async(): Promise<void> => {
templateEngine = {
handleSafe: jest.fn().mockReturnValue(Promise.resolve('<html>')),
handleSafe: jest.fn().mockResolvedValue('<html>'),
} as any;
converter = new ErrorToTemplateConverter(templateEngine,
{ mainTemplatePath, codeTemplatesPath, extension, contentType });

View File

@@ -11,7 +11,7 @@ describe('A MarkdownToHtmlConverter', (): void => {
beforeEach(async(): Promise<void> => {
templateEngine = {
handleSafe: jest.fn().mockReturnValue(Promise.resolve('<html>')),
handleSafe: jest.fn().mockResolvedValue('<html>'),
} as any;
converter = new MarkdownToHtmlConverter(templateEngine);
});

View File

@@ -136,15 +136,16 @@ describe('A ImmutableMetadataPatcher', (): void => {
handler = new ImmutableMetadataPatcher(patcher, metaStrategy, [
new FilterPattern(undefined, `${base}p`, `${base}o`),
]);
patcher.handle = jest.fn(async(patcherInput: RepresentationPatcherInput<RdfDatasetRepresentation>):
Promise<RdfDatasetRepresentation> => {
const patcherStore = new Store([
quad(namedNode(`${base}a`), namedNode(`${base}p`), namedNode(`${base}c`)),
quad(namedNode(`${base}a`), namedNode(`${base}b`), namedNode(`${base}o`)),
]);
patcherInput.representation!.dataset = patcherStore;
return patcherInput.representation!;
});
jest.spyOn(patcher, 'handle').mockImplementation(
async(patcherInput: RepresentationPatcherInput<RdfDatasetRepresentation>): Promise<RdfDatasetRepresentation> => {
const patcherStore = new Store([
quad(namedNode(`${base}a`), namedNode(`${base}p`), namedNode(`${base}c`)),
quad(namedNode(`${base}a`), namedNode(`${base}b`), namedNode(`${base}o`)),
]);
patcherInput.representation!.dataset = patcherStore;
return patcherInput.representation!;
},
);
const result = await handler.handleSafe(input);
expect(result.dataset).toBeRdfIsomorphic([
@@ -157,14 +158,15 @@ describe('A ImmutableMetadataPatcher', (): void => {
it('rejects patches that replaces immutable triples.', async(): Promise<void> => {
input.representation!.dataset.addQuad(namedNode(identifier.path), namedNode(`${base}p`), namedNode(`${base}o1`));
patcher.handle = jest.fn(async(patcherInput: RepresentationPatcherInput<RdfDatasetRepresentation>):
Promise<RdfDatasetRepresentation> => {
const patcherStore = new Store([
quad(namedNode(identifier.path), namedNode(`${base}p`), namedNode(`${base}o2`)),
]);
patcherInput.representation!.dataset = patcherStore;
return patcherInput.representation!;
});
jest.spyOn(patcher, 'handle').mockImplementation(
async(patcherInput: RepresentationPatcherInput<RdfDatasetRepresentation>): Promise<RdfDatasetRepresentation> => {
const patcherStore = new Store([
quad(namedNode(identifier.path), namedNode(`${base}p`), namedNode(`${base}o2`)),
]);
patcherInput.representation!.dataset = patcherStore;
return patcherInput.representation!;
},
);
handler = new ImmutableMetadataPatcher(patcher, metaStrategy, [
new FilterPattern(`${base}foo`, `${base}p`),
]);

View File

@@ -6,8 +6,8 @@ import type { PreferenceSupport } from '../../../../src/storage/routing/Preferen
import { InternalServerError } from '../../../../src/util/errors/InternalServerError';
describe('A ConvertingRouterRule', (): void => {
let store1: ResourceStore;
let store2: ResourceStore;
let store1: jest.Mocked<ResourceStore>;
let store2: jest.Mocked<ResourceStore>;
let defaultStore: ResourceStore;
let checker1: PreferenceSupport;
let checker2: PreferenceSupport;
@@ -16,8 +16,14 @@ describe('A ConvertingRouterRule', (): void => {
let metadata: RepresentationMetadata;
beforeEach(async(): Promise<void> => {
store1 = { name: 'turtleStore' } as any;
store2 = { name: 'textStore' } as any;
store1 = {
name: 'turtleStore',
hasResource: jest.fn(),
} as any satisfies ResourceStore;
store2 = {
name: 'textStore',
hasResource: jest.fn(),
} as any satisfies ResourceStore;
defaultStore = { name: 'defaultStore' } as any;
checker1 = {
@@ -53,19 +59,19 @@ describe('A ConvertingRouterRule', (): void => {
});
it('checks if the stores contain the identifier if there is no data.', async(): Promise<void> => {
store1.hasResource = jest.fn().mockImplementationOnce((): any => true);
store1.hasResource.mockImplementationOnce((): any => true);
await expect(rule.handle({ identifier: { path: 'identifier' }})).resolves.toBe(store1);
expect(store1.hasResource).toHaveBeenCalledTimes(1);
});
it('returns the defaultStore if no other store has the resource.', async(): Promise<void> => {
store1.hasResource = jest.fn().mockImplementationOnce((): any => false);
store2.hasResource = jest.fn().mockImplementationOnce((): any => false);
store1.hasResource.mockImplementationOnce((): any => false);
store2.hasResource.mockImplementationOnce((): any => false);
await expect(rule.handle({ identifier: { path: 'identifier' }})).resolves.toBe(defaultStore);
});
it('throws the error if a store had a non-404 error.', async(): Promise<void> => {
store1.hasResource = jest.fn().mockRejectedValueOnce(new InternalServerError());
store1.hasResource.mockRejectedValueOnce(new InternalServerError());
await expect(rule.handle({ identifier: { path: 'identifier' }})).rejects.toThrow(InternalServerError);
});
});

View File

@@ -26,7 +26,7 @@ describe('A PreferenceSupport', (): void => {
});
it('returns false if the converter does not support the input.', async(): Promise<void> => {
converter.canHandle = jest.fn((): any => {
jest.spyOn(converter, 'canHandle').mockImplementation((): any => {
throw new BadRequestHttpError();
});
await expect(support.supports({ identifier, representation })).resolves.toBe(false);