From b1ac0f9c83f21ba64e52d0ae22de3ca065bf256c Mon Sep 17 00:00:00 2001 From: Eli Bosley Date: Thu, 19 Dec 2024 13:29:23 -0500 Subject: [PATCH] fix: update tests --- .../resolvers/subscription/network.test.ts | 12 +++++----- api/src/__test__/store/modules/config.test.ts | 12 +++++++--- .../unraid-api/auth/api-key.service.spec.ts | 24 +++++++++++-------- api/src/unraid-api/auth/api-key.service.ts | 6 ++--- 4 files changed, 32 insertions(+), 22 deletions(-) diff --git a/api/src/__test__/graphql/resolvers/subscription/network.test.ts b/api/src/__test__/graphql/resolvers/subscription/network.test.ts index 0422009e9..5795cd9bc 100644 --- a/api/src/__test__/graphql/resolvers/subscription/network.test.ts +++ b/api/src/__test__/graphql/resolvers/subscription/network.test.ts @@ -58,15 +58,15 @@ test('getUrlForServer - field exists, ssl yes, port empty', () => { expect(result).toMatchInlineSnapshot('"https://192.168.1.1/"'); }); -test('getUrlForServer - field exists, ssl auto', () => { +test('getUrlForServer - field exists, ssl auto', async () => { const getResult = async () => getUrlForServer({ nginx: { lanIp: '192.168.1.1', sslEnabled: true, sslMode: 'auto', httpPort: 123, httpsPort: 445 } as const as Nginx, field: 'lanIp', }); - void expect(getResult).rejects.toThrowErrorMatchingInlineSnapshot(`[Error: Cannot get IP Based URL for field: "lanIp" SSL mode auto]`); + await expect(getResult).rejects.toThrowErrorMatchingInlineSnapshot(`[Error: Cannot get IP Based URL for field: "lanIp" SSL mode auto]`); }); -test('getUrlForServer - field does not exist, ssl disabled', () => { +test('getUrlForServer - field does not exist, ssl disabled', async () => { const getResult = async () => getUrlForServer( { nginx: { lanIp: '192.168.1.1', sslEnabled: false, sslMode: 'no' } as const as Nginx, @@ -76,7 +76,7 @@ test('getUrlForServer - field does not exist, ssl disabled', () => { // @ts-expect-error Field doesn't exist field: 'idontexist', }); - void expect(getResult).rejects.toThrowErrorMatchingInlineSnapshot(`[Error: IP URL Resolver: Could not resolve any access URL for field: "idontexist", is FQDN?: false]`); + await expect(getResult).rejects.toThrowErrorMatchingInlineSnapshot(`[Error: IP URL Resolver: Could not resolve any access URL for field: "idontexist", is FQDN?: false]`); }); test('getUrlForServer - FQDN - field exists, port non-empty', () => { @@ -104,13 +104,13 @@ test.each([ expect(result.toString()).toBe('https://my-fqdn.unraid.net/'); }); -test('getUrlForServer - field does not exist, ssl disabled', () => { +test('getUrlForServer - field does not exist, ssl disabled', async () => { const getResult = async () => getUrlForServer({ nginx: { lanFqdn: 'my-fqdn.unraid.net' } as const as Nginx, ports: { portSsl: '', port: '', defaultUrl: new URL('https://my-default-url.unraid.net') }, // @ts-expect-error Field doesn't exist field: 'idontexist' }); - void expect(getResult).rejects.toThrowErrorMatchingInlineSnapshot(`[Error: IP URL Resolver: Could not resolve any access URL for field: "idontexist", is FQDN?: false]`); + await expect(getResult).rejects.toThrowErrorMatchingInlineSnapshot(`[Error: IP URL Resolver: Could not resolve any access URL for field: "idontexist", is FQDN?: false]`); }); test('integration test, loading nginx ini and generating all URLs', async () => { diff --git a/api/src/__test__/store/modules/config.test.ts b/api/src/__test__/store/modules/config.test.ts index dc9455ed8..a1b4a6085 100644 --- a/api/src/__test__/store/modules/config.test.ts +++ b/api/src/__test__/store/modules/config.test.ts @@ -1,7 +1,13 @@ import { expect, test } from 'vitest'; + + import { store } from '@app/store'; + + + + test('Before init returns default values for all fields', async () => { const state = store.getState().config; expect(state).toMatchInlineSnapshot(` @@ -74,7 +80,7 @@ test('After init returns values from cfg file for all fields', async () => { dynamicRemoteAccessType: 'DISABLED', email: 'test@example.com', idtoken: '', - localApiKey: '', + localApiKey: '426b62b4d51e441fa97a93dfa1259920390a6eb61bd8675db0caa18dd0e414e9', refreshtoken: '', regWizTime: '1611175408732_0951-1653-3509-FBA155FA23C0', upnpEnabled: 'no', @@ -127,7 +133,7 @@ test('updateUserConfig merges in changes to current state', async () => { dynamicRemoteAccessType: 'DISABLED', email: 'test@example.com', idtoken: '', - localApiKey: '', + localApiKey: '426b62b4d51e441fa97a93dfa1259920390a6eb61bd8675db0caa18dd0e414e9', refreshtoken: '', regWizTime: '1611175408732_0951-1653-3509-FBA155FA23C0', upnpEnabled: 'no', @@ -141,4 +147,4 @@ test('updateUserConfig merges in changes to current state', async () => { }, }) ); -}); +}); \ No newline at end of file diff --git a/api/src/unraid-api/auth/api-key.service.spec.ts b/api/src/unraid-api/auth/api-key.service.spec.ts index 9826aa1c1..d3d43599b 100644 --- a/api/src/unraid-api/auth/api-key.service.spec.ts +++ b/api/src/unraid-api/auth/api-key.service.spec.ts @@ -2,17 +2,24 @@ import { Logger } from '@nestjs/common'; import { readdir, readFile, writeFile } from 'fs/promises'; import { join } from 'path'; + + import { ensureDir } from 'fs-extra'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { ZodError } from 'zod'; + + import type { ApiKey, ApiKeyWithSecret } from '@app/graphql/generated/api/types'; import { ApiKeySchema, ApiKeyWithSecretSchema } from '@app/graphql/generated/api/operations'; import { Role } from '@app/graphql/generated/api/types'; import { getters } from '@app/store'; + + import { ApiKeyService } from './api-key.service'; + vi.mock('fs/promises', async () => ({ readdir: vi.fn(), readFile: vi.fn(), @@ -127,15 +134,14 @@ describe('ApiKeyService', () => { it('should create ApiKeyWithSecret with generated key', async () => { const saveSpy = vi.spyOn(apiKeyService, 'saveApiKey').mockResolvedValue(); const { key, id, description, roles } = mockApiKeyWithSecret; - const inputName = 'Test API Key'; - const expectedName = 'TEST_API_KEY'; + const name = 'Test API Key'; - const result = await apiKeyService.create(inputName, description ?? '', roles); + const result = await apiKeyService.create(name, description ?? '', roles); expect(result).toMatchObject({ id, key, - name: expectedName, + name: name, description, roles, createdAt: expect.any(String), @@ -148,7 +154,7 @@ describe('ApiKeyService', () => { const saveSpy = vi.spyOn(apiKeyService, 'saveApiKey'); await expect(apiKeyService.create('', 'desc', [Role.GUEST])).rejects.toThrow( - 'API key name is required' + 'API key name must be alphanumeric + spaces' ); await expect(apiKeyService.create('name', 'desc', [])).rejects.toThrow( @@ -300,13 +306,11 @@ describe('ApiKeyService', () => { expect(readFile).toHaveBeenCalledTimes(2); }); - it('should throw authentication error when file read fails', async () => { + it('Should return null if an API key is invalid', async () => { vi.mocked(readdir).mockResolvedValue(['key1.json'] as any); vi.mocked(readFile).mockRejectedValue(new Error('Read error')); - await expect(apiKeyService.findByKey(mockApiKeyWithSecret.key)).rejects.toThrow( - 'Authentication system error' - ); + await expect(apiKeyService.findByKey(mockApiKeyWithSecret.key)).resolves.toBeNull(); }); it('should throw specific error for corrupted JSON', async () => { @@ -465,4 +469,4 @@ describe('ApiKeyService', () => { ); }); }); -}); +}); \ No newline at end of file diff --git a/api/src/unraid-api/auth/api-key.service.ts b/api/src/unraid-api/auth/api-key.service.ts index a53a5e8ad..0032ebab1 100644 --- a/api/src/unraid-api/auth/api-key.service.ts +++ b/api/src/unraid-api/auth/api-key.service.ts @@ -55,7 +55,7 @@ export class ApiKeyService implements OnModuleInit { if (/^[\p{L}\p{N} ]+$/u.test(name)) { return name; } else { - throw new GraphQLError('API key name must be alphanumeric and can only contain spaces'); + throw new GraphQLError('API key name must be alphanumeric + spaces'); } } @@ -189,7 +189,7 @@ export class ApiKeyService implements OnModuleInit { try { const files = await readdir(this.basePath); - for (const file of files) { + for (const file of (files ?? [])) { if (!file.endsWith('.json')) continue; try { @@ -233,7 +233,7 @@ export class ApiKeyService implements OnModuleInit { } this.logger.error(`Failed to read API key storage: ${error}`); - throw new GraphQLError('Authentication system unavailable'); + throw new GraphQLError('Authentication system unavailable - please see logs'); } }