jsonapi-server-mini
Version:
Minimalistic JSON:API server for Node.js and MongoDB
275 lines (253 loc) • 6.64 kB
JavaScript
const chai = require('chai')
const chaiHttp = require('chai-http')
const mongoose = require('mongoose')
const { ObjectId } = mongoose.Types
const { assert, expect } = chai
chai.should()
chai.use(chaiHttp)
describe('Updating Resources', function() {
let dog, cat, Animal, Person, id, person
before('Set up database', async function() {
if (process.env.NODE_ENV === 'test') {
Animal = mongoose.model('Animal')
Person = mongoose.model('Person')
dog = new Animal({name: 'Dogmeat'})
cat = new Animal({name: 'Tiger'})
dog.save()
cat.save()
// for (const i of [1, 2, 3]) {
// const person = new Person({
// name : `Redsandro ${i}`,
// age : i,
// pets : [dog, cat]
// })
// await person.save()
// }
}
else throw new Error('This is not a testing environment. You will nuke your database.')
})
beforeEach(async function() {
if (process.env.NODE_ENV === 'test') {
person = new Person({
name : 'Sir Redsandro',
age : 541,
pets : [dog, cat]
})
await person.save()
id = person.id
return id
}
else throw new Error('This is not a testing environment. You will nuke your database.')
})
it('should return 404 when id is invalid type for model', async function() {
return chai.request(await global.app)
.patch('/chats/ThisIdClearlyDoesNotExist')
.type('application/vnd.api+json')
.send({ data: {
attributes: {
name: 'name',
count: 0,
},
}})
.then(res => res.should.have.status(404) && res)
.then(global.validateJSONAPI)
})
it('should return 404 when resource does not exist', async function() {
return chai.request(await global.app)
.patch(`/chats/${ObjectId()}`)
.type('application/vnd.api+json')
.send({ data: {
attributes: {
name: 'name',
count: 0,
},
}})
.then(res => res.should.have.status(404) && res)
.then(global.validateJSONAPI)
})
it('should ignore bad attributes', async function() {
const myId = await chai.request(await global.app)
.post('/people')
.type('application/vnd.api+json')
.send({ data: {
type: 'people',
attributes: {
name: 'Test',
}
}})
.then(res => res.body.data.id)
const originalData = await chai.request(await global.app)
.get(`/people/${myId}`)
.then(res => res.body)
const patchedData = await chai.request(await global.app)
.patch(`/people/${myId}`)
.type('application/vnd.api+json')
.send({ data: {
type: 'people',
attributes: {
secret: 'My Little Pony',
}
}})
.then(res => {
res.should.have.status(200)
res.body.should.not.have.nested.property('data.attributes.secret')
return res
})
.then(res => res.body)
return await chai.request(await global.app)
.get(`/people/${myId}`)
.then(res => res.body)
.then(newData => {
expect(originalData).to.deep.equal(patchedData)
expect(originalData).to.deep.equal(newData)
})
})
it('should return updated document', async function() {
const body = await chai.request(await global.app)
.post('/people')
.type('application/vnd.api+json')
.send({ data: {
type: 'people',
attributes: {
name: 'Test',
}
}})
.then(res => res.body)
return await chai.request(await global.app)
.patch(`/people/${body.data.id}`)
.type('application/vnd.api+json')
.send({ data: {
type: 'people',
attributes: {
name: 'Milo',
}
}})
.then(res => {
res.should.have.status(200)
res.body.should.have.nested.property('data.attributes.name', 'Milo')
return res
})
})
it('should only change patched attributes', async function() {
const newId = ObjectId()
const body = await chai.request(await global.app)
.post('/people')
.type('application/vnd.api+json')
.send({ data: {
type: 'people',
attributes: {
name: 'Youngster',
age: 1
},
relationships: {
pets: {
data: [{type: 'Animal', id: newId}]
}
}
}})
.then(res => res.should.have.status(201) && res)
.then(res => res.body)
return await chai.request(await global.app)
.patch(`/people/${body.data.id}`)
.type('application/vnd.api+json')
.send({ data: {
type: 'people',
attributes: {
age: 2,
}
}})
.then(res => {
res.should.have.status(200)
res.body.should.nested.include({
'data.attributes.name': 'Youngster',
'data.attributes.age': 2,
})
expect(res.body.data.relationships.pets.data[0]).to.have.property('id', newId.toString())
return res
})
})
it('should convert dasherized patch to camelCase', async function() {
const p1 = ObjectId()
const p2 = ObjectId()
await chai.request(await global.app)
.post('/people')
.type('application/vnd.api+json')
.send({ data: {
type: 'people',
id: p1,
attributes: {
name: 'Yetti',
}
}})
.then(res => res.should.have.status(201) && res)
.then(res => res.body)
await chai.request(await global.app)
.patch(`/people/${p1}`)
.type('application/vnd.api+json')
.send({ data: {
type: 'people',
relationships: {
'in-law': {
data: {
type: 'people',
id: p2
}
}
}
}})
.then(res => {
res.should.have.status(200)
})
return await Person.findOne({_id: p1}).exec().then(doc => {
doc.should.have.deep.property('inLaw', p2)
})
})
})
describe('Updating Relationships', function() {
it('should remove relationship with patch', async function() {
const newId = ObjectId()
const body = await chai.request(await global.app)
.post('/people')
.type('application/vnd.api+json')
.send({ data: {
type: 'people',
attributes: {
name: 'Youngster',
age: 1
},
relationships: {
pets: {
data: [{type: 'Animal', id: newId}]
}
}
}})
.then(res => res.should.have.status(201) && res)
.then(res => res.body)
return await chai.request(await global.app)
.patch(`/people/${body.data.id}`)
.type('application/vnd.api+json')
.send({ data: {
type: 'people',
attributes: {
age: 49
},
relationships: {
pets: {
data: []
},
}
}})
.then(res => {
res.should.have.status(200)
res.body.should.nested.include({
'data.attributes.name': 'Youngster',
'data.attributes.age': 49,
})
expect(res.body.data.relationships.pets.data).to.be.empty
return res
})
})
it('should add one-to-one (object) relationship with patch')
it('should add one-to-many (array) relationship with patch')
it('should patch relationships independently (PATCH /articles/1/relationships/author)')
})