diff --git a/eslint.config.js b/eslint.config.js index 9b7a070a7..510288033 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -210,17 +210,11 @@ module.exports = antfu( // Default rules that are overkill 'jest/no-hooks': 'off', 'jest/max-expects': 'off', + 'jest/no-conditional-in-test': 'off', 'jest/prefer-expect-assertions': 'off', 'jest/prefer-lowercase-title': '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-to-throw-message': 'off', 'ts/naming-convention': 'off', 'ts/no-unsafe-argument': 'off', diff --git a/test/integration/Conditions.test.ts b/test/integration/Conditions.test.ts index ef4296a1a..a6db6e9e6 100644 --- a/test/integration/Conditions.test.ts +++ b/test/integration/Conditions.test.ts @@ -76,7 +76,7 @@ describe.each(stores)('A server supporting conditions with %s', (name, { storeCo await expect(response.text()).resolves.toBe('TESTFILE'); // DELETE - expect(await deleteResource(documentUrl)).toBeUndefined(); + await expect(deleteResource(documentUrl)).resolves.toBeUndefined(); }); it('prevents creating new resources with "if-match: *" header.', async(): Promise => { @@ -112,7 +112,7 @@ describe.each(stores)('A server supporting conditions with %s', (name, { storeCo await expectQuads(response, expected, true); // 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 => { @@ -140,7 +140,7 @@ describe.each(stores)('A server supporting conditions with %s', (name, { storeCo expect(typeof documentUrl).toBe('string'); // 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 => { @@ -168,7 +168,7 @@ describe.each(stores)('A server supporting conditions with %s', (name, { storeCo expect(typeof documentUrl).toBe('string'); // 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 => { diff --git a/test/integration/GuardedStream.test.ts b/test/integration/GuardedStream.test.ts index fd47b545e..ac586e65b 100644 --- a/test/integration/GuardedStream.test.ts +++ b/test/integration/GuardedStream.test.ts @@ -45,7 +45,7 @@ describe('A chained converter where data gets ignored', (): void => { jest.useFakeTimers(); 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); expect(logger.error).toHaveBeenCalledTimes(1); diff --git a/test/integration/LdpHandlerWithAuth.test.ts b/test/integration/LdpHandlerWithAuth.test.ts index bfd730e80..c4f643813 100644 --- a/test/integration/LdpHandlerWithAuth.test.ts +++ b/test/integration/LdpHandlerWithAuth.test.ts @@ -232,7 +232,7 @@ describe.each(stores)('An LDP handler with auth using %s', (name, { storeConfig, // GET file 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 => { diff --git a/test/integration/LdpHandlerWithoutAuth.test.ts b/test/integration/LdpHandlerWithoutAuth.test.ts index 3009ad524..d9e3f84f2 100644 --- a/test/integration/LdpHandlerWithoutAuth.test.ts +++ b/test/integration/LdpHandlerWithoutAuth.test.ts @@ -107,7 +107,7 @@ describe.each(stores)('An LDP handler allowing all requests %s', (name, { storeC await expect(response.text()).resolves.toBe('TESTFILE0'); // DELETE - expect(await deleteResource(documentUrl)).toBeUndefined(); + await expect(deleteResource(documentUrl)).resolves.toBeUndefined(); }); it('can add and overwrite a document.', async(): Promise => { @@ -127,7 +127,7 @@ describe.each(stores)('An LDP handler allowing all requests %s', (name, { storeC await expect(response.text()).resolves.toBe('TESTFILE1'); // DELETE - expect(await deleteResource(documentUrl)).toBeUndefined(); + await expect(deleteResource(documentUrl)).resolves.toBeUndefined(); }); it('can create a container and delete it.', async(): Promise => { @@ -144,7 +144,7 @@ describe.each(stores)('An LDP handler allowing all requests %s', (name, { storeC ]); // DELETE - expect(await deleteResource(containerUrl)).toBeUndefined(); + await expect(deleteResource(containerUrl)).resolves.toBeUndefined(); }); it('can create a container and retrieve it.', async(): Promise => { @@ -157,7 +157,7 @@ describe.each(stores)('An LDP handler allowing all requests %s', (name, { storeC await expect(response.text()).resolves.toContain('ldp:BasicContainer'); // DELETE - expect(await deleteResource(containerUrl)).toBeUndefined(); + await expect(deleteResource(containerUrl)).resolves.toBeUndefined(); }); it('can create a container and view it as HTML.', async(): Promise => { @@ -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'); // 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 => { @@ -187,8 +187,8 @@ describe.each(stores)('An LDP handler allowing all requests %s', (name, { storeC await expect(response.text()).resolves.toBe('TESTFILE0'); // DELETE - expect(await deleteResource(documentUrl)).toBeUndefined(); - expect(await deleteResource(containerUrl)).toBeUndefined(); + await expect(deleteResource(documentUrl)).resolves.toBeUndefined(); + await expect(deleteResource(containerUrl)).resolves.toBeUndefined(); }); it('can create a container without content-type.', async(): Promise => { @@ -212,8 +212,8 @@ describe.each(stores)('An LDP handler allowing all requests %s', (name, { storeC expect(postResponse.headers.get('location')).toBe(baseUrl + slug); // DELETE - expect(await deleteResource(containerUrl)).toBeUndefined(); - expect(await deleteResource(baseUrl + slug)).toBeUndefined(); + await expect(deleteResource(containerUrl)).resolves.toBeUndefined(); + await expect(deleteResource(baseUrl + slug)).resolves.toBeUndefined(); }); it('cannot remove a container when the container contains a document.', async(): Promise => { // 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.'); // DELETE - expect(await deleteResource(documentUrl)).toBeUndefined(); - expect(await deleteResource(containerUrl)).toBeUndefined(); + await expect(deleteResource(documentUrl)).resolves.toBeUndefined(); + await expect(deleteResource(containerUrl)).resolves.toBeUndefined(); }); it('cannot remove a container when the container contains a subfolder.', async(): Promise => { @@ -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.'); // DELETE - expect(await deleteResource(subContainerUrl)).toBeUndefined(); - expect(await deleteResource(containerUrl)).toBeUndefined(); + await expect(deleteResource(subContainerUrl)).resolves.toBeUndefined(); + await expect(deleteResource(containerUrl)).resolves.toBeUndefined(); }); it('can read the contents of a container.', async(): Promise => { @@ -273,9 +273,9 @@ describe.each(stores)('An LDP handler allowing all requests %s', (name, { storeC ]); // DELETE - expect(await deleteResource(documentUrl)).toBeUndefined(); - expect(await deleteResource(subContainerUrl)).toBeUndefined(); - expect(await deleteResource(containerUrl)).toBeUndefined(); + await expect(deleteResource(documentUrl)).resolves.toBeUndefined(); + await expect(deleteResource(subContainerUrl)).resolves.toBeUndefined(); + await expect(deleteResource(containerUrl)).resolves.toBeUndefined(); }); it('can upload and delete an image.', async(): Promise => { @@ -295,7 +295,7 @@ describe.each(stores)('An LDP handler allowing all requests %s', (name, { storeC await getResource(documentUrl, {}, { contentType: 'image/png' }); // 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 => { @@ -314,7 +314,7 @@ describe.each(stores)('An LDP handler allowing all requests %s', (name, { storeC ]); // DELETE - expect(await deleteResource(containerUrl)).toBeUndefined(); + await expect(deleteResource(containerUrl)).resolves.toBeUndefined(); }); // 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); // DELETE - expect(await deleteResource(documentUrl)).toBeUndefined(); + await expect(deleteResource(documentUrl)).resolves.toBeUndefined(); }); it('can handle simple SPARQL updates.', async(): Promise => { @@ -382,7 +382,7 @@ describe.each(stores)('An LDP handler allowing all requests %s', (name, { storeC await expectQuads(response, expected, true); // DELETE - expect(await deleteResource(documentUrl)).toBeUndefined(); + await expect(deleteResource(documentUrl)).resolves.toBeUndefined(); }); it('can handle simple N3 Patch updates.', async(): Promise => { @@ -433,7 +433,7 @@ describe.each(stores)('An LDP handler allowing all requests %s', (name, { storeC await expectQuads(response, expected, true); // DELETE - expect(await deleteResource(documentUrl)).toBeUndefined(); + await expect(deleteResource(documentUrl)).resolves.toBeUndefined(); }); it('can not handle SPARQL updates on containers.', async(): Promise => { @@ -460,7 +460,7 @@ describe.each(stores)('An LDP handler allowing all requests %s', (name, { storeC expect(response.status).toBe(409); // DELETE - expect(await deleteResource(documentUrl)).toBeUndefined(); + await expect(deleteResource(documentUrl)).resolves.toBeUndefined(); }); it('can not handle N3 Patch updates on containers.', async(): Promise => { @@ -488,7 +488,7 @@ describe.each(stores)('An LDP handler allowing all requests %s', (name, { storeC expect(response.status).toBe(409); // DELETE - expect(await deleteResource(documentUrl)).toBeUndefined(); + await expect(deleteResource(documentUrl)).resolves.toBeUndefined(); }); it('returns 405 for unsupported methods.', async(): Promise => { @@ -564,7 +564,7 @@ describe.each(stores)('An LDP handler allowing all requests %s', (name, { storeC expect(quads).toHaveLength(3); // DELETE - expect(await deleteResource(documentUrl)).toBeUndefined(); + await expect(deleteResource(documentUrl)).resolves.toBeUndefined(); }); it('can not delete metadata resources directly.', async(): Promise => { @@ -578,7 +578,7 @@ describe.each(stores)('An LDP handler allowing all requests %s', (name, { storeC expect(response.status).toBe(409); // DELETE - expect(await deleteResource(documentUrl)).toBeUndefined(); + await expect(deleteResource(documentUrl)).resolves.toBeUndefined(); }); it('can not create metadata directly.', async(): Promise => { @@ -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`)) ]); // DELETE - expect(await deleteResource(documentUrl)).toBeUndefined(); + await expect(deleteResource(documentUrl)).resolves.toBeUndefined(); }); it('can not update metadata triples that are deemed immutable.', async(): Promise => { @@ -656,7 +656,7 @@ describe.each(stores)('An LDP handler allowing all requests %s', (name, { storeC expect(ldpResponse.status).toBe(409); // DELETE - expect(await deleteResource(containerUrl)).toBeUndefined(); + await expect(deleteResource(containerUrl)).resolves.toBeUndefined(); }); it('can not create metadata resource of a metadata resource.', async(): Promise => { diff --git a/test/integration/RedisLocker.test.ts b/test/integration/RedisLocker.test.ts index c3067ef80..baa4db5f3 100644 --- a/test/integration/RedisLocker.test.ts +++ b/test/integration/RedisLocker.test.ts @@ -223,6 +223,7 @@ describeIf('docker')('A server with a RedisLocker', (): void => { await expect(locker.withWriteLock(identifier, (): void => { res += 'l1'; res += 'r1'; + // eslint-disable-next-line jest/require-to-throw-message })).rejects.toThrow(); res += 'r0'; })).resolves.toBeUndefined(); diff --git a/test/unit/http/auxiliary/RdfValidator.test.ts b/test/unit/http/auxiliary/RdfValidator.test.ts index 4d5062018..55c9cde3c 100644 --- a/test/unit/http/auxiliary/RdfValidator.test.ts +++ b/test/unit/http/auxiliary/RdfValidator.test.ts @@ -26,7 +26,7 @@ describe('An RdfValidator', (): void => { }); it('validates data by running it through a converter.', async(): Promise => { - 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 quads = representation.metadata.quads(); // 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 => { - 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'); await expect(validator.handle({ representation, identifier })).rejects.toThrow('bad data!'); // Make sure the data on the readable has not been reset diff --git a/test/unit/http/auxiliary/RoutingAuxiliaryStrategy.test.ts b/test/unit/http/auxiliary/RoutingAuxiliaryStrategy.test.ts index 3d3050cb7..60498871b 100644 --- a/test/unit/http/auxiliary/RoutingAuxiliaryStrategy.test.ts +++ b/test/unit/http/auxiliary/RoutingAuxiliaryStrategy.test.ts @@ -61,8 +61,8 @@ describe('A RoutingAuxiliaryStrategy', (): void => { }); it('#addMetadata adds the metadata of all sources for the base identifier.', async(): Promise => { - sources[0].addMetadata = jest.fn(); - sources[1].addMetadata = jest.fn(); + jest.spyOn(sources[0], 'addMetadata').mockImplementation(); + jest.spyOn(sources[1], 'addMetadata').mockImplementation(); const metadata = new RepresentationMetadata(baseId); await expect(strategy.addMetadata(metadata)).resolves.toBeUndefined(); 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 => { - sources[0].addMetadata = jest.fn(); - sources[1].addMetadata = jest.fn(); + jest.spyOn(sources[0], 'addMetadata').mockImplementation(); + jest.spyOn(sources[1], 'addMetadata').mockImplementation(); const metadata = new RepresentationMetadata(dummy2Id); await expect(strategy.addMetadata(metadata)).resolves.toBeUndefined(); 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 => { - sources[0].usesOwnAuthorization = jest.fn(); - sources[1].usesOwnAuthorization = jest.fn(); + jest.spyOn(sources[0], 'usesOwnAuthorization').mockImplementation(); + jest.spyOn(sources[1], 'usesOwnAuthorization').mockImplementation(); strategy.usesOwnAuthorization(dummy2Id); expect(sources[0].usesOwnAuthorization).toHaveBeenCalledTimes(0); 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 => { - sources[0].isRequiredInRoot = jest.fn(); - sources[1].isRequiredInRoot = jest.fn(); + jest.spyOn(sources[0], 'isRequiredInRoot').mockImplementation(); + jest.spyOn(sources[1], 'isRequiredInRoot').mockImplementation(); strategy.isRequiredInRoot(dummy2Id); expect(sources[0].isRequiredInRoot).toHaveBeenCalledTimes(0); expect(sources[1].isRequiredInRoot).toHaveBeenCalledTimes(1); @@ -100,8 +100,8 @@ describe('A RoutingAuxiliaryStrategy', (): void => { }); it('#validates using the correct validator.', async(): Promise => { - sources[0].validate = jest.fn(); - sources[1].validate = jest.fn(); + jest.spyOn(sources[0], 'validate').mockImplementation(); + jest.spyOn(sources[1], 'validate').mockImplementation(); let metadata = new RepresentationMetadata(dummy1Id); await expect(strategy.validate({ metadata } as any)).resolves.toBeUndefined(); diff --git a/test/unit/http/input/body/SparqlUpdateBodyParser.test.ts b/test/unit/http/input/body/SparqlUpdateBodyParser.test.ts index 4158c5ceb..9031bbf59 100644 --- a/test/unit/http/input/body/SparqlUpdateBodyParser.test.ts +++ b/test/unit/http/input/body/SparqlUpdateBodyParser.test.ts @@ -64,7 +64,7 @@ describe('A SparqlUpdateBodyParser', (): void => { expect(result.binary).toBe(true); expect(result.metadata).toBe(input.metadata); - expect(await arrayifyStream(result.data)).toEqual( + await expect(arrayifyStream(result.data)).resolves.toEqual( [ 'DELETE DATA { }' ], ); }); @@ -84,7 +84,7 @@ describe('A SparqlUpdateBodyParser', (): void => { expect(result.binary).toBe(true); expect(result.metadata).toBe(input.metadata); - expect(await arrayifyStream(result.data)).toEqual( + await expect(arrayifyStream(result.data)).resolves.toEqual( [ 'INSERT DATA { <#it> }' ], ); }); diff --git a/test/unit/http/ldp/DeleteOperationHandler.test.ts b/test/unit/http/ldp/DeleteOperationHandler.test.ts index 993ba9ed4..f1af96847 100644 --- a/test/unit/http/ldp/DeleteOperationHandler.test.ts +++ b/test/unit/http/ldp/DeleteOperationHandler.test.ts @@ -9,11 +9,14 @@ describe('A DeleteOperationHandler', (): void => { let operation: Operation; const conditions: Conditions = { matchesMetadata: jest.fn() }; const body = new BasicRepresentation(); - const store = {} as unknown as ResourceStore; - const handler = new DeleteOperationHandler(store); + let store: jest.Mocked; + let handler: DeleteOperationHandler; beforeEach(async(): Promise => { operation = { method: 'DELETE', target: { path: 'http://test.com/foo' }, preferences: {}, conditions, body }; - store.deleteResource = jest.fn(async(): Promise => undefined); + store = { + deleteResource: jest.fn(async(): Promise => undefined), + } as any satisfies ResourceStore; + handler = new DeleteOperationHandler(store); }); it('only supports DELETE operations.', async(): Promise => { diff --git a/test/unit/http/representation/BasicRepresentation.test.ts b/test/unit/http/representation/BasicRepresentation.test.ts index 03a705b89..80f3ab6db 100644 --- a/test/unit/http/representation/BasicRepresentation.test.ts +++ b/test/unit/http/representation/BasicRepresentation.test.ts @@ -48,7 +48,7 @@ describe('BasicRepresentation', (): void => { const data = [ 'my', 'data' ]; const metadata = new RepresentationMetadata(); 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.binary).toBe(true); }); @@ -57,7 +57,7 @@ describe('BasicRepresentation', (): void => { const data = 'my data'; const metadata = new RepresentationMetadata(); 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.binary).toBe(true); }); diff --git a/test/unit/http/representation/RepresentationMetadata.test.ts b/test/unit/http/representation/RepresentationMetadata.test.ts index f699e1e22..626869a49 100644 --- a/test/unit/http/representation/RepresentationMetadata.test.ts +++ b/test/unit/http/representation/RepresentationMetadata.test.ts @@ -303,7 +303,7 @@ describe('A RepresentationMetadata', (): void => { it('errors if a shorthand has multiple values.', async(): Promise => { metadata.add(CONTENT_TYPE_TERM, 'a/b'); 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 => { diff --git a/test/unit/identity/configuration/AccountPromptFactory.test.ts b/test/unit/identity/configuration/AccountPromptFactory.test.ts index 69b0a84fe..6174e6db2 100644 --- a/test/unit/identity/configuration/AccountPromptFactory.test.ts +++ b/test/unit/identity/configuration/AccountPromptFactory.test.ts @@ -18,7 +18,9 @@ describe('An AccountPromptFactory', (): void => { beforeEach(async(): Promise => { policy = [] as any; + // eslint-disable-next-line jest/prefer-spy-on policy.add = jest.fn(); + // eslint-disable-next-line jest/prefer-spy-on policy.get = jest.fn().mockReturnValue(new Prompt({ name: 'login' })); ctx = { @@ -57,7 +59,7 @@ describe('An AccountPromptFactory', (): void => { }); it('returns true if there is no cookie.', async(): Promise => { - ctx.cookies.get = jest.fn(); + jest.spyOn(ctx.cookies, 'get').mockImplementation(); await expect(factory.handle(policy)).resolves.toBeUndefined(); const prompt = policy.add.mock.calls[0][0]; const check = prompt.checks[1]; @@ -66,7 +68,7 @@ describe('An AccountPromptFactory', (): void => { it('returns true if there is no matching account.', async(): Promise => { cookieStore.get.mockResolvedValueOnce(undefined); - ctx.cookies.get = jest.fn(); + jest.spyOn(ctx.cookies, 'get').mockImplementation(); await expect(factory.handle(policy)).resolves.toBeUndefined(); const prompt = policy.add.mock.calls[0][0]; const check = prompt.checks[1]; diff --git a/test/unit/identity/configuration/CachedJwkGenerator.test.ts b/test/unit/identity/configuration/CachedJwkGenerator.test.ts index 0eda0c5e4..5484f324a 100644 --- a/test/unit/identity/configuration/CachedJwkGenerator.test.ts +++ b/test/unit/identity/configuration/CachedJwkGenerator.test.ts @@ -40,7 +40,7 @@ describe('A CachedJwkGenerator', (): void => { }); 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 => { diff --git a/test/unit/identity/interaction/HtmlViewHandler.test.ts b/test/unit/identity/interaction/HtmlViewHandler.test.ts index ae0fff9ee..15fc83308 100644 --- a/test/unit/identity/interaction/HtmlViewHandler.test.ts +++ b/test/unit/identity/interaction/HtmlViewHandler.test.ts @@ -42,7 +42,7 @@ describe('An HtmlViewHandler', (): void => { ]; templateEngine = { - handleSafe: jest.fn().mockReturnValue(Promise.resolve('')), + handleSafe: jest.fn().mockResolvedValue(''), } as any; handler = new HtmlViewHandler(index, templateEngine, templates); diff --git a/test/unit/identity/interaction/oidc/ConsentHandler.test.ts b/test/unit/identity/interaction/oidc/ConsentHandler.test.ts index 11285d43a..5bd8fc0a7 100644 --- a/test/unit/identity/interaction/oidc/ConsentHandler.test.ts +++ b/test/unit/identity/interaction/oidc/ConsentHandler.test.ts @@ -66,6 +66,7 @@ describe('A ConsentHandler', (): void => { knownGrant = new DummyGrant({ accountId, clientId }); 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); provider = { Grant: grantFn, diff --git a/test/unit/logging/Logger.test.ts b/test/unit/logging/Logger.test.ts index 188c5286e..167ddd91e 100644 --- a/test/unit/logging/Logger.test.ts +++ b/test/unit/logging/Logger.test.ts @@ -2,6 +2,12 @@ import process from 'process'; import { BaseLogger, WrappingLogger } from '../../../src/logging/Logger'; import type { LogMetadata, SimpleLogger } from '../../../src/logging/Logger'; +class DummyLogger extends BaseLogger { + log(): this { + return this; + } +} + describe('Logger', (): void => { describe('a BaseLogger', (): void => { let logger: BaseLogger; @@ -11,8 +17,8 @@ describe('Logger', (): void => { }; beforeEach(async(): Promise => { - logger = new (BaseLogger as any)(); - logger.log = jest.fn(); + logger = new DummyLogger(); + jest.spyOn(logger, 'log').mockImplementation(); }); it('delegates error to log.', async(): Promise => { diff --git a/test/unit/logging/WinstonLoggerFactory.test.ts b/test/unit/logging/WinstonLoggerFactory.test.ts index ad26c8b5b..a843e96d6 100644 --- a/test/unit/logging/WinstonLoggerFactory.test.ts +++ b/test/unit/logging/WinstonLoggerFactory.test.ts @@ -17,7 +17,8 @@ describe('WinstonLoggerFactory', (): void => { // Create a dummy log transport 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(); }); diff --git a/test/unit/pods/generate/BaseResourcesGenerator.test.ts b/test/unit/pods/generate/BaseResourcesGenerator.test.ts index e4c0a1b1e..2025392f4 100644 --- a/test/unit/pods/generate/BaseResourcesGenerator.test.ts +++ b/test/unit/pods/generate/BaseResourcesGenerator.test.ts @@ -149,7 +149,7 @@ describe('A BaseResourcesGenerator', (): void => { it('does not create container when it already exists.', async(): Promise => { const meta = '<> "metadata".'; 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 identifiers = result.map((res): ResourceIdentifier => res.identifier); diff --git a/test/unit/quota/QuotaStrategy.test.ts b/test/unit/quota/QuotaStrategy.test.ts index f0820dc19..091cd0b7e 100644 --- a/test/unit/quota/QuotaStrategy.test.ts +++ b/test/unit/quota/QuotaStrategy.test.ts @@ -59,7 +59,7 @@ describe('A QuotaStrategy', (): void => { describe('createQuotaGuard()', (): void => { it('should return a passthrough that destroys the stream when quota is exceeded.', async(): Promise => { - 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 stream = guardedStreamFrom(fiftyChars); const track = await strategy.createQuotaGuard({ path: `${base}nested/file2.txt` }); diff --git a/test/unit/server/WebSocketServerConfigurator.test.ts b/test/unit/server/WebSocketServerConfigurator.test.ts index 78c5ac608..851e5b2ec 100644 --- a/test/unit/server/WebSocketServerConfigurator.test.ts +++ b/test/unit/server/WebSocketServerConfigurator.test.ts @@ -34,9 +34,10 @@ describe('A WebSocketServerConfigurator', (): void => { // Clearing the logger mock jest.clearAllMocks(); server = new EventEmitter() as any; - webSocket = new EventEmitter() as any; - webSocket.send = jest.fn(); - webSocket.close = jest.fn(); + webSocket = { + send: jest.fn(), + close: jest.fn(), + } as any; upgradeRequest = new EventEmitter() as any; diff --git a/test/unit/server/middleware/StaticAssetHandler.test.ts b/test/unit/server/middleware/StaticAssetHandler.test.ts index ff662c68b..f75bf70a4 100644 --- a/test/unit/server/middleware/StaticAssetHandler.test.ts +++ b/test/unit/server/middleware/StaticAssetHandler.test.ts @@ -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 => { const request = { method: 'GET', url: '/foo/bar/folder/../def.css' }; 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 => { diff --git a/test/unit/server/notifications/WebSocketChannel2023/WebSocket2023Emitter.test.ts b/test/unit/server/notifications/WebSocketChannel2023/WebSocket2023Emitter.test.ts index 0a50ecd73..236f3f7a7 100644 --- a/test/unit/server/notifications/WebSocketChannel2023/WebSocket2023Emitter.test.ts +++ b/test/unit/server/notifications/WebSocketChannel2023/WebSocket2023Emitter.test.ts @@ -1,4 +1,3 @@ -import { EventEmitter } from 'events'; import type { WebSocket } from 'ws'; import { BasicRepresentation } from '../../../../../src/http/representation/BasicRepresentation'; import type { NotificationChannel } from '../../../../../src/server/notifications/NotificationChannel'; @@ -20,9 +19,10 @@ describe('A WebSocket2023Emitter', (): void => { let emitter: WebSocket2023Emitter; beforeEach(async(): Promise => { - webSocket = new EventEmitter() as any; - webSocket.send = jest.fn(); - webSocket.close = jest.fn(); + webSocket = { + send: jest.fn(), + close: jest.fn(), + } as any; socketMap = new WrappedSetMultiMap(); @@ -46,8 +46,9 @@ describe('A WebSocket2023Emitter', (): void => { }); it('can send to multiple matching WebSockets.', async(): Promise => { - const webSocket2: jest.Mocked = new EventEmitter() as any; - webSocket2.send = jest.fn(); + const webSocket2: jest.Mocked = { + send: jest.fn(), + } as any; socketMap.add(channel.id, webSocket); socketMap.add(channel.id, webSocket2); @@ -61,8 +62,9 @@ describe('A WebSocket2023Emitter', (): void => { }); it('only sends to the matching WebSockets.', async(): Promise => { - const webSocket2: jest.Mocked = new EventEmitter() as any; - webSocket2.send = jest.fn(); + const webSocket2: jest.Mocked = { + send: jest.fn(), + } as any; const channel2: NotificationChannel = { ...channel, id: 'other', diff --git a/test/unit/server/notifications/WebSocketChannel2023/WebSocket2023Listener.test.ts b/test/unit/server/notifications/WebSocketChannel2023/WebSocket2023Listener.test.ts index 60bee6767..ad9137beb 100644 --- a/test/unit/server/notifications/WebSocketChannel2023/WebSocket2023Listener.test.ts +++ b/test/unit/server/notifications/WebSocketChannel2023/WebSocket2023Listener.test.ts @@ -1,4 +1,3 @@ -import { EventEmitter } from 'events'; import type { WebSocket } from 'ws'; import type { HttpRequest } from '../../../../../src/server/HttpRequest'; @@ -36,9 +35,10 @@ describe('A WebSocket2023Listener', (): void => { let listener: WebSocket2023Listener; beforeEach(async(): Promise => { - webSocket = new EventEmitter() as any; - webSocket.send = jest.fn(); - webSocket.close = jest.fn(); + webSocket = { + send: jest.fn(), + close: jest.fn(), + } as any; upgradeRequest = { url: `/foo/123456` } as any; diff --git a/test/unit/server/notifications/WebSocketChannel2023/WebSocket2023Storer.test.ts b/test/unit/server/notifications/WebSocketChannel2023/WebSocket2023Storer.test.ts index 699cd0b0f..6e4589593 100644 --- a/test/unit/server/notifications/WebSocketChannel2023/WebSocket2023Storer.test.ts +++ b/test/unit/server/notifications/WebSocketChannel2023/WebSocket2023Storer.test.ts @@ -12,6 +12,7 @@ import type { SetMultiMap } from '../../../../../src/util/map/SetMultiMap'; import { WrappedSetMultiMap } from '../../../../../src/util/map/WrappedSetMultiMap'; import { flushPromises } from '../../../../util/Util'; +/* eslint-disable jest/prefer-spy-on */ describe('A WebSocket2023Storer', (): void => { const channel: NotificationChannel = { id: 'id', diff --git a/test/unit/storage/BinarySliceResourceStore.test.ts b/test/unit/storage/BinarySliceResourceStore.test.ts index ed6d6eed9..49fa74740 100644 --- a/test/unit/storage/BinarySliceResourceStore.test.ts +++ b/test/unit/storage/BinarySliceResourceStore.test.ts @@ -80,7 +80,7 @@ describe('A BinarySliceResourceStore', (): void => { }); it('closes the source stream if there was an error creating the SliceStream.', async(): Promise => { - 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); diff --git a/test/unit/storage/DataAccessorBasedStore.test.ts b/test/unit/storage/DataAccessorBasedStore.test.ts index a0be4929e..09e500f26 100644 --- a/test/unit/storage/DataAccessorBasedStore.test.ts +++ b/test/unit/storage/DataAccessorBasedStore.test.ts @@ -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 => { 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 => { - accessor.getMetadata = jest.fn(async(): Promise => { + jest.spyOn(accessor, 'getMetadata').mockImplementation(async(): Promise => { 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 => { - if (auxiliaryStrategy.isAuxiliaryIdentifier(identifier)) { - throw new Error('auxiliary error!'); - } - await deleteFn.call(accessor, identifier); - }); + jest.spyOn(accessor, 'deleteResource') + .mockImplementation(async(identifier: ResourceIdentifier): Promise => { + 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 => { const resourceID = { path: `${root}resource` }; const originalMetaData = accessor.getMetadata; - accessor.getMetadata = jest.fn(async(): Promise => { + jest.spyOn(accessor, 'getMetadata').mockImplementation(async(): Promise => { throw new Error('error'); }); await expect(store.hasResource(resourceID)).rejects.toThrow('error'); diff --git a/test/unit/storage/LockingResourceStore.test.ts b/test/unit/storage/LockingResourceStore.test.ts index 009d2b74b..12cec1d85 100644 --- a/test/unit/storage/LockingResourceStore.test.ts +++ b/test/unit/storage/LockingResourceStore.test.ts @@ -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 => { - source.getRepresentation = jest.fn(async(): Promise => { + jest.spyOn(source, 'getRepresentation').mockImplementation(async(): Promise => { order.push('useless get'); // This will never resolve return new Promise(emptyFn); diff --git a/test/unit/storage/MonitoringStore.test.ts b/test/unit/storage/MonitoringStore.test.ts index 2f98b0bba..2fcc91c32 100644 --- a/test/unit/storage/MonitoringStore.test.ts +++ b/test/unit/storage/MonitoringStore.test.ts @@ -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 => { - 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' }) ], ])); diff --git a/test/unit/storage/PatchingStore.test.ts b/test/unit/storage/PatchingStore.test.ts index 487218e60..7c08840dc 100644 --- a/test/unit/storage/PatchingStore.test.ts +++ b/test/unit/storage/PatchingStore.test.ts @@ -28,7 +28,7 @@ describe('A PatchingStore', (): void => { }); it('calls its patcher if modifyResource is not implemented.', async(): Promise => { - source.modifyResource = jest.fn(async(): Promise => { + jest.spyOn(source, 'modifyResource').mockImplementation(async(): Promise => { 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 => { - source.modifyResource = jest.fn(async(): Promise => { + jest.spyOn(source, 'modifyResource').mockImplementation(async(): Promise => { throw new Error('dummy'); }); await expect(store.modifyResource({ path: 'modifyPath' }, {} as Patch)).rejects.toThrow('dummy'); diff --git a/test/unit/storage/accessors/AtomicFileDataAccessor.test.ts b/test/unit/storage/accessors/AtomicFileDataAccessor.test.ts index c592db11b..bf513b9d9 100644 --- a/test/unit/storage/accessors/AtomicFileDataAccessor.test.ts +++ b/test/unit/storage/accessors/AtomicFileDataAccessor.test.ts @@ -56,31 +56,31 @@ describe('AtomicFileDataAccessor', (): void => { }); it('should throw an error when writing the data goes wrong.', async(): Promise => { - 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 => { - 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 => { - 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 => { - 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'); }); }); diff --git a/test/unit/storage/accessors/FileDataAccessor.test.ts b/test/unit/storage/accessors/FileDataAccessor.test.ts index 452d6e2fd..db16eff54 100644 --- a/test/unit/storage/accessors/FileDataAccessor.test.ts +++ b/test/unit/storage/accessors/FileDataAccessor.test.ts @@ -260,7 +260,8 @@ describe('A FileDataAccessor', (): void => { it('throws an error if there is a problem with the internal metadata.', async(): Promise => { 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 => { diff --git a/test/unit/storage/accessors/FilterMetadataDataAccessor.test.ts b/test/unit/storage/accessors/FilterMetadataDataAccessor.test.ts index 365f83bf0..2471979f1 100644 --- a/test/unit/storage/accessors/FilterMetadataDataAccessor.test.ts +++ b/test/unit/storage/accessors/FilterMetadataDataAccessor.test.ts @@ -13,10 +13,10 @@ describe('FilterMetadataDataAccessor', (): void => { beforeEach(async(): Promise => { 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 => { diff --git a/test/unit/storage/accessors/InMemoryDataAccessor.test.ts b/test/unit/storage/accessors/InMemoryDataAccessor.test.ts index 0eaca9ef7..d02db448c 100644 --- a/test/unit/storage/accessors/InMemoryDataAccessor.test.ts +++ b/test/unit/storage/accessors/InMemoryDataAccessor.test.ts @@ -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 => { @@ -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 => { diff --git a/test/unit/storage/accessors/PassthroughDataAccessor.test.ts b/test/unit/storage/accessors/PassthroughDataAccessor.test.ts index 75570a9ef..be94ac8f6 100644 --- a/test/unit/storage/accessors/PassthroughDataAccessor.test.ts +++ b/test/unit/storage/accessors/PassthroughDataAccessor.test.ts @@ -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); }); diff --git a/test/unit/storage/accessors/ValidatingDataAccessor.test.ts b/test/unit/storage/accessors/ValidatingDataAccessor.test.ts index 645526c63..09eb10e1f 100644 --- a/test/unit/storage/accessors/ValidatingDataAccessor.test.ts +++ b/test/unit/storage/accessors/ValidatingDataAccessor.test.ts @@ -19,10 +19,10 @@ describe('ValidatingDataAccessor', (): void => { beforeEach(async(): Promise => { 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 => input.representation), } as any; diff --git a/test/unit/storage/conversion/ConstantConverter.test.ts b/test/unit/storage/conversion/ConstantConverter.test.ts index d634fd178..a7d935dfe 100644 --- a/test/unit/storage/conversion/ConstantConverter.test.ts +++ b/test/unit/storage/conversion/ConstantConverter.test.ts @@ -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 => { diff --git a/test/unit/storage/conversion/ContainerToTemplateConverter.test.ts b/test/unit/storage/conversion/ContainerToTemplateConverter.test.ts index bfc307ed6..0e58eac61 100644 --- a/test/unit/storage/conversion/ContainerToTemplateConverter.test.ts +++ b/test/unit/storage/conversion/ContainerToTemplateConverter.test.ts @@ -16,7 +16,7 @@ describe('A ContainerToTemplateConverter', (): void => { beforeEach(async(): Promise => { templateEngine = { - handleSafe: jest.fn().mockReturnValue(Promise.resolve('')), + handleSafe: jest.fn().mockResolvedValue(''), } as any; converter = new ContainerToTemplateConverter(templateEngine, 'text/html', identifierStrategy); }); diff --git a/test/unit/storage/conversion/DynamicJsonToTemplateConverter.test.ts b/test/unit/storage/conversion/DynamicJsonToTemplateConverter.test.ts index 303c3c966..99af5993e 100644 --- a/test/unit/storage/conversion/DynamicJsonToTemplateConverter.test.ts +++ b/test/unit/storage/conversion/DynamicJsonToTemplateConverter.test.ts @@ -33,7 +33,7 @@ describe('A DynamicJsonToTemplateConverter', (): void => { input = { identifier, representation, preferences }; templateEngine = { - handleSafe: jest.fn().mockReturnValue(Promise.resolve('')), + handleSafe: jest.fn().mockResolvedValue(''), } as any; converter = new DynamicJsonToTemplateConverter(templateEngine); }); diff --git a/test/unit/storage/conversion/ErrorToTemplateConverter.test.ts b/test/unit/storage/conversion/ErrorToTemplateConverter.test.ts index c17b232d3..863c7a3da 100644 --- a/test/unit/storage/conversion/ErrorToTemplateConverter.test.ts +++ b/test/unit/storage/conversion/ErrorToTemplateConverter.test.ts @@ -20,7 +20,7 @@ describe('An ErrorToTemplateConverter', (): void => { beforeEach(async(): Promise => { templateEngine = { - handleSafe: jest.fn().mockReturnValue(Promise.resolve('')), + handleSafe: jest.fn().mockResolvedValue(''), } as any; converter = new ErrorToTemplateConverter(templateEngine, { mainTemplatePath, codeTemplatesPath, extension, contentType }); diff --git a/test/unit/storage/conversion/MarkdownToHtmlConverter.test.ts b/test/unit/storage/conversion/MarkdownToHtmlConverter.test.ts index 64570bf3f..f1985b55b 100644 --- a/test/unit/storage/conversion/MarkdownToHtmlConverter.test.ts +++ b/test/unit/storage/conversion/MarkdownToHtmlConverter.test.ts @@ -11,7 +11,7 @@ describe('A MarkdownToHtmlConverter', (): void => { beforeEach(async(): Promise => { templateEngine = { - handleSafe: jest.fn().mockReturnValue(Promise.resolve('')), + handleSafe: jest.fn().mockResolvedValue(''), } as any; converter = new MarkdownToHtmlConverter(templateEngine); }); diff --git a/test/unit/storage/patch/ImmutableMetadataPatcher.test.ts b/test/unit/storage/patch/ImmutableMetadataPatcher.test.ts index 2b97d94cc..9ddd49f63 100644 --- a/test/unit/storage/patch/ImmutableMetadataPatcher.test.ts +++ b/test/unit/storage/patch/ImmutableMetadataPatcher.test.ts @@ -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): - Promise => { - 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): Promise => { + 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 => { input.representation!.dataset.addQuad(namedNode(identifier.path), namedNode(`${base}p`), namedNode(`${base}o1`)); - patcher.handle = jest.fn(async(patcherInput: RepresentationPatcherInput): - Promise => { - 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): Promise => { + 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`), ]); diff --git a/test/unit/storage/routing/ConvertingRouterRule.test.ts b/test/unit/storage/routing/ConvertingRouterRule.test.ts index b6a86541f..5b77ce2cf 100644 --- a/test/unit/storage/routing/ConvertingRouterRule.test.ts +++ b/test/unit/storage/routing/ConvertingRouterRule.test.ts @@ -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; + let store2: jest.Mocked; let defaultStore: ResourceStore; let checker1: PreferenceSupport; let checker2: PreferenceSupport; @@ -16,8 +16,14 @@ describe('A ConvertingRouterRule', (): void => { let metadata: RepresentationMetadata; beforeEach(async(): Promise => { - 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 => { - 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 => { - 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 => { - store1.hasResource = jest.fn().mockRejectedValueOnce(new InternalServerError()); + store1.hasResource.mockRejectedValueOnce(new InternalServerError()); await expect(rule.handle({ identifier: { path: 'identifier' }})).rejects.toThrow(InternalServerError); }); }); diff --git a/test/unit/storage/routing/PreferenceSupport.test.ts b/test/unit/storage/routing/PreferenceSupport.test.ts index eb11c5052..4bb96ca39 100644 --- a/test/unit/storage/routing/PreferenceSupport.test.ts +++ b/test/unit/storage/routing/PreferenceSupport.test.ts @@ -26,7 +26,7 @@ describe('A PreferenceSupport', (): void => { }); it('returns false if the converter does not support the input.', async(): Promise => { - converter.canHandle = jest.fn((): any => { + jest.spyOn(converter, 'canHandle').mockImplementation((): any => { throw new BadRequestHttpError(); }); await expect(support.supports({ identifier, representation })).resolves.toBe(false); diff --git a/test/unit/util/PathUtil.test.ts b/test/unit/util/PathUtil.test.ts index 40201577d..340a02c8e 100644 --- a/test/unit/util/PathUtil.test.ts +++ b/test/unit/util/PathUtil.test.ts @@ -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 const root = getModuleRoot(); const packageJson = joinFilePath(root, 'package.json'); - expect(await fsPromises.access(packageJson)).toBeUndefined(); + await expect(fsPromises.access(packageJson)).resolves.toBeUndefined(); }); }); diff --git a/test/unit/util/handlers/HandlerUtil.test.ts b/test/unit/util/handlers/HandlerUtil.test.ts index a3cb7498b..64dfbc589 100644 --- a/test/unit/util/handlers/HandlerUtil.test.ts +++ b/test/unit/util/handlers/HandlerUtil.test.ts @@ -21,7 +21,7 @@ describe('HandlerUtil', (): void => { }); it('supports non-native Errors.', async(): Promise => { - handlerFalse.canHandle = jest.fn().mockRejectedValue('apple'); + jest.spyOn(handlerFalse, 'canHandle').mockRejectedValue('apple'); await expect(findHandler([ handlerFalse ], null)).rejects.toThrow('Unknown error: apple'); }); }); diff --git a/test/unit/util/locking/FileSystemResourceLocker.test.ts b/test/unit/util/locking/FileSystemResourceLocker.test.ts index 2be9ea850..31f774dd3 100644 --- a/test/unit/util/locking/FileSystemResourceLocker.test.ts +++ b/test/unit/util/locking/FileSystemResourceLocker.test.ts @@ -125,7 +125,7 @@ describe('A FileSystemResourceLocker', (): void => { it('stops proper-lock from throwing errors after finalize was called.', async(): Promise => { // 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. - expect((): void => (locker as any).customOnCompromised(new Error('test'))).toThrow(); + expect((): void => (locker as any).customOnCompromised(new Error('test'))).toThrow('test'); await locker.finalize(); expect((locker as any).customOnCompromised(new Error('test'))).toBeUndefined(); }); diff --git a/test/unit/util/locking/GreedyReadWriteLocker.test.ts b/test/unit/util/locking/GreedyReadWriteLocker.test.ts index d8dd7c595..366dee8fa 100644 --- a/test/unit/util/locking/GreedyReadWriteLocker.test.ts +++ b/test/unit/util/locking/GreedyReadWriteLocker.test.ts @@ -36,7 +36,7 @@ describe('A GreedyReadWriteLocker', (): void => { }); it('errors if the read counter has an unexpected value.', async(): Promise => { - storage.get = jest.fn().mockResolvedValue(0); + jest.spyOn(storage, 'get').mockResolvedValue(0); await expect(locker.withReadLock(resourceId, (): number => 5)).rejects.toThrow(InternalServerError); }); });