Skip to content

Commit

Permalink
Merge branch 'badges:master' into feat/9493/improve-auth-testing
Browse files Browse the repository at this point in the history
  • Loading branch information
jNullj authored Feb 22, 2024
2 parents a2b838c + 8ab9dfa commit 2590482
Show file tree
Hide file tree
Showing 9 changed files with 164 additions and 72 deletions.
20 changes: 10 additions & 10 deletions package-lock.json

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

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
"semver": "~7.6.0",
"simple-icons": "11.4.0",
"smol-toml": "1.1.4",
"webextension-store-meta": "^1.0.5",
"webextension-store-meta": "^1.1.0",
"xpath": "~0.0.34"
},
"scripts": {
Expand Down Expand Up @@ -171,7 +171,7 @@
"eslint-plugin-cypress": "^2.15.1",
"eslint-plugin-icedfrisby": "^0.1.0",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-jsdoc": "^48.0.6",
"eslint-plugin-jsdoc": "^48.1.0",
"eslint-plugin-mocha": "^10.3.0",
"eslint-plugin-no-extension-in-require": "^0.2.0",
"eslint-plugin-node": "^11.1.0",
Expand Down
45 changes: 8 additions & 37 deletions services/chrome-web-store/chrome-web-store-price.service.js
Original file line number Diff line number Diff line change
@@ -1,39 +1,10 @@
import { currencyFromCode } from '../text-formatters.js'
import { NotFound, pathParams } from '../index.js'
import BaseChromeWebStoreService from './chrome-web-store-base.js'
import { deprecatedService } from '../index.js'

export default class ChromeWebStorePrice extends BaseChromeWebStoreService {
static category = 'funding'
static route = { base: 'chrome-web-store/price', pattern: ':storeId' }
const ChromeWebStorePrice = deprecatedService({
category: 'funding',
route: { base: 'chrome-web-store/price', pattern: ':storeId' },
label: 'price',
dateAdded: new Date('2024-02-18'),
})

static openApi = {
'/chrome-web-store/price/{storeId}': {
get: {
summary: 'Chrome Web Store Price',
parameters: pathParams({
name: 'storeId',
example: 'ogffaloegjglncjfehdfplabnoondfjo',
}),
},
},
}

static defaultBadgeData = { label: 'price' }

static render({ priceCurrency, price }) {
return {
message: `${currencyFromCode(priceCurrency) + price}`,
color: 'brightgreen',
}
}

async handle({ storeId }) {
const chromeWebStore = await this.fetch({ storeId })
const priceCurrency = chromeWebStore.priceCurrency()
const price = chromeWebStore.price()
if (priceCurrency == null || price == null) {
throw new NotFound({ prettyMessage: 'not found' })
}
return this.constructor.render({ priceCurrency, price })
}
}
export default ChromeWebStorePrice
28 changes: 10 additions & 18 deletions services/chrome-web-store/chrome-web-store-price.tester.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,12 @@
import Joi from 'joi'
import { createServiceTester } from '../tester.js'
export const t = await createServiceTester()
import { ServiceTester } from '../tester.js'

t.create('Price')
.get('/alhjnofcnnpeaphgeakdhkebafjcpeae.json')
.expectBadge({
label: 'price',
message: Joi.string().regex(/^\$\d+(.\d{1,2})?$/),
})
export const t = new ServiceTester({
id: 'ChromeWebStorePrice',
title: 'ChromeWebStorePrice',
pathPrefix: '/chrome-web-store/price',
})

t.create('Price (not found)')
.get('/invalid-name-of-addon.json')
.expectBadge({ label: 'price', message: 'not found' })

// Keep this "inaccessible" test, since this service does not use BaseService#_request.
t.create('Price (inaccessible)')
.get('/alhjnofcnnpeaphgeakdhkebafjcpeae.json')
.networkOff()
.expectBadge({ label: 'price', message: 'inaccessible' })
t.create('Price').get('/alhjnofcnnpeaphgeakdhkebafjcpeae.json').expectBadge({
label: 'price',
message: 'no longer available',
})
4 changes: 3 additions & 1 deletion services/chrome-web-store/chrome-web-store-users.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ class ChromeWebStoreUsers extends BaseChromeWebStoreService {
if (downloads == null) {
throw new NotFound({ prettyMessage: 'not found' })
}
return renderDownloadsBadge({ downloads })
return renderDownloadsBadge({
downloads: String(downloads.replace(',', '')),
})
}
}

Expand Down
87 changes: 87 additions & 0 deletions services/npm/npm-unpacked-size.service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import Joi from 'joi'
import prettyBytes from 'pretty-bytes'
import { pathParam, queryParam } from '../index.js'
import { optionalNonNegativeInteger } from '../validators.js'
import NpmBase, { packageNameDescription } from './npm-base.js'

const schema = Joi.object({
dist: Joi.object({
unpackedSize: optionalNonNegativeInteger,
}).required(),
}).required()

export default class NpmUnpackedSize extends NpmBase {
static category = 'size'

static route = {
base: 'npm/unpacked-size',
pattern: ':scope(@[^/]+)?/:packageName/:version*',
}

static openApi = {
'/npm/unpacked-size/{packageName}': {
get: {
summary: 'NPM Unpacked Size',
parameters: [
pathParam({
name: 'packageName',
example: 'npm',
description: packageNameDescription,
}),
queryParam({
name: 'registry_uri',
example: 'https://registry.npmjs.com',
}),
],
},
},
'/npm/unpacked-size/{packageName}/{version}': {
get: {
summary: 'NPM Unpacked Size (with version)',
parameters: [
pathParam({
name: 'packageName',
example: 'npm',
description: packageNameDescription,
}),
pathParam({
name: 'version',
example: '4.18.2',
}),
queryParam({
name: 'registry_uri',
example: 'https://registry.npmjs.com',
}),
],
},
},
}

static defaultBadgeData = { label: 'unpacked size' }

async fetch({ registryUrl, packageName, version }) {
return this._requestJson({
schema,
url: `${registryUrl}/${packageName}/${version}`,
})
}

async handle(
{ scope, packageName, version },
{ registry_uri: registryUrl = 'https://registry.npmjs.org' },
) {
const packageNameWithScope = scope ? `${scope}/${packageName}` : packageName
const { dist } = await this.fetch({
registryUrl,
packageName: packageNameWithScope,
version: version ?? 'latest',
})
const { unpackedSize } = dist

return {
label: 'unpacked size',
message: unpackedSize ? prettyBytes(unpackedSize) : 'unknown',
color: unpackedSize ? 'blue' : 'lightgray',
}
}
}
28 changes: 28 additions & 0 deletions services/npm/npm-unpacked-size.tester.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { isFileSize } from '../test-validators.js'
import { createServiceTester } from '../tester.js'

export const t = await createServiceTester()

t.create('Latest unpacked size')
.get('/firereact.json')
.expectBadge({ label: 'unpacked size', message: isFileSize })

t.create('Nonexistent unpacked size with version')
.get('/express/4.16.0.json')
.expectBadge({ label: 'unpacked size', message: 'unknown' })

t.create('Unpacked size with version')
.get('/firereact/0.7.0.json')
.expectBadge({ label: 'unpacked size', message: '147 kB' })

t.create('Unpacked size for scoped package')
.get('/@testing-library/react.json')
.expectBadge({ label: 'unpacked size', message: isFileSize })

t.create('Unpacked size for scoped package with version')
.get('/@testing-library/react/14.2.1.json')
.expectBadge({ label: 'unpacked size', message: '5.41 MB' })

t.create('Nonexistent unpacked size for scoped package with version')
.get('/@cycle/rx-run/7.2.0.json')
.expectBadge({ label: 'unpacked size', message: 'unknown' })
13 changes: 9 additions & 4 deletions services/website/website.service.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
import Joi from 'joi'
import emojic from 'emojic'
import Joi from 'joi'
import trace from '../../core/base-service/trace.js'
import { BaseService, queryParams } from '../index.js'
import { optionalUrl } from '../validators.js'
import {
queryParamSchema,
queryParams as websiteQueryParams,
renderWebsiteStatus,
queryParams as websiteQueryParams,
} from '../website-status.js'
import { BaseService, queryParams } from '../index.js'
import trace from '../../core/base-service/trace.js'

const description = `
The existence of a specific path on the server can be checked by appending
a path after the domain name, e.g.
\`https://img.shields.io/website?url=http%3A//www.website.com/path/to/page.html\`.
The messages and colors for the up and down states can also be customized.
A site will be classified as "down" if it fails to respond within 3.5 seconds.
`

const urlQueryParamSchema = Joi.object({
Expand Down Expand Up @@ -75,6 +77,9 @@ export default class Website extends BaseService {
url,
options: {
method: 'HEAD',
timeout: {
response: 3500,
},
},
})
// We consider all HTTP status codes below 310 as success.
Expand Down
7 changes: 7 additions & 0 deletions services/website/website.tester.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ t.create('status is down if response code is 401')
.intercept(nock => nock('http://offline.com').head('/').reply(401))
.expectBadge({ label: 'website', message: 'down' })

t.create('status is down if it is unresponsive for more than 3500 ms')
.get('/website.json?url=http://offline.com')
.intercept(nock =>
nock('http://offline.com').head('/').delay(4000).reply(200),
)
.expectBadge({ label: 'website', message: 'down' })

t.create('custom online label, online message and online color')
.get(
'/website.json?url=http://online.com&up_message=up&down_message=down&up_color=green&down_color=grey',
Expand Down

0 comments on commit 2590482

Please sign in to comment.