Skip to content
Snippets Groups Projects
Unverified Commit a2751af0 authored by Alexandre Sanlim's avatar Alexandre Sanlim Committed by GitHub
Browse files

Add [Coincap] Cryptocurrency badges (#8623)


* Add concap services

* Add concap services

* add tests

* Changes after review

* fix import

* fix format

* fix given

* pretty format fix

* changes to code review.

* fix lower label

* fix coincap rank test

* fix labels in static examples

Co-authored-by: default avatarchris48s <chris.shaw480@gmail.com>
Co-authored-by: default avatarrepo-ranger[bot] <39074581+repo-ranger[bot]@users.noreply.github.com>
Co-authored-by: default avatarchris48s <chris48s@users.noreply.github.com>
parent 1baa8468
No related branches found
No related tags found
No related merge requests found
import { BaseJsonService } from '../index.js'
export default class BaseCoincapService extends BaseJsonService {
static category = 'other'
static defaultBadgeData = { label: 'coincap' }
// Doc this API. From https://docs.coincap.io/
// example: https://api.coincap.io/v2/assets/bitcoin
async fetch({ assetId, schema }) {
return this._requestJson({
schema,
url: `https://api.coincap.io/v2/assets/${assetId}`,
errorMessages: {
404: 'asset not found',
},
})
}
}
export { BaseCoincapService }
import Joi from 'joi'
import { floorCount } from '../color-formatters.js'
import BaseCoincapService from './coincap-base.js'
const schema = Joi.object({
data: Joi.object({
changePercent24Hr: Joi.string()
.pattern(/[0-9]*\.[0-9]+/i)
.required(),
name: Joi.string().required(),
}).required(),
}).required()
export default class CoincapChangePercent24HrUsd extends BaseCoincapService {
static route = { base: 'coincap/change-percent-24hr', pattern: ':assetId' }
static examples = [
{
title: 'Coincap (Change Percent 24Hr)',
namedParams: { assetId: 'bitcoin' },
staticPreview: this.render({
asset: { name: 'bitcoin', changePercent24Hr: '2.0670573674501840"' },
}),
keywords: ['bitcoin', 'crypto', 'cryptocurrency'],
},
]
static percentFormat(changePercent24Hr) {
return `${parseInt(changePercent24Hr).toFixed(2)}%`
}
static render({ asset }) {
return {
label: `${asset.name}`.toLowerCase(),
message: this.percentFormat(asset.changePercent24Hr),
color: floorCount(asset.changePercent24Hr),
}
}
async handle({ assetId }) {
const { data: asset } = await this.fetch({ assetId, schema })
return this.constructor.render({ asset })
}
}
import { isPercentage } from '../test-validators.js'
import { createServiceTester } from '../tester.js'
export const t = await createServiceTester()
t.create('request for existing asset with positive')
.get('/bitcoin.json')
.intercept(nock =>
nock('https://api.coincap.io')
.get('/v2/assets/bitcoin')
.reply(200, {
data: { changePercent24Hr: '1.4767080598737783', name: 'Bitcoin' },
})
)
.expectBadge({
label: 'bitcoin',
message: '1.00%',
color: 'brightgreen',
})
t.create('request for existing asset with negative')
.get('/bitcoin.json')
.intercept(nock =>
nock('https://api.coincap.io')
.get('/v2/assets/bitcoin')
.reply(200, {
data: { changePercent24Hr: '-1.4767080598737783', name: 'Bitcoin' },
})
)
.expectBadge({
label: 'bitcoin',
message: '-1.00%',
color: 'red',
})
t.create('change percent 24hr').get('/bitcoin.json').expectBadge({
label: 'bitcoin',
message: isPercentage,
})
t.create('asset not found').get('/not-a-valid-asset.json').expectBadge({
label: 'coincap',
message: 'asset not found',
})
import Joi from 'joi'
import BaseCoincapService from './coincap-base.js'
const schema = Joi.object({
data: Joi.object({
priceUsd: Joi.string()
.pattern(/[0-9]*\.[0-9]+/i)
.required(),
name: Joi.string().required(),
}).required(),
}).required()
export default class CoincapPriceUsd extends BaseCoincapService {
static route = { base: 'coincap/price-usd', pattern: ':assetId' }
static examples = [
{
title: 'Coincap (Price USD)',
namedParams: { assetId: 'bitcoin' },
staticPreview: this.render({
asset: { name: 'bitcoin', priceUsd: '19116.0479117336250772' },
}),
keywords: ['bitcoin', 'crypto', 'cryptocurrency'],
},
]
static priceFormat(price) {
return `$${parseFloat(price)
.toFixed(2)
.replace(/\d(?=(\d{3})+\.)/g, '$&,')}`
}
static render({ asset }) {
return {
label: `${asset.name}`.toLowerCase(),
message: this.priceFormat(asset.priceUsd),
color: 'blue',
}
}
async handle({ assetId }) {
const { data: asset } = await this.fetch({ assetId, schema })
return this.constructor.render({ asset })
}
}
import { test, given } from 'sazerac'
import CoincapPriceUsd from './coincap-priceusd.service.js'
describe('PriceUsd Format', function () {
test(CoincapPriceUsd.priceFormat, () => {
given('3').expect('$3.00')
given('33').expect('$33.00')
given('332').expect('$332.00')
given('3324').expect('$3,324.00')
given('332432').expect('$332,432.00')
given('332432.2').expect('$332,432.20')
given('332432.25').expect('$332,432.25')
given('332432432').expect('$332,432,432.00')
given('332432432.3432432').expect('$332,432,432.34')
})
})
import { isCurrency } from '../test-validators.js'
import { createServiceTester } from '../tester.js'
export const t = await createServiceTester()
t.create('request for existing asset')
.get('/bitcoin.json')
.intercept(nock =>
nock('https://api.coincap.io')
.get('/v2/assets/bitcoin')
.reply(200, {
data: { priceUsd: '16417.7176754790740415', name: 'Bitcoin' },
})
)
.expectBadge({
label: 'bitcoin',
message: '$16,417.72',
color: 'blue',
})
t.create('price usd').get('/bitcoin.json').expectBadge({
label: 'bitcoin',
message: isCurrency,
color: 'blue',
})
t.create('asset not found').get('/not-a-valid-asset.json').expectBadge({
label: 'coincap',
message: 'asset not found',
})
import Joi from 'joi'
import BaseCoincapService from './coincap-base.js'
const schema = Joi.object({
data: Joi.object({
rank: Joi.string()
.pattern(/^[0-9]+$/)
.required(),
name: Joi.string().required(),
}).required(),
}).required()
export default class CoincapRank extends BaseCoincapService {
static route = { base: 'coincap/rank', pattern: ':assetId' }
static examples = [
{
title: 'Coincap (Rank)',
namedParams: { assetId: 'bitcoin' },
staticPreview: this.render({ asset: { name: 'bitcoin', rank: '1' } }),
keywords: ['bitcoin', 'crypto', 'cryptocurrency'],
},
]
static render({ asset }) {
return {
label: `${asset.name}`.toLowerCase(),
message: asset.rank,
color: 'blue',
}
}
async handle({ assetId }) {
const { data: asset } = await this.fetch({ assetId, schema })
return this.constructor.render({ asset })
}
}
import Joi from 'joi'
import { createServiceTester } from '../tester.js'
export const t = await createServiceTester()
t.create('request for existing asset')
.get('/bitcoin.json')
.intercept(nock =>
nock('https://api.coincap.io')
.get('/v2/assets/bitcoin')
.reply(200, { data: { rank: '1', name: 'Bitcoin' } })
)
.expectBadge({
label: 'bitcoin',
message: '1',
color: 'blue',
})
t.create('rank')
.get('/bitcoin.json')
.expectBadge({
label: 'bitcoin',
message: Joi.number().integer().min(1).required(),
color: 'blue',
})
t.create('asset not found').get('/not-a-valid-asset.json').expectBadge({
label: 'coincap',
message: 'asset not found',
})
...@@ -94,10 +94,14 @@ const isZeroOverTimePeriod = withRegex( ...@@ -94,10 +94,14 @@ const isZeroOverTimePeriod = withRegex(
) )
const isIntegerPercentage = withRegex(/^[1-9][0-9]?%|^100%|^0%$/) const isIntegerPercentage = withRegex(/^[1-9][0-9]?%|^100%|^0%$/)
const isIntegerPercentageNegative = withRegex(/^-?[1-9][0-9]?%|^100%|^0%$/)
const isDecimalPercentage = withRegex(/^[0-9]+\.[0-9]*%$/) const isDecimalPercentage = withRegex(/^[0-9]+\.[0-9]*%$/)
const isDecimalPercentageNegative = withRegex(/^-?[0-9]+\.[0-9]*%$/)
const isPercentage = Joi.alternatives().try( const isPercentage = Joi.alternatives().try(
isIntegerPercentage, isIntegerPercentage,
isDecimalPercentage isDecimalPercentage,
isIntegerPercentageNegative,
isDecimalPercentageNegative
) )
const isFileSize = withRegex( const isFileSize = withRegex(
...@@ -164,6 +168,16 @@ const isHumanized = Joi.string().regex( ...@@ -164,6 +168,16 @@ const isHumanized = Joi.string().regex(
/[0-9a-z]+ (second|seconds|minute|minutes|hour|hours|day|days|month|months|year|years)/ /[0-9a-z]+ (second|seconds|minute|minutes|hour|hours|day|days|month|months|year|years)/
) )
// $1,530,602.24 // true
// 1,530,602.24 // true
// $1,666.24$ // false
// ,1,666,88, // false
// 1.6.66,6 // false
// .1555. // false
const isCurrency = withRegex(
/(?=.*\d)^\$?(([1-9]\d{0,2}(,\d{3})*)|0)?(\.\d{1,2})?$/
)
export { export {
isSemver, isSemver,
isVPlusTripleDottedVersion, isVPlusTripleDottedVersion,
...@@ -199,4 +213,5 @@ export { ...@@ -199,4 +213,5 @@ export {
isOrdinalNumber, isOrdinalNumber,
isOrdinalNumberDaily, isOrdinalNumberDaily,
isHumanized, isHumanized,
isCurrency,
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment