Skip to content

Commit

Permalink
Implement patch but it is broken!
Browse files Browse the repository at this point in the history
That is a little harsh. It does work, but it has now retry support from Got unlike the other types of requests.

So, our retry tests fail. Good to know they are working as expected!
  • Loading branch information
Cruikshanks committed Mar 4, 2023
1 parent 7936a49 commit 70fc645
Show file tree
Hide file tree
Showing 2 changed files with 200 additions and 0 deletions.
5 changes: 5 additions & 0 deletions app/lib/request.lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ async function get (url, additionalOptions = {}) {
return await _sendRequest('get', url, additionalOptions)
}

async function patch (url, additionalOptions = {}) {
return await _sendRequest('patch', url, additionalOptions)
}

async function post (url, additionalOptions = {}) {
return await _sendRequest('post', url, additionalOptions)
}
Expand Down Expand Up @@ -162,5 +166,6 @@ function _requestOptions (additionalOptions) {

module.exports = {
get,
patch,
post
}
195 changes: 195 additions & 0 deletions test/lib/request.lib.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,201 @@ describe('RequestLib', () => {
})
})

describe.only('#patch()', () => {
describe('When a request succeeds', () => {
beforeEach(() => {
Nock(testDomain).patch('/').reply(200, { data: 'hello world' })
})

describe('the result it returns', () => {
it("has a 'succeeded' property marked as true", async () => {
const result = await RequestLib.patch(testDomain)

expect(result.succeeded).to.be.true()
})

it("has a 'response' property containing the web response", async () => {
const result = await RequestLib.patch(testDomain)

expect(result.response).to.exist()
expect(result.response.statusCode).to.equal(200)
expect(result.response.body).to.equal('{"data":"hello world"}')
})
})
})

describe('When a request fails', () => {
describe('because the response was a 500', () => {
beforeEach(() => {
Nock(testDomain).patch('/').reply(500, { data: 'hello world' })
})

it('logs the failure', async () => {
await RequestLib.patch(testDomain)

const logDataArg = notifierStub.omg.args[0][1]

expect(notifierStub.omg.calledWith('PATCH request failed')).to.be.true()
expect(logDataArg.method).to.equal('PATCH')
expect(logDataArg.url).to.equal('http://example.com')
expect(logDataArg.additionalOptions).to.equal({})
expect(logDataArg.result.succeeded).to.be.false()
expect(logDataArg.result.response).to.equal({
statusCode: 500,
body: '{"data":"hello world"}'
})
})

describe('the result it returns', () => {
it("has a 'succeeded' property marked as false", async () => {
const result = await RequestLib.patch(testDomain)

expect(result.succeeded).to.be.false()
})

it("has a 'response' property containing the web response", async () => {
const result = await RequestLib.patch(testDomain)

expect(result.response).to.exist()
expect(result.response.statusCode).to.equal(500)
expect(result.response.body).to.equal('{"data":"hello world"}')
})
})
})

describe('because there was a network issue', () => {
beforeEach(() => {
Nock(testDomain).patch('/').replyWithError({ code: 'ECONNRESET' })
})

it('logs and records the error', async () => {
await RequestLib.patch(testDomain)

const logDataArg = notifierStub.omfg.args[0][1]

expect(notifierStub.omfg.calledWith('PATCH request errored')).to.be.true()
expect(logDataArg.method).to.equal('PATCH')
expect(logDataArg.url).to.equal('http://example.com')
expect(logDataArg.additionalOptions).to.equal({})
expect(logDataArg.result.succeeded).to.be.false()
expect(logDataArg.result.response).to.be.an.error()
})

describe('the result it returns', () => {
it("has a 'succeeded' property marked as false", async () => {
const result = await RequestLib.patch(testDomain)

expect(result.succeeded).to.be.false()
})

it("has a 'response' property containing the error", async () => {
const result = await RequestLib.patch(testDomain)

expect(result.response).to.exist()
expect(result.response).to.be.an.error()
expect(result.response.code).to.equal('ECONNRESET')
})
})
})

describe('because request timed out', () => {
beforeEach(async () => {
// Set the timeout value to 50ms for these tests
Sinon.replace(requestConfig, 'timeout', 50)
})

// Because of the fake delay in this test, Lab will timeout (by default tests have 2 seconds to finish). So, we
// have to override the timeout for this specific test to all it to complete
describe('and all retries fail', { timeout: 5000 }, () => {
beforeEach(async () => {
Nock(testDomain)
.patch(() => true)
.delay(100)
.reply(200, { data: 'hello world' })
.persist()
})

describe('the result it returns', () => {
it("has a 'succeeded' property marked as false", async () => {
const result = await RequestLib.patch(testDomain)

expect(result.succeeded).to.be.false()
})

it("has a 'response' property containing the error", async () => {
const result = await RequestLib.patch(testDomain)

expect(result.response).to.exist()
expect(result.response).to.be.an.error()
expect(result.response.code).to.equal('ETIMEDOUT')
})
})
})

describe('and a retry succeeds', () => {
beforeEach(async () => {
// The first response will time out, the second response will return OK
Nock(testDomain)
.patch(() => true)
.delay(100)
.reply(200, { data: 'hello world' })
.patch(() => true)
.reply(200, { data: 'delayed hello world' })
})

describe('the result it returns', () => {
it("has a 'succeeded' property marked as true", async () => {
const result = await RequestLib.patch(testDomain)

expect(result.succeeded).to.be.true()
})

it("has a 'response' property containing the web response", async () => {
const result = await RequestLib.patch(testDomain)

expect(result.response).to.exist()
expect(result.response.statusCode).to.equal(200)
expect(result.response.body).to.equal('{"data":"delayed hello world"}')
})
})
})
})
})

describe('When I provide additional options', () => {
describe('and they expand the default options', () => {
beforeEach(() => {
Nock(testDomain).patch('/').reply(200, { data: 'hello world' })
})

it('adds them to the options used when making the request', async () => {
// We tell Got to return the response as json rather than text. We can confirm the option has been applied by
// checking the result.response.body below.
const options = { responseType: 'json' }
const result = await RequestLib.patch(testDomain, options)

expect(result.succeeded).to.be.true()
expect(result.response.body).to.equal({ data: 'hello world' })
})
})

describe('and they replace a default option', () => {
beforeEach(() => {
Nock(testDomain).patch('/').reply(500)
})

it('uses them in the options used when making the request', async () => {
// We tell Got throw an error if the response is not 2xx or 3xx
const options = { throwHttpErrors: true }
const result = await RequestLib.patch(testDomain, options)

expect(result.succeeded).to.be.false()
expect(result.response).to.be.an.error()
})
})
})
})

describe('#post()', () => {
describe('When a request succeeds', () => {
beforeEach(() => {
Expand Down

0 comments on commit 70fc645

Please sign in to comment.