UNPKG

@furystack/rest-service

Version:

Repository implementation for FuryStack

140 lines 6.62 kB
import { InMemoryStore, User, addStore } from '@furystack/core'; import { getPort } from '@furystack/core/port-generator'; import { Injector } from '@furystack/inject'; import { serializeValue } from '@furystack/rest'; import { PathHelper, usingAsync } from '@furystack/utils'; import { describe, expect, it } from 'vitest'; import { GetCurrentUser, IsAuthenticated, LoginAction, LogoutAction } from './actions/index.js'; import './helpers'; import { useHttpAuthentication, useRestService } from './helpers.js'; import { DefaultSession } from './models/default-session.js'; import { JsonResult } from './request-action-implementation.js'; const createIntegrationApi = async () => { const i = new Injector(); const port = getPort(); const root = 'test-api'; addStore(i, new InMemoryStore({ model: User, primaryKey: 'username' })).addStore(new InMemoryStore({ model: DefaultSession, primaryKey: 'sessionId' })); useHttpAuthentication(i, { getUserStore: (sm) => sm.getStoreFor(User, 'username'), getSessionStore: (sm) => sm.getStoreFor(DefaultSession, 'sessionId'), }); await useRestService({ injector: i, root, port, cors: { credentials: true, origins: ['http://localhost:8080'], headers: ['cache', 'content-type'], }, api: { GET: { '/currentUser': GetCurrentUser, '/isAuthenticated': IsAuthenticated, '/testQuery': async (options) => JsonResult({ param1Value: options.getQuery().param1 }), '/testUrlParams/:urlParam': async (options) => JsonResult({ urlParamValue: options.getUrlParams().urlParam }), }, POST: { '/login': LoginAction, '/logout': LogoutAction, '/testPostBody': async (options) => { const body = await options.getBody(); const body2 = await options.getBody(); return JsonResult({ bodyValue: body.value, body2Value: body2.value }); }, }, }, }); return { apiUrl: `http://127.0.0.1:${port}/${root}`, port, [Symbol.asyncDispose]: i[Symbol.asyncDispose].bind(i), }; }; describe('@furystack/rest-service inregration tests', () => { it('Should be started and disposed', async () => { await usingAsync(await createIntegrationApi(), async () => { }); }); it('Should respond with 404 when a route is not found', async () => { await usingAsync(await createIntegrationApi(), async ({ apiUrl }) => { const result = await fetch(PathHelper.joinPaths(apiUrl, 'some-route-that-does-not-exists'), { method: 'GET', }); expect(result.ok).toBe(false); expect(result.status).toBe(404); const responseText = await result.json(); expect(responseText).toEqual({ error: 'Content not found' }); }); }); it('Should respond with 401 for unauthorized request errors', async () => { await usingAsync(await createIntegrationApi(), async ({ apiUrl }) => { const result = await fetch(PathHelper.joinPaths(apiUrl, 'currentUser')); expect(result.ok).toBe(false); expect(result.status).toBe(401); const responseText = await result.json(); expect(responseText).toEqual({ error: 'unauthorized' }); }); }); it('Should respond with 401 for unauthorized request errors', async () => { await usingAsync(await createIntegrationApi(), async ({ apiUrl }) => { const result = await fetch(PathHelper.joinPaths(apiUrl, 'currentUser')); expect(result.ok).toBe(false); expect(result.status).toBe(401); const responseText = await result.json(); expect(responseText).toEqual({ error: 'unauthorized' }); }); }); it('Should respond with the correct result body', async () => { await usingAsync(await createIntegrationApi(), async ({ apiUrl }) => { const response = await fetch(PathHelper.joinPaths(apiUrl, 'isAuthenticated')); expect(response.status).toBe(200); const result = await response.json(); expect(result).toEqual({ isAuthenticated: false }); }); }); it('Should be able to read query parameters', async () => { await usingAsync(await createIntegrationApi(), async ({ apiUrl }) => { console.log('apiUrl', apiUrl); const response = await fetch(PathHelper.joinPaths(apiUrl, `testQuery?param1=${serializeValue('foo')}`)); expect(response.status).toBe(200); const result = await response.json(); expect(result).toEqual({ param1Value: 'foo' }); }); }); it('Should be able to read url parameters', async () => { await usingAsync(await createIntegrationApi(), async ({ apiUrl }) => { const response = await fetch(PathHelper.joinPaths(apiUrl, 'testUrlParams/bar')); expect(response.status).toBe(200); const result = await response.json(); expect(result).toEqual({ urlParamValue: 'bar' }); }); }); it('Should be able to read post body', async () => { await usingAsync(await createIntegrationApi(), async ({ apiUrl }) => { const response = await fetch(PathHelper.joinPaths(apiUrl, 'testPostBody'), { method: 'POST', body: JSON.stringify({ value: 'baz' }), }); expect(response.status).toBe(200); const result = await response.json(); expect(result).toEqual({ bodyValue: 'baz', body2Value: 'baz' }); }); }); it('Should respond with OK to OPTIONS requests', async () => { await usingAsync(await createIntegrationApi(), async ({ apiUrl }) => { const response = await fetch(PathHelper.joinPaths(apiUrl, 'testPostBody'), { method: 'OPTIONS', }).catch((e) => { console.log(e); throw e; }); expect(response.status).toBe(200); }); }); it('Should reject requests outside of the API Root', async () => { await usingAsync(await createIntegrationApi(), async ({ port }) => { await expect(fetch(PathHelper.joinPaths(`http://127.0.0.1:${port}`, 'not-my-api-root'))).rejects.toThrowError('fetch failed'); }); }); }); //# sourceMappingURL=rest-service.integration.spec.js.map