Skip to content

Commit

Permalink
Reduce boilerplate for creating new testers [npm appveyor gem uptimer…
Browse files Browse the repository at this point in the history
…obot clojars] (#1934)

This is a bit of sugar that reduces the boilerplate for creating testers in what I expect will become the standard case: a service in `foo/foo-thing.service.js` with its tests in `foo/foo-thing.tester.js`.

This makes a small stylistic change, which is to name the service by its CamelCase class name rather than an invented snake-case ID. Whereas before the name was specified in `class FooThing extends Base[Json]Service` and a second time in the tester, it now only needs to be specified once.
  • Loading branch information
paulmelnikow authored Aug 22, 2018
1 parent 452affb commit a0c43ed
Show file tree
Hide file tree
Showing 24 changed files with 629 additions and 531 deletions.
6 changes: 6 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@
"babel-eslint": "^8.0.2",
"babel-polyfill": "^6.26.0",
"babel-preset-env": "^1.7.0",
"caller": "^1.0.1",
"chai": "^4.1.2",
"chai-as-promised": "^7.1.1",
"chai-string": "^1.4.0",
Expand Down
29 changes: 29 additions & 0 deletions services/appveyor/appveyor-ci.tester.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
'use strict'

const Joi = require('joi')
const createServiceTester = require('../create-service-tester')

const { isBuildStatus } = require('../test-validators')

const t = createServiceTester()
module.exports = t

// Test AppVeyor build status badge
t.create('CI build status')
.get('/gruntjs/grunt.json')
.expectJSONTypes(Joi.object().keys({ name: 'build', value: isBuildStatus }))

// Test AppVeyor branch build status badge
t.create('CI build status on master branch')
.get('/gruntjs/grunt/master.json')
.expectJSONTypes(Joi.object().keys({ name: 'build', value: isBuildStatus }))

// Test AppVeyor build status badge on a non-existing project
t.create('CI 404')
.get('/somerandomproject/thatdoesntexits.json')
.expectJSON({ name: 'build', value: 'project not found or access denied' })

t.create('CI (connection error)')
.get('/this-one/is-not-real-either.json')
.networkOff()
.expectJSON({ name: 'build', value: 'inaccessible' })
30 changes: 30 additions & 0 deletions services/appveyor/appveyor-tests.tester.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
'use strict'

const Joi = require('joi')
const createServiceTester = require('../create-service-tester')

const isAppveyorTestTotals = Joi.string().regex(
/^(?:[0-9]+ (?:passed|skipped|failed)(?:, )?)+$/
)

const t = createServiceTester()
module.exports = t

// Test AppVeyor tests status badge
t.create('tests status')
.get('/NZSmartie/coap-net-iu0to.json')
.expectJSONTypes(
Joi.object().keys({ name: 'tests', value: isAppveyorTestTotals })
)

// Test AppVeyor branch tests status badge
t.create('tests status on master branch')
.get('/NZSmartie/coap-net-iu0to/master.json')
.expectJSONTypes(
Joi.object().keys({ name: 'tests', value: isAppveyorTestTotals })
)

// Test AppVeyor tests status badge for a non-existing project
t.create('tests 404')
.get('/somerandomproject/thatdoesntexits.json')
.expectJSON({ name: 'tests', value: 'project not found or access denied' })
51 changes: 0 additions & 51 deletions services/appveyor/appveyor.tester.js

This file was deleted.

File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
'use strict'

const Joi = require('joi')
const ServiceTester = require('../service-tester')
const createServiceTester = require('../create-service-tester')

const t = new ServiceTester({ id: 'clojars', title: 'clojars' })
const t = createServiceTester()
module.exports = t

t.create('clojars (valid)')
.get('/v/prismic.json')
.get('/prismic.json')
.expectJSONTypes(
Joi.object().keys({
name: 'clojars',
Expand All @@ -16,5 +16,5 @@ t.create('clojars (valid)')
)

t.create('clojars (not found)')
.get('/v/not-a-package.json')
.get('/not-a-package.json')
.expectJSON({ name: 'clojars', value: 'not found' })
29 changes: 29 additions & 0 deletions services/create-service-tester.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
'use strict'

const caller = require('caller')
const ServiceTester = require('./service-tester')
const BaseService = require('./base')

// Automatically create a ServiceTester. When run from e.g.
// `gem-rank.tester.js`, this will create a tester that attaches to the
// service found in `gem-rank.service.js`.
//
// This can't be used for `.service.js` files which export more than one
// service.
function createServiceTester() {
const servicePath = caller().replace('.tester.js', '.service.js')
let ServiceClass
try {
ServiceClass = require(servicePath)
} catch (e) {
throw Error(`Couldn't load service from ${servicePath}`)
}
if (!(ServiceClass.prototype instanceof BaseService)) {
throw Error(
`${servicePath} does not export a single service. Invoke new ServiceTester() directly.`
)
}
return ServiceTester.forServiceClass(ServiceClass)
}

module.exports = createServiceTester
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,15 @@
const Joi = require('joi')
const ServiceTester = require('../service-tester')

const {
isVPlusDottedVersionAtLeastOne,
isMetric,
} = require('../test-validators')
const isOrdinalNumber = Joi.string().regex(/^[1-9][0-9]+(ᵗʰ|ˢᵗ|ⁿᵈ|ʳᵈ)$/)
const isOrdinalNumberDaily = Joi.string().regex(
/^[1-9][0-9]+(ᵗʰ|ˢᵗ|ⁿᵈ|ʳᵈ) daily$/
)
const { isMetric } = require('../test-validators')

const t = new ServiceTester({ id: 'gem', title: 'Ruby Gems' })
const t = new ServiceTester({
id: 'gem-downloads',
title: 'Ruby Gem Downloads',
pathPrefix: '/gem',
})
module.exports = t

// version endpoint

t.create('version (valid)')
.get('/v/formatador.json')
.expectJSONTypes(
Joi.object().keys({
name: 'gem',
value: isVPlusDottedVersionAtLeastOne,
})
)

t.create('version (not found)')
.get('/v/not-a-package.json')
.expectJSON({ name: 'gem', value: 'not found' })

// downloads endpoints

// total downloads
t.create('total downloads (valid)')
.get('/dt/rails.json')
Expand Down Expand Up @@ -90,42 +70,3 @@ t.create('latest version downloads (valid)')
t.create('latest version downloads (not found)')
.get('/dtv/not-a-package.json')
.expectJSON({ name: 'downloads', value: 'not found' })

// users endpoint

t.create('users (valid)')
.get('/u/raphink.json')
.expectJSONTypes(
Joi.object().keys({
name: 'gems',
value: Joi.string().regex(/^[0-9]+$/),
})
)

t.create('users (not found)')
.get('/u/not-a-package.json')
.expectJSON({ name: 'gems', value: 'not found' })

// rank endpoint

t.create('total rank (valid)')
.get('/rt/rspec-puppet-facts.json')
.expectJSONTypes(
Joi.object().keys({
name: 'rank',
value: isOrdinalNumber,
})
)

t.create('daily rank (valid)')
.get('/rd/rspec-puppet-facts.json')
.expectJSONTypes(
Joi.object().keys({
name: 'rank',
value: isOrdinalNumberDaily,
})
)

t.create('rank (not found)')
.get('/rt/not-a-package.json')
.expectJSON({ name: 'rank', value: 'not found' })
20 changes: 20 additions & 0 deletions services/gem/gem-owner.tester.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
'use strict'

const Joi = require('joi')
const createServiceTester = require('../create-service-tester')

const t = createServiceTester()
module.exports = t

t.create('users (valid)')
.get('/raphink.json')
.expectJSONTypes(
Joi.object().keys({
name: 'gems',
value: Joi.string().regex(/^[0-9]+$/),
})
)

t.create('users (not found)')
.get('/not-a-package.json')
.expectJSON({ name: 'gems', value: 'not found' })
34 changes: 34 additions & 0 deletions services/gem/gem-rank.tester.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
'use strict'

const Joi = require('joi')
const createServiceTester = require('../create-service-tester')

const isOrdinalNumber = Joi.string().regex(/^[1-9][0-9]+(ᵗʰ|ˢᵗ|ⁿᵈ|ʳᵈ)$/)
const isOrdinalNumberDaily = Joi.string().regex(
/^[1-9][0-9]+(ᵗʰ|ˢᵗ|ⁿᵈ|ʳᵈ) daily$/
)

const t = createServiceTester()
module.exports = t

t.create('total rank (valid)')
.get('/rt/rspec-puppet-facts.json')
.expectJSONTypes(
Joi.object().keys({
name: 'rank',
value: isOrdinalNumber,
})
)

t.create('daily rank (valid)')
.get('/rd/rspec-puppet-facts.json')
.expectJSONTypes(
Joi.object().keys({
name: 'rank',
value: isOrdinalNumberDaily,
})
)

t.create('rank (not found)')
.get('/rt/not-a-package.json')
.expectJSON({ name: 'rank', value: 'not found' })
22 changes: 22 additions & 0 deletions services/gem/gem-version.tester.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
'use strict'

const Joi = require('joi')
const createServiceTester = require('../create-service-tester')

const { isVPlusDottedVersionAtLeastOne } = require('../test-validators')

const t = createServiceTester()
module.exports = t

t.create('version (valid)')
.get('/formatador.json')
.expectJSONTypes(
Joi.object().keys({
name: 'gem',
value: isVPlusDottedVersionAtLeastOne,
})
)

t.create('version (not found)')
.get('/not-a-package.json')
.expectJSON({ name: 'gem', value: 'not found' })
8 changes: 2 additions & 6 deletions services/librariesio/librariesio-dependent-repos.tester.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
'use strict'

const Joi = require('joi')
const ServiceTester = require('../service-tester')
const createServiceTester = require('../create-service-tester')
const { isMetric } = require('../test-validators')

const t = new ServiceTester({
id: 'librariesio-dependent-repos',
title: 'Libraries.io dependent repos',
pathPrefix: '/librariesio/dependent-repos',
})
const t = createServiceTester()
module.exports = t

t.create('dependent repo count')
Expand Down
8 changes: 2 additions & 6 deletions services/librariesio/librariesio-dependents.tester.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
'use strict'

const Joi = require('joi')
const ServiceTester = require('../service-tester')
const createServiceTester = require('../create-service-tester')
const { isMetric } = require('../test-validators')

const t = new ServiceTester({
id: 'librariesio-dependents',
title: 'Libraries.io dependents',
pathPrefix: '/librariesio/dependents',
})
const t = createServiceTester()
module.exports = t

t.create('dependent count')
Expand Down
Loading

0 comments on commit a0c43ed

Please sign in to comment.