Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Update mode #2241

Merged
merged 4 commits into from Nov 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Expand Up @@ -1471,6 +1471,8 @@ To set the mode call `nockBack.setMode(mode)` or run the tests with the `NOCK_BA

- record: use recorded nocks, record new nocks

- update: remove recorded nocks, record nocks

- lockdown: use recorded nocks, disables all http calls even when not nocked, doesn't record

## Common issues
Expand Down
56 changes: 56 additions & 0 deletions lib/back.js
Expand Up @@ -175,6 +175,47 @@ const record = {
},
}

const update = {
setup: function () {
recorder.restore()
recorder.clear()
cleanAll()
activate()
disableNetConnect()
},

start: function (fixture, options) {
if (!fs) {
throw new Error('no fs')
}
const context = removeFixture(fixture)
recorder.record({
dont_print: true,
output_objects: true,
...options.recorder,
})

context.isRecording = true

return context
},

finish: function (fixture, options, context) {
let outputs = recorder.outputs()

if (typeof options.afterRecord === 'function') {
outputs = options.afterRecord(outputs)
}

outputs =
typeof outputs === 'string' ? outputs : JSON.stringify(outputs, null, 4)
debug('recorder outputs:', outputs)

fs.mkdirSync(path.dirname(fixture), { recursive: true })
fs.writeFileSync(fixture, outputs)
},
}

const lockdown = {
setup: function () {
recorder.restore()
Expand Down Expand Up @@ -215,6 +256,19 @@ function load(fixture, options) {
return context
}

function removeFixture(fixture, options) {
const context = {
scopes: [],
assertScopesFinished: function () {},
}

if (fixture && fixtureExists(fixture)) {
fs.rmSync ? fs.rmSync(fixture) : fs.unlinkSync(fixture)
}
context.isLoaded = false
return context
}

function applyHook(scopes, fn) {
if (!fn) {
return
Expand Down Expand Up @@ -258,6 +312,8 @@ const Modes = {

record, // use recorded nocks, record new nocks

update, // allow http calls, record all nocks, don't use recorded nocks

lockdown, // use recorded nocks, disables all http calls even when not nocked, doesnt record
}

Expand Down
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -61,7 +61,7 @@
"lint:js": "eslint --cache --cache-location './.cache/eslint' '**/*.js'",
"lint:js:fix": "eslint --cache --cache-location './.cache/eslint' --fix '**/*.js'",
"lint:ts": "dtslint types",
"test": "nyc mocha tests",
"test": "nyc --reporter=lcov --reporter=text mocha tests",
"test:coverage": "open coverage/lcov-report/index.html"
},
"license": "MIT",
Expand Down
264 changes: 264 additions & 0 deletions tests/test_back.js
Expand Up @@ -482,6 +482,270 @@ describe('Nock Back', () => {
})
})

describe('update mode', () => {
let fixture
let fixtureLoc
let fixturePath

beforeEach(() => {
// random fixture file so tests don't interfere with each other
const token = crypto.randomBytes(4).toString('hex')
fixture = `temp_${token}.json`
fixtureLoc = path.resolve(__dirname, 'fixtures', fixture)
fixturePath = path.resolve(__dirname, 'fixtures')
nockBack.setMode('update')
fs.copyFileSync(
path.resolve(fixturePath, 'wrong_uri.json'),
path.resolve(fixturePath, 'temp_wrong_uri.json')
)
})

after(() => {
rimraf.sync(path.resolve(__dirname, 'fixtures', 'temp_*.json'))
})

it('should record when configured correctly', done => {
expect(fs.existsSync(fixtureLoc)).to.be.false()

nockBack(fixture, nockDone => {
startHttpServer(requestListener).then(server => {
const request = http.request(
{
host: 'localhost',
path: '/',
port: server.address().port,
},
response => {
nockDone()

expect(response.statusCode).to.equal(217)
expect(fs.existsSync(fixtureLoc)).to.be.true()
done()
}
)

request.on('error', () => expect.fail())
request.end()
})
})
})

it('should record the expected data', done => {
nockBack(fixture, nockDone => {
startHttpServer(requestListener).then(server => {
const request = http.request(
{
host: 'localhost',
path: '/',
port: server.address().port,
method: 'GET',
},
response => {
response.once('end', () => {
nockDone()

const fixtureContent = JSON.parse(
fs.readFileSync(fixtureLoc).toString('utf8')
)
expect(fixtureContent).to.have.length(1)

const [firstFixture] = fixtureContent
expect(firstFixture).to.include({
method: 'GET',
path: '/',
status: 217,
})

done()
})

response.resume()
}
)

request.on('error', err => expect.fail(err.message))
request.end()
})
})
})

// Adding this test because there was an issue when not calling
// nock.activate() after calling nock.restore().
it('can record twice', done => {
expect(fs.existsSync(fixtureLoc)).to.be.false()

nockBack(fixture, function (nockDone) {
startHttpServer(requestListener).then(server => {
const request = http.request(
{
host: 'localhost',
path: '/',
port: server.address().port,
},
response => {
nockDone()

expect(response.statusCode).to.equal(217)
expect(fs.existsSync(fixtureLoc)).to.be.true()
done()
}
)

request.on('error', () => expect.fail())
request.end()
})
})
})

it('should allow outside calls', done => {
nockBack('temp_wrong_uri.json', nockDone => {
startHttpServer(requestListener).then(server => {
const request = http.request(
{
host: 'localhost',
path: '/',
port: server.address().port,
},
response => {
nockDone()
expect(response.statusCode).to.equal(217)
expect(
fs.existsSync(`${fixturePath}/temp_wrong_uri.json`)
).to.be.true()
done()
}
)

request.on('error', () => expect.fail())
request.end()
})
})
})

it("shouldn't load recorded tests", done => {
fs.copyFileSync(
path.resolve(fixturePath, 'good_request.json'),
path.resolve(fixturePath, 'temp_good_request.json')
)
nockBack('temp_good_request.json', function (nockDone) {
expect(this.scopes).to.have.lengthOf.at.least(0)
http
.get('http://www.example.test/', () => {
expect.fail()
})
.on('error', () => {
nockDone()
done()
})
})
})

it('should filter after recording', done => {
expect(fs.existsSync(fixtureLoc)).to.be.false()

// You would do some filtering here, but for this test we'll just return
// an empty array.
const afterRecord = () => []

nockBack(fixture, { afterRecord }, function (nockDone) {
startHttpServer(requestListener).then(server => {
const request = http.request(
{
host: 'localhost',
path: '/',
port: server.address().port,
},
response => {
nockDone()

expect(response.statusCode).to.equal(217)
expect(fs.existsSync(fixtureLoc)).to.be.true()
expect(this.scopes).to.be.empty()
done()
}
)
request.on('error', () => expect.fail())
request.end()
})
})
})

it('should format after recording', done => {
expect(fs.existsSync(fixtureLoc)).to.be.false()

const afterRecord = () => 'string-response'

nockBack(fixture, { afterRecord }, function (nockDone) {
startHttpServer(requestListener).then(server => {
const request = http.request(
{
host: 'localhost',
path: '/',
port: server.address().port,
},
response => {
nockDone()

expect(response.statusCode).to.equal(217)
expect(fs.existsSync(fixtureLoc)).to.be.true()
expect(fs.readFileSync(fixtureLoc, 'utf8')).to.equal(
'string-response'
)
done()
}
)
request.on('error', () => expect.fail())
request.end()
})
})
})

it('should pass custom options to recorder', done => {
nockBack(
fixture,
{ recorder: { enable_reqheaders_recording: true } },
nockDone => {
startHttpServer(requestListener).then(server => {
const request = http.request(
{
host: 'localhost',
path: '/',
port: server.address().port,
method: 'GET',
},
response => {
response.once('end', () => {
nockDone()

const fixtureContent = JSON.parse(
fs.readFileSync(fixtureLoc).toString('utf8')
)

expect(fixtureContent).to.have.length(1)
expect(fixtureContent[0].reqheaders).to.be.ok()

done()
})
response.resume()
}
)

request.on('error', () => expect.fail())
request.end()
})
}
)
})

it('should throw the expected exception when fs is not available', () => {
const nockBackWithoutFs = proxyquire('../lib/back', { fs: null })
nockBackWithoutFs.setMode('update')

nockBackWithoutFs.fixtures = path.resolve(__dirname, 'fixtures')
expect(() => nockBackWithoutFs('good_request.json')).to.throw('no fs')
})
})

describe('lockdown mode', () => {
beforeEach(() => {
nockBack.setMode('lockdown')
Expand Down