Squashed commit of the following:

commit c0148e8301
Author: Roberto Tonino <roberto.tonino5@gmail.com>
Date:   Fri Apr 9 21:06:02 2021 +0200

    test: disabled logger when in test mode; refactor: type names

commit 418fc5647f
Author: Roberto Tonino <roberto.tonino5@gmail.com>
Date:   Fri Apr 9 20:49:54 2021 +0200

    test: added albumSearch test; chore: removed sample endpoint

commit e2c79f6ee6
Author: Roberto Tonino <roberto.tonino5@gmail.com>
Date:   Fri Apr 9 19:16:25 2021 +0200

    test: added cookie parser test

commit 78d70b7369
Author: Roberto Tonino <roberto.tonino5@gmail.com>
Date:   Fri Apr 9 19:07:44 2021 +0200

    feat: added root path first test

commit eb91ff06d6
Author: Roberto Tonino <roberto.tonino5@gmail.com>
Date:   Fri Apr 9 18:45:32 2021 +0200

    feat: added test deps
This commit is contained in:
Roberto Tonino 2021-04-24 18:03:27 +02:00
parent 9800edf68d
commit 29c84cf8b9
13 changed files with 3427 additions and 727 deletions

View file

@ -3,5 +3,8 @@ NODE_BIN ?= .\node_modules\.bin
lint: lint:
@$(NODE_BIN)\eslint ./src/** --fix @$(NODE_BIN)\eslint ./src/** --fix
build: lint test:
@$(NODE_BIN)\jest
build: lint test
@$(NODE_BIN)\tsc @$(NODE_BIN)\tsc

6
server/jest.config.js Normal file
View file

@ -0,0 +1,6 @@
module.exports = {
clearMocks: true,
roots: ['<rootDir>/src'],
testEnvironment: 'node',
preset: 'ts-jest'
}

View file

@ -8,7 +8,9 @@
"start-build": "node dist/app.js", "start-build": "node dist/app.js",
"lint": "eslint . --fix", "lint": "eslint . --fix",
"prebuild": "yarn lint", "prebuild": "yarn lint",
"build": "tsc" "build": "tsc",
"test": "jest",
"test-watch": "jest --watch"
}, },
"dependencies": { "dependencies": {
"cookie-parser": "1.4.5", "cookie-parser": "1.4.5",
@ -24,16 +26,21 @@
"@types/cookie-parser": "1.4.2", "@types/cookie-parser": "1.4.2",
"@types/debug": "4.1.5", "@types/debug": "4.1.5",
"@types/express": "4.17.11", "@types/express": "4.17.11",
"@types/jest": "26.0.22",
"@types/morgan": "1.9.2", "@types/morgan": "1.9.2",
"@types/node": "14.14.37", "@types/node": "14.14.37",
"@types/ws": "^7.4.1", "@types/ws": "^7.4.1",
"@types/supertest": "2.0.11",
"@typescript-eslint/eslint-plugin": "4.21.0", "@typescript-eslint/eslint-plugin": "4.21.0",
"@typescript-eslint/parser": "4.21.0", "@typescript-eslint/parser": "4.21.0",
"eslint": "7.23.0", "eslint": "7.23.0",
"eslint-config-prettier": "^8.1.0", "eslint-config-prettier": "^8.1.0",
"eslint-plugin-prettier": "3.3.1", "eslint-plugin-prettier": "3.3.1",
"jest": "26.6.3",
"nodemon": "2.0.7", "nodemon": "2.0.7",
"prettier": "2.2.1", "prettier": "2.2.1",
"supertest": "6.1.3",
"ts-jest": "26.5.4",
"ts-node": "9.1.1", "ts-node": "9.1.1",
"ts-node-dev": "1.1.6", "ts-node-dev": "1.1.6",
"typescript": "4.2.4" "typescript": "4.2.4"

View file

@ -1,6 +1,6 @@
import http from 'http' import http from 'http'
import express, { Application } from 'express' import express, { Application } from 'express'
import {Server as wsServer } from 'ws' import { Server as wsServer } from 'ws'
import initDebug from 'debug' import initDebug from 'debug'
import { registerMiddlewares } from './middlewares' import { registerMiddlewares } from './middlewares'
@ -14,7 +14,7 @@ import { registerApis } from './routes/api/register'
const PORT = normalizePort(process.env.PORT || '6595') const PORT = normalizePort(process.env.PORT || '6595')
const debug = initDebug('deemix-gui:server') const debug = initDebug('deemix-gui:server')
const app: Application = express() export const app: Application = express()
const ws = new wsServer({ noServer: true }) const ws = new wsServer({ noServer: true })
const server = http.createServer(app) const server = http.createServer(app)
@ -31,13 +31,15 @@ registerApis(app)
app.set('port', PORT) app.set('port', PORT)
/* === Server port === */ /* === Server port === */
server.listen(PORT) if (process.env.NODE_ENV !== 'test') {
server.listen(PORT)
}
/* === Server callbacks === */ /* === Server callbacks === */
server.on('upgrade', (request, socket, head) => { server.on('upgrade', (request, socket, head) => {
ws.handleUpgrade(request, socket, head, socket => { ws.handleUpgrade(request, socket, head, socket => {
ws.emit('connection', socket, request) ws.emit('connection', socket, request)
}) })
}) })
server.on('error', getErrorCb(PORT)) server.on('error', getErrorCb(PORT))
server.on('listening', getListeningCb(server, debug)) server.on('listening', getListeningCb(server, debug))

View file

@ -5,7 +5,10 @@ import cookieParser from 'cookie-parser'
import { WEBUI_DIR } from './helpers/paths' import { WEBUI_DIR } from './helpers/paths'
export function registerMiddlewares(app: Application) { export function registerMiddlewares(app: Application) {
app.use(logger('dev')) if (process.env.NODE_ENV !== 'test') {
app.use(logger('dev'))
}
app.use(express.json()) app.use(express.json())
app.use(express.urlencoded({ extended: false })) app.use(express.urlencoded({ extended: false }))
app.use(cookieParser()) app.use(cookieParser())

View file

@ -0,0 +1,41 @@
import request from 'supertest'
import { app } from '../../../app'
describe('albumSearch requests', () => {
it('should respond 200 to calls with term', async () => {
const responseStatusCollector: number[] = []
const batchCalls = [
'/api/album-search/?term=eminem',
'/api/album-search/?term=eminem?start=10',
'/api/album-search/?term=eminem?ack=aa',
'/api/album-search/?term=eminem?ack=aa?start=10',
'/api/album-search/?term=eminem?ack=aa?start=10?nb=34'
]
for (const uri of batchCalls) {
responseStatusCollector.push((await request(app).get(uri).send()).status)
}
expect(responseStatusCollector).toMatchObject(new Array(batchCalls.length).fill(200))
expect(responseStatusCollector).toMatchObject(new Array(responseStatusCollector.length).fill(200))
})
it('should respond 400 to calls without term', async () => {
const responseStatusCollector: number[] = []
const batchCalls = [
'/api/album-search/',
'/api/album-search/?start=10',
'/api/album-search/?ack=aa',
'/api/album-search/?ack=aa?start=10',
'/api/album-search/?ack=aa?start=10?nb=34'
]
for (const uri of batchCalls) {
responseStatusCollector.push((await request(app).get(uri).send()).status)
}
expect(responseStatusCollector).toMatchObject(new Array(responseStatusCollector.length).fill(400))
})
it.todo('should respond the desired search result')
})

View file

@ -0,0 +1,77 @@
import { RequestHandler } from 'express'
import { ApiHandler } from '../../../types'
export interface RawAlbumQuery {
term: string
start?: string
nb?: string
ack: number
}
export interface AlbumSearchParams extends Omit<RawAlbumQuery, 'start' | 'nb'> {
start: number
nb: number
}
export interface AlbumResponse {
data: any[]
total: number
ack: RawAlbumQuery['ack']
}
const path: ApiHandler['path'] = '/album-search/'
const handler: RequestHandler<{}, {}, {}, RawAlbumQuery> = (req, res, next) => {
if (!req.query) {
res.status(400).send()
next()
}
const { term, start, nb, ack } = parseQuery(req.query)
if (!term || term.trim() === '') {
res.status(400).send()
next()
}
// const albums = getAlbums(term, start, nb)
// const output: AlbumResponse = {
// data: albums,
// total: albums.length,
// ack
// }
// res.send(output)
res.send()
next()
}
const apiHandler = { path, handler }
export default apiHandler
function parseQuery(query: RawAlbumQuery): AlbumSearchParams {
let startingPoint = 0
if (typeof query.start !== 'undefined') {
startingPoint = parseInt(query.start)
}
let newNb = 30
if (typeof query.nb !== 'undefined') {
newNb = parseInt(query.nb)
}
return {
term: query.term,
start: startingPoint,
nb: newNb,
ack: query.ack
}
}
// function getAlbums(term: string, start: number, nb: number): any[] {
// return []
// }

View file

@ -1,8 +1,8 @@
import sample from './sample'
import getHome from './getHome' import getHome from './getHome'
import getCharts from './getCharts' import getCharts from './getCharts'
import mainSearch from './mainSearch' import mainSearch from './mainSearch'
import search from './search' import search from './search'
import getTracklist from './getTracklist' import getTracklist from './getTracklist'
import albumSearch from './albumSearch'
export default [sample, getHome, getCharts, mainSearch, search, getTracklist] export default [albumSearch, getHome, getCharts, mainSearch, search, getTracklist]

View file

@ -1,11 +0,0 @@
import { ApiHandler } from '../../../types'
const path: ApiHandler['path'] = '/sample'
const handler: ApiHandler['handler'] = (_, res) => {
res.send('Mandi')
}
const apiHandler: ApiHandler = { path, handler }
export default apiHandler

View file

@ -0,0 +1,28 @@
import request from 'supertest'
import { app } from '../app'
describe('root path requests', () => {
it('it responds 200 to the GET method', async () => {
const result = await request(app).get('/').send()
expect(result.status).toBe(200)
})
it('it responds 404 to the POST method', async () => {
const result = await request(app).post('/').send()
expect(result.status).toBe(404)
})
it('it responds 404 to the PATCH method', async () => {
const result = await request(app).patch('/').send()
expect(result.status).toBe(404)
})
it('it responds 404 to the DELETE method', async () => {
const result = await request(app).delete('/').send()
expect(result.status).toBe(404)
})
})

View file

@ -0,0 +1,30 @@
// Taken from https://github.com/visionmedia/supertest
import request from 'supertest'
import express from 'express'
import cookieParser from 'cookie-parser'
describe('cookie parser', () => {
const app = express()
app.use(cookieParser())
app.get('/', (_, res) => {
res.cookie('cookie', 'hey')
res.send()
})
app.get('/return', (req, res) => {
if (req.cookies.cookie) res.send(req.cookies.cookie)
else res.send(':(')
})
const agent = request.agent(app)
it('should save cookies', done => {
agent.get('/').expect('set-cookie', 'cookie=hey; Path=/', done)
})
it('should send cookies', done => {
agent.get('/return').expect('hey', done)
})
})

View file

@ -1,8 +1,12 @@
import { RequestHandler } from 'express' import { RequestHandler } from 'express'
/* === Utilities === */
// https://github.com/Microsoft/TypeScript/issues/25760#issuecomment-614417742
export type Optional<T, K extends keyof T> = Omit<T, K> & Partial<T>
export type Port = number | string | boolean export type Port = number | string | boolean
export interface ApiHandler { export interface ApiHandler {
path: string path: string
handler: RequestHandler handler: RequestHandler<any, any, any, any>
} }

File diff suppressed because it is too large Load diff