UNPKG

@shackpank/truman

Version:

Simple test fixtures for single page apps

232 lines (182 loc) 6.23 kB
'use strict'; require('Base64'); let _ = require('lodash'); let PouchDB = require('pouchdb'); const STORAGE_PREFIX = 'fixture-'; const NO_NAME_ERR_MSG = 'Fixture collection name not provided.'; let config = {}; let localDB = null; let remoteDB = null; let cachedRevisionMapping = null; let fixtureHelper = module.exports = { initialize(options) { _.assign(config, options); window.PouchDB = PouchDB; // Necessary for the PouchDB Chrome inspector localDB = new PouchDB('truman', { adapter: 'idb' }); if (config.database) { let remoteConfig = { ajax: { timeout: 120000 } }; if (config.database.user && config.database.password) { remoteConfig.ajax.headers = { Authorization: 'Basic ' + window.btoa(config.database.user + ':' + config.database.password) }; } remoteDB = new PouchDB(config.database.url, remoteConfig); } }, load(fixtureCollectionName) { if (!fixtureCollectionName) { throw new Error(NO_NAME_ERR_MSG); } const id = fixtureHelper._buildId(fixtureCollectionName); return fixtureHelper._loadFromDatabase(localDB, id); }, store(fixtures, fixtureCollectionName) { if (!fixtureCollectionName) { throw new Error(NO_NAME_ERR_MSG); } const id = fixtureHelper._buildId(fixtureCollectionName); let fixtureRecord = { _id: id, fixtures: fixtures }; return fixtureHelper._storeToDatabase(localDB, id, fixtureRecord); }, push(fixtureCollectionName, tag) { if (!fixtureCollectionName) { throw new Error(NO_NAME_ERR_MSG); } return fixtureHelper.load(fixtureCollectionName) .then((fixtures) => { const id = fixtureHelper._buildId(fixtureCollectionName); const fixtureRecord = { _id: id, fixtures: fixtures }; return fixtureHelper._storeToDatabase(remoteDB, id, fixtureRecord, tag) .then(() => fixtures) .catch((err) => { console.error(err); }); }); }, pull(fixtureCollectionName, tags) { if (!fixtureCollectionName) { throw new Error(NO_NAME_ERR_MSG); } return fixtureHelper.getLatestRevisionMapping(fixtureCollectionName, tags) .then((latestRevisionMapping) => { const id = fixtureHelper._buildId(fixtureCollectionName); if (!latestRevisionMapping) { return fixtureHelper._copyFromRemote(fixtureCollectionName, id); } return fixtureHelper._copyFromRemote(fixtureCollectionName, id, latestRevisionMapping.revision); }); }, clear(fixtureCollectionName) { if (!fixtureCollectionName) { throw new Error(NO_NAME_ERR_MSG); } const id = fixtureHelper._buildId(fixtureCollectionName); return localDB.get(id) .catch(fixtureHelper._swallow404) .then((existingFixtureRecord) => { if (existingFixtureRecord) { existingFixtureRecord.fixtures = []; return localDB.put(existingFixtureRecord); } }); }, getLatestRevisionMapping(fixtureCollectionName, tags) { if (!fixtureCollectionName) { throw new Error(NO_NAME_ERR_MSG); } if (!_.isArray(tags)) { tags = _.compact([tags]); } return fixtureHelper._getRevisionMapping(fixtureCollectionName) .then((fixtureRevisionMappings) => { return _.find(fixtureRevisionMappings, (fixtureRevisionMapping) => _.includes(tags, fixtureRevisionMapping.tag)); }); }, _getRevisionMapping(fixtureCollectionName) { if (!fixtureCollectionName) { throw new Error(NO_NAME_ERR_MSG); } if (cachedRevisionMapping) { return Promise.resolve(cachedRevisionMapping); } const id = fixtureHelper._buildId(fixtureCollectionName); return remoteDB.get(id, { revs_info: true }) .catch(fixtureHelper._swallow404) .then((response) => { if (!response) { return []; } const tagMapping = response.localRevisionMap; const availableRevisions = response._revs_info .filter((revInfo) => revInfo.status === 'available') .map((revInfo) => revInfo.rev); let result = []; _.each(availableRevisions, (revision) => { let matchingTag = null; for (const tag in tagMapping) { if (Number.parseInt(revision.match(/[^-]+/)[0], 10) === tagMapping[tag]) { matchingTag = tag; break; } } result.push({ revision: revision, tag: matchingTag }); }); cachedRevisionMapping = result; return result; }); }, _storeToDatabase(database, id, fixtureRecord, tag) { return database.get(id) .catch(fixtureHelper._swallow404) .then((existingFixtureRecord) => { if (!existingFixtureRecord) { return database.put(fixtureRecord); } existingFixtureRecord.fixtures = fixtureRecord.fixtures; if (!existingFixtureRecord.localRevisionMap) { existingFixtureRecord.localRevisionMap = {}; } if (tag) { existingFixtureRecord.localRevisionMap[tag] = fixtureHelper._getNextRevisionNumber(existingFixtureRecord._rev); } return database.put(existingFixtureRecord); }); }, _loadFromDatabase(database, id, revision) { let options = {}; if (revision) { options.rev = revision; } return database.get(id, options) .then((fixture) => fixture.fixtures || []) .catch((err) => { fixtureHelper._swallow404(err); return []; }); }, _copyFromRemote(fixtureCollectionName, id, revision) { return fixtureHelper._loadFromDatabase(remoteDB, id, revision) .then((fixtures) => { return fixtureHelper.store(fixtures, fixtureCollectionName) .then(() => fixtures); }); }, _getNextRevisionNumber(revision) { return window.parseInt(revision.match(/[^-]+/)[0], 10) + 1; }, _buildId(fixtureCollectionName) { return STORAGE_PREFIX + fixtureCollectionName; }, // Swallow the error if the record doesn't exist yet... _swallow404(err) { if (err.status !== 404) { throw err; } } };