Files
metrics/source/app/mocks.mjs
2020-12-30 20:05:31 +01:00

766 lines
34 KiB
JavaScript

//Imports
import axios from "axios"
import urls from "url"
//Mocked state
let mocked = false
//Mocking
export default async function ({graphql, rest}) {
//Check if already mocked
if (mocked)
return {graphql, rest}
mocked = true
console.debug(`metrics/compute/mocks > mocking`)
//GraphQL API mocking
{
console.debug(`metrics/compute/mocks > mocking graphql api`)
const unmocked = graphql
graphql = new Proxy(unmocked, {
apply(target, that, args) {
//Arguments
const [query] = args
//Common query
if (/^query Metrics /.test(query)) {
console.debug(`metrics/compute/mocks > mocking graphql api result > Metrics`)
return ({
user: {
databaseId:22963968,
name:"Simon Lecoq",
login:"lowlighter",
createdAt:"2016-10-20T16:49:29Z",
avatarUrl:"https://avatars0.githubusercontent.com/u/22963968?u=f5097de6f06ed2e31906f784163fc1e9fc84ed57&v=4",
websiteUrl:"https://simon.lecoq.io",
isHireable:false,
twitterUsername:"lecoqsimon",
repositories:{totalCount:Math.floor(Math.random()*100), totalDiskUsage:Math.floor(Math.random()*100000), nodes:[]},
packages:{totalCount:Math.floor(Math.random()*10)},
starredRepositories:{totalCount:Math.floor(Math.random()*1000)},
watching:{totalCount:Math.floor(Math.random()*100)},
sponsorshipsAsSponsor:{totalCount:Math.floor(Math.random()*5)},
sponsorshipsAsMaintainer:{totalCount:Math.floor(Math.random()*5)},
contributionsCollection:{
totalRepositoriesWithContributedCommits:Math.floor(Math.random()*30),
totalCommitContributions:Math.floor(Math.random()*1000),
restrictedContributionsCount:Math.floor(Math.random()*500),
totalIssueContributions:Math.floor(Math.random()*100),
totalPullRequestContributions:Math.floor(Math.random()*100),
totalPullRequestReviewContributions:Math.floor(Math.random()*100)
},
calendar:{
contributionCalendar:{
weeks:[
{
contributionDays:[
{color:"#40c463"},
{color:"#ebedf0"},
{color:"#9be9a8"},
{color:"#ebedf0"},
{color:"#ebedf0"}
]
},
{
contributionDays:[
{color:"#30a14e"},
{color:"#9be9a8"},
{color:"#40c463"},
{color:"#9be9a8"},
{color:"#ebedf0"},
{color:"#ebedf0"},
{color:"#ebedf0"}
]
},
{
contributionDays:[
{color:"#40c463"},
{color:"#216e39"},
{color:"#9be9a8"}
]
}
]
}
},
repositoriesContributedTo:{totalCount:Math.floor(Math.random()*10)},
followers:{totalCount:Math.floor(Math.random()*100)},
following:{totalCount:Math.floor(Math.random()*100)},
issueComments:{totalCount:Math.floor(Math.random()*100)},
organizations:{totalCount:Math.floor(Math.random()*5)}
}
})
}
//Repositories query
if (/^query Repositories /.test(query)) {
console.debug(`metrics/compute/mocks > mocking graphql api result > Repositories`)
return /after: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"/m.test(query) ? ({
user:{
repositories:{
edges:[],
nodes:[],
}
}
}) : ({
user:{
repositories:{
edges:[
{
cursor:"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
],
nodes:[
{
name:"metrics",
watchers:{totalCount:Math.floor(Math.random()*100)},
stargazers:{totalCount:Math.floor(Math.random()*1000)},
languages:{
edges:[
{size:111733, node:{color:"#f1e05a", name:"JavaScript"}
},
{size:14398, node:{color:"#563d7c", name:"CSS"}},
{size:13223, node:{color:"#e34c26", name:"HTML"}},
]
},
issues_open:{totalCount:Math.floor(Math.random()*100)},
issues_closed:{totalCount:Math.floor(Math.random()*100)},
pr_open:{totalCount:Math.floor(Math.random()*100)},
pr_merged:{totalCount:Math.floor(Math.random()*100)},
releases:{totalCount:Math.floor(Math.random()*100)},
forkCount:Math.floor(Math.random()*100),
licenseInfo:{spdxId:"MIT"}
},
]
}
}
})
}
//Single repository query
if (/^query Repository /.test(query)) {
console.debug(`metrics/compute/mocks > mocking graphql api result > Repository`)
return ({
user:{
repository:{
name:"metrics",
createdAt:new Date().toISOString(),
diskUsage:Math.floor(Math.random()*10000),
watchers:{totalCount:Math.floor(Math.random()*100)},
stargazers:{totalCount:Math.floor(Math.random()*1000)},
languages:{
edges:[
{size:111733, node:{color:"#f1e05a", name:"JavaScript"}
},
{size:14398, node:{color:"#563d7c", name:"CSS"}},
{size:13223, node:{color:"#e34c26", name:"HTML"}},
]
},
issues_open:{totalCount:Math.floor(Math.random()*100)},
issues_closed:{totalCount:Math.floor(Math.random()*100)},
pr_open:{totalCount:Math.floor(Math.random()*100)},
pr_merged:{totalCount:Math.floor(Math.random()*100)},
releases:{totalCount:Math.floor(Math.random()*100)},
forkCount:Math.floor(Math.random()*100),
licenseInfo:{spdxId:"MIT"}
},
}
})
}
//Calendar query
if (/^query Calendar /.test(query)) {
console.debug(`metrics/compute/mocks > mocking graphql api result > Calendar`)
//Generate calendar
const date = new Date(query.match(/from: "(?<date>\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z)"/)?.groups?.date)
const to = new Date(query.match(/to: "(?<date>\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z)"/)?.groups?.date)
const weeks = []
let contributionDays = []
for (; date <= to; date.setDate(date.getDate()+1)) {
//Create new week on sunday
if (date.getDay() === 0) {
weeks.push({contributionDays})
contributionDays = []
}
//Random contributions
const contributionCount = Math.min(10, Math.max(0, Math.floor(Math.random()*14-4)))
contributionDays.push({
contributionCount,
color:["#ebedf0", "#9be9a8", "#40c463", "#30a14e", "#216e39"][Math.ceil(contributionCount/10/0.25)],
date:date.toISOString().substring(0, 10)
})
}
return ({
user: {
calendar:{
contributionCalendar:{
weeks
}
}
}
})
}
//Gists query
if (/^query Gists /.test(query)) {
console.debug(`metrics/compute/mocks > mocking graphql api result > Projects`)
return ({
user:{
gists:{
totalCount:1,
nodes:[
{
stargazerCount:Math.floor(Math.random()*10),
isFork:false,
forks:{totalCount:Math.floor(Math.random()*10)},
files:[{name:"example"}],
comments:{totalCount:Math.floor(Math.random()*10)}
}
]
}
}
})
}
//Projects query
if (/^query Projects /.test(query)) {
console.debug(`metrics/compute/mocks > mocking graphql api result > Projects`)
return ({
user:{
projects:{
totalCount:1,
nodes:[
{
name:"User-owned project",
updatedAt:new Date().toISOString(),
progress:{
doneCount:Math.floor(Math.random()*10),
inProgressCount:Math.floor(Math.random()*10),
todoCount:Math.floor(Math.random()*10),
enabled:true
}
}
]
}
}
})
}
//Repository project query
if (/^query RepositoryProject /.test(query)) {
console.debug(`metrics/compute/mocks > mocking graphql api result > RepositoryProject`)
return ({
user:{
repository:{
project:{
name:"Repository project example",
updatedAt:new Date().toISOString(),
progress:{
doneCount:Math.floor(Math.random()*10),
inProgressCount:Math.floor(Math.random()*10),
todoCount:Math.floor(Math.random()*10),
enabled:true
}
}
}
}
})
}
//Unmocked call
return target(...args)
}
})
}
//Rest API mocking
{
console.debug(`metrics/compute/mocks > mocking rest api`)
const unmocked = {
request:rest.request,
rateLimit:rest.rateLimit.get,
listEventsForAuthenticatedUser:rest.activity.listEventsForAuthenticatedUser,
getViews:rest.repos.getViews,
getContributorsStats:rest.repos.getContributorsStats,
listCommits:rest.repos.listCommits,
}
//Raw request
rest.request = new Proxy(unmocked.request, {
apply:function(target, that, args) {
//Arguments
const [url] = args
//Head request
if (/^HEAD .$/.test(url)) {
console.debug(`metrics/compute/mocks > mocking rest api result > rest.request HEAD`)
return ({
status: 200,
url:"https://api.github.com/",
headers:{
server:"GitHub.com",
status:"200 OK",
"x-oauth-scopes":"repo",
},
data:undefined
})
}
//Commit content
if (/^https:..api.github.com.repos.lowlighter.metrics.commits.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/.test(url)) {
console.debug(`metrics/compute/mocks > mocking rest api result > rest.request ${url}`)
return ({
status: 200,
url:"https://api.github.com/repos/lowlighter/metrics/commits/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
data:{
sha:"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
commit:{
author:{
name:"lowlighter",
email:"22963968+lowlighter@users.noreply.github.com",
date:new Date().toISOString(),
},
committer:{
name:"lowlighter",
email:"22963968+lowlighter@users.noreply.github.com",
date:new Date().toISOString(),
},
},
author:{
login:"lowlighter",
id:22963968,
},
committer:{
login:"lowlighter",
id:22963968,
},
files: [
{
sha:"5ab8c4fb6a0be4c157419c3b9d7b522dca354b3f",
filename:"index.mjs",
patch:"@@ -0,0 +1,5 @@\n+//Imports\n+ import app from \"./src/app.mjs\"\n+\n+//Start app\n+ await app()\n\\ No newline at end of file"
},
]
}
})
}
return target(...args)
}
})
//Rate limit
rest.rateLimit.get = new Proxy(unmocked.rateLimit, {
apply:function(target, that, args) {
return ({
status: 200,
url:"https://api.github.com/rate_limit",
headers:{
server:"GitHub.com",
status:"200 OK",
"x-oauth-scopes":"repo",
},
data:{
resources:{
core:{limit:5000, used:0, remaining:5000, reset:0 },
search:{limit:30, used:0, remaining:30, reset:0 },
graphql:{limit:5000, used:0, remaining:5000, reset:0 },
integration_manifest:{limit:5000, used:0, remaining:5000, reset:0 },
source_import:{limit:100, used:0, remaining:100, reset:0 },
code_scanning_upload:{limit:500, used:0, remaining:500, reset:0 },
},
rate:{limit:5000, used:0, remaining:"MOCKED", reset:0}
}
})
}
})
//Events list
rest.activity.listEventsForAuthenticatedUser = new Proxy(unmocked.listEventsForAuthenticatedUser, {
apply:function(target, that, [{page, per_page}]) {
console.debug(`metrics/compute/mocks > mocking rest api result > rest.activity.listEventsForAuthenticatedUser`)
return ({
status:200,
url:`https://api.github.com/users/lowlighter/events?per_page=${per_page}&page=${page}`,
headers:{
server:"GitHub.com",
status:"200 OK",
"x-oauth-scopes":"repo",
},
data:page < 1 ? new Array(10).fill(null).map(() =>
(false ? {
id:"10000000001",
type:"IssueCommentEvent",
} : {
id:"10000000000",
type:"PushEvent",
actor:{
id:22963968,
login:"lowlighter",
},
repo: {
id:293860197,
name:"lowlighter/metrics",
},
payload: {
ref:"refs/heads/master",
commits: [
{
url:"https://api.github.com/repos/lowlighter/metrics/commits/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
]
},
created_at:new Date(Date.now()-Math.floor(-Math.random()*14)*Math.floor(-Math.random()*24)*60*60*1000).toISOString()
})
) : []
})
}
})
//Repository traffic
rest.repos.getViews = new Proxy(unmocked.getViews, {
apply:function(target, that, args) {
console.debug(`metrics/compute/mocks > mocking rest api result > rest.repos.getViews`)
const count = Math.floor(Math.random()*1000)*2
const uniques = Math.floor(Math.random()*count)*2
return ({
status:200,
url:"https://api.github.com/repos/lowlighter/metrics/traffic/views",
headers:{
server:"GitHub.com",
status:"200 OK",
"x-oauth-scopes":"repo",
},
data:{
count,
uniques,
views:[
{timestamp:new Date().toISOString(), count:count/2, uniques:uniques/2},
{timestamp:new Date().toISOString(), count:count/2, uniques:uniques/2},
]
}
})
}
})
//Repository contributions
rest.repos.getContributorsStats = new Proxy(unmocked.getContributorsStats, {
apply:function(target, that, args) {
console.debug(`metrics/compute/mocks > mocking rest api result > rest.repos.getContributorsStats`)
return ({
status:200,
url:"https://api.github.com/repos/lowlighter/metrics/stats/contributors",
headers: {
server:"GitHub.com",
status:"200 OK",
"x-oauth-scopes":"repo",
},
data:[
{
total:Math.floor(Math.random()*1000),
weeks:[
{w:1, a:Math.floor(Math.random()*10000), d:Math.floor(Math.random()*10000), c:Math.floor(Math.random()*10000)},
{w:2, a:Math.floor(Math.random()*10000), d:Math.floor(Math.random()*10000), c:Math.floor(Math.random()*10000)},
{w:3, a:Math.floor(Math.random()*10000), d:Math.floor(Math.random()*10000), c:Math.floor(Math.random()*10000)},
{w:4, a:Math.floor(Math.random()*10000), d:Math.floor(Math.random()*10000), c:Math.floor(Math.random()*10000)},
],
author: {
login:"lowlighter",
}
}
]
})
}
})
//Repository contributions
rest.repos.listCommits = new Proxy(unmocked.listCommits, {
apply:function(target, that, [{page, per_page}]) {
console.debug(`metrics/compute/mocks > mocking rest api result > rest.repos.listCommits`)
return ({
status:200,
url:`https://api.github.com/repos/lowlighter/metrics/commits?per_page=${per_page}&page=${page}`,
headers: {
server:"GitHub.com",
status:"200 OK",
"x-oauth-scopes":"repo",
},
data:page < 2 ? new Array(per_page).fill(null).map(() =>
({
sha:"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
commit:{
author:{
name:"lowlighter",
date:new Date(Date.now()-Math.floor(-Math.random()*14)*24*60*60*1000).toISOString()
},
committer:{
name:"lowlighter",
date:new Date(Date.now()-Math.floor(-Math.random()*14)*24*60*60*1000).toISOString()
},
}
})
) : []
})
}
})
}
//Axios mocking
{
console.debug(`metrics/compute/mocks > mocking axios`)
const unmocked = {
get:axios.get,
post:axios.post,
}
//Post requests
axios.post = new Proxy(unmocked.post, {
apply:function(target, that, args) {
//Arguments
const [url, body] = args
//Spotify api
if (/^https:..accounts.spotify.com.api.token/.test(url)) {
//Access token generator
const params = new urls.URLSearchParams(body)
if ((params.get("grant_type") === "refresh_token")&&(params.get("client_id") === "MOCKED_CLIENT_ID")&&(params.get("client_secret") === "MOCKED_CLIENT_SECRET")&&(params.get("refresh_token") === "MOCKED_REFRESH_TOKEN")) {
console.debug(`metrics/compute/mocks > mocking spotify api result > ${url}`)
return ({
status:200,
data:{
access_token:"MOCKED_TOKEN_ACCESS",
token_type:"Bearer",
expires_in:3600,
scope:"user-read-recently-played user-read-private",
}
})
}
}
return target(...args)
}
})
//Get requests
axios.get = new Proxy(unmocked.get, {
apply:function(target, that, args) {
//Arguments
const [url, options] = args
//Pagespeed api
if (/^https:..www.googleapis.com.pagespeedonline.v5/.test(url)) {
//Pagespeed result
if (/v5.runPagespeed.*&key=MOCKED_TOKEN/.test(url)) {
console.debug(`metrics/compute/mocks > mocking pagespeed api result > ${url}`)
return ({
status:200,
data:{
captchaResult:"CAPTCHA_NOT_NEEDED",
id:"https://simon.lecoq.io/",
lighthouseResult:{
requestedUrl:"https://simon.lecoq.io/",
finalUrl:"https://simon.lecoq.io/",
lighthouseVersion:"6.3.0",
audits:{
"final-screenshot":{
id:"final-screenshot",
title:"Final Screenshot",
score: null,
details:{
data:"data:image/jpg;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mOcOnfpfwAGfgLYttYINwAAAABJRU5ErkJggg==",
type:"screenshot",
timestamp:Date.now()
}
},
metrics:{
id:"metrics",
title:"Metrics",
score: null,
details:{
items:[
{
observedFirstContentfulPaint:283,
observedFirstVisualChangeTs:1789259909429,
observedFirstContentfulPaintTs:1789259857628,
firstContentfulPaint:370,
observedDomContentLoaded:251,
observedFirstMeaningfulPaint:642,
maxPotentialFID:203,
observedLoad:330,
firstMeaningfulPaint:370,
observedCumulativeLayoutShift:0.0028944855967078186,
observedSpeedIndex:711,
observedSpeedIndexTs:1789260285891,
observedTimeOriginTs:1789259574429,
observedLargestContentfulPaint:857,
cumulativeLayoutShift:0.0028944855967078186,
observedFirstPaintTs:1789259857628,
observedTraceEndTs:1789261300953,
largestContentfulPaint:1085,
observedTimeOrigin:0,
speedIndex:578,
observedTraceEnd:1727,
observedDomContentLoadedTs:1789259825567,
observedFirstPaint:283,
totalBlockingTime:133,
observedLastVisualChangeTs:1789260426429,
observedFirstVisualChange:335,
observedLargestContentfulPaintTs:1789260431554,
estimatedInputLatency:13,
observedLoadTs:1789259904916,
observedLastVisualChange:852,
firstCPUIdle:773,
interactive:953,
observedNavigationStartTs:1789259574429,
observedNavigationStart:0,
observedFirstMeaningfulPaintTs:1789260216895
},
]
},
},
},
categories:{
"best-practices":{
id:"best-practices",
title:"Best Practices",
score:Math.floor(Math.random()*100)/100,
},
seo:{
id:"seo",
title:"SEO",
score:Math.floor(Math.random()*100)/100,
},
accessibility:{
id:"accessibility",
title:"Accessibility",
score:Math.floor(Math.random()*100)/100,
},
performance: {
id:"performance",
title:"Performance",
score:Math.floor(Math.random()*100)/100,
}
},
},
analysisUTCTimestamp:new Date().toISOString()
}
})
}
}
//Spotify api
if (/^https:..api.spotify.com/.test(url)) {
//Get recently played tracks
if (/me.player.recently-played/.test(url)&&(options?.headers?.Authorization === "Bearer MOCKED_TOKEN_ACCESS")) {
console.debug(`metrics/compute/mocks > mocking spotify api result > ${url}`)
return ({
status:200,
data:{
items:[
{
track:{
album:{
album_type:"single",
artists:[
{
name:"EGOIST",
type:"artist",
}
],
images:[
{
height:640,
url:"https://i.scdn.co/image/ab67616d0000b27366371d0ad05c3f402d9cb2ae",
width:640
},
{
height:300,
url:"https://i.scdn.co/image/ab67616d00001e0266371d0ad05c3f402d9cb2ae",
width:300
},
{
height:64,
url:"https://i.scdn.co/image/ab67616d0000485166371d0ad05c3f402d9cb2ae",
width:64
}
],
name:"Fallen",
release_date:"2014-11-19",
type:"album",
},
artists:[
{
name:"EGOIST",
type:"artist",
}
],
name:"Fallen",
preview_url:"https://p.scdn.co/mp3-preview/f30eb6d1c55afa13ce754559a41ab683a1a76b02?cid=fa6ae353840041ee8af3bd1d21a66783",
type:"track",
},
played_at:new Date().toISOString(),
context:{
type:"album",
}
},
],
}
})
}
}
//Twitter api
if (/^https:..api.twitter.com/.test(url)) {
//Get user profile
if ((/users.by.username/.test(url))&&(options?.headers?.Authorization === "Bearer MOCKED_TOKEN")) {
console.debug(`metrics/compute/mocks > mocking twitter api result > ${url}`)
return ({
status:200,
data:{
data:{
profile_image_url:"https://pbs.twimg.com/profile_images/1338344493234286592/C_ujKIUa_normal.png",
name:"GitHub",
verified:true,
id:"13334762",
username:"github",
},
}
})
}
//Get recent tweets
if ((/tweets.search.recent/.test(url))&&(options?.headers?.Authorization === "Bearer MOCKED_TOKEN")) {
console.debug(`metrics/compute/mocks > mocking twitter api result > ${url}`)
return ({
status:200,
data:{
data:[
{
id:"1000000000000000001",
created_at:new Date().toISOString(),
entities:{
mentions:[
{start:22, end:33, username:"lowlighter"},
],
},
text:"Checkout metrics from @lowlighter ! #GitHub",
},
{
id:"1000000000000000000",
created_at:new Date().toISOString(),
text:"Hello world !",
}
],
includes:{
users:[
{
id:"100000000000000000",
name:"lowlighter",
username:"lowlighter",
},
]
},
meta:{
newest_id:"1000000000000000001",
oldest_id:"1000000000000000000",
result_count:2,
next_token:"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
},
}
})
}
}
return target(...args)
}
})
}
//Return mocked elements
return {graphql, rest}
}