mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-27 09:35:39 -05:00
Extended the LevelLoader to load thang types and components dynamically for hero levels.
This commit is contained in:
parent
0c5364eebb
commit
cc025942f8
12 changed files with 272 additions and 7 deletions
|
@ -260,6 +260,32 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
return matching_requests;
|
return matching_requests;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.sendResponses = function(responseMap) {
|
||||||
|
var urls = Object.keys(responseMap);
|
||||||
|
for(var i in urls) {
|
||||||
|
var url = urls[i];
|
||||||
|
var responseBody = responseMap[url];
|
||||||
|
var responded = false;
|
||||||
|
|
||||||
|
var requests = jasmine.Ajax.requests.all();
|
||||||
|
for(var j in requests) {
|
||||||
|
var request = requests[j];
|
||||||
|
if(request.url.startsWith(url)) {
|
||||||
|
request.response({status: 200, responseText: JSON.stringify(responseBody)});
|
||||||
|
responded = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!responded) {
|
||||||
|
var allRequests = jasmine.Ajax.requests.all();
|
||||||
|
urls = [];
|
||||||
|
for(var k in allRequests) urls.push(allRequests[k].url);
|
||||||
|
console.error('could not find response for', url, 'in', urls, allRequests);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function RequestStub(url, stubData) {
|
function RequestStub(url, stubData) {
|
||||||
|
|
|
@ -33,6 +33,8 @@ module.exports = class LevelLoader extends CocoClass
|
||||||
@headless = options.headless
|
@headless = options.headless
|
||||||
@spectateMode = options.spectateMode ? false
|
@spectateMode = options.spectateMode ? false
|
||||||
|
|
||||||
|
@worldNecessities = []
|
||||||
|
@listenTo @supermodel, 'resource-loaded', @onWorldNecessityLoaded
|
||||||
@loadSession()
|
@loadSession()
|
||||||
@loadLevel()
|
@loadLevel()
|
||||||
@loadAudio()
|
@loadAudio()
|
||||||
|
@ -64,12 +66,23 @@ module.exports = class LevelLoader extends CocoClass
|
||||||
session = new LevelSession().setURL url
|
session = new LevelSession().setURL url
|
||||||
@sessionResource = @supermodel.loadModel(session, 'level_session', {cache: false})
|
@sessionResource = @supermodel.loadModel(session, 'level_session', {cache: false})
|
||||||
@session = @sessionResource.model
|
@session = @sessionResource.model
|
||||||
@session.once 'sync', -> @url = -> '/db/level.session/' + @id
|
@listenToOnce @session, 'sync', @onSessionLoaded
|
||||||
|
|
||||||
if @opponentSessionID
|
if @opponentSessionID
|
||||||
opponentSession = new LevelSession().setURL "/db/level_session/#{@opponentSessionID}"
|
opponentSession = new LevelSession().setURL "/db/level_session/#{@opponentSessionID}"
|
||||||
@opponentSessionResource = @supermodel.loadModel(opponentSession, 'opponent_session')
|
@opponentSessionResource = @supermodel.loadModel(opponentSession, 'opponent_session')
|
||||||
@opponentSession = @opponentSessionResource.model
|
@opponentSession = @opponentSessionResource.model
|
||||||
|
@listenToOnce @opponentSession, 'sync', @onSessionLoaded
|
||||||
|
|
||||||
|
onSessionLoaded: (session) ->
|
||||||
|
session.url = -> '/db/level.session/' + @id
|
||||||
|
if heroConfig = session.get('heroConfig')
|
||||||
|
url = "/db/thang.type/#{heroConfig.thangType}/version?project=name,components"
|
||||||
|
@worldNecessities.push @maybeLoadURL(url, ThangType, 'thang')
|
||||||
|
|
||||||
|
for itemThangType in _.values(heroConfig.inventory)
|
||||||
|
url = "/db/thang.type/#{itemThangType}/version?project=name,components"
|
||||||
|
@worldNecessities.push @maybeLoadURL(url, ThangType, 'thang')
|
||||||
|
|
||||||
# Supermodel (Level) Loading
|
# Supermodel (Level) Loading
|
||||||
|
|
||||||
|
@ -92,6 +105,7 @@ module.exports = class LevelLoader extends CocoClass
|
||||||
|
|
||||||
for thang in @level.get('thangs') or []
|
for thang in @level.get('thangs') or []
|
||||||
thangIDs.push thang.thangType
|
thangIDs.push thang.thangType
|
||||||
|
@loadItemThangsEquippedByLevelThang(thang)
|
||||||
for comp in thang.components or []
|
for comp in thang.components or []
|
||||||
componentVersions.push _.pick(comp, ['original', 'majorVersion'])
|
componentVersions.push _.pick(comp, ['original', 'majorVersion'])
|
||||||
|
|
||||||
|
@ -112,6 +126,7 @@ module.exports = class LevelLoader extends CocoClass
|
||||||
@thangIDs = _.uniq thangIDs
|
@thangIDs = _.uniq thangIDs
|
||||||
@thangNames = new ThangNamesCollection(@thangIDs)
|
@thangNames = new ThangNamesCollection(@thangIDs)
|
||||||
worldNecessities.push @supermodel.loadCollection(@thangNames, 'thang_names')
|
worldNecessities.push @supermodel.loadCollection(@thangNames, 'thang_names')
|
||||||
|
@listenToOnce @thangNames, 'sync', @onThangNamesLoaded
|
||||||
worldNecessities.push @sessionResource if @sessionResource?.isLoading
|
worldNecessities.push @sessionResource if @sessionResource?.isLoading
|
||||||
worldNecessities.push @opponentSessionResource if @opponentSessionResource?.isLoading
|
worldNecessities.push @opponentSessionResource if @opponentSessionResource?.isLoading
|
||||||
|
|
||||||
|
@ -132,8 +147,50 @@ module.exports = class LevelLoader extends CocoClass
|
||||||
wizard = ThangType.loadUniversalWizard()
|
wizard = ThangType.loadUniversalWizard()
|
||||||
@supermodel.loadModel wizard, 'thang'
|
@supermodel.loadModel wizard, 'thang'
|
||||||
|
|
||||||
jqxhrs = (resource.jqxhr for resource in worldNecessities when resource?.jqxhr)
|
@worldNecessities = @worldNecessities.concat worldNecessities
|
||||||
$.when(jqxhrs...).done(@onWorldNecessitiesLoaded)
|
|
||||||
|
loadItemThangsEquippedByLevelThang: (levelThang) ->
|
||||||
|
return unless levelThang.components
|
||||||
|
for component in levelThang.components
|
||||||
|
if component.original is LevelComponent.EquipsID and inventory = component.config?.inventory
|
||||||
|
for itemThangType in _.values(inventory)
|
||||||
|
url = "/db/thang.type/#{itemThangType}/version?project=name,components"
|
||||||
|
@worldNecessities.push @maybeLoadURL(url, ThangType, 'thang')
|
||||||
|
|
||||||
|
onThangNamesLoaded: (thangNames) ->
|
||||||
|
if @level.get('type') is 'hero'
|
||||||
|
for thangType in thangNames.models
|
||||||
|
@loadDefaultComponentsForThangType(thangType)
|
||||||
|
@loadEquippedItemsInheritedFromThangType(thangType)
|
||||||
|
|
||||||
|
loadDefaultComponentsForThangType: (thangType) ->
|
||||||
|
return unless components = thangType.get('components')
|
||||||
|
for component in components
|
||||||
|
url = "/db/level.component/#{component.original}/version/#{component.majorVersion}"
|
||||||
|
@worldNecessities.push @maybeLoadURL(url, LevelComponent, 'component')
|
||||||
|
|
||||||
|
loadEquippedItemsInheritedFromThangType: (thangType) ->
|
||||||
|
for levelThang in @level.get('thangs') or []
|
||||||
|
if levelThang.thangType is thangType.get('original')
|
||||||
|
levelThang = $.extend true, {}, levelThang
|
||||||
|
@level.denormalizeThang(levelThang, @supermodel)
|
||||||
|
equipsComponent = _.find levelThang.components, {original: LevelComponent.EquipsID}
|
||||||
|
inventory = equipsComponent.config?.inventory
|
||||||
|
continue unless inventory
|
||||||
|
for itemThangType in _.values inventory
|
||||||
|
url = "/db/thang.type/#{itemThangType}/version?project=name,components"
|
||||||
|
@worldNecessities.push @maybeLoadURL(url, ThangType, 'thang')
|
||||||
|
|
||||||
|
onWorldNecessityLoaded: (resource) ->
|
||||||
|
index = @worldNecessities.indexOf(resource)
|
||||||
|
if @level.get('type') is 'hero' and resource.name is 'thang'
|
||||||
|
@loadDefaultComponentsForThangType(resource.model)
|
||||||
|
@loadEquippedItemsInheritedFromThangType(resource.model)
|
||||||
|
|
||||||
|
return unless index >= 0
|
||||||
|
@worldNecessities.splice(index, 1)
|
||||||
|
@worldNecessities = (r for r in @worldNecessities when r?)
|
||||||
|
@onWorldNecessitiesLoaded() if @worldNecessities.length is 0
|
||||||
|
|
||||||
onWorldNecessitiesLoaded: =>
|
onWorldNecessitiesLoaded: =>
|
||||||
@initWorld()
|
@initWorld()
|
||||||
|
|
|
@ -32,6 +32,7 @@ module.exports = class Level extends CocoModel
|
||||||
o
|
o
|
||||||
|
|
||||||
denormalizeThang: (levelThang, supermodel) ->
|
denormalizeThang: (levelThang, supermodel) ->
|
||||||
|
levelThang.components ?= []
|
||||||
thangType = supermodel.getModelByOriginal(ThangType, levelThang.thangType)
|
thangType = supermodel.getModelByOriginal(ThangType, levelThang.thangType)
|
||||||
configs = {}
|
configs = {}
|
||||||
for thangComponent in levelThang.components
|
for thangComponent in levelThang.components
|
||||||
|
|
|
@ -3,6 +3,8 @@ CocoModel = require './CocoModel'
|
||||||
module.exports = class LevelComponent extends CocoModel
|
module.exports = class LevelComponent extends CocoModel
|
||||||
@className: 'LevelComponent'
|
@className: 'LevelComponent'
|
||||||
@schema: require 'schemas/models/level_component'
|
@schema: require 'schemas/models/level_component'
|
||||||
|
|
||||||
|
@EquipsID: '53e217d253457600003e3ebb'
|
||||||
urlRoot: '/db/level.component'
|
urlRoot: '/db/level.component'
|
||||||
|
|
||||||
set: (key, val, options) ->
|
set: (key, val, options) ->
|
||||||
|
|
|
@ -170,6 +170,7 @@ module.exports = class SuperModel extends Backbone.Model
|
||||||
@num += r.value
|
@num += r.value
|
||||||
_.defer @updateProgress
|
_.defer @updateProgress
|
||||||
r.clean()
|
r.clean()
|
||||||
|
@trigger 'resource-loaded', r
|
||||||
|
|
||||||
onResourceFailed: (r) ->
|
onResourceFailed: (r) ->
|
||||||
return unless @resources[r.rid]
|
return unless @resources[r.rid]
|
||||||
|
|
|
@ -174,7 +174,6 @@ LevelThangSchema = c.object {
|
||||||
components: []
|
components: []
|
||||||
},
|
},
|
||||||
id: thang # TODO: figure out if we can make this unique and how to set dynamic defaults
|
id: thang # TODO: figure out if we can make this unique and how to set dynamic defaults
|
||||||
# TODO: split thangType into 'original' and 'majorVersion' like the rest for consistency
|
|
||||||
thangType: c.objectId(links: [{rel: 'db', href: '/db/thang.type/{($)}/version'}], title: 'Thang Type', description: 'A reference to the original Thang template being configured.', format: 'thang-type')
|
thangType: c.objectId(links: [{rel: 'db', href: '/db/thang.type/{($)}/version'}], title: 'Thang Type', description: 'A reference to the original Thang template being configured.', format: 'thang-type')
|
||||||
components: c.array {title: 'Components', description: 'Thangs are configured by changing the Components attached to them.', uniqueItems: true, format: 'thang-components-array'}, ThangComponentSchema # TODO: uniqueness should be based on 'original', not whole thing
|
components: c.array {title: 'Components', description: 'Thangs are configured by changing the Components attached to them.', uniqueItems: true, format: 'thang-components-array'}, ThangComponentSchema # TODO: uniqueness should be based on 'original', not whole thing
|
||||||
|
|
||||||
|
@ -239,7 +238,7 @@ _.extend LevelSchema.properties,
|
||||||
icon: {type: 'string', format: 'image-file', title: 'Icon'}
|
icon: {type: 'string', format: 'image-file', title: 'Icon'}
|
||||||
banner: {type: 'string', format: 'image-file', title: 'Banner'}
|
banner: {type: 'string', format: 'image-file', title: 'Banner'}
|
||||||
goals: c.array {title: 'Goals', description: 'An array of goals which are visible to the player and can trigger scripts.'}, GoalSchema
|
goals: c.array {title: 'Goals', description: 'An array of goals which are visible to the player and can trigger scripts.'}, GoalSchema
|
||||||
type: c.shortString(title: 'Type', description: 'What kind of level this is.', 'enum': ['campaign', 'ladder', 'ladder-tutorial'])
|
type: c.shortString(title: 'Type', description: 'What kind of level this is.', 'enum': ['campaign', 'ladder', 'ladder-tutorial', 'hero'])
|
||||||
showsGuide: c.shortString(title: 'Shows Guide', description: 'If the guide is shown at the beginning of the level.', 'enum': ['first-time', 'always'])
|
showsGuide: c.shortString(title: 'Shows Guide', description: 'If the guide is shown at the beginning of the level.', 'enum': ['first-time', 'always'])
|
||||||
|
|
||||||
c.extendBasicProperties LevelSchema, 'level'
|
c.extendBasicProperties LevelSchema, 'level'
|
||||||
|
|
|
@ -55,6 +55,10 @@ _.extend LevelSessionSchema.properties,
|
||||||
|
|
||||||
screenshot:
|
screenshot:
|
||||||
type: 'string'
|
type: 'string'
|
||||||
|
|
||||||
|
heroConfig: c.object {},
|
||||||
|
inventory: c.object()
|
||||||
|
thangType: c.objectId()
|
||||||
|
|
||||||
state: c.object {},
|
state: c.object {},
|
||||||
complete:
|
complete:
|
||||||
|
|
|
@ -166,7 +166,9 @@ module.exports = class Handler
|
||||||
ids = ids.split(',') if _.isString ids
|
ids = ids.split(',') if _.isString ids
|
||||||
ids = _.uniq ids
|
ids = _.uniq ids
|
||||||
|
|
||||||
project = {name:1, original:1, kind:1}
|
# HACK: levels loading thang types need the components returned as well
|
||||||
|
# Need a way to specify a projection for a query.
|
||||||
|
project = {name:1, original:1, kind:1, components: 1}
|
||||||
sort = {'version.major':-1, 'version.minor':-1}
|
sort = {'version.major':-1, 'version.minor':-1}
|
||||||
|
|
||||||
makeFunc = (id) =>
|
makeFunc = (id) =>
|
||||||
|
|
171
test/app/lib/LevelLoader.spec.coffee
Normal file
171
test/app/lib/LevelLoader.spec.coffee
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
Level = require 'models/Level'
|
||||||
|
LevelSession = require 'models/LevelSession'
|
||||||
|
SuperModel = require 'models/SuperModel'
|
||||||
|
LevelComponent = require 'models/LevelComponent'
|
||||||
|
LevelLoader = require 'lib/LevelLoader'
|
||||||
|
|
||||||
|
# LEVELS
|
||||||
|
|
||||||
|
levelWithOgreWithMace = {
|
||||||
|
type: 'hero'
|
||||||
|
thangs: [{
|
||||||
|
thangType: 'ogre'
|
||||||
|
components: [{
|
||||||
|
original: LevelComponent.EquipsID
|
||||||
|
majorVersion: 0
|
||||||
|
config: { inventory: { 'left-hand': 'mace' } }
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
levelWithShaman = {
|
||||||
|
type: 'hero'
|
||||||
|
thangs: [{
|
||||||
|
thangType: 'shaman'
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
levelWithShamanWithSuperWand = {
|
||||||
|
type: 'hero'
|
||||||
|
thangs: [{
|
||||||
|
thangType: 'shaman'
|
||||||
|
components: [{
|
||||||
|
original: LevelComponent.EquipsID
|
||||||
|
majorVersion: 0
|
||||||
|
config: { inventory: { 'left-hand': 'super-wand' } }
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
# SESSIONS
|
||||||
|
|
||||||
|
sessionWithTharinWithHelmet = { heroConfig: { thangType: 'tharin', inventory: { 'head': 'helmet' }}}
|
||||||
|
|
||||||
|
# THANG TYPES
|
||||||
|
|
||||||
|
thangTypeOgreWithPhysicalComponent = {
|
||||||
|
name: 'Ogre'
|
||||||
|
original: 'ogre'
|
||||||
|
components: [{
|
||||||
|
original: 'physical'
|
||||||
|
majorVersion: 0
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
thangTypeShamanWithWandEquipped = {
|
||||||
|
name: 'Shaman'
|
||||||
|
original: 'shaman'
|
||||||
|
components: [{
|
||||||
|
original: LevelComponent.EquipsID
|
||||||
|
majorVersion: 0
|
||||||
|
config: { inventory: { 'left-hand': 'wand' }}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
thangTypeTharinWithHealsComponent = {
|
||||||
|
name: 'Tharin'
|
||||||
|
original: 'tharin'
|
||||||
|
components: [{
|
||||||
|
original: 'heals'
|
||||||
|
majorVersion: 0
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
thangTypeWand = {
|
||||||
|
name: 'Wand'
|
||||||
|
original: 'wand'
|
||||||
|
components: [{
|
||||||
|
original: 'poisons'
|
||||||
|
majorVersion: 0
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
describe 'LevelLoader', ->
|
||||||
|
it 'loads hero and item thang types from heroConfig in the LevelSession', ->
|
||||||
|
new LevelLoader({supermodel:new SuperModel(), sessionID: 'id', levelID: 'id'})
|
||||||
|
|
||||||
|
responses = {
|
||||||
|
'/db/level_session/id': sessionWithTharinWithHelmet
|
||||||
|
}
|
||||||
|
|
||||||
|
jasmine.Ajax.requests.sendResponses(responses)
|
||||||
|
requests = jasmine.Ajax.requests.all()
|
||||||
|
urls = (r.url for r in requests)
|
||||||
|
expect('/db/thang.type/helmet/version?project=name,components' in urls).toBeTruthy()
|
||||||
|
expect('/db/thang.type/tharin/version?project=name,components' in urls).toBeTruthy()
|
||||||
|
|
||||||
|
it 'loads components for the hero in the heroConfig in the LevelSession', ->
|
||||||
|
new LevelLoader({supermodel:new SuperModel(), sessionID: 'id', levelID: 'id'})
|
||||||
|
|
||||||
|
responses = {
|
||||||
|
'/db/level_session/id': sessionWithTharinWithHelmet
|
||||||
|
'/db/thang.type/tharin/version?project=name,components': thangTypeTharinWithHealsComponent
|
||||||
|
}
|
||||||
|
|
||||||
|
jasmine.Ajax.requests.sendResponses(responses)
|
||||||
|
requests = jasmine.Ajax.requests.all()
|
||||||
|
urls = (r.url for r in requests)
|
||||||
|
expect('/db/level.component/heals/version/0' in urls).toBeTruthy()
|
||||||
|
|
||||||
|
it 'loads thangs for items that the level thangs have in their Equips component configs', ->
|
||||||
|
new LevelLoader({supermodel:supermodel = new SuperModel(), sessionID: 'id', levelID: 'id'})
|
||||||
|
|
||||||
|
responses = {
|
||||||
|
'/db/level/id': levelWithOgreWithMace
|
||||||
|
}
|
||||||
|
|
||||||
|
jasmine.Ajax.requests.sendResponses(responses)
|
||||||
|
requests = jasmine.Ajax.requests.all()
|
||||||
|
urls = (r.url for r in requests)
|
||||||
|
expect('/db/thang.type/mace/version?project=name,components' in urls).toBeTruthy()
|
||||||
|
|
||||||
|
it 'loads components which are inherited by level thangs from thang type default components', ->
|
||||||
|
new LevelLoader({supermodel:new SuperModel(), sessionID: 'id', levelID: 'id'})
|
||||||
|
|
||||||
|
responses =
|
||||||
|
'/db/level/id': levelWithOgreWithMace
|
||||||
|
'/db/thang.type/names': [thangTypeOgreWithPhysicalComponent]
|
||||||
|
|
||||||
|
jasmine.Ajax.requests.sendResponses(responses)
|
||||||
|
requests = jasmine.Ajax.requests.all()
|
||||||
|
urls = (r.url for r in requests)
|
||||||
|
expect('/db/level.component/physical/version/0' in urls).toBeTruthy()
|
||||||
|
|
||||||
|
it 'loads item thang types which are inherited by level thangs from thang type default equips component configs', ->
|
||||||
|
new LevelLoader({supermodel:new SuperModel(), sessionID: 'id', levelID: 'id'})
|
||||||
|
|
||||||
|
responses =
|
||||||
|
'/db/level/id': levelWithShaman
|
||||||
|
'/db/thang.type/names': [thangTypeShamanWithWandEquipped]
|
||||||
|
|
||||||
|
jasmine.Ajax.requests.sendResponses(responses)
|
||||||
|
requests = jasmine.Ajax.requests.all()
|
||||||
|
urls = (r.url for r in requests)
|
||||||
|
expect('/db/thang.type/wand/version?project=name,components' in urls).toBeTruthy()
|
||||||
|
|
||||||
|
it 'loads components for item thang types which are inherited by level thangs from thang type default equips component configs', ->
|
||||||
|
new LevelLoader({supermodel:new SuperModel(), sessionID: 'id', levelID: 'id'})
|
||||||
|
|
||||||
|
responses =
|
||||||
|
'/db/level/id': levelWithShaman
|
||||||
|
'/db/thang.type/names': [thangTypeShamanWithWandEquipped]
|
||||||
|
'/db/thang.type/wand/version?project=name,components': thangTypeWand
|
||||||
|
|
||||||
|
jasmine.Ajax.requests.sendResponses(responses)
|
||||||
|
requests = jasmine.Ajax.requests.all()
|
||||||
|
urls = (r.url for r in requests)
|
||||||
|
expect('/db/level.component/poisons/version/0' in urls).toBeTruthy()
|
||||||
|
|
||||||
|
it 'does not load item thang types from thang type equips component configs which are overriden by level thang equips component configs', ->
|
||||||
|
new LevelLoader({supermodel:new SuperModel(), sessionID: 'id', levelID: 'id'})
|
||||||
|
|
||||||
|
responses =
|
||||||
|
'/db/level/id': levelWithShamanWithSuperWand
|
||||||
|
'/db/thang.type/names': [thangTypeShamanWithWandEquipped]
|
||||||
|
|
||||||
|
jasmine.Ajax.requests.sendResponses(responses)
|
||||||
|
requests = jasmine.Ajax.requests.all()
|
||||||
|
urls = (r.url for r in requests)
|
||||||
|
expect('/db/thang.type/wand/version?project=name,components' in urls).toBeFalsy()
|
|
@ -1,6 +1,6 @@
|
||||||
describe 'require', ->
|
describe 'require', ->
|
||||||
it 'has no modules that error when you import them', ->
|
it 'has no modules that error when you import them', ->
|
||||||
modules = window.require.list()
|
modules = window.require.list();
|
||||||
for module in modules
|
for module in modules
|
||||||
try
|
try
|
||||||
require(module)
|
require(module)
|
||||||
|
|
2
test/app/utils.coffee
Normal file
2
test/app/utils.coffee
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
module.exports.sendTestResponses = (responseMap) ->
|
||||||
|
|
Loading…
Reference in a new issue