diff --git a/backend/src/api-tests/write.test.ts b/backend/src/api-tests/write.test.ts index fb126c60..44b9a1b4 100644 --- a/backend/src/api-tests/write.test.ts +++ b/backend/src/api-tests/write.test.ts @@ -1,35 +1,56 @@ -import { describe, it } from 'node:test' -import assert from 'node:assert' -import { EditDataType, EditMetaData, LocalityDetailsType } from '../../../frontend/src/backendTypes' +import { describe, it, before } from 'node:test' +import assert from 'node:assert/strict' +import { EditDataType, EditMetaData, LocalityDetailsType, SpeciesDetailsType } from '../../../frontend/src/backendTypes' const baseUrl = 'http://localhost:4000' let token: string | null = null -const send = async (path: string, method: 'GET' | 'POST' | 'PUT' | 'DELETE', body?: object) => { +const send = async >( + path: string, + method: 'GET' | 'POST' | 'PUT' | 'DELETE', + body?: object +) => { const headers = new Headers() headers.append('Content-Type', 'application/json') - if (token) headers.append('authorization', `bearer ${token}`) - const options = method === 'GET' ? {} : { body: JSON.stringify(body), method, headers } + const options = { body: method !== 'GET' ? JSON.stringify(body) : undefined, method, headers } const result = await fetch(`${baseUrl}/${path}`, options) - const resultBody = (await result.json()) as Record - return { body: resultBody, status: result.status } + if (!result) return {} + const r = await result.text() + if (!r) return { body: {} as T, status: result.status } + return { body: JSON.parse(r) as T, status: result.status } } -void describe('Locality editing works', () => { - void it('works', async () => { - const loginResponse = await send('user/login', 'POST', { username: 'testSu', password: 'test' }) - if (loginResponse?.body?.token) token = loginResponse.body.token as string +void describe('Locality write works', () => { + before(async () => { + await send('test/create-test-users', 'GET') + }) + void it('Edits name, synonyms and locality species correctly', async () => { + const loginResponse = await send<{ token: string }>('user/login', 'POST', { username: 'testSu', password: 'test' }) + if (loginResponse?.body?.token) token = loginResponse.body.token else throw Error('Login unsuccessful') const locality: EditDataType & EditMetaData = { - lid: 20920, + lid: 21050, loc_name: 'new_test_name', now_mus: [], - now_ls: [], + now_ls: [ + { + rowState: 'new', + species_id: 21052, + lid: 21050, + com_species: { species_id: 21052 } as SpeciesDetailsType, + }, + { + rowState: 'removed', + species_id: 85729, + lid: 21050, + com_species: { species_id: 85729 } as SpeciesDetailsType, + }, + ], projects: [], now_plr: [], now_ss: [], @@ -40,7 +61,17 @@ void describe('Locality editing works', () => { references: [], } - const result = await send('locality', 'PUT', { locality }) - assert(result.body.id === 20920, 'Invalid result') + const writeResult = await send<{ id: number }>('locality', 'PUT', { locality }) + assert(writeResult.body.id === locality.lid, `Invalid result returned on write: ${writeResult.body.id}`) + + const { body: resultLocality } = await send(`locality/${locality.lid}`, 'GET') + assert(resultLocality.loc_name === locality.loc_name, 'Name was not changed correctly') + + assert( + resultLocality.now_ls.find(ls => ls.species_id === 21052 && ls.lid === 21050), + 'Added locality species not found' + ) + + assert(resultLocality.now_ls.length === 2, `Unexpected now_ls length: ${resultLocality.now_ls.length}`) }) }) diff --git a/backend/src/app.ts b/backend/src/app.ts new file mode 100644 index 00000000..23f8748b --- /dev/null +++ b/backend/src/app.ts @@ -0,0 +1,65 @@ +import 'express-async-errors' +import express from 'express' +import cors from 'cors' +import localityRouter from './routes/locality' +import museumRouter from './routes/museum' +import referenceRouter from './routes/reference' +import sedimentaryStructureRouter from './routes/sedimentaryStructure' +import regionRouter from './routes/region' +import personRouter from './routes/person' +import projectRouter from './routes/project' +import speciesRouter from './routes/species' +import localitySpeciesRouter from './routes/localitySpecies' +import refreshTokenRouter from './routes/refresh' +import timeBoundRouter from './routes/timeBound' +import timeUnitRouter from './routes/timeUnit' +import userRouter from './routes/user' +import emailRouter from './routes/email' +import { responseLogger } from './middlewares/requestLogger' +import compression from 'compression' +import { ENABLE_WRITE, RUNNING_ENV } from './utils/config' +import { tokenExtractor, userExtractor } from './middlewares/authenticator' +import { errorHandler } from './middlewares/errorHandler' +import { requireOneOf } from './middlewares/authorizer' +import { Role } from './../../frontend/src/types' +import { blockWriteRequests } from './middlewares/misc' +import testRouter from './routes/test' + +const app = express() + +app.use(express.json({ limit: '50mb' })) +app.use(cors()) +app.use(compression()) + +app.use(responseLogger) + +if (!ENABLE_WRITE && RUNNING_ENV !== 'dev') { + app.use(blockWriteRequests) +} + +app.use(refreshTokenRouter) + +app.use(tokenExtractor) +app.use(userExtractor) + +app.use('/user', userRouter) +app.use('/locality', localityRouter) +app.use('/locality-species', localitySpeciesRouter) +app.use('/species', speciesRouter) +app.use('/reference', referenceRouter) +app.use('/time-unit', timeUnitRouter) +app.use('/time-bound', requireOneOf([Role.Admin, Role.EditUnrestricted]), timeBoundRouter) +app.use('/region', requireOneOf([Role.Admin]), regionRouter) +app.use('/person', personRouter) +app.use('/project', projectRouter) +app.use('/museum', museumRouter) +app.use('/sedimentary-structure', sedimentaryStructureRouter) +app.use('/email', requireOneOf([Role.Admin]), emailRouter) + +if (RUNNING_ENV === 'dev') { + app.use('/test', testRouter) +} + +app.use(errorHandler) + +export default app diff --git a/backend/src/index.ts b/backend/src/index.ts index 42240a98..20e86b72 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -1,63 +1,8 @@ -import 'express-async-errors' -import express from 'express' -import cors from 'cors' -import localityRouter from './routes/locality' -import museumRouter from './routes/museum' -import referenceRouter from './routes/reference' -import sedimentaryStructureRouter from './routes/sedimentaryStructure' -import regionRouter from './routes/region' -import personRouter from './routes/person' -import projectRouter from './routes/project' -import speciesRouter from './routes/species' -import localitySpeciesRouter from './routes/localitySpecies' -import refreshTokenRouter from './routes/refresh' -import timeBoundRouter from './routes/timeBound' -import timeUnitRouter from './routes/timeUnit' -import userRouter from './routes/user' -import emailRouter from './routes/email' -import { responseLogger } from './middlewares/requestLogger' -import compression from 'compression' -import { logger } from './utils/logger' -import { ENABLE_WRITE, PORT, RUNNING_ENV } from './utils/config' -import { tokenExtractor, userExtractor } from './middlewares/authenticator' -import { errorHandler } from './middlewares/errorHandler' +import app from './app' import { createTestUsers } from './services/user' +import { PORT, RUNNING_ENV } from './utils/config' import { testDbConnection } from './utils/db' -import { requireOneOf } from './middlewares/authorizer' -import { Role } from './../../frontend/src/types' -import { blockWriteRequests } from './middlewares/misc' - -const app = express() - -app.use(express.json({ limit: '50mb' })) -app.use(cors()) -app.use(compression()) - -app.use(responseLogger) - -if (!ENABLE_WRITE && RUNNING_ENV !== 'dev') { - app.use(blockWriteRequests) -} - -app.use(refreshTokenRouter) - -app.use(tokenExtractor) -app.use(userExtractor) - -app.use('/user', userRouter) -app.use('/locality', localityRouter) -app.use('/locality-species', localitySpeciesRouter) -app.use('/species', speciesRouter) -app.use('/reference', referenceRouter) -app.use('/time-unit', timeUnitRouter) -app.use('/time-bound', requireOneOf([Role.Admin, Role.EditUnrestricted]), timeBoundRouter) -app.use('/region', requireOneOf([Role.Admin]), regionRouter) -app.use('/person', personRouter) -app.use('/project', projectRouter) -app.use('/museum', museumRouter) -app.use('/sedimentary-structure', sedimentaryStructureRouter) -app.use('/email', requireOneOf([Role.Admin]), emailRouter) -app.use(errorHandler) +import { logger } from './utils/logger' app.listen(PORT, async () => { logger.info(`Server running on port ${PORT} in "${RUNNING_ENV}"-mode.`) diff --git a/backend/src/routes/test.ts b/backend/src/routes/test.ts new file mode 100644 index 00000000..05b0a1a7 --- /dev/null +++ b/backend/src/routes/test.ts @@ -0,0 +1,10 @@ +import { Router } from 'express' +import { createTestUsers } from '../services/user' +const router = Router() + +router.get('/create-test-users', async (_req, res) => { + await createTestUsers() + res.status(200).send() +}) + +export default router