diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..a1c1525 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,6 @@ +module.exports = { + "extends": "airbnb-base", + "env": { + "mocha": true + } +}; \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 24a8ab9..efb0983 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,3 @@ language: node_js node_js: - - "5" + - "8" diff --git a/lib/RequestMiddleware.js b/lib/RequestMiddleware.js index ab51b8a..736f941 100644 --- a/lib/RequestMiddleware.js +++ b/lib/RequestMiddleware.js @@ -1,41 +1,22 @@ -var digest = require('./digest') -var jsonDB = require('./jsonDb') +/* eslint-disable no-param-reassign */ +const digest = require('./digest'); +const jsonDB = require('./jsonDb'); -function loadFixture(cassettePath, axiosConfig) { - var requestKey = digest(axiosConfig) - return jsonDB.loadAt(cassettePath, requestKey) -} +const loadFixture = (cassettePath, axiosConfig) => { + const requestKey = digest(axiosConfig); + return jsonDB.loadAt(cassettePath, requestKey); +}; -function injectVCRHeader(axiosConfig) { - // This is done like this because Axios injects a custom User-Agent in - // the request config if it hasn't been defined by the client. - // - // We need to do the same thing and inject our own so Axios doesn't modify - // the request config object at a later point (which breaks our logic because - // digests will be different at request and response times) +exports.success = cassettePath => + axiosConfig => + loadFixture(cassettePath, axiosConfig) + .then((cassette) => { + axiosConfig.adapter = () => + new Promise((resolve) => { + cassette.originalResponseData.fixture = true; + return resolve(cassette.originalResponseData); + }); + return axiosConfig; + }).catch(() => axiosConfig); - var headers = axiosConfig.headers - if (!headers['User-Agent'] && !headers['user-agent']) { - headers['User-Agent'] = 'axios-vcr' - } -} - -exports.success = function (cassettePath) { - return function(axiosConfig) { - injectVCRHeader(axiosConfig) - - return loadFixture(cassettePath, axiosConfig).then(function(cassette) { - axiosConfig.adapter = function(resolve, _reject, _cfg) { - cassette.originalResponseData.fixture = true - return resolve(cassette.originalResponseData) - } - return axiosConfig - }).catch(function(err) { - return axiosConfig - }) - } -} - -exports.failure = function(error) { - return Promise.reject(error) -} +exports.failure = error => Promise.reject(error); diff --git a/lib/ResponseMiddleware.js b/lib/ResponseMiddleware.js index bddd44c..2576b9a 100644 --- a/lib/ResponseMiddleware.js +++ b/lib/ResponseMiddleware.js @@ -1,16 +1,16 @@ -var jsonDB = require('./jsonDb') -var digest = require('./digest') +const jsonDB = require('./jsonDb'); +const digest = require('./digest'); -function serialize(response) { - var meta = { +const serialize = (response) => { + const meta = { url: response.config.url, method: response.config.method, data: response.config.data, - headers: response.config.headers - } + headers: response.config.headers, + }; return { - meta: meta, + meta, fixture: true, originalResponseData: { @@ -18,28 +18,24 @@ function serialize(response) { statusText: response.statusText, headers: response.headers, data: response.data, - config: meta - } - } -} + config: meta, + }, + }; +}; -function storeFixture(cassettePath, response) { - var requestKey = digest(response.config) - var fixture = serialize(response) - return jsonDB.writeAt(cassettePath, requestKey, fixture) -} +const storeFixture = (cassettePath, response) => { + const requestKey = digest(response.config); + const fixture = serialize(response); + return jsonDB.writeAt(cassettePath, requestKey, fixture); +}; -exports.success = function (cassettePath) { - return function(res) { - if (res.fixture) - return res +exports.success = cassettePath => + (res) => { + if (res.fixture) { + return res; + } - return storeFixture(cassettePath, res).then(function() { - return res - }) - } -} + return storeFixture(cassettePath, res).then(() => res); + }; -exports.failure = function(error) { - return Promise.reject(error) -} +exports.failure = error => Promise.reject(error); diff --git a/lib/digest.js b/lib/digest.js index f40a5d0..afe352f 100644 --- a/lib/digest.js +++ b/lib/digest.js @@ -1,21 +1,44 @@ -var md5 = require('md5') -var _ = require('lodash') +const md5 = require('md5'); +const _ = require('lodash'); -function key(axiosConfig) { - //Content-Length is calculated automatically by Axios before sending a request - //We don't want to include it here because it could be changed by axios +const key = (args) => { + const { + baseURL, method, data, transformRequest, + } = args; + let { url, headers = {} } = args; + // Flatten headers + // Same happening in dispatchResponse.js - - var baseConfig = { - url: axiosConfig.url, - method: axiosConfig.method, - data: axiosConfig.data, - headers: _.omit(axiosConfig.headers, [ - 'Content-Length', 'content-length' - ]) + // Support baseURL config + if (baseURL && !/^([a-z][a-z\d+\-.]*:)?\/\//i.test(url)) { + url = url + ? `${baseURL.replace(/\/+$/, '')}/${url.replace(/^\/+/, '')}` + : baseURL; } - return md5(JSON.stringify(baseConfig)) -} + headers = _.merge( + headers.common || {}, + headers[method] || {}, + headers || {}, + ); + + headers = _.omit( + headers, + ['delete', 'get', 'head', 'post', 'put', 'patch', 'common', + // Content-Length is calculated automatically by Axios before sending a request + // We don't want to include it here because it could be changed by axios + 'Content-Length', 'content-length', + ], + ); + + const baseConfig = { + url, + method, + data: _.values(transformRequest).reduce((nextData, fn) => fn(nextData, headers), data), + headers, + }; + + return md5(JSON.stringify(baseConfig)); +}; -module.exports = key +module.exports = key; diff --git a/lib/jsonDb.js b/lib/jsonDb.js index 8c33403..d6101c5 100644 --- a/lib/jsonDb.js +++ b/lib/jsonDb.js @@ -1,35 +1,38 @@ -var fs = require('fs-promise') -var _ = require('lodash') -var mkdirp = require('mkdirp') -var getDirName = require('path').dirname - -function loadAt(filePath, jsonPath) { - return fs.readJson(filePath).then(function(json) { - if (_.isUndefined(jsonPath)) - return json - - var value = _.get(json, jsonPath) - if (!_.isUndefined(value)) - return value - else - throw "Invalid JSON Path" - }) -} - -function writeAt(filePath, jsonPath, value) { - mkdirp.sync(getDirName(filePath)) - - return fs.readJson(filePath).then(function(json) { - _.set(json, jsonPath, value) - return fs.writeJson(filePath, json) - }).catch(function(error) { - var json = {} - _.set(json, jsonPath, value) - return fs.writeJson(filePath, json) - }) -} + +const _ = require('lodash'); +const mkdirp = require('mkdirp'); +const getDirName = require('path').dirname; + +const { readJson, writeJson } = require('./readWriteJson'); + +const loadAt = (filePath, jsonPath) => + readJson(filePath).then((json) => { + if (_.isUndefined(jsonPath)) { + return json; + } + + const value = _.get(json, jsonPath); + if (!_.isUndefined(value)) { + return value; + } + + throw new Error('Invalid JSON Path'); + }); + +const writeAt = (filePath, jsonPath, value) => { + mkdirp.sync(getDirName(filePath)); + + return readJson(filePath).then((json) => { + _.set(json, jsonPath, value); + return writeJson(filePath, json); + }).catch(() => { + const json = {}; + _.set(json, jsonPath, value); + return writeJson(filePath, json); + }); +}; module.exports = { - loadAt: loadAt, - writeAt: writeAt -} + loadAt, + writeAt, +}; diff --git a/lib/readWriteJson.js b/lib/readWriteJson.js new file mode 100644 index 0000000..53c1c56 --- /dev/null +++ b/lib/readWriteJson.js @@ -0,0 +1,9 @@ +const util = require('util'); +const fs = require('fs'); + +const readFile = util.promisify(fs.readFile); +const writeFile = util.promisify(fs.writeFile); +const readJson = filePath => readFile(filePath, 'utf8').then(data => JSON.parse(data)); +const writeJson = (filePath, json) => writeFile(filePath, JSON.stringify(json)); + +module.exports = { readJson, writeJson }; diff --git a/mocha.opts b/mocha.opts new file mode 100644 index 0000000..fb7f43c --- /dev/null +++ b/mocha.opts @@ -0,0 +1 @@ +--require test/setup.js \ No newline at end of file diff --git a/package.json b/package.json index 2a28d0f..fce6f56 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,8 @@ "main": "index.js", "homepage": "http://github.com/nettofarah/axios-vcr", "scripts": { - "test": "mocha test/" + "test": "npm run lint && mocha test/", + "lint": "eslint test/ lib/" }, "bugs": { "url": "https://github.com/nettofarah/axios-vcr/issues" @@ -15,9 +16,9 @@ "url": "https://github.com/nettofarah/axios-vcr.git" }, "files": [ - "index.js", - "lib" - ], + "index.js", + "lib" + ], "keywords": [ "axios", "vcr", @@ -28,12 +29,17 @@ "author": "Netto Farah", "license": "MIT", "devDependencies": { - "axios": "^0.11.1", + "axios": "^0.17.0", + "eslint": "^4.10.0", + "eslint-config-airbnb-base": "^12.1.0", + "eslint-plugin-import": "^2.8.0", "mocha": "^2.5.3", "rimraf": "^2.5.2" }, + "peerDependencies": { + "axios": "^0.17.0" + }, "dependencies": { - "fs-promise": "^0.5.0", "lodash": "^4.13.1", "md5": "^2.1.0", "mkdirp": "^0.5.1" diff --git a/test/axios_vcr_test.js b/test/axios_vcr_test.js index a85a0a8..b79b81c 100644 --- a/test/axios_vcr_test.js +++ b/test/axios_vcr_test.js @@ -1,158 +1,172 @@ -var fs = require('fs') -var rimraf = require('rimraf') -var assert = require('assert') -var VCR = require('../index') -var _ = require('lodash') +/* eslint-disable func-names */ +const fs = require('fs'); +const rimraf = require('rimraf'); +const assert = require('assert'); +const VCR = require('../index'); +const _ = require('lodash'); +const axios = require('axios'); + +const { loadAt } = require('../lib/jsonDb'); +const digest = require('../lib/digest'); function clearFixtures() { - rimraf.sync('./test/fixtures') + rimraf.sync('./test/fixtures'); } function fileExists(path) { try { - return fs.statSync(path).isFile() - } catch(e) { - return false + return fs.statSync(path).isFile(); + } catch (e) { + return false; } } function getFixture(cassettePath, config) { - var loadAt = require('../lib/jsonDb').loadAt - var digest = require('../lib/digest') - var key = digest(config) + const key = digest(config); - return loadAt(cassettePath, key) + return loadAt(cassettePath, key); } -describe('Axios VCR', function() { - this.timeout(10000) - var posts = 'http://jsonplaceholder.typicode.com/posts/1' - var axios = require('axios') - - describe('recording', function() { - beforeEach(clearFixtures) - afterEach(clearFixtures) - - it('generates stubs for requests', function(done) { - var path = './test/fixtures/posts.json' - VCR.mountCassette(path) - - axios.get(posts).then(function(response) { - getFixture(path, response.config).then(function(fixture) { - assert.deepEqual(fixture.originalResponseData.data, response.data) - done() - VCR.ejectCassette(path) - }) - }) - }) - - it('works with nested folders', function(done) { - var cassettePath = './test/fixtures/nested/posts.json' - VCR.mountCassette(cassettePath) - - axios.get(posts).then(function(response) { - getFixture(cassettePath, response.config).then(function(fixture) { - assert.deepEqual(fixture.originalResponseData.data, response.data) - done() - - VCR.ejectCassette(cassettePath) - }) - }).catch(function(err) { console.log(err) }) - }) - - it('stores headers and status', function(done) { - var cassettePath = './test/fixtures/posts.json' - VCR.mountCassette(cassettePath) - - axios.get(posts).then(function(response) { - getFixture(cassettePath, response.config).then(function(fixture) { - assert.deepEqual(fixture.originalResponseData.headers, response.headers) - assert.equal(fixture.originalResponseData.status, response.status) - assert.equal(fixture.originalResponseData.statusText, response.statusText) - done() - - VCR.ejectCassette(cassettePath) - }) - }) - }) - }) - - describe('replaying', function() { +describe('Axios VCR', function () { + this.timeout(10000); + + const posts = 'http://jsonplaceholder.typicode.com/posts/1'; + + describe('recording', () => { + beforeEach(clearFixtures); + afterEach(clearFixtures); + + it('generates stubs for requests', () => { + const path = './test/fixtures/posts.json'; + VCR.mountCassette(path); + + return axios.get(posts).then(response => + getFixture(path, response.config) + .then((fixture) => { + assert.deepEqual(fixture.originalResponseData.data, response.data); + })).finally(() => VCR.ejectCassette(path)); + }); + + it('works with nested folders', () => { + const cassettePath = './test/fixtures/nested/posts.json'; + VCR.mountCassette(cassettePath); + + return axios + .get(posts) + .then(response => + getFixture(cassettePath, response.config) + .then((fixture) => { + assert.deepEqual(fixture.originalResponseData.data, response.data); + })) + .finally(() => { + VCR.ejectCassette(cassettePath); + }); + }); + + it('stores headers and status', () => { + const cassettePath = './test/fixtures/posts.json'; + VCR.mountCassette(cassettePath); + + return axios.get(posts).then(response => + getFixture(cassettePath, response.config).then((fixture) => { + assert.deepEqual( + fixture.originalResponseData.headers, + response.headers, + ); + assert.equal(fixture.originalResponseData.status, response.status); + assert.equal( + fixture.originalResponseData.statusText, + response.statusText, + ); + })).finally(() => VCR.ejectCassette(cassettePath)); + }); + }); + + describe('replaying', () => { /* This is a tricky test. I'm not aware of any way to check that a network request has been made. So instead we hit an unexisting URL that is backed by a cassette. We can now check that the response is the same as the cassette file. */ - it('skips remote calls', function(done) { - var path = './test/static_fixtures/posts.json' - assert(fileExists(path)) - - var url = 'http://something.com/unexisting' - VCR.mountCassette(path) - - axios.get(url).then(function(res) { - getFixture(path, res.config).then(function(fixture) { - assert.deepEqual(fixture.originalResponseData, _.omit(res, 'fixture')) - done() - - VCR.ejectCassette(path) - }).catch(err => { console.log(err); done() }) - }) - }) - - it('makes remote call when a cassette is not available', function(done) { - var path = './test/static_fixtures/no_posts.json' + it('skips remote calls', () => { + const path = './test/static_fixtures/posts.json'; + assert(fileExists(path)); + + const url = 'http://something.com/unexisting'; + VCR.mountCassette(path); + + return axios + .get(url) + .then(res => + getFixture(path, res.config) + .then((fixture) => { + assert.deepEqual( + fixture.originalResponseData, + _.omit(res, 'fixture'), + ); + })).finally(() => VCR.ejectCassette(path)); + }); + + it('makes remote call when a cassette is not available', () => { + const path = './test/static_fixtures/no_posts.json'; try { - fs.unlinkSync(path) - } catch(e) {} - - assert(!fileExists(path)) - VCR.mountCassette(path) - - axios.get(posts).then(function(response) { - assert.equal(200, response.status) - fs.unlinkSync(path) - done() - - VCR.ejectCassette(path) - }) - }) - }) - - describe('Multiple Requests', function() { - this.timeout(15000) - - beforeEach(clearFixtures) - afterEach(clearFixtures) - - var usersUrl = 'http://jsonplaceholder.typicode.com/users' - var todosUrl = 'http://jsonplaceholder.typicode.com/todos' - - it('stores multiple requests in the same cassette', function(done) { - var path = './test/fixtures/multiple.json' - - VCR.mountCassette(path) - - var usersPromise = axios.get(usersUrl) - var todosPromise = axios.get(todosUrl) - - Promise.all([usersPromise, todosPromise]).then(function(responses) { - var usersResponse = responses[0] - var todosResponse = responses[1] - - var usersResponsePromise = getFixture(path, usersResponse.config) - var todosResponsePromise = getFixture(path, todosResponse.config) - - Promise.all([usersResponsePromise, todosResponsePromise]).then(function(fixtures) { - assert.deepEqual(fixtures[0].originalResponseData.data, usersResponse.data) - assert.deepEqual(fixtures[1].originalResponseData.data, todosResponse.data) - done() - - VCR.ejectCassette(path) - }) - }) - }) - }) -}) + fs.unlinkSync(path); + } catch (e) { + // Do nothing + } + + assert(!fileExists(path)); + VCR.mountCassette(path); + + return axios.get(posts).then((response) => { + assert.equal(200, response.status); + }).finally(() => { + fs.unlinkSync(path); + VCR.ejectCassette(path); + }); + }); + }); + + describe('Multiple Requests', function () { + this.timeout(15000); + + beforeEach(clearFixtures); + afterEach(clearFixtures); + + const usersUrl = 'http://jsonplaceholder.typicode.com/users'; + const todosUrl = 'http://jsonplaceholder.typicode.com/todos'; + + it('stores multiple requests in the same cassette', (done) => { + const path = './test/fixtures/multiple.json'; + + VCR.mountCassette(path); + + const usersPromise = axios.get(usersUrl); + const todosPromise = axios.get(todosUrl); + + Promise.all([usersPromise, todosPromise]).then((responses) => { + const usersResponse = responses[0]; + const todosResponse = responses[1]; + + const usersResponsePromise = getFixture(path, usersResponse.config); + const todosResponsePromise = getFixture(path, todosResponse.config); + + Promise.all([usersResponsePromise, todosResponsePromise]).then((fixtures) => { + assert.deepEqual( + fixtures[0].originalResponseData.data, + usersResponse.data, + ); + assert.deepEqual( + fixtures[1].originalResponseData.data, + todosResponse.data, + ); + done(); + + VCR.ejectCassette(path); + }); + }); + }); + }); +}); diff --git a/test/digest_test.js b/test/digest_test.js index 0ae5c9c..a53563f 100644 --- a/test/digest_test.js +++ b/test/digest_test.js @@ -1,31 +1,30 @@ -var digest = require('../lib/digest') -var md5 = require('md5') -var assert = require('assert') -var _ = require('lodash') +const digest = require('../lib/digest'); +const md5 = require('md5'); +const assert = require('assert'); +const _ = require('lodash'); function testDigest(cfg) { - var config = _.pick(cfg, ['url', 'method', 'data', 'headers']) - return md5(JSON.stringify(config)) + const config = _.pick(cfg, ['url', 'method', 'data', 'headers']); + return md5(JSON.stringify(config)); } -describe('Digest', function() { - - it('md5s certain parameters from an axiosConfig object', function() { - var sampleConfig = { +describe('Digest', () => { + it('md5s certain parameters from an axiosConfig object', () => { + const sampleConfig = { url: 'http://cats.com', method: 'get', data: {}, headers: { - 'user-agent': 'test' + 'user-agent': 'test', }, extraProperty: 'bla', - somethingElse: 'irrelevant' - } + somethingElse: 'irrelevant', + }; - var fullDigest = md5(JSON.stringify(sampleConfig)) - var expectedDigest = digest(sampleConfig) + const fullDigest = md5(JSON.stringify(sampleConfig)); + const expectedDigest = digest(sampleConfig); - assert.notEqual(fullDigest, expectedDigest) - assert.equal(testDigest(sampleConfig), expectedDigest) - }) -}) + assert.notEqual(fullDigest, expectedDigest); + assert.equal(testDigest(sampleConfig), expectedDigest); + }); +}); diff --git a/test/jsonDb_test.js b/test/jsonDb_test.js index 128461f..ea0386d 100644 --- a/test/jsonDb_test.js +++ b/test/jsonDb_test.js @@ -1,106 +1,95 @@ -var jsonDB = require('../lib/jsonDb') -var assert = require('assert') -var fs = require('fs-promise') -var rimraf = require('rimraf') +const assert = require('assert'); +const rimraf = require('rimraf'); + +const jsonDB = require('../lib/jsonDb'); +const { writeJson } = require('../lib/readWriteJson'); + function clearFixtures() { - rimraf.sync('./test/jdb/*') + rimraf.sync('./test/jdb/*'); } -describe('JsonDB', function() { - afterEach(clearFixtures) +describe('JsonDB', () => { + afterEach(clearFixtures); - describe('loadAt', function() { - var path = './test/jdb/temp.json' + describe('loadAt', () => { + const path = './test/jdb/temp.json'; - beforeEach(function() { - fs.writeJsonSync(path, { + beforeEach(() => + writeJson(path, { a: { b: { - c: 'it works!' - } - } - }) - }) - - it('loads an object from a JSON stored in a file', function(done) { - jsonDB.loadAt(path).then(function(payload) { + c: 'it works!', + }, + }, + })); + + it('loads an object from a JSON stored in a file', () => + jsonDB.loadAt(path).then((payload) => { assert.deepEqual(payload, { a: { b: { - c: 'it works!' - } - } - }) - done() - }) - }) - - it('accepts nested paths', function(done) { - jsonDB.loadAt(path, 'a.b.c').then(function(payload) { - assert.equal(payload, 'it works!') - done() - }) - }) - - it('fails when the file does not exist', function(done) { - jsonDB.loadAt('./test/jdb/unexisting.json').catch(function(error) { - assert.equal(error.code, 'ENOENT') - done() - }) - }) - - it('fails when the json path does not exist', function(done) { - jsonDB.loadAt('./test/jdb/temp.json', 'a.b.c.d').catch(function(error) { - assert.equal(error, 'Invalid JSON Path') - done() - }) - }) - }) - - describe('writeAt', function() { - var path = './test/jdb/temp_write.json' - - beforeEach(function() { - fs.writeJsonSync(path, { + c: 'it works!', + }, + }, + }); + })); + + it('accepts nested paths', () => + jsonDB.loadAt(path, 'a.b.c').then((payload) => { + assert.equal(payload, 'it works!'); + })); + + it('fails when the file does not exist', () => + jsonDB.loadAt('./test/jdb/unexisting.json').catch((error) => { + assert.equal(error.code, 'ENOENT'); + })); + + it('fails when the json path does not exist', () => + jsonDB.loadAt('./test/jdb/temp.json', 'a.b.c.d').catch((error) => { + assert.deepEqual(error, new Error('Invalid JSON Path')); + })); + }); + + describe('writeAt', () => { + const path = './test/jdb/temp_write.json'; + + beforeEach(() => + writeJson(path, { a: { - b: {} - } - }) - }) - - it('writes at a given path', function(done) { - var time = new Date().getTime() - var payload = { c: 'Axios VCR', time: time } - - jsonDB.writeAt(path, 'a.b', payload).then(function() { - jsonDB.loadAt(path, 'a.b').then(function(json) { - assert.deepEqual(payload, json) - done() - }) - }) - }) - - it('creates missing keys', function(done) { - var payload = 'nested stuff' - jsonDB.writeAt(path, 'a.b.c.d.e', payload).then(function() { - jsonDB.loadAt(path, 'a.b.c.d.e').then(function(json) { - assert.deepEqual(payload, json) - done() - }) - }) - }) - - it('creates missing parts of the path', function(done) { - var path = './test/jdb/nested/temp_write.json' - var payload = 'something' - - jsonDB.writeAt(path, 'a', payload).then(function() { - jsonDB.loadAt(path, 'a').then(function(json) { - assert.deepEqual(payload, json) - done() - }) - }) - }) - }) -}) + b: {}, + }, + })); + + it('writes at a given path', () => { + const time = new Date().getTime(); + const payload = { c: 'Axios VCR', time }; + + return jsonDB.writeAt(path, 'a.b', payload).then(() => { + jsonDB.loadAt(path, 'a.b').then((json) => { + assert.deepEqual(payload, json); + }); + }); + }); + + it('creates missing keys', () => { + const payload = 'nested stuff'; + return jsonDB.writeAt(path, 'a.b.c.d.e', payload).then(() => { + jsonDB.loadAt(path, 'a.b.c.d.e').then((json) => { + assert.deepEqual(payload, json); + }); + }); + }); + + it('creates missing parts of the path', () => { + const tempWritePath = './test/jdb/nested/temp_write.json'; + const payload = 'something'; + + return jsonDB.writeAt(tempWritePath, 'a', payload).then(() => { + jsonDB.loadAt(tempWritePath, 'a').then((json) => { + assert.deepEqual(payload, json); + }); + }); + }); + }); +}); diff --git a/test/promise-finally-polyfill.js b/test/promise-finally-polyfill.js new file mode 100644 index 0000000..e215ebf --- /dev/null +++ b/test/promise-finally-polyfill.js @@ -0,0 +1,47 @@ +/* eslint-disable no-extend-native */ + +if (typeof Promise !== 'function') { + throw new TypeError('A global Promise is required'); +} + +if (typeof Promise.prototype.finally !== 'function') { + const speciesConstructor = (O, defaultConstructor) => { + if (!O || (typeof O !== 'object' && typeof O !== 'function')) { + throw new TypeError('Assertion failed: Type(O) is not Object'); + } + const C = O.constructor; + if (typeof C === 'undefined') { + return defaultConstructor; + } + if (!C || (typeof C !== 'object' && typeof C !== 'function')) { + throw new TypeError('O.constructor is not an Object'); + } + const S = typeof Symbol === 'function' && typeof Symbol.species === 'symbol' ? C[Symbol.species] : undefined; + if (S === null) { + return defaultConstructor; + } + if (typeof S === 'function' && S.prototype) { + return S; + } + throw new TypeError('no constructor found'); + }; + + const shim = { + finally(onFinally) { + const promise = this; + if (typeof promise !== 'object' || promise === null) { + throw new TypeError('"this" value is not an Object'); + } + const C = speciesConstructor(promise, Promise); // throws if SpeciesConstructor throws + const handler = typeof onFinally === 'function' ? onFinally : () => {}; + return Promise.prototype.then.call( + promise, + x => new C(resolve => resolve(handler())).then(() => x), + e => new C(resolve => resolve(handler())).then(() => { + throw e; + }), + ); + }, + }; + Object.defineProperty(Promise.prototype, 'finally', { configurable: true, writable: true, value: shim.finally }); +} diff --git a/test/setup.js b/test/setup.js new file mode 100644 index 0000000..5879a7f --- /dev/null +++ b/test/setup.js @@ -0,0 +1 @@ +require('./promise-finally-polyfill'); diff --git a/test/static_fixtures/posts.json b/test/static_fixtures/posts.json index 0f8e4f7..da92c33 100644 --- a/test/static_fixtures/posts.json +++ b/test/static_fixtures/posts.json @@ -1,11 +1,10 @@ { - "6d51a168265ddf1c33f60fa111a26dc7": { + "56e7cedef2202ac3a46947b52d90a2d6": { "meta": { "url": "http://something.com/unexisting", "method": "get", "headers": { - "Accept": "application/json, text/plain, */*", - "User-Agent": "axios-vcr" + "Accept": "application/json, text/plain, */*" } }, "fixture": true, @@ -33,8 +32,7 @@ "url": "http://something.com/unexisting", "method": "get", "headers": { - "Accept": "application/json, text/plain, */*", - "User-Agent": "axios-vcr" + "Accept": "application/json, text/plain, */*" } } }