1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 | 28× 28× 28× 28× 28× 28× 28× 28× 28× 28× 28× 28× 28× 28× 28× 28× 24× 60× 42× 28× 40× 40× 28× 40× 40× 40× 40× 40× 40× 39× 5× 5× 39× 28× 24× 24× 24× 24× 24× 21× 21× 3× 28× 28× 28× 28× 28× 28× 28× 28× 1× 1× 27× 14× 13× 13× 1× 28× 26× 26× 26× 10× 10× 10× 10× 10× 9× 10× 7× 7× 3× 3× 3× 26× 8× 8× 8× 5× 3× 3× 8× 8× 8× 16× 16× 16× 20× 12× 12× 40× 40× 40× 20× 20× 20× 40× 12× 4× 4× 4× 4× 8× 8× 8× 6× 6× 6× 6× 8× 8× 26× 26× 28× 28× 26× | 'use strict' const fs = require('fs') const path = require('path') const appRoot = require('app-root-path').path const async = require('async') const merge = require('merge') const DebugGenerator = require('debug') const debug = DebugGenerator('loopback:component:fixtures:') const debugSetup = DebugGenerator('loopback:component:fixtures:setup:verbose:') const debugTeardown = DebugGenerator('loopback:component:fixtures:teardown:verbose:') let models let fixtureNames let fixturePath let cachedFixtures let config const defaults = { loadFixturesOnStartup: false, errorOnSetupFailure: false, environments: 'test', fixturesPath: '/server/test-fixtures/' } const createFixtureList = () => { const fixtureFolderContents = fs.readdirSync(fixturePath) return fixtureFolderContents.filter(fileName => fileName.match(/\.json$/)) .map(fileName => fileName.replace('.json', '')) } const addToCache = (fixtureName) => { const fixtureData = require(fixturePath + fixtureName) cachedFixtures[fixtureName] = fixtureData } const loadFixture = (fixtureName, done) => { debugSetup('Loading fixture', fixtureName) /* istanbul ignore else */ Eif (!cachedFixtures[fixtureName]) { debugSetup('Fixture not cached, loading from disk') addToCache(fixtureName) } debugSetup('Loading fixtures for', fixtureName) models[fixtureName].create(cachedFixtures[fixtureName], (err) => { if (err) { debugSetup('Error when attempting to add fixtures for', fixtureName) debugSetup(err) } done(err) }) } const loadFixtures = (fixtures, cb) => { /* istanbul ignore else */ Eif (!cachedFixtures) { debugSetup('No cached fixtures loading fixture files from', fixturePath) cachedFixtures = {} fixtureNames = createFixtureList() } if (!cb) { cb = fixtures async.each(fixtureNames, loadFixture, cb) } else { async.each(fixtures, loadFixture, cb) } } const init = (app, options) => { models = app.models config = merge(defaults, options) fixturePath = path.join(appRoot, config.fixturesPath) debug('Initializing component with options', config) const environment = app.settings && app.settings.env ? app.settings.env : process.env.NODE_ENV const match = Array.isArray(config.environments) ? config.environments.indexOf(environment) !== -1 : environment === config.environments if (!match) { debug('Skipping fixtures because environment', environment, 'is not in options.environments') return } if (config.loadFixturesOnStartup) { loadFixtures((err) => { if (err) debug('Error when loading fixtures on startup:', err) if (err && config.errorOnSetupFailure) { throw new Error('Failed to load fixtures on startup:', err) } }) } } const setupInterface = (app) => { const Fixtures = app.registry.createModel({name: 'Fixtures', base: 'Model'}) app.model(Fixtures, { dataSource: false, base: 'Model' }) Fixtures.setupFixtures = app.setupFixtures = (select, cb) => { if (typeof select === 'function') cb = select debug('Loading fixtures') const setupCallback = (errors) => { if (errors) debug('Fixtures failed to load:', errors) if (errors && config.errorOnSetupFailure) return cb(errors) cb(null, 'setup complete') } if (typeof select !== 'string') { debugSetup('Loading all fixtures in folder') loadFixtures(setupCallback) } else { /* istanbul ignore else */ Eif (!Array.isArray(select)) select = select.split(',') debugSetup('Loading following fixtures: ', select) loadFixtures(select, setupCallback) } } Fixtures.teardownFixtures = app.teardownFixtures = (select, cb) => { if (typeof select === 'function') cb = select let fixturesToTeardown if (typeof select !== 'string') { fixturesToTeardown = fixtureNames } else { /* istanbul ignore else */ Eif (!Array.isArray(select)) select = select.split(',') fixturesToTeardown = select } debugTeardown('Tearing down fixtures for', Object.keys(app.datasources)) const dataSourceNames = Object.keys(app.datasources) const migrateDataSource = (dataSourceName, done) => { debugTeardown('Tearing down fixtures for', dataSourceName) const dataSource = app.datasources[dataSourceName] if (Array.isArray(fixtureNames)) { // build modelNames and modelNamesLower as a bit of hack to ensure we // migrate the correct model name. its not possible to figure out // which is the correct (lower or upper case) and automigrate doesn't // do anything if the case is incorrect. const modelNamesLower = fixturesToTeardown.map(modelName => modelName.toLowerCase()) const modelNamesBothCases = fixturesToTeardown.concat(modelNamesLower) const remigrateModel = (model, done) => { debugTeardown('Dropping model', model, 'from', dataSourceName) dataSource.automigrate(model, (err) => { if (err) { debugTeardown('Error when attempting to automigrate', model) debugTeardown(err) } else { debugTeardown('Successfully migrated', model) } done(err) }) } async.each(modelNamesBothCases, remigrateModel, done) } else { debugTeardown('Dropping all models for', dataSourceName) dataSource.automigrate(() => { debugTeardown('Returning fixture teardown success (ignoring success/fail messages)') done() }) } } debug('Tearing down data sources:', dataSourceNames) async.each(dataSourceNames, migrateDataSource, (errors) => { if (errors) { debug('Failed to tear down fixtures:', errors) debug('Note that errors here does not necessarily mean the teardown') debug('itself failed you should look at your database to ensure that') debug('your collections/tables are now empty.') } debug('Returning fixture teardown success message') cb(null, 'teardown complete') }) } Fixtures.remoteMethod('setupFixtures', { description: 'Setup fixtures', accepts: {arg: 'select', type: 'string', http: { source: 'query' }}, returns: {arg: 'fixtures', type: 'string'}, http: {path: '/setup', verb: 'get'} }) Fixtures.remoteMethod('teardownFixtures', { description: 'Teardown fixtures', accepts: {arg: 'select', type: 'string', http: { source: 'query' }}, returns: {arg: 'fixtures', type: 'string'}, http: {path: '/teardown', verb: 'get'} }) } module.exports = (app, options) => { init(app, options) setupInterface(app) } |