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

@ -210,17 +210,11 @@ module.exports = antfu(
// Default rules that are overkill // Default rules that are overkill
'jest/no-hooks': 'off', 'jest/no-hooks': 'off',
'jest/max-expects': 'off', 'jest/max-expects': 'off',
'jest/no-conditional-in-test': 'off',
'jest/prefer-expect-assertions': 'off', 'jest/prefer-expect-assertions': 'off',
'jest/prefer-lowercase-title': 'off', 'jest/prefer-lowercase-title': 'off',
'jest/prefer-strict-equal': 'off', 'jest/prefer-strict-equal': 'off',
// Default rules that might be useful but would require too many files to be changed right now
'jest/no-conditional-in-test': 'off',
'jest/prefer-mock-promise-shorthand': 'off',
'jest/prefer-expect-resolves': 'off',
'jest/prefer-spy-on': 'off',
'jest/require-hook': 'off', 'jest/require-hook': 'off',
'jest/require-to-throw-message': 'off',
'ts/naming-convention': 'off', 'ts/naming-convention': 'off',
'ts/no-unsafe-argument': 'off', 'ts/no-unsafe-argument': 'off',

View File

@ -76,7 +76,7 @@ describe.each(stores)('A server supporting conditions with %s', (name, { storeCo
await expect(response.text()).resolves.toBe('TESTFILE'); await expect(response.text()).resolves.toBe('TESTFILE');
// DELETE // DELETE
expect(await deleteResource(documentUrl)).toBeUndefined(); await expect(deleteResource(documentUrl)).resolves.toBeUndefined();
}); });
it('prevents creating new resources with "if-match: *" header.', async(): Promise<void> => { it('prevents creating new resources with "if-match: *" header.', async(): Promise<void> => {
@ -112,7 +112,7 @@ describe.each(stores)('A server supporting conditions with %s', (name, { storeCo
await expectQuads(response, expected, true); await expectQuads(response, expected, true);
// DELETE // DELETE
expect(await deleteResource(documentUrl)).toBeUndefined(); await expect(deleteResource(documentUrl)).resolves.toBeUndefined();
}); });
it('prevents operations if the "if-match" header does not match.', async(): Promise<void> => { it('prevents operations if the "if-match" header does not match.', async(): Promise<void> => {
@ -140,7 +140,7 @@ describe.each(stores)('A server supporting conditions with %s', (name, { storeCo
expect(typeof documentUrl).toBe('string'); expect(typeof documentUrl).toBe('string');
// DELETE // DELETE
expect(await deleteResource(documentUrl!)).toBeUndefined(); await expect(deleteResource(documentUrl!)).resolves.toBeUndefined();
}); });
it('prevents operations if the "if-none-match" header does match.', async(): Promise<void> => { it('prevents operations if the "if-none-match" header does match.', async(): Promise<void> => {
@ -168,7 +168,7 @@ describe.each(stores)('A server supporting conditions with %s', (name, { storeCo
expect(typeof documentUrl).toBe('string'); expect(typeof documentUrl).toBe('string');
// DELETE // DELETE
expect(await deleteResource(documentUrl!)).toBeUndefined(); await expect(deleteResource(documentUrl!)).resolves.toBeUndefined();
}); });
it('throws 304 error if "if-none-match" header matches and request type is GET or HEAD.', async(): Promise<void> => { it('throws 304 error if "if-none-match" header matches and request type is GET or HEAD.', async(): Promise<void> => {

View File

@ -45,7 +45,7 @@ describe('A chained converter where data gets ignored', (): void => {
jest.useFakeTimers(); jest.useFakeTimers();
const result = await converter.handleSafe({ identifier, representation: rep, preferences: { type: { 'x/x': 1 }}}); const result = await converter.handleSafe({ identifier, representation: rep, preferences: { type: { 'x/x': 1 }}});
expect(await readableToString(result.data)).toBe('dummy'); await expect(readableToString(result.data)).resolves.toBe('dummy');
jest.advanceTimersByTime(1000); jest.advanceTimersByTime(1000);
expect(logger.error).toHaveBeenCalledTimes(1); expect(logger.error).toHaveBeenCalledTimes(1);

View File

@ -232,7 +232,7 @@ describe.each(stores)('An LDP handler with auth using %s', (name, { storeConfig,
// GET file // GET file
const response = await getResource(identifier.path); const response = await getResource(identifier.path);
expect(await response.text()).toContain('valid data'); await expect(response.text()).resolves.toContain('valid data');
}); });
it('prevents creation of intermediate intermediate containers if they are not allowed.', async(): Promise<void> => { it('prevents creation of intermediate intermediate containers if they are not allowed.', async(): Promise<void> => {

View File

@ -107,7 +107,7 @@ describe.each(stores)('An LDP handler allowing all requests %s', (name, { storeC
await expect(response.text()).resolves.toBe('TESTFILE0'); await expect(response.text()).resolves.toBe('TESTFILE0');
// DELETE // DELETE
expect(await deleteResource(documentUrl)).toBeUndefined(); await expect(deleteResource(documentUrl)).resolves.toBeUndefined();
}); });
it('can add and overwrite a document.', async(): Promise<void> => { it('can add and overwrite a document.', async(): Promise<void> => {
@ -127,7 +127,7 @@ describe.each(stores)('An LDP handler allowing all requests %s', (name, { storeC
await expect(response.text()).resolves.toBe('TESTFILE1'); await expect(response.text()).resolves.toBe('TESTFILE1');
// DELETE // DELETE
expect(await deleteResource(documentUrl)).toBeUndefined(); await expect(deleteResource(documentUrl)).resolves.toBeUndefined();
}); });
it('can create a container and delete it.', async(): Promise<void> => { it('can create a container and delete it.', async(): Promise<void> => {
@ -144,7 +144,7 @@ describe.each(stores)('An LDP handler allowing all requests %s', (name, { storeC
]); ]);
// DELETE // DELETE
expect(await deleteResource(containerUrl)).toBeUndefined(); await expect(deleteResource(containerUrl)).resolves.toBeUndefined();
}); });
it('can create a container and retrieve it.', async(): Promise<void> => { it('can create a container and retrieve it.', async(): Promise<void> => {
@ -157,7 +157,7 @@ describe.each(stores)('An LDP handler allowing all requests %s', (name, { storeC
await expect(response.text()).resolves.toContain('ldp:BasicContainer'); await expect(response.text()).resolves.toContain('ldp:BasicContainer');
// DELETE // DELETE
expect(await deleteResource(containerUrl)).toBeUndefined(); await expect(deleteResource(containerUrl)).resolves.toBeUndefined();
}); });
it('can create a container and view it as HTML.', async(): Promise<void> => { it('can create a container and view it as HTML.', async(): Promise<void> => {
@ -170,7 +170,7 @@ describe.each(stores)('An LDP handler allowing all requests %s', (name, { storeC
await expect(response.text()).resolves.toContain('Contents of testcontainer0'); await expect(response.text()).resolves.toContain('Contents of testcontainer0');
// DELETE // DELETE
expect(await deleteResource(containerUrl)).toBeUndefined(); await expect(deleteResource(containerUrl)).resolves.toBeUndefined();
}); });
it('can create a container and put a document in it.', async(): Promise<void> => { it('can create a container and put a document in it.', async(): Promise<void> => {
@ -187,8 +187,8 @@ describe.each(stores)('An LDP handler allowing all requests %s', (name, { storeC
await expect(response.text()).resolves.toBe('TESTFILE0'); await expect(response.text()).resolves.toBe('TESTFILE0');
// DELETE // DELETE
expect(await deleteResource(documentUrl)).toBeUndefined(); await expect(deleteResource(documentUrl)).resolves.toBeUndefined();
expect(await deleteResource(containerUrl)).toBeUndefined(); await expect(deleteResource(containerUrl)).resolves.toBeUndefined();
}); });
it('can create a container without content-type.', async(): Promise<void> => { it('can create a container without content-type.', async(): Promise<void> => {
@ -212,8 +212,8 @@ describe.each(stores)('An LDP handler allowing all requests %s', (name, { storeC
expect(postResponse.headers.get('location')).toBe(baseUrl + slug); expect(postResponse.headers.get('location')).toBe(baseUrl + slug);
// DELETE // DELETE
expect(await deleteResource(containerUrl)).toBeUndefined(); await expect(deleteResource(containerUrl)).resolves.toBeUndefined();
expect(await deleteResource(baseUrl + slug)).toBeUndefined(); await expect(deleteResource(baseUrl + slug)).resolves.toBeUndefined();
}); });
it('cannot remove a container when the container contains a document.', async(): Promise<void> => { it('cannot remove a container when the container contains a document.', async(): Promise<void> => {
// Create container // Create container
@ -230,8 +230,8 @@ describe.each(stores)('An LDP handler allowing all requests %s', (name, { storeC
await expect(response.text()).resolves.toContain('ConflictHttpError: Can only delete empty containers.'); await expect(response.text()).resolves.toContain('ConflictHttpError: Can only delete empty containers.');
// DELETE // DELETE
expect(await deleteResource(documentUrl)).toBeUndefined(); await expect(deleteResource(documentUrl)).resolves.toBeUndefined();
expect(await deleteResource(containerUrl)).toBeUndefined(); await expect(deleteResource(containerUrl)).resolves.toBeUndefined();
}); });
it('cannot remove a container when the container contains a subfolder.', async(): Promise<void> => { it('cannot remove a container when the container contains a subfolder.', async(): Promise<void> => {
@ -249,8 +249,8 @@ describe.each(stores)('An LDP handler allowing all requests %s', (name, { storeC
await expect(response.text()).resolves.toContain('ConflictHttpError: Can only delete empty containers.'); await expect(response.text()).resolves.toContain('ConflictHttpError: Can only delete empty containers.');
// DELETE // DELETE
expect(await deleteResource(subContainerUrl)).toBeUndefined(); await expect(deleteResource(subContainerUrl)).resolves.toBeUndefined();
expect(await deleteResource(containerUrl)).toBeUndefined(); await expect(deleteResource(containerUrl)).resolves.toBeUndefined();
}); });
it('can read the contents of a container.', async(): Promise<void> => { it('can read the contents of a container.', async(): Promise<void> => {
@ -273,9 +273,9 @@ describe.each(stores)('An LDP handler allowing all requests %s', (name, { storeC
]); ]);
// DELETE // DELETE
expect(await deleteResource(documentUrl)).toBeUndefined(); await expect(deleteResource(documentUrl)).resolves.toBeUndefined();
expect(await deleteResource(subContainerUrl)).toBeUndefined(); await expect(deleteResource(subContainerUrl)).resolves.toBeUndefined();
expect(await deleteResource(containerUrl)).toBeUndefined(); await expect(deleteResource(containerUrl)).resolves.toBeUndefined();
}); });
it('can upload and delete an image.', async(): Promise<void> => { it('can upload and delete an image.', async(): Promise<void> => {
@ -295,7 +295,7 @@ describe.each(stores)('An LDP handler allowing all requests %s', (name, { storeC
await getResource(documentUrl, {}, { contentType: 'image/png' }); await getResource(documentUrl, {}, { contentType: 'image/png' });
// DELETE // DELETE
expect(await deleteResource(documentUrl)).toBeUndefined(); await expect(deleteResource(documentUrl)).resolves.toBeUndefined();
}); });
it('can create a resource with a diamond identifier in the data.', async(): Promise<void> => { it('can create a resource with a diamond identifier in the data.', async(): Promise<void> => {
@ -314,7 +314,7 @@ describe.each(stores)('An LDP handler allowing all requests %s', (name, { storeC
]); ]);
// DELETE // DELETE
expect(await deleteResource(containerUrl)).toBeUndefined(); await expect(deleteResource(containerUrl)).resolves.toBeUndefined();
}); });
// https://github.com/CommunitySolidServer/CommunitySolidServer/issues/498 // https://github.com/CommunitySolidServer/CommunitySolidServer/issues/498
@ -333,7 +333,7 @@ describe.each(stores)('An LDP handler allowing all requests %s', (name, { storeC
await getResource(documentUrl); await getResource(documentUrl);
// DELETE // DELETE
expect(await deleteResource(documentUrl)).toBeUndefined(); await expect(deleteResource(documentUrl)).resolves.toBeUndefined();
}); });
it('can handle simple SPARQL updates.', async(): Promise<void> => { it('can handle simple SPARQL updates.', async(): Promise<void> => {
@ -382,7 +382,7 @@ describe.each(stores)('An LDP handler allowing all requests %s', (name, { storeC
await expectQuads(response, expected, true); await expectQuads(response, expected, true);
// DELETE // DELETE
expect(await deleteResource(documentUrl)).toBeUndefined(); await expect(deleteResource(documentUrl)).resolves.toBeUndefined();
}); });
it('can handle simple N3 Patch updates.', async(): Promise<void> => { it('can handle simple N3 Patch updates.', async(): Promise<void> => {
@ -433,7 +433,7 @@ describe.each(stores)('An LDP handler allowing all requests %s', (name, { storeC
await expectQuads(response, expected, true); await expectQuads(response, expected, true);
// DELETE // DELETE
expect(await deleteResource(documentUrl)).toBeUndefined(); await expect(deleteResource(documentUrl)).resolves.toBeUndefined();
}); });
it('can not handle SPARQL updates on containers.', async(): Promise<void> => { it('can not handle SPARQL updates on containers.', async(): Promise<void> => {
@ -460,7 +460,7 @@ describe.each(stores)('An LDP handler allowing all requests %s', (name, { storeC
expect(response.status).toBe(409); expect(response.status).toBe(409);
// DELETE // DELETE
expect(await deleteResource(documentUrl)).toBeUndefined(); await expect(deleteResource(documentUrl)).resolves.toBeUndefined();
}); });
it('can not handle N3 Patch updates on containers.', async(): Promise<void> => { it('can not handle N3 Patch updates on containers.', async(): Promise<void> => {
@ -488,7 +488,7 @@ describe.each(stores)('An LDP handler allowing all requests %s', (name, { storeC
expect(response.status).toBe(409); expect(response.status).toBe(409);
// DELETE // DELETE
expect(await deleteResource(documentUrl)).toBeUndefined(); await expect(deleteResource(documentUrl)).resolves.toBeUndefined();
}); });
it('returns 405 for unsupported methods.', async(): Promise<void> => { it('returns 405 for unsupported methods.', async(): Promise<void> => {
@ -564,7 +564,7 @@ describe.each(stores)('An LDP handler allowing all requests %s', (name, { storeC
expect(quads).toHaveLength(3); expect(quads).toHaveLength(3);
// DELETE // DELETE
expect(await deleteResource(documentUrl)).toBeUndefined(); await expect(deleteResource(documentUrl)).resolves.toBeUndefined();
}); });
it('can not delete metadata resources directly.', async(): Promise<void> => { it('can not delete metadata resources directly.', async(): Promise<void> => {
@ -578,7 +578,7 @@ describe.each(stores)('An LDP handler allowing all requests %s', (name, { storeC
expect(response.status).toBe(409); expect(response.status).toBe(409);
// DELETE // DELETE
expect(await deleteResource(documentUrl)).toBeUndefined(); await expect(deleteResource(documentUrl)).resolves.toBeUndefined();
}); });
it('can not create metadata directly.', async(): Promise<void> => { it('can not create metadata directly.', async(): Promise<void> => {
@ -630,7 +630,7 @@ describe.each(stores)('An LDP handler allowing all requests %s', (name, { storeC
await expectQuads(response, [ quad(namedNode(`${baseUrl}a`), namedNode(`${baseUrl}b`), namedNode(`${baseUrl}c`)) ]); await expectQuads(response, [ quad(namedNode(`${baseUrl}a`), namedNode(`${baseUrl}b`), namedNode(`${baseUrl}c`)) ]);
// DELETE // DELETE
expect(await deleteResource(documentUrl)).toBeUndefined(); await expect(deleteResource(documentUrl)).resolves.toBeUndefined();
}); });
it('can not update metadata triples that are deemed immutable.', async(): Promise<void> => { it('can not update metadata triples that are deemed immutable.', async(): Promise<void> => {
@ -656,7 +656,7 @@ describe.each(stores)('An LDP handler allowing all requests %s', (name, { storeC
expect(ldpResponse.status).toBe(409); expect(ldpResponse.status).toBe(409);
// DELETE // DELETE
expect(await deleteResource(containerUrl)).toBeUndefined(); await expect(deleteResource(containerUrl)).resolves.toBeUndefined();
}); });
it('can not create metadata resource of a metadata resource.', async(): Promise<void> => { it('can not create metadata resource of a metadata resource.', async(): Promise<void> => {

View File

@ -223,6 +223,7 @@ describeIf('docker')('A server with a RedisLocker', (): void => {
await expect(locker.withWriteLock(identifier, (): void => { await expect(locker.withWriteLock(identifier, (): void => {
res += 'l1'; res += 'l1';
res += 'r1'; res += 'r1';
// eslint-disable-next-line jest/require-to-throw-message
})).rejects.toThrow(); })).rejects.toThrow();
res += 'r0'; res += 'r0';
})).resolves.toBeUndefined(); })).resolves.toBeUndefined();

View File

@ -26,7 +26,7 @@ describe('An RdfValidator', (): void => {
}); });
it('validates data by running it through a converter.', async(): Promise<void> => { it('validates data by running it through a converter.', async(): Promise<void> => {
converter.handleSafe = jest.fn().mockResolvedValue(new BasicRepresentation('transformedData', 'wrong/type')); jest.spyOn(converter, 'handleSafe').mockResolvedValue(new BasicRepresentation('transformedData', 'wrong/type'));
const representation = new BasicRepresentation('data', 'content/type'); const representation = new BasicRepresentation('data', 'content/type');
const quads = representation.metadata.quads(); const quads = representation.metadata.quads();
// Output is not important for this Validator // Output is not important for this Validator
@ -38,7 +38,7 @@ describe('An RdfValidator', (): void => {
}); });
it('throws an error when validating invalid data.', async(): Promise<void> => { it('throws an error when validating invalid data.', async(): Promise<void> => {
converter.handleSafe = jest.fn().mockRejectedValue(new Error('bad data!')); jest.spyOn(converter, 'handleSafe').mockRejectedValue(new Error('bad data!'));
const representation = new BasicRepresentation('data', 'content/type'); const representation = new BasicRepresentation('data', 'content/type');
await expect(validator.handle({ representation, identifier })).rejects.toThrow('bad data!'); await expect(validator.handle({ representation, identifier })).rejects.toThrow('bad data!');
// Make sure the data on the readable has not been reset // Make sure the data on the readable has not been reset

View File

@ -61,8 +61,8 @@ describe('A RoutingAuxiliaryStrategy', (): void => {
}); });
it('#addMetadata adds the metadata of all sources for the base identifier.', async(): Promise<void> => { it('#addMetadata adds the metadata of all sources for the base identifier.', async(): Promise<void> => {
sources[0].addMetadata = jest.fn(); jest.spyOn(sources[0], 'addMetadata').mockImplementation();
sources[1].addMetadata = jest.fn(); jest.spyOn(sources[1], 'addMetadata').mockImplementation();
const metadata = new RepresentationMetadata(baseId); const metadata = new RepresentationMetadata(baseId);
await expect(strategy.addMetadata(metadata)).resolves.toBeUndefined(); await expect(strategy.addMetadata(metadata)).resolves.toBeUndefined();
expect(sources[0].addMetadata).toHaveBeenCalledTimes(1); expect(sources[0].addMetadata).toHaveBeenCalledTimes(1);
@ -72,8 +72,8 @@ describe('A RoutingAuxiliaryStrategy', (): void => {
}); });
it('#addMetadata adds the metadata of the correct source for auxiliary identifiers.', async(): Promise<void> => { it('#addMetadata adds the metadata of the correct source for auxiliary identifiers.', async(): Promise<void> => {
sources[0].addMetadata = jest.fn(); jest.spyOn(sources[0], 'addMetadata').mockImplementation();
sources[1].addMetadata = jest.fn(); jest.spyOn(sources[1], 'addMetadata').mockImplementation();
const metadata = new RepresentationMetadata(dummy2Id); const metadata = new RepresentationMetadata(dummy2Id);
await expect(strategy.addMetadata(metadata)).resolves.toBeUndefined(); await expect(strategy.addMetadata(metadata)).resolves.toBeUndefined();
expect(sources[0].addMetadata).toHaveBeenCalledTimes(0); expect(sources[0].addMetadata).toHaveBeenCalledTimes(0);
@ -82,8 +82,8 @@ describe('A RoutingAuxiliaryStrategy', (): void => {
}); });
it('#usesOwnAuthorization returns the result of the correct source.', async(): Promise<void> => { it('#usesOwnAuthorization returns the result of the correct source.', async(): Promise<void> => {
sources[0].usesOwnAuthorization = jest.fn(); jest.spyOn(sources[0], 'usesOwnAuthorization').mockImplementation();
sources[1].usesOwnAuthorization = jest.fn(); jest.spyOn(sources[1], 'usesOwnAuthorization').mockImplementation();
strategy.usesOwnAuthorization(dummy2Id); strategy.usesOwnAuthorization(dummy2Id);
expect(sources[0].usesOwnAuthorization).toHaveBeenCalledTimes(0); expect(sources[0].usesOwnAuthorization).toHaveBeenCalledTimes(0);
expect(sources[1].usesOwnAuthorization).toHaveBeenCalledTimes(1); expect(sources[1].usesOwnAuthorization).toHaveBeenCalledTimes(1);
@ -91,8 +91,8 @@ describe('A RoutingAuxiliaryStrategy', (): void => {
}); });
it('#isRequiredInRoot returns the result of the correct source.', async(): Promise<void> => { it('#isRequiredInRoot returns the result of the correct source.', async(): Promise<void> => {
sources[0].isRequiredInRoot = jest.fn(); jest.spyOn(sources[0], 'isRequiredInRoot').mockImplementation();
sources[1].isRequiredInRoot = jest.fn(); jest.spyOn(sources[1], 'isRequiredInRoot').mockImplementation();
strategy.isRequiredInRoot(dummy2Id); strategy.isRequiredInRoot(dummy2Id);
expect(sources[0].isRequiredInRoot).toHaveBeenCalledTimes(0); expect(sources[0].isRequiredInRoot).toHaveBeenCalledTimes(0);
expect(sources[1].isRequiredInRoot).toHaveBeenCalledTimes(1); expect(sources[1].isRequiredInRoot).toHaveBeenCalledTimes(1);
@ -100,8 +100,8 @@ describe('A RoutingAuxiliaryStrategy', (): void => {
}); });
it('#validates using the correct validator.', async(): Promise<void> => { it('#validates using the correct validator.', async(): Promise<void> => {
sources[0].validate = jest.fn(); jest.spyOn(sources[0], 'validate').mockImplementation();
sources[1].validate = jest.fn(); jest.spyOn(sources[1], 'validate').mockImplementation();
let metadata = new RepresentationMetadata(dummy1Id); let metadata = new RepresentationMetadata(dummy1Id);
await expect(strategy.validate({ metadata } as any)).resolves.toBeUndefined(); await expect(strategy.validate({ metadata } as any)).resolves.toBeUndefined();

View File

@ -64,7 +64,7 @@ describe('A SparqlUpdateBodyParser', (): void => {
expect(result.binary).toBe(true); expect(result.binary).toBe(true);
expect(result.metadata).toBe(input.metadata); expect(result.metadata).toBe(input.metadata);
expect(await arrayifyStream(result.data)).toEqual( await expect(arrayifyStream(result.data)).resolves.toEqual(
[ 'DELETE DATA { <http://test.com/s> <http://test.com/p> <http://test.com/o> }' ], [ 'DELETE DATA { <http://test.com/s> <http://test.com/p> <http://test.com/o> }' ],
); );
}); });
@ -84,7 +84,7 @@ describe('A SparqlUpdateBodyParser', (): void => {
expect(result.binary).toBe(true); expect(result.binary).toBe(true);
expect(result.metadata).toBe(input.metadata); expect(result.metadata).toBe(input.metadata);
expect(await arrayifyStream(result.data)).toEqual( await expect(arrayifyStream(result.data)).resolves.toEqual(
[ 'INSERT DATA { <#it> <http://test.com/p> <http://test.com/o> }' ], [ 'INSERT DATA { <#it> <http://test.com/p> <http://test.com/o> }' ],
); );
}); });

View File

@ -9,11 +9,14 @@ describe('A DeleteOperationHandler', (): void => {
let operation: Operation; let operation: Operation;
const conditions: Conditions = { matchesMetadata: jest.fn() }; const conditions: Conditions = { matchesMetadata: jest.fn() };
const body = new BasicRepresentation(); const body = new BasicRepresentation();
const store = {} as unknown as ResourceStore; let store: jest.Mocked<ResourceStore>;
const handler = new DeleteOperationHandler(store); let handler: DeleteOperationHandler;
beforeEach(async(): Promise<void> => { beforeEach(async(): Promise<void> => {
operation = { method: 'DELETE', target: { path: 'http://test.com/foo' }, preferences: {}, conditions, body }; operation = { method: 'DELETE', target: { path: 'http://test.com/foo' }, preferences: {}, conditions, body };
store.deleteResource = jest.fn(async(): Promise<any> => undefined); store = {
deleteResource: jest.fn(async(): Promise<any> => undefined),
} as any satisfies ResourceStore;
handler = new DeleteOperationHandler(store);
}); });
it('only supports DELETE operations.', async(): Promise<void> => { it('only supports DELETE operations.', async(): Promise<void> => {

View File

@ -48,7 +48,7 @@ describe('BasicRepresentation', (): void => {
const data = [ 'my', 'data' ]; const data = [ 'my', 'data' ];
const metadata = new RepresentationMetadata(); const metadata = new RepresentationMetadata();
const representation = new BasicRepresentation(data, metadata); const representation = new BasicRepresentation(data, metadata);
expect(await arrayifyStream(representation.data)).toEqual(data); await expect(arrayifyStream(representation.data)).resolves.toEqual(data);
expect(representation.metadata).toBe(metadata); expect(representation.metadata).toBe(metadata);
expect(representation.binary).toBe(true); expect(representation.binary).toBe(true);
}); });
@ -57,7 +57,7 @@ describe('BasicRepresentation', (): void => {
const data = 'my data'; const data = 'my data';
const metadata = new RepresentationMetadata(); const metadata = new RepresentationMetadata();
const representation = new BasicRepresentation(data, metadata); const representation = new BasicRepresentation(data, metadata);
expect(await arrayifyStream(representation.data)).toEqual([ data ]); await expect(arrayifyStream(representation.data)).resolves.toEqual([ data ]);
expect(representation.metadata).toBe(metadata); expect(representation.metadata).toBe(metadata);
expect(representation.binary).toBe(true); expect(representation.binary).toBe(true);
}); });

View File

@ -303,7 +303,7 @@ describe('A RepresentationMetadata', (): void => {
it('errors if a shorthand has multiple values.', async(): Promise<void> => { it('errors if a shorthand has multiple values.', async(): Promise<void> => {
metadata.add(CONTENT_TYPE_TERM, 'a/b'); metadata.add(CONTENT_TYPE_TERM, 'a/b');
metadata.add(CONTENT_TYPE_TERM, 'c/d'); metadata.add(CONTENT_TYPE_TERM, 'c/d');
expect((): any => metadata.contentType).toThrow(); expect((): any => metadata.contentType).toThrow('Multiple results for http://www.w3.org/ns/ma-ont#format');
}); });
it('has a shorthand for Content-Type as string.', async(): Promise<void> => { it('has a shorthand for Content-Type as string.', async(): Promise<void> => {

View File

@ -18,7 +18,9 @@ describe('An AccountPromptFactory', (): void => {
beforeEach(async(): Promise<void> => { beforeEach(async(): Promise<void> => {
policy = [] as any; policy = [] as any;
// eslint-disable-next-line jest/prefer-spy-on
policy.add = jest.fn(); policy.add = jest.fn();
// eslint-disable-next-line jest/prefer-spy-on
policy.get = jest.fn().mockReturnValue(new Prompt({ name: 'login' })); policy.get = jest.fn().mockReturnValue(new Prompt({ name: 'login' }));
ctx = { ctx = {
@ -57,7 +59,7 @@ describe('An AccountPromptFactory', (): void => {
}); });
it('returns true if there is no cookie.', async(): Promise<void> => { it('returns true if there is no cookie.', async(): Promise<void> => {
ctx.cookies.get = jest.fn(); jest.spyOn(ctx.cookies, 'get').mockImplementation();
await expect(factory.handle(policy)).resolves.toBeUndefined(); await expect(factory.handle(policy)).resolves.toBeUndefined();
const prompt = policy.add.mock.calls[0][0]; const prompt = policy.add.mock.calls[0][0];
const check = prompt.checks[1]; const check = prompt.checks[1];
@ -66,7 +68,7 @@ describe('An AccountPromptFactory', (): void => {
it('returns true if there is no matching account.', async(): Promise<void> => { it('returns true if there is no matching account.', async(): Promise<void> => {
cookieStore.get.mockResolvedValueOnce(undefined); cookieStore.get.mockResolvedValueOnce(undefined);
ctx.cookies.get = jest.fn(); jest.spyOn(ctx.cookies, 'get').mockImplementation();
await expect(factory.handle(policy)).resolves.toBeUndefined(); await expect(factory.handle(policy)).resolves.toBeUndefined();
const prompt = policy.add.mock.calls[0][0]; const prompt = policy.add.mock.calls[0][0];
const check = prompt.checks[1]; const check = prompt.checks[1];

View File

@ -40,7 +40,7 @@ describe('A CachedJwkGenerator', (): void => {
}); });
const otherKey = (await generateKeyPair(alg)).publicKey; const otherKey = (await generateKeyPair(alg)).publicKey;
await expect(jwtVerify(signed, otherKey)).rejects.toThrow(); await expect(jwtVerify(signed, otherKey)).rejects.toThrow('signature verification failed');
}); });
it('caches the private key in memory.', async(): Promise<void> => { it('caches the private key in memory.', async(): Promise<void> => {

View File

@ -42,7 +42,7 @@ describe('An HtmlViewHandler', (): void => {
]; ];
templateEngine = { templateEngine = {
handleSafe: jest.fn().mockReturnValue(Promise.resolve('<html>')), handleSafe: jest.fn().mockResolvedValue('<html>'),
} as any; } as any;
handler = new HtmlViewHandler(index, templateEngine, templates); handler = new HtmlViewHandler(index, templateEngine, templates);

View File

@ -66,6 +66,7 @@ describe('A ConsentHandler', (): void => {
knownGrant = new DummyGrant({ accountId, clientId }); knownGrant = new DummyGrant({ accountId, clientId });
grantFn = jest.fn((props): DummyGrant => new DummyGrant(props)) as any; grantFn = jest.fn((props): DummyGrant => new DummyGrant(props)) as any;
// eslint-disable-next-line jest/prefer-spy-on
grantFn.find = jest.fn((grantId: string): any => grantId ? knownGrant : undefined); grantFn.find = jest.fn((grantId: string): any => grantId ? knownGrant : undefined);
provider = { provider = {
Grant: grantFn, Grant: grantFn,

View File

@ -2,6 +2,12 @@ import process from 'process';
import { BaseLogger, WrappingLogger } from '../../../src/logging/Logger'; import { BaseLogger, WrappingLogger } from '../../../src/logging/Logger';
import type { LogMetadata, SimpleLogger } from '../../../src/logging/Logger'; import type { LogMetadata, SimpleLogger } from '../../../src/logging/Logger';
class DummyLogger extends BaseLogger {
log(): this {
return this;
}
}
describe('Logger', (): void => { describe('Logger', (): void => {
describe('a BaseLogger', (): void => { describe('a BaseLogger', (): void => {
let logger: BaseLogger; let logger: BaseLogger;
@ -11,8 +17,8 @@ describe('Logger', (): void => {
}; };
beforeEach(async(): Promise<void> => { beforeEach(async(): Promise<void> => {
logger = new (BaseLogger as any)(); logger = new DummyLogger();
logger.log = jest.fn(); jest.spyOn(logger, 'log').mockImplementation();
}); });
it('delegates error to log.', async(): Promise<void> => { it('delegates error to log.', async(): Promise<void> => {

View File

@ -17,7 +17,8 @@ describe('WinstonLoggerFactory', (): void => {
// Create a dummy log transport // Create a dummy log transport
transport = new PassThrough({ objectMode: true }) as any; transport = new PassThrough({ objectMode: true }) as any;
transport.write = jest.fn(); jest.spyOn(transport, 'write').mockImplementation();
// eslint-disable-next-line jest/prefer-spy-on
transport.log = jest.fn(); transport.log = jest.fn();
}); });

View File

@ -149,7 +149,7 @@ describe('A BaseResourcesGenerator', (): void => {
it('does not create container when it already exists.', async(): Promise<void> => { it('does not create container when it already exists.', async(): Promise<void> => {
const meta = '<> <pre:has> "metadata".'; const meta = '<> <pre:has> "metadata".';
cache.data = { '.meta': meta }; cache.data = { '.meta': meta };
store.hasResource = jest.fn().mockResolvedValue(true); jest.spyOn(store, 'hasResource').mockResolvedValue(true);
const result = await asyncToArray(generator.generate(rootFilePath, location, { webId })); const result = await asyncToArray(generator.generate(rootFilePath, location, { webId }));
const identifiers = result.map((res): ResourceIdentifier => res.identifier); const identifiers = result.map((res): ResourceIdentifier => res.identifier);

View File

@ -59,7 +59,7 @@ describe('A QuotaStrategy', (): void => {
describe('createQuotaGuard()', (): void => { describe('createQuotaGuard()', (): void => {
it('should return a passthrough that destroys the stream when quota is exceeded.', async(): Promise<void> => { it('should return a passthrough that destroys the stream when quota is exceeded.', async(): Promise<void> => {
strategy.getAvailableSpace = jest.fn().mockReturnValue({ amount: 50, unit: mockSize.unit }); jest.spyOn(strategy, 'getAvailableSpace').mockResolvedValue({ amount: 50, unit: mockSize.unit });
const fiftyChars = 'A'.repeat(50); const fiftyChars = 'A'.repeat(50);
const stream = guardedStreamFrom(fiftyChars); const stream = guardedStreamFrom(fiftyChars);
const track = await strategy.createQuotaGuard({ path: `${base}nested/file2.txt` }); const track = await strategy.createQuotaGuard({ path: `${base}nested/file2.txt` });

View File

@ -34,9 +34,10 @@ describe('A WebSocketServerConfigurator', (): void => {
// Clearing the logger mock // Clearing the logger mock
jest.clearAllMocks(); jest.clearAllMocks();
server = new EventEmitter() as any; server = new EventEmitter() as any;
webSocket = new EventEmitter() as any; webSocket = {
webSocket.send = jest.fn(); send: jest.fn(),
webSocket.close = jest.fn(); close: jest.fn(),
} as any;
upgradeRequest = new EventEmitter() as any; upgradeRequest = new EventEmitter() as any;

View File

@ -222,7 +222,8 @@ describe('A StaticAssetHandler', (): void => {
it('does not handle a request to a known folder URL with parent path segments.', async(): Promise<void> => { it('does not handle a request to a known folder URL with parent path segments.', async(): Promise<void> => {
const request = { method: 'GET', url: '/foo/bar/folder/../def.css' }; const request = { method: 'GET', url: '/foo/bar/folder/../def.css' };
const response = createResponse({ eventEmitter: EventEmitter }); const response = createResponse({ eventEmitter: EventEmitter });
await expect(handler.canHandle({ request, response } as any)).rejects.toThrow(); await expect(handler.canHandle({ request, response } as any))
.rejects.toThrow('No static resource configured at /foo/bar/folder/../def.css');
}); });
it('caches responses when the expires option is set.', async(): Promise<void> => { it('caches responses when the expires option is set.', async(): Promise<void> => {

View File

@ -1,4 +1,3 @@
import { EventEmitter } from 'events';
import type { WebSocket } from 'ws'; import type { WebSocket } from 'ws';
import { BasicRepresentation } from '../../../../../src/http/representation/BasicRepresentation'; import { BasicRepresentation } from '../../../../../src/http/representation/BasicRepresentation';
import type { NotificationChannel } from '../../../../../src/server/notifications/NotificationChannel'; import type { NotificationChannel } from '../../../../../src/server/notifications/NotificationChannel';
@ -20,9 +19,10 @@ describe('A WebSocket2023Emitter', (): void => {
let emitter: WebSocket2023Emitter; let emitter: WebSocket2023Emitter;
beforeEach(async(): Promise<void> => { beforeEach(async(): Promise<void> => {
webSocket = new EventEmitter() as any; webSocket = {
webSocket.send = jest.fn(); send: jest.fn(),
webSocket.close = jest.fn(); close: jest.fn(),
} as any;
socketMap = new WrappedSetMultiMap(); socketMap = new WrappedSetMultiMap();
@ -46,8 +46,9 @@ describe('A WebSocket2023Emitter', (): void => {
}); });
it('can send to multiple matching WebSockets.', async(): Promise<void> => { it('can send to multiple matching WebSockets.', async(): Promise<void> => {
const webSocket2: jest.Mocked<WebSocket> = new EventEmitter() as any; const webSocket2: jest.Mocked<WebSocket> = {
webSocket2.send = jest.fn(); send: jest.fn(),
} as any;
socketMap.add(channel.id, webSocket); socketMap.add(channel.id, webSocket);
socketMap.add(channel.id, webSocket2); socketMap.add(channel.id, webSocket2);
@ -61,8 +62,9 @@ describe('A WebSocket2023Emitter', (): void => {
}); });
it('only sends to the matching WebSockets.', async(): Promise<void> => { it('only sends to the matching WebSockets.', async(): Promise<void> => {
const webSocket2: jest.Mocked<WebSocket> = new EventEmitter() as any; const webSocket2: jest.Mocked<WebSocket> = {
webSocket2.send = jest.fn(); send: jest.fn(),
} as any;
const channel2: NotificationChannel = { const channel2: NotificationChannel = {
...channel, ...channel,
id: 'other', id: 'other',

View File

@ -1,4 +1,3 @@
import { EventEmitter } from 'events';
import type { WebSocket } from 'ws'; import type { WebSocket } from 'ws';
import type { HttpRequest } from '../../../../../src/server/HttpRequest'; import type { HttpRequest } from '../../../../../src/server/HttpRequest';
@ -36,9 +35,10 @@ describe('A WebSocket2023Listener', (): void => {
let listener: WebSocket2023Listener; let listener: WebSocket2023Listener;
beforeEach(async(): Promise<void> => { beforeEach(async(): Promise<void> => {
webSocket = new EventEmitter() as any; webSocket = {
webSocket.send = jest.fn(); send: jest.fn(),
webSocket.close = jest.fn(); close: jest.fn(),
} as any;
upgradeRequest = { url: `/foo/123456` } as any; upgradeRequest = { url: `/foo/123456` } as any;

View File

@ -12,6 +12,7 @@ import type { SetMultiMap } from '../../../../../src/util/map/SetMultiMap';
import { WrappedSetMultiMap } from '../../../../../src/util/map/WrappedSetMultiMap'; import { WrappedSetMultiMap } from '../../../../../src/util/map/WrappedSetMultiMap';
import { flushPromises } from '../../../../util/Util'; import { flushPromises } from '../../../../util/Util';
/* eslint-disable jest/prefer-spy-on */
describe('A WebSocket2023Storer', (): void => { describe('A WebSocket2023Storer', (): void => {
const channel: NotificationChannel = { const channel: NotificationChannel = {
id: 'id', id: 'id',

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> => { 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 }]}})) await expect(store.getRepresentation(identifier, { range: { unit: 'bytes', parts: [{ start: -5 }]}}))
.rejects.toThrow(RangeNotSatisfiedHttpError); .rejects.toThrow(RangeNotSatisfiedHttpError);
expect(representation.data.destroy).toHaveBeenCalledTimes(1); expect(representation.data.destroy).toHaveBeenCalledTimes(1);

View File

@ -147,7 +147,7 @@ describe('A DataAccessorBasedStore', (): void => {
accessor.data[resourceID.path] = representation; accessor.data[resourceID.path] = representation;
const result = await store.getRepresentation(resourceID); const result = await store.getRepresentation(resourceID);
expect(result).toMatchObject({ binary: true }); 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.contentType).toBe('text/plain');
expect(result.metadata.get(namedNode('AUXILIARY'))?.value) expect(result.metadata.get(namedNode('AUXILIARY'))?.value)
.toBe(auxiliaryStrategy.getAuxiliaryIdentifier(resourceID).path); .toBe(auxiliaryStrategy.getAuxiliaryIdentifier(resourceID).path);
@ -163,7 +163,7 @@ describe('A DataAccessorBasedStore', (): void => {
await auxiliaryStrategy.addMetadata(metaMirror); await auxiliaryStrategy.addMetadata(metaMirror);
const result = await store.getRepresentation(resourceID); const result = await store.getRepresentation(resourceID);
expect(result).toMatchObject({ binary: false }); 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.contentType).toEqual(INTERNAL_QUADS);
expect(result.metadata.get(namedNode('AUXILIARY'))?.value) expect(result.metadata.get(namedNode('AUXILIARY'))?.value)
.toBe(auxiliaryStrategy.getAuxiliaryIdentifier(resourceID).path); .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> => { it('errors when trying to create an auxiliary resource with invalid data.', async(): Promise<void> => {
const resourceID = { path: `${root}resource.dummy` }; 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!'); 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> => { 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'); throw new Error('error');
}); });
@ -738,7 +738,7 @@ describe('A DataAccessorBasedStore', (): void => {
storageMetadata.add(RDF.terms.type, PIM.terms.Storage); storageMetadata.add(RDF.terms.type, PIM.terms.Storage);
accessor.data[`${root}container/`] = new BasicRepresentation(representation.data, storageMetadata); accessor.data[`${root}container/`] = new BasicRepresentation(representation.data, storageMetadata);
accessor.data[`${root}container/.dummy`] = representation; 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` }); const result = store.deleteResource({ path: `${root}container/.dummy` });
await expect(result).rejects.toThrow(MethodNotAllowedHttpError); await expect(result).rejects.toThrow(MethodNotAllowedHttpError);
await expect(result).rejects.toThrow( await expect(result).rejects.toThrow(
@ -787,7 +787,7 @@ describe('A DataAccessorBasedStore', (): void => {
const storageMetadata = new RepresentationMetadata(representation.metadata); const storageMetadata = new RepresentationMetadata(representation.metadata);
accessor.data[resourceID.path] = new BasicRepresentation(representation.data, storageMetadata); accessor.data[resourceID.path] = new BasicRepresentation(representation.data, storageMetadata);
accessor.data[auxResourceID.path] = representation; accessor.data[auxResourceID.path] = representation;
auxiliaryStrategy.isRequiredInRoot = jest.fn().mockReturnValue(true); jest.spyOn(auxiliaryStrategy, 'isRequiredInRoot').mockReturnValue(true);
const result = await store.deleteResource(auxResourceID); const result = await store.deleteResource(auxResourceID);
expect(result.size).toBe(2); expect(result.size).toBe(2);
expect(result.get(resourceID)?.get(SOLID_AS.terms.activity)).toEqual(AS.terms.Remove); 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[resourceID.path] = representation;
accessor.data[auxResourceID.path] = representation; accessor.data[auxResourceID.path] = representation;
const deleteFn = accessor.deleteResource; const deleteFn = accessor.deleteResource;
accessor.deleteResource = jest.fn(async(identifier: ResourceIdentifier): Promise<void> => { jest.spyOn(accessor, 'deleteResource')
if (auxiliaryStrategy.isAuxiliaryIdentifier(identifier)) { .mockImplementation(async(identifier: ResourceIdentifier): Promise<void> => {
throw new Error('auxiliary error!'); if (auxiliaryStrategy.isAuxiliaryIdentifier(identifier)) {
} throw new Error('auxiliary error!');
await deleteFn.call(accessor, identifier); }
}); await deleteFn.call(accessor, identifier);
});
const { logger } = store as any; const { logger } = store as any;
logger.error = jest.fn(); jest.spyOn(logger, 'error').mockImplementation();
const result = await store.deleteResource(resourceID); const result = await store.deleteResource(resourceID);
expect(result.size).toBe(2); expect(result.size).toBe(2);
expect(result.get({ path: root })?.get(SOLID_AS.terms.activity)).toEqual(AS.terms.Remove); 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> => { it('should rethrow any unexpected errors from validateIdentifier.', async(): Promise<void> => {
const resourceID = { path: `${root}resource` }; const resourceID = { path: `${root}resource` };
const originalMetaData = accessor.getMetadata; const originalMetaData = accessor.getMetadata;
accessor.getMetadata = jest.fn(async(): Promise<any> => { jest.spyOn(accessor, 'getMetadata').mockImplementation(async(): Promise<any> => {
throw new Error('error'); throw new Error('error');
}); });
await expect(store.hasResource(resourceID)).rejects.toThrow('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 readable = guardedStreamFrom([ 1, 2, 3 ]);
const { destroy } = readable; 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 = { source = {
getRepresentation: jest.fn((): any => addOrder('getRepresentation', { data: readable } as Representation)), getRepresentation: jest.fn((): any => addOrder('getRepresentation', { data: readable } as Representation)),
addResource: jest.fn((): any => addOrder('addResource')), 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> => { 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'); order.push('useless get');
// This will never resolve // This will never resolve
return new Promise(emptyFn); 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> => { 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' }) ], [{ 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> => { 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(); throw new NotImplementedHttpError();
}); });
await expect(store.modifyResource({ path: 'modifyPath' }, {} as Patch)).resolves.toBe('patcher'); 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> => { 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'); throw new Error('dummy');
}); });
await expect(store.modifyResource({ path: 'modifyPath' }, {} as Patch)).rejects.toThrow('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> => { 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')); data.emit('error', new Error('error'));
return null; return null;
}); });
jest.requireMock('fs-extra').stat = jest.fn((): any => ({ jest.spyOn(jest.requireMock('fs-extra'), 'stat').mockImplementation((): any => ({
isFile: (): boolean => false, isFile: (): boolean => false,
})); }));
await expect(accessor.writeDocument({ path: `${base}res.ttl` }, data, metadata)).rejects.toThrow('error'); 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> => { 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'); throw new Error('error');
}); });
jest.requireMock('fs-extra').stat = jest.fn((): any => ({ jest.spyOn(jest.requireMock('fs-extra'), 'stat').mockImplementation((): any => ({
isFile: (): boolean => true, isFile: (): boolean => true,
})); }));
await expect(accessor.writeDocument({ path: `${base}res.ttl` }, data, metadata)).rejects.toThrow('error'); 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> => { 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'); throw new Error('error');
}); });
jest.requireMock('fs-extra').stat = jest.fn((): any => ({ jest.spyOn(jest.requireMock('fs-extra'), 'stat').mockImplementation((): any => ({
isFile: (): boolean => false, isFile: (): boolean => false,
})); }));
await expect(accessor.writeDocument({ path: `${base}res.ttl` }, data, metadata)).rejects.toThrow('error'); 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.', it('should throw when renaming / moving the file goes wrong and the temp file does not exist.',
async(): Promise<void> => { async(): Promise<void> => {
jest.requireMock('fs-extra').rename = jest.fn((): any => { jest.spyOn(jest.requireMock('fs-extra'), 'rename').mockImplementation((): any => {
throw new Error('error'); 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'); 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> => { it('throws an error if there is a problem with the internal metadata.', async(): Promise<void> => {
cache.data = { resource: 'data', 'resource.meta': 'invalid metadata!.' }; 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 => { jest.requireMock('fs-extra').remove = (): any => {
throw new Error('error'); 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> => { it('removes the corresponding folder for containers.', async(): Promise<void> => {

View File

@ -13,10 +13,10 @@ describe('FilterMetadataDataAccessor', (): void => {
beforeEach(async(): Promise<void> => { beforeEach(async(): Promise<void> => {
jest.clearAllMocks(); jest.clearAllMocks();
childAccessor = { childAccessor = {
getChildren: jest.fn(),
writeDocument: jest.fn(), writeDocument: jest.fn(),
writeContainer: jest.fn(), writeContainer: jest.fn(),
} as any; } as any;
childAccessor.getChildren = jest.fn();
}); });
it('removes only the matching metadata properties when calling writeDocument.', async(): Promise<void> => { 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` })) await expect(accessor.getMetadata({ path: `${base}container/resource` }))
.resolves.toBeInstanceOf(RepresentationMetadata); .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> => { 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` })) await expect(accessor.getMetadata({ path: `${base}resource` }))
.resolves.toBeInstanceOf(RepresentationMetadata); .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> => { it('errors when writing to an invalid container path.', async(): Promise<void> => {

View File

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

View File

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

View File

@ -114,7 +114,7 @@ describe('A ConstantConverter', (): void => {
expect(createReadStream).toHaveBeenCalledWith('abc/def/index.html', 'utf8'); expect(createReadStream).toHaveBeenCalledWith('abc/def/index.html', 'utf8');
expect(converted.metadata.contentType).toBe('text/html'); 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> => { it('defaults to the most permissive options.', async(): Promise<void> => {

View File

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

View File

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

View File

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

View File

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

View File

@ -136,15 +136,16 @@ describe('A ImmutableMetadataPatcher', (): void => {
handler = new ImmutableMetadataPatcher(patcher, metaStrategy, [ handler = new ImmutableMetadataPatcher(patcher, metaStrategy, [
new FilterPattern(undefined, `${base}p`, `${base}o`), new FilterPattern(undefined, `${base}p`, `${base}o`),
]); ]);
patcher.handle = jest.fn(async(patcherInput: RepresentationPatcherInput<RdfDatasetRepresentation>): jest.spyOn(patcher, 'handle').mockImplementation(
Promise<RdfDatasetRepresentation> => { async(patcherInput: RepresentationPatcherInput<RdfDatasetRepresentation>): Promise<RdfDatasetRepresentation> => {
const patcherStore = new Store([ const patcherStore = new Store([
quad(namedNode(`${base}a`), namedNode(`${base}p`), namedNode(`${base}c`)), quad(namedNode(`${base}a`), namedNode(`${base}p`), namedNode(`${base}c`)),
quad(namedNode(`${base}a`), namedNode(`${base}b`), namedNode(`${base}o`)), quad(namedNode(`${base}a`), namedNode(`${base}b`), namedNode(`${base}o`)),
]); ]);
patcherInput.representation!.dataset = patcherStore; patcherInput.representation!.dataset = patcherStore;
return patcherInput.representation!; return patcherInput.representation!;
}); },
);
const result = await handler.handleSafe(input); const result = await handler.handleSafe(input);
expect(result.dataset).toBeRdfIsomorphic([ expect(result.dataset).toBeRdfIsomorphic([
@ -157,14 +158,15 @@ describe('A ImmutableMetadataPatcher', (): void => {
it('rejects patches that replaces immutable triples.', async(): Promise<void> => { it('rejects patches that replaces immutable triples.', async(): Promise<void> => {
input.representation!.dataset.addQuad(namedNode(identifier.path), namedNode(`${base}p`), namedNode(`${base}o1`)); input.representation!.dataset.addQuad(namedNode(identifier.path), namedNode(`${base}p`), namedNode(`${base}o1`));
patcher.handle = jest.fn(async(patcherInput: RepresentationPatcherInput<RdfDatasetRepresentation>): jest.spyOn(patcher, 'handle').mockImplementation(
Promise<RdfDatasetRepresentation> => { async(patcherInput: RepresentationPatcherInput<RdfDatasetRepresentation>): Promise<RdfDatasetRepresentation> => {
const patcherStore = new Store([ const patcherStore = new Store([
quad(namedNode(identifier.path), namedNode(`${base}p`), namedNode(`${base}o2`)), quad(namedNode(identifier.path), namedNode(`${base}p`), namedNode(`${base}o2`)),
]); ]);
patcherInput.representation!.dataset = patcherStore; patcherInput.representation!.dataset = patcherStore;
return patcherInput.representation!; return patcherInput.representation!;
}); },
);
handler = new ImmutableMetadataPatcher(patcher, metaStrategy, [ handler = new ImmutableMetadataPatcher(patcher, metaStrategy, [
new FilterPattern(`${base}foo`, `${base}p`), 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'; import { InternalServerError } from '../../../../src/util/errors/InternalServerError';
describe('A ConvertingRouterRule', (): void => { describe('A ConvertingRouterRule', (): void => {
let store1: ResourceStore; let store1: jest.Mocked<ResourceStore>;
let store2: ResourceStore; let store2: jest.Mocked<ResourceStore>;
let defaultStore: ResourceStore; let defaultStore: ResourceStore;
let checker1: PreferenceSupport; let checker1: PreferenceSupport;
let checker2: PreferenceSupport; let checker2: PreferenceSupport;
@ -16,8 +16,14 @@ describe('A ConvertingRouterRule', (): void => {
let metadata: RepresentationMetadata; let metadata: RepresentationMetadata;
beforeEach(async(): Promise<void> => { beforeEach(async(): Promise<void> => {
store1 = { name: 'turtleStore' } as any; store1 = {
store2 = { name: 'textStore' } as any; name: 'turtleStore',
hasResource: jest.fn(),
} as any satisfies ResourceStore;
store2 = {
name: 'textStore',
hasResource: jest.fn(),
} as any satisfies ResourceStore;
defaultStore = { name: 'defaultStore' } as any; defaultStore = { name: 'defaultStore' } as any;
checker1 = { 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> => { 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); await expect(rule.handle({ identifier: { path: 'identifier' }})).resolves.toBe(store1);
expect(store1.hasResource).toHaveBeenCalledTimes(1); expect(store1.hasResource).toHaveBeenCalledTimes(1);
}); });
it('returns the defaultStore if no other store has the resource.', async(): Promise<void> => { it('returns the defaultStore if no other store has the resource.', async(): Promise<void> => {
store1.hasResource = jest.fn().mockImplementationOnce((): any => false); store1.hasResource.mockImplementationOnce((): any => false);
store2.hasResource = jest.fn().mockImplementationOnce((): any => false); store2.hasResource.mockImplementationOnce((): any => false);
await expect(rule.handle({ identifier: { path: 'identifier' }})).resolves.toBe(defaultStore); 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> => { 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); 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> => { 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(); throw new BadRequestHttpError();
}); });
await expect(support.supports({ identifier, representation })).resolves.toBe(false); await expect(support.supports({ identifier, representation })).resolves.toBe(false);

View File

@ -249,7 +249,7 @@ describe('PathUtil', (): void => {
// Note that this test only makes sense as long as the dist folder is on the same level as the src folder // Note that this test only makes sense as long as the dist folder is on the same level as the src folder
const root = getModuleRoot(); const root = getModuleRoot();
const packageJson = joinFilePath(root, 'package.json'); const packageJson = joinFilePath(root, 'package.json');
expect(await fsPromises.access(packageJson)).toBeUndefined(); await expect(fsPromises.access(packageJson)).resolves.toBeUndefined();
}); });
}); });

View File

@ -21,7 +21,7 @@ describe('HandlerUtil', (): void => {
}); });
it('supports non-native Errors.', async(): Promise<void> => { it('supports non-native Errors.', async(): Promise<void> => {
handlerFalse.canHandle = jest.fn().mockRejectedValue('apple'); jest.spyOn(handlerFalse, 'canHandle').mockRejectedValue('apple');
await expect(findHandler([ handlerFalse ], null)).rejects.toThrow('Unknown error: apple'); await expect(findHandler([ handlerFalse ], null)).rejects.toThrow('Unknown error: apple');
}); });
}); });

View File

@ -125,7 +125,7 @@ describe('A FileSystemResourceLocker', (): void => {
it('stops proper-lock from throwing errors after finalize was called.', async(): Promise<void> => { it('stops proper-lock from throwing errors after finalize was called.', async(): Promise<void> => {
// Tests should never access private fields so we need to change this after splitting the test as mentioned above. // Tests should never access private fields so we need to change this after splitting the test as mentioned above.
// Once we have a mock we can check which parameters `unlock` was called with and extract the function from there. // Once we have a mock we can check which parameters `unlock` was called with and extract the function from there.
expect((): void => (locker as any).customOnCompromised(new Error('test'))).toThrow(); expect((): void => (locker as any).customOnCompromised(new Error('test'))).toThrow('test');
await locker.finalize(); await locker.finalize();
expect((locker as any).customOnCompromised(new Error('test'))).toBeUndefined(); expect((locker as any).customOnCompromised(new Error('test'))).toBeUndefined();
}); });

View File

@ -36,7 +36,7 @@ describe('A GreedyReadWriteLocker', (): void => {
}); });
it('errors if the read counter has an unexpected value.', async(): Promise<void> => { it('errors if the read counter has an unexpected value.', async(): Promise<void> => {
storage.get = jest.fn().mockResolvedValue(0); jest.spyOn(storage, 'get').mockResolvedValue(0);
await expect(locker.withReadLock(resourceId, (): number => 5)).rejects.toThrow(InternalServerError); await expect(locker.withReadLock(resourceId, (): number => 5)).rejects.toThrow(InternalServerError);
}); });
}); });