UNPKG

truman

Version:

Simple test fixtures for single page apps

151 lines (124 loc) 4.67 kB
'use strict' const findIndex = require('lodash/findIndex') const isEqual = require('lodash/isEqual') const filter = require('lodash/filter') const includes = require('lodash/includes') const omitDeep = require('omit-deep') const xhrHelper = require('./xhr') const levenshtein = require('fast-levenshtein') const _ = { findIndex, isEqual, filter, includes } const fixtureHelper = module.exports = { _config: { omittedQueryParams: [], omittedDataParams: [], domainSynonyms: {} }, initialize (options) { Object.assign(fixtureHelper._config, options) }, addXhr (fixtures, xhr) { fixtures.push({ request: { method: xhr.method, headers: xhr.requestHeaders, url: xhr.url, query: xhrHelper.getQueryStringObject(xhr, fixtureHelper._config.omittedQueryParams), body: xhr.requestBody }, response: { status: xhr.status, headers: xhrHelper.getResponseHeadersObject(xhr), body: xhr.responseText } }) }, removeFirst (fixtures, fixture) { // Use old-school splicing instead of _.remove so we only remove the first match, not all matches. const spliceIndex = _.findIndex(fixtures, (currentFixture) => _.isEqual(currentFixture, fixture)) fixtures.splice(spliceIndex, 1) }, find (fixtures, options) { return _.filter(fixtures, (fixture) => { if (options.method && options.method !== fixture.request.method) { return false } if (options.url) { // Sometimes things vary in the query string that don't affect request results, // so we exclude from the URL comparison and compare separately. const requestedUrl = options.url.split('?')[0] const fixtureUrl = fixture.request.url.split('?')[0] const fixtureDomain = fixtureHelper.domainFromUrl(fixtureUrl) const fixtureDomainSynonyms = fixtureHelper._config.domainSynonyms[fixtureDomain] || [] const fixtureUrls = [fixtureUrl].concat(fixtureDomainSynonyms.map((domainSynonym) => fixtureUrl.replace(fixtureDomain, domainSynonym))) if (!_.includes(fixtureUrls, requestedUrl)) { return false } } const filteredFixturedQuery = xhrHelper.getQueryStringObject({ url: 'http://ignore.the.domain.only.querystring.matters/?' + Object.keys(fixture.request.query || {}).map(function (key) { return key + '=' + fixture.request.query[key] }).join('&') }, fixtureHelper._config.omittedQueryParams) if (options.query && !_.isEqual(options.query, filteredFixturedQuery)) { return false } if (options.requestBody) { let parsedOptionRequestBody = null try { parsedOptionRequestBody = omitDeep(JSON.parse(options.requestBody), fixtureHelper._config.omittedDataParams) } catch (e) { console.error('Could not parse option request body for', options.url, options.requestBody) } let parsedFixtureRequestBody = null try { parsedFixtureRequestBody = omitDeep(JSON.parse(fixture.request.body), fixtureHelper._config.omittedDataParams) } catch (e) { console.error('Could not parse fixture request body for', fixture.request.url, fixture.request.body) } // We deliberately return true if either the fixture request body or option request body can't be parsed. if (parsedOptionRequestBody && parsedFixtureRequestBody && !_.isEqual(parsedOptionRequestBody, parsedFixtureRequestBody)) { return false } } return true }) }, sortByClosestMatchingURL (fixtures, xhr) { // Sort sorts in place, which we don't want to do, so we clone the array. fixtures = JSON.parse(JSON.stringify(fixtures)) return fixtures.sort(function (a, b) { const aDistance = levenshtein.get(a.request.url, xhr.url) const bDistance = levenshtein.get(b.request.url, xhr.url) if (aDistance < bDistance) { return -1 } if (aDistance > bDistance) { return 1 } return 0 }) }, domainFromUrl (url) { const protocol = url.split('/')[0] const domain = url.split('/')[2] if (!protocol || !domain) { return null } return `${protocol}//${domain}` }, findForSinonXHR (fixtures, xhr) { const queryStringObject = xhrHelper.getQueryStringObject(xhr, fixtureHelper._config.omittedQueryParams) const findObject = { method: xhr.method, url: xhr.url, query: queryStringObject, requestBody: xhr.requestBody } return fixtureHelper.find(fixtures, findObject) } }