|
|
@@ -1,765 +0,0 @@ |
|
|
|
import { |
|
|
|
beforeAll, |
|
|
|
afterAll, |
|
|
|
afterEach, |
|
|
|
beforeEach, |
|
|
|
describe, |
|
|
|
expect, |
|
|
|
it, |
|
|
|
} from 'vitest'; |
|
|
|
import { |
|
|
|
tmpdir |
|
|
|
} from 'os'; |
|
|
|
import { |
|
|
|
mkdtemp, |
|
|
|
rm, |
|
|
|
writeFile, |
|
|
|
} from 'fs/promises'; |
|
|
|
import { |
|
|
|
join |
|
|
|
} from 'path'; |
|
|
|
import {request, Server} from 'http'; |
|
|
|
import {constants} from 'http2'; |
|
|
|
import {DataSource} from '../../src/backend/data-source'; |
|
|
|
import { dataSources } from '../../src/backend'; |
|
|
|
import { application, resource, validation as v, Resource } from '../../src'; |
|
|
|
|
|
|
|
const PORT = 3000; |
|
|
|
const HOST = '127.0.0.1'; |
|
|
|
const ACCEPT = 'application/json'; |
|
|
|
const ACCEPT_LANGUAGE = 'en'; |
|
|
|
const CONTENT_TYPE_CHARSET = 'utf-8'; |
|
|
|
const CONTENT_TYPE = ACCEPT; |
|
|
|
|
|
|
|
const autoIncrement = async (dataSource: DataSource) => { |
|
|
|
const data = await dataSource.getMultiple() as Record<string, string>[]; |
|
|
|
|
|
|
|
const highestId = data.reduce<number>( |
|
|
|
(highestId, d) => (Number(d.id) > highestId ? Number(d.id) : highestId), |
|
|
|
-Infinity |
|
|
|
); |
|
|
|
|
|
|
|
if (Number.isFinite(highestId)) { |
|
|
|
return (highestId + 1); |
|
|
|
} |
|
|
|
|
|
|
|
return 1; |
|
|
|
}; |
|
|
|
|
|
|
|
describe('yasumi', () => { |
|
|
|
let baseDir: string; |
|
|
|
beforeAll(async () => { |
|
|
|
try { |
|
|
|
baseDir = await mkdtemp(join(tmpdir(), 'yasumi-')); |
|
|
|
} catch { |
|
|
|
// noop |
|
|
|
} |
|
|
|
}); |
|
|
|
afterAll(async () => { |
|
|
|
try { |
|
|
|
await rm(baseDir, { |
|
|
|
recursive: true, |
|
|
|
}); |
|
|
|
} catch { |
|
|
|
// noop |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
let Piano: Resource; |
|
|
|
beforeEach(() => { |
|
|
|
Piano = resource(v.object( |
|
|
|
{ |
|
|
|
brand: v.string() |
|
|
|
}, |
|
|
|
v.never() |
|
|
|
)) |
|
|
|
.name('Piano' as const) |
|
|
|
.route('pianos' as const) |
|
|
|
.id('id' as const, { |
|
|
|
generationStrategy: autoIncrement, |
|
|
|
serialize: (id) => id?.toString() ?? '0', |
|
|
|
deserialize: (id) => Number.isFinite(Number(id)) ? Number(id) : 0, |
|
|
|
schema: v.number(), |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
let server: Server; |
|
|
|
beforeEach(() => { |
|
|
|
const app = application({ |
|
|
|
name: 'piano-service', |
|
|
|
}) |
|
|
|
.resource(Piano); |
|
|
|
|
|
|
|
const backend = app |
|
|
|
.createBackend({ |
|
|
|
dataSource: new dataSources.jsonlFile.DataSource(baseDir), |
|
|
|
}) |
|
|
|
.throwsErrorOnDeletingNotFound(); |
|
|
|
|
|
|
|
server = backend.createHttpServer({ |
|
|
|
basePath: '/api' |
|
|
|
}); |
|
|
|
|
|
|
|
return new Promise((resolve, reject) => { |
|
|
|
server.on('error', (err) => { |
|
|
|
reject(err); |
|
|
|
}); |
|
|
|
|
|
|
|
server.on('listening', () => { |
|
|
|
resolve(); |
|
|
|
}); |
|
|
|
|
|
|
|
server.listen({ |
|
|
|
port: PORT |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
afterEach(() => new Promise((resolve, reject) => { |
|
|
|
server.close((err) => { |
|
|
|
if (err) { |
|
|
|
reject(err); |
|
|
|
} |
|
|
|
|
|
|
|
resolve(); |
|
|
|
}); |
|
|
|
})); |
|
|
|
|
|
|
|
describe('serving collections', () => { |
|
|
|
beforeEach(() => { |
|
|
|
Piano.canFetchCollection(); |
|
|
|
return new Promise((resolve) => { |
|
|
|
setTimeout(() => { |
|
|
|
resolve(); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
afterEach(() => { |
|
|
|
Piano.canFetchCollection(false); |
|
|
|
}); |
|
|
|
|
|
|
|
it('returns data', () => { |
|
|
|
return new Promise<void>((resolve, reject) => { |
|
|
|
const req = request( |
|
|
|
{ |
|
|
|
host: HOST, |
|
|
|
port: PORT, |
|
|
|
path: '/api/pianos', |
|
|
|
method: 'GET', |
|
|
|
headers: { |
|
|
|
'Accept': ACCEPT, |
|
|
|
'Accept-Language': ACCEPT_LANGUAGE, |
|
|
|
}, |
|
|
|
}, |
|
|
|
(res) => { |
|
|
|
res.on('error', (err) => { |
|
|
|
reject(err); |
|
|
|
}); |
|
|
|
|
|
|
|
expect(res).toHaveProperty('statusCode', constants.HTTP_STATUS_OK); |
|
|
|
// TODO test status messsages |
|
|
|
expect(res.headers).toHaveProperty('content-type', expect.stringContaining(ACCEPT)); |
|
|
|
|
|
|
|
let resBuffer = Buffer.from(''); |
|
|
|
res.on('data', (c) => { |
|
|
|
resBuffer = Buffer.concat([resBuffer, c]); |
|
|
|
}); |
|
|
|
|
|
|
|
res.on('close', () => { |
|
|
|
const resBufferJson = resBuffer.toString(CONTENT_TYPE_CHARSET); |
|
|
|
const resData = JSON.parse(resBufferJson); |
|
|
|
expect(resData).toEqual([]); |
|
|
|
resolve(); |
|
|
|
}); |
|
|
|
}, |
|
|
|
); |
|
|
|
|
|
|
|
req.on('error', (err) => { |
|
|
|
reject(err); |
|
|
|
}); |
|
|
|
|
|
|
|
req.end(); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
it('returns data on HEAD method', () => { |
|
|
|
return new Promise<void>((resolve, reject) => { |
|
|
|
const req = request( |
|
|
|
{ |
|
|
|
host: HOST, |
|
|
|
port: PORT, |
|
|
|
path: '/api/pianos', |
|
|
|
method: 'HEAD', |
|
|
|
headers: { |
|
|
|
'Accept': ACCEPT, |
|
|
|
'Accept-Language': ACCEPT_LANGUAGE, |
|
|
|
}, |
|
|
|
}, |
|
|
|
(res) => { |
|
|
|
res.on('error', (err) => { |
|
|
|
reject(err); |
|
|
|
}); |
|
|
|
|
|
|
|
expect(res).toHaveProperty('statusCode', constants.HTTP_STATUS_OK); |
|
|
|
resolve(); |
|
|
|
}, |
|
|
|
); |
|
|
|
|
|
|
|
req.on('error', (err) => { |
|
|
|
reject(err); |
|
|
|
}); |
|
|
|
|
|
|
|
req.end(); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
describe('serving items', () => { |
|
|
|
const data = { |
|
|
|
id: 1, |
|
|
|
brand: 'Yamaha' |
|
|
|
}; |
|
|
|
|
|
|
|
beforeEach(async () => { |
|
|
|
const resourcePath = join(baseDir, 'pianos.jsonl'); |
|
|
|
await writeFile(resourcePath, JSON.stringify(data)); |
|
|
|
}); |
|
|
|
|
|
|
|
beforeEach(() => { |
|
|
|
Piano.canFetchItem(); |
|
|
|
return new Promise((resolve) => { |
|
|
|
setTimeout(() => { |
|
|
|
resolve(); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
afterEach(() => { |
|
|
|
Piano.canFetchItem(false); |
|
|
|
}); |
|
|
|
|
|
|
|
it('returns data', () => { |
|
|
|
return new Promise<void>((resolve, reject) => { |
|
|
|
// TODO all responses should have serialized ids |
|
|
|
const req = request( |
|
|
|
{ |
|
|
|
host: HOST, |
|
|
|
port: PORT, |
|
|
|
path: '/api/pianos/1', |
|
|
|
method: 'GET', |
|
|
|
headers: { |
|
|
|
'Accept': ACCEPT, |
|
|
|
'Accept-Language': ACCEPT_LANGUAGE, |
|
|
|
}, |
|
|
|
}, |
|
|
|
(res) => { |
|
|
|
res.on('error', (err) => { |
|
|
|
reject(err); |
|
|
|
}); |
|
|
|
|
|
|
|
expect(res).toHaveProperty('statusCode', constants.HTTP_STATUS_OK); |
|
|
|
expect(res.headers).toHaveProperty('content-type', expect.stringContaining(ACCEPT)); |
|
|
|
|
|
|
|
let resBuffer = Buffer.from(''); |
|
|
|
res.on('data', (c) => { |
|
|
|
resBuffer = Buffer.concat([resBuffer, c]); |
|
|
|
}); |
|
|
|
|
|
|
|
res.on('close', () => { |
|
|
|
const resBufferJson = resBuffer.toString(CONTENT_TYPE_CHARSET); |
|
|
|
const resData = JSON.parse(resBufferJson); |
|
|
|
expect(resData).toEqual(data); |
|
|
|
resolve(); |
|
|
|
}); |
|
|
|
}, |
|
|
|
); |
|
|
|
|
|
|
|
req.on('error', (err) => { |
|
|
|
reject(err); |
|
|
|
}); |
|
|
|
|
|
|
|
req.end(); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
it('returns data on HEAD method', () => { |
|
|
|
return new Promise<void>((resolve, reject) => { |
|
|
|
// TODO all responses should have serialized ids |
|
|
|
const req = request( |
|
|
|
{ |
|
|
|
host: HOST, |
|
|
|
port: PORT, |
|
|
|
path: '/api/pianos/1', |
|
|
|
method: 'HEAD', |
|
|
|
headers: { |
|
|
|
'Accept': ACCEPT, |
|
|
|
'Accept-Language': ACCEPT_LANGUAGE, |
|
|
|
}, |
|
|
|
}, |
|
|
|
(res) => { |
|
|
|
res.on('error', (err) => { |
|
|
|
reject(err); |
|
|
|
}); |
|
|
|
|
|
|
|
expect(res).toHaveProperty('statusCode', constants.HTTP_STATUS_OK); |
|
|
|
resolve(); |
|
|
|
}, |
|
|
|
); |
|
|
|
|
|
|
|
req.on('error', (err) => { |
|
|
|
reject(err); |
|
|
|
}); |
|
|
|
|
|
|
|
req.end(); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
it('throws on item not found', () => { |
|
|
|
return new Promise<void>((resolve, reject) => { |
|
|
|
const req = request( |
|
|
|
{ |
|
|
|
host: HOST, |
|
|
|
port: PORT, |
|
|
|
path: '/api/pianos/2', |
|
|
|
method: 'GET', |
|
|
|
headers: { |
|
|
|
'Accept': ACCEPT, |
|
|
|
'Accept-Language': ACCEPT_LANGUAGE, |
|
|
|
}, |
|
|
|
}, |
|
|
|
(res) => { |
|
|
|
res.on('error', (err) => { |
|
|
|
Piano.canFetchItem(false); |
|
|
|
reject(err); |
|
|
|
}); |
|
|
|
|
|
|
|
expect(res).toHaveProperty('statusCode', constants.HTTP_STATUS_NOT_FOUND); |
|
|
|
resolve(); |
|
|
|
}, |
|
|
|
); |
|
|
|
|
|
|
|
req.on('error', (err) => { |
|
|
|
reject(err); |
|
|
|
}); |
|
|
|
|
|
|
|
req.end(); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
it('throws on item not found on HEAD method', () => { |
|
|
|
return new Promise<void>((resolve, reject) => { |
|
|
|
const req = request( |
|
|
|
{ |
|
|
|
host: HOST, |
|
|
|
port: PORT, |
|
|
|
path: '/api/pianos/2', |
|
|
|
method: 'HEAD', |
|
|
|
headers: { |
|
|
|
'Accept': ACCEPT, |
|
|
|
'Accept-Language': ACCEPT_LANGUAGE, |
|
|
|
}, |
|
|
|
}, |
|
|
|
(res) => { |
|
|
|
res.on('error', (err) => { |
|
|
|
Piano.canFetchItem(false); |
|
|
|
reject(err); |
|
|
|
}); |
|
|
|
|
|
|
|
expect(res).toHaveProperty('statusCode', constants.HTTP_STATUS_NOT_FOUND); |
|
|
|
resolve(); |
|
|
|
}, |
|
|
|
); |
|
|
|
|
|
|
|
req.on('error', (err) => { |
|
|
|
reject(err); |
|
|
|
}); |
|
|
|
|
|
|
|
req.end(); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
describe('creating items', () => { |
|
|
|
const data = { |
|
|
|
id: 1, |
|
|
|
brand: 'Yamaha' |
|
|
|
}; |
|
|
|
|
|
|
|
const newData = { |
|
|
|
brand: 'K. Kawai' |
|
|
|
}; |
|
|
|
|
|
|
|
beforeEach(async () => { |
|
|
|
const resourcePath = join(baseDir, 'pianos.jsonl'); |
|
|
|
await writeFile(resourcePath, JSON.stringify(data)); |
|
|
|
}); |
|
|
|
|
|
|
|
beforeEach(() => { |
|
|
|
Piano.canCreate(); |
|
|
|
}); |
|
|
|
|
|
|
|
afterEach(() => { |
|
|
|
Piano.canCreate(false); |
|
|
|
}); |
|
|
|
|
|
|
|
it('returns data', () => { |
|
|
|
return new Promise<void>((resolve, reject) => { |
|
|
|
const req = request( |
|
|
|
{ |
|
|
|
host: HOST, |
|
|
|
port: PORT, |
|
|
|
path: '/api/pianos', |
|
|
|
method: 'POST', |
|
|
|
headers: { |
|
|
|
'Accept': ACCEPT, |
|
|
|
'Accept-Language': ACCEPT_LANGUAGE, |
|
|
|
'Content-Type': `${CONTENT_TYPE}; charset="${CONTENT_TYPE_CHARSET}"`, |
|
|
|
}, |
|
|
|
}, |
|
|
|
(res) => { |
|
|
|
res.on('error', (err) => { |
|
|
|
reject(err); |
|
|
|
}); |
|
|
|
|
|
|
|
expect(res).toHaveProperty('statusCode', constants.HTTP_STATUS_CREATED); |
|
|
|
expect(res.headers).toHaveProperty('content-type', expect.stringContaining(ACCEPT)); |
|
|
|
|
|
|
|
let resBuffer = Buffer.from(''); |
|
|
|
res.on('data', (c) => { |
|
|
|
resBuffer = Buffer.concat([resBuffer, c]); |
|
|
|
}); |
|
|
|
|
|
|
|
res.on('close', () => { |
|
|
|
const resBufferJson = resBuffer.toString(CONTENT_TYPE_CHARSET); |
|
|
|
const resData = JSON.parse(resBufferJson); |
|
|
|
expect(resData).toEqual({ |
|
|
|
...newData, |
|
|
|
id: 2 |
|
|
|
}); |
|
|
|
|
|
|
|
resolve(); |
|
|
|
}); |
|
|
|
}, |
|
|
|
); |
|
|
|
|
|
|
|
req.on('error', (err) => { |
|
|
|
reject(err); |
|
|
|
}); |
|
|
|
|
|
|
|
req.write(JSON.stringify(newData)); |
|
|
|
req.end(); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
describe('patching items', () => { |
|
|
|
const data = { |
|
|
|
id: 1, |
|
|
|
brand: 'Yamaha' |
|
|
|
}; |
|
|
|
|
|
|
|
const newData = { |
|
|
|
brand: 'K. Kawai' |
|
|
|
}; |
|
|
|
|
|
|
|
beforeEach(async () => { |
|
|
|
const resourcePath = join(baseDir, 'pianos.jsonl'); |
|
|
|
await writeFile(resourcePath, JSON.stringify(data)); |
|
|
|
}); |
|
|
|
|
|
|
|
beforeEach(() => { |
|
|
|
Piano.canPatch(); |
|
|
|
}); |
|
|
|
|
|
|
|
afterEach(() => { |
|
|
|
Piano.canPatch(false); |
|
|
|
}); |
|
|
|
|
|
|
|
it('returns data', () => { |
|
|
|
return new Promise<void>((resolve, reject) => { |
|
|
|
const req = request( |
|
|
|
{ |
|
|
|
host: HOST, |
|
|
|
port: PORT, |
|
|
|
path: `/api/pianos/${data.id}`, |
|
|
|
method: 'PATCH', |
|
|
|
headers: { |
|
|
|
'Accept': ACCEPT, |
|
|
|
'Accept-Language': ACCEPT_LANGUAGE, |
|
|
|
'Content-Type': `${CONTENT_TYPE}; charset="${CONTENT_TYPE_CHARSET}"`, |
|
|
|
}, |
|
|
|
}, |
|
|
|
(res) => { |
|
|
|
res.on('error', (err) => { |
|
|
|
reject(err); |
|
|
|
}); |
|
|
|
|
|
|
|
expect(res).toHaveProperty('statusCode', constants.HTTP_STATUS_OK); |
|
|
|
expect(res.headers).toHaveProperty('content-type', expect.stringContaining(ACCEPT)); |
|
|
|
|
|
|
|
let resBuffer = Buffer.from(''); |
|
|
|
res.on('data', (c) => { |
|
|
|
resBuffer = Buffer.concat([resBuffer, c]); |
|
|
|
}); |
|
|
|
|
|
|
|
res.on('close', () => { |
|
|
|
const resBufferJson = resBuffer.toString(CONTENT_TYPE_CHARSET); |
|
|
|
const resData = JSON.parse(resBufferJson); |
|
|
|
expect(resData).toEqual({ |
|
|
|
...data, |
|
|
|
...newData, |
|
|
|
}); |
|
|
|
resolve(); |
|
|
|
}); |
|
|
|
}, |
|
|
|
); |
|
|
|
|
|
|
|
req.on('error', (err) => { |
|
|
|
reject(err); |
|
|
|
}); |
|
|
|
|
|
|
|
req.write(JSON.stringify(newData)); |
|
|
|
req.end(); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
it('throws on item to patch not found', () => { |
|
|
|
return new Promise<void>((resolve, reject) => { |
|
|
|
const req = request( |
|
|
|
{ |
|
|
|
host: HOST, |
|
|
|
port: PORT, |
|
|
|
path: '/api/pianos/2', |
|
|
|
method: 'PATCH', |
|
|
|
headers: { |
|
|
|
'Accept': ACCEPT, |
|
|
|
'Accept-Language': ACCEPT_LANGUAGE, |
|
|
|
'Content-Type': `${CONTENT_TYPE}; charset="${CONTENT_TYPE_CHARSET}"`, |
|
|
|
}, |
|
|
|
}, |
|
|
|
(res) => { |
|
|
|
res.on('error', (err) => { |
|
|
|
reject(err); |
|
|
|
}); |
|
|
|
|
|
|
|
expect(res).toHaveProperty('statusCode', constants.HTTP_STATUS_NOT_FOUND); |
|
|
|
resolve(); |
|
|
|
}, |
|
|
|
); |
|
|
|
|
|
|
|
req.on('error', (err) => { |
|
|
|
reject(err); |
|
|
|
}); |
|
|
|
|
|
|
|
req.write(JSON.stringify(newData)); |
|
|
|
req.end(); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
describe('emplacing items', () => { |
|
|
|
const data = { |
|
|
|
id: 1, |
|
|
|
brand: 'Yamaha' |
|
|
|
}; |
|
|
|
|
|
|
|
const newData = { |
|
|
|
id: 1, |
|
|
|
brand: 'K. Kawai' |
|
|
|
}; |
|
|
|
|
|
|
|
beforeEach(async () => { |
|
|
|
const resourcePath = join(baseDir, 'pianos.jsonl'); |
|
|
|
await writeFile(resourcePath, JSON.stringify(data)); |
|
|
|
}); |
|
|
|
|
|
|
|
beforeEach(() => { |
|
|
|
Piano.canEmplace(); |
|
|
|
}); |
|
|
|
|
|
|
|
afterEach(() => { |
|
|
|
Piano.canEmplace(false); |
|
|
|
}); |
|
|
|
|
|
|
|
it('returns data for replacement', () => { |
|
|
|
return new Promise<void>((resolve, reject) => { |
|
|
|
const req = request( |
|
|
|
{ |
|
|
|
host: HOST, |
|
|
|
port: PORT, |
|
|
|
path: `/api/pianos/${newData.id}`, |
|
|
|
method: 'PUT', |
|
|
|
headers: { |
|
|
|
'Accept': ACCEPT, |
|
|
|
'Accept-Language': ACCEPT_LANGUAGE, |
|
|
|
'Content-Type': `${CONTENT_TYPE}; charset="${CONTENT_TYPE_CHARSET}"`, |
|
|
|
}, |
|
|
|
}, |
|
|
|
(res) => { |
|
|
|
res.on('error', (err) => { |
|
|
|
reject(err); |
|
|
|
}); |
|
|
|
|
|
|
|
expect(res).toHaveProperty('statusCode', constants.HTTP_STATUS_OK); |
|
|
|
expect(res.headers).toHaveProperty('content-type', expect.stringContaining(ACCEPT)); |
|
|
|
|
|
|
|
let resBuffer = Buffer.from(''); |
|
|
|
res.on('data', (c) => { |
|
|
|
resBuffer = Buffer.concat([resBuffer, c]); |
|
|
|
}); |
|
|
|
|
|
|
|
res.on('close', () => { |
|
|
|
const resBufferJson = resBuffer.toString(CONTENT_TYPE_CHARSET); |
|
|
|
const resData = JSON.parse(resBufferJson); |
|
|
|
expect(resData).toEqual(newData); |
|
|
|
resolve(); |
|
|
|
}); |
|
|
|
}, |
|
|
|
); |
|
|
|
|
|
|
|
req.on('error', (err) => { |
|
|
|
reject(err); |
|
|
|
}); |
|
|
|
|
|
|
|
req.write(JSON.stringify(newData)); |
|
|
|
req.end(); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
it('returns data for creation', () => { |
|
|
|
return new Promise<void>((resolve, reject) => { |
|
|
|
const id = 2; |
|
|
|
|
|
|
|
const req = request( |
|
|
|
{ |
|
|
|
host: HOST, |
|
|
|
port: PORT, |
|
|
|
path: `/api/pianos/${id}`, |
|
|
|
method: 'PUT', |
|
|
|
headers: { |
|
|
|
'Accept': ACCEPT, |
|
|
|
'Accept-Language': ACCEPT_LANGUAGE, |
|
|
|
'Content-Type': `${CONTENT_TYPE}; charset="${CONTENT_TYPE_CHARSET}"`, |
|
|
|
}, |
|
|
|
}, |
|
|
|
(res) => { |
|
|
|
res.on('error', (err) => { |
|
|
|
reject(err); |
|
|
|
}); |
|
|
|
|
|
|
|
expect(res).toHaveProperty('statusCode', constants.HTTP_STATUS_CREATED); |
|
|
|
expect(res.headers).toHaveProperty('content-type', expect.stringContaining(ACCEPT)); |
|
|
|
|
|
|
|
let resBuffer = Buffer.from(''); |
|
|
|
res.on('data', (c) => { |
|
|
|
resBuffer = Buffer.concat([resBuffer, c]); |
|
|
|
}); |
|
|
|
|
|
|
|
res.on('close', () => { |
|
|
|
const resBufferJson = resBuffer.toString(CONTENT_TYPE_CHARSET); |
|
|
|
const resData = JSON.parse(resBufferJson); |
|
|
|
expect(resData).toEqual({ |
|
|
|
...newData, |
|
|
|
id, |
|
|
|
}); |
|
|
|
resolve(); |
|
|
|
}); |
|
|
|
}, |
|
|
|
); |
|
|
|
|
|
|
|
req.on('error', (err) => { |
|
|
|
reject(err); |
|
|
|
}); |
|
|
|
|
|
|
|
req.write(JSON.stringify({ |
|
|
|
...newData, |
|
|
|
id, |
|
|
|
})); |
|
|
|
req.end(); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
describe('deleting items', () => { |
|
|
|
const data = { |
|
|
|
id: 1, |
|
|
|
brand: 'Yamaha' |
|
|
|
}; |
|
|
|
|
|
|
|
beforeEach(async () => { |
|
|
|
const resourcePath = join(baseDir, 'pianos.jsonl'); |
|
|
|
await writeFile(resourcePath, JSON.stringify(data)); |
|
|
|
}); |
|
|
|
|
|
|
|
beforeEach(() => { |
|
|
|
Piano.canDelete(); |
|
|
|
}); |
|
|
|
|
|
|
|
afterEach(() => { |
|
|
|
Piano.canDelete(false); |
|
|
|
}); |
|
|
|
|
|
|
|
it('returns data', () => { |
|
|
|
return new Promise<void>((resolve, reject) => { |
|
|
|
const req = request( |
|
|
|
{ |
|
|
|
host: HOST, |
|
|
|
port: PORT, |
|
|
|
path: `/api/pianos/${data.id}`, |
|
|
|
method: 'DELETE', |
|
|
|
headers: { |
|
|
|
'Accept': ACCEPT, |
|
|
|
'Accept-Language': ACCEPT_LANGUAGE, |
|
|
|
}, |
|
|
|
}, |
|
|
|
(res) => { |
|
|
|
res.on('error', (err) => { |
|
|
|
reject(err); |
|
|
|
}); |
|
|
|
|
|
|
|
expect(res).toHaveProperty('statusCode', constants.HTTP_STATUS_NO_CONTENT); |
|
|
|
resolve(); |
|
|
|
}, |
|
|
|
); |
|
|
|
|
|
|
|
req.on('error', (err) => { |
|
|
|
reject(err); |
|
|
|
}); |
|
|
|
|
|
|
|
req.end(); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
it('throws on item not found', () => { |
|
|
|
return new Promise<void>((resolve, reject) => { |
|
|
|
const req = request( |
|
|
|
{ |
|
|
|
host: HOST, |
|
|
|
port: PORT, |
|
|
|
path: '/api/pianos/2', |
|
|
|
method: 'DELETE', |
|
|
|
headers: { |
|
|
|
'Accept': ACCEPT, |
|
|
|
'Accept-Language': ACCEPT_LANGUAGE, |
|
|
|
}, |
|
|
|
}, |
|
|
|
(res) => { |
|
|
|
res.on('error', (err) => { |
|
|
|
reject(err); |
|
|
|
}); |
|
|
|
|
|
|
|
expect(res).toHaveProperty('statusCode', constants.HTTP_STATUS_NOT_FOUND); |
|
|
|
resolve(); |
|
|
|
}, |
|
|
|
); |
|
|
|
|
|
|
|
req.on('error', (err) => { |
|
|
|
reject(err); |
|
|
|
}); |
|
|
|
|
|
|
|
req.end(); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |