-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
929 additions
and
132 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,22 @@ | ||
/** | ||
* The main module | ||
*/ | ||
|
||
import { isDevMode } from '@angular/core'; | ||
import { bootstrapApplication } from '@angular/platform-browser'; | ||
import { appConfig } from './app/app.config'; | ||
import { AppComponent } from './app/app.component'; | ||
import { appConfig } from './app/app.config'; | ||
|
||
/** | ||
* Start the application | ||
*/ | ||
async function startApp() { | ||
if (isDevMode()) { | ||
const { worker } = await import('./mocks/setup'); | ||
await worker.start({ waitUntilReady: true }); | ||
} | ||
} | ||
|
||
bootstrapApplication(AppComponent, appConfig).catch((err) => console.error(err)); | ||
startApp().then(() => | ||
bootstrapApplication(AppComponent, appConfig).catch((err) => console.error(err)), | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
/** | ||
* Mock data to be used in MSW responses | ||
*/ | ||
|
||
/** TODO: Add type annotations using the models that are also used in the application code. */ | ||
|
||
/** | ||
* Metldata API | ||
*/ | ||
|
||
export const metadataGlobalSummary = { | ||
resource_stats: { | ||
SequencingProcessFile: { | ||
count: 532, | ||
stats: { | ||
format: [ | ||
{ value: 'fastq', count: 124 }, | ||
{ value: 'bam', count: 408 }, | ||
], | ||
}, | ||
}, | ||
Individual: { | ||
count: 5432, | ||
stats: { | ||
sex: [ | ||
{ value: 'Female', count: 1935 }, | ||
{ value: 'Male', count: 2358 }, | ||
], | ||
}, | ||
}, | ||
ExperimentMethod: { | ||
count: 1400, | ||
stats: { | ||
instrument_model: [ | ||
{ | ||
value: 'Ilumina_test', | ||
count: 700, | ||
}, | ||
{ | ||
value: 'HiSeq_test', | ||
count: 700, | ||
}, | ||
], | ||
}, | ||
}, | ||
Dataset: { | ||
count: 252, | ||
stats: {}, | ||
}, | ||
}, | ||
}; | ||
|
||
/** | ||
* MASS API | ||
*/ | ||
|
||
export const searchResults = { | ||
facets: [ | ||
{ | ||
key: 'studies.type', | ||
name: 'Study Type', | ||
options: [ | ||
{ value: 'Option 1', count: 62 }, | ||
{ value: 'Option 2', count: 37 }, | ||
], | ||
}, | ||
{ | ||
key: 'type', | ||
name: 'Dataset Type', | ||
options: [ | ||
{ value: 'Test dataset type 1', count: 12 }, | ||
{ value: 'Test dataset type 2', count: 87 }, | ||
], | ||
}, | ||
], | ||
count: 25, // just to test the paginator | ||
hits: [ | ||
{ | ||
id_: 'GHGAD588887987', | ||
content: { | ||
accession: 'GHGAD588887987', | ||
ega_accession: 'EGAD588887987', | ||
title: 'Test dataset for details', | ||
description: | ||
'Test dataset for Metadata Repository get dataset details call. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Vel risus commodo viverra maecenas accumsan lacus vel. Sit amet risus nullam eget felis eget nunc lobortis mattis. Iaculis at erat pellentesque adipiscing commodo. Volutpat consequat mauris nunc congue. At lectus urna duis convallis convallis tellus id interdum velit. Gravida cum sociis natoque penatibus et. Mauris in aliquam sem fringilla ut morbi. Ultrices gravida dictum fusce ut. At consectetur lorem donec massa sapien faucibus et molestie.', | ||
types: ['Test dataset type 1'], | ||
}, | ||
}, | ||
{ | ||
id_: 'GHGAD588887988', | ||
content: { | ||
accession: 'GHGAD588887988', | ||
ega_accession: 'EGAD588887988', | ||
title: 'Test dataset for details', | ||
description: | ||
'Test dataset for Metadata Repository get dataset details call. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Vel risus commodo viverra maecenas accumsan lacus vel. Sit amet risus nullam eget felis eget nunc lobortis mattis. Iaculis at erat pellentesque adipiscing commodo. Volutpat consequat mauris nunc congue. At lectus urna duis convallis convallis tellus id interdum velit. Gravida cum sociis natoque penatibus et. Mauris in aliquam sem fringilla ut morbi. Ultrices gravida dictum fusce ut. At consectetur lorem donec massa sapien faucibus et molestie.', | ||
types: ['Test dataset type 1'], | ||
}, | ||
}, | ||
{ | ||
id_: 'GHGAD588887989', | ||
content: { | ||
accession: 'GHGAD588887989', | ||
ega_accession: 'EGAD588887989', | ||
title: 'Test dataset for details', | ||
description: | ||
'Test dataset for Metadata Repository get dataset details call. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Vel risus commodo viverra maecenas accumsan lacus vel. Sit amet risus nullam eget felis eget nunc lobortis mattis. Iaculis at erat pellentesque adipiscing commodo. Volutpat consequat mauris nunc congue. At lectus urna duis convallis convallis tellus id interdum velit. Gravida cum sociis natoque penatibus et. Mauris in aliquam sem fringilla ut morbi. Ultrices gravida dictum fusce ut. At consectetur lorem donec massa sapien faucibus et molestie.', | ||
types: ['Test dataset type 1'], | ||
}, | ||
}, | ||
], | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
/** | ||
* Create response handlers for MSW | ||
* | ||
* This module takes a list of static responses for different endpoints and | ||
* converts it into a list of response handlers that can be used to* setup MSW. | ||
*/ | ||
|
||
import { http, HttpResponse, RequestHandler } from 'msw'; | ||
import { responses, ResponseValue } from './responses'; | ||
|
||
/** | ||
* List of handlers for REST endpoints | ||
*/ | ||
export const handlers: RequestHandler[] = []; | ||
|
||
type ResponseMap = { [params: string]: ResponseValue }; | ||
|
||
const groupedResponses: { [endpoint: string]: ResponseMap } = {}; | ||
|
||
/** | ||
* Collect responses with different query parameters for the same endpoint | ||
*/ | ||
Object.keys(responses).forEach((endpoint) => { | ||
let method, url, params; | ||
[method, url] = endpoint.split(' '); | ||
method = method.toLowerCase(); | ||
if (!/^(get|post|patch|put|delete)$/.test(method)) { | ||
console.error('Invalid endpoint in fake data:', endpoint); | ||
return; | ||
} | ||
[url, params] = url.split('?'); | ||
let bareEndpoint = `${method} ${url}`; | ||
let responseMap = groupedResponses[bareEndpoint]; | ||
if (!responseMap) { | ||
groupedResponses[bareEndpoint] = responseMap = {}; | ||
} | ||
responseMap[params || '*'] = responses[endpoint]; | ||
}); | ||
|
||
/** | ||
Find the response with the most matching parameters | ||
@param request - the request that should be matched | ||
@param responseMap - the map of responses to choose from | ||
@returns the query string that matches the most parameters | ||
*/ | ||
async function getMatchingParamString(request: Request, responseMap: ResponseMap) { | ||
const paramStrings = Object.keys(responseMap); | ||
if (paramStrings.length < 2) { | ||
return paramStrings[0]; | ||
} | ||
// combine parameters from query string and body | ||
const requestParams = new URL(request.url).searchParams; | ||
const method = request.method.toLowerCase(); | ||
if (/post|patch|put|delete/.test(method)) { | ||
try { | ||
const bodyParams = await request.json(); | ||
Object.entries(bodyParams).forEach(([key, value]) => { | ||
const paramValue = typeof value === 'string' ? value : JSON.stringify(value); | ||
requestParams.set(key, paramValue); | ||
}); | ||
} catch {} | ||
} | ||
// find the response with the most matching parameters | ||
let bestParamString: string | null = null; | ||
let bestNumParams = 0; | ||
let bestStringLen = 0; | ||
Object.keys(responseMap).forEach((paramString) => { | ||
const params = new URLSearchParams(paramString); | ||
const numParams = Array.from(requestParams.keys()).reduce( | ||
(num, param) => num + (params.get(param) === requestParams.get(param) ? 1 : 0), | ||
0, | ||
); | ||
if ( | ||
bestParamString === null || | ||
numParams > bestNumParams || | ||
(numParams === bestNumParams && paramString.length < bestStringLen) | ||
) { | ||
bestParamString = paramString; | ||
bestNumParams = numParams; | ||
bestStringLen = paramString.length; | ||
} | ||
}); | ||
return bestParamString; | ||
} | ||
|
||
// create request handlers for the different endpoints | ||
Object.keys(groupedResponses).forEach((endpoint) => { | ||
let method, url; | ||
[method, url] = endpoint.split(' '); | ||
const responseMap = groupedResponses[endpoint]; | ||
/** | ||
* Resolver for the given endpoint | ||
* @param options - an options object containing the request | ||
* @param options.request - the request object | ||
* @returns - a response | ||
*/ | ||
const resolver = async ({ request }: { request: Request }) => { | ||
const paramString = await getMatchingParamString(request, responseMap); | ||
let response = responseMap[paramString || '*']; | ||
if (response === undefined) { | ||
console.debug('Not mocking', url); | ||
return; | ||
} | ||
if (Object.keys(responseMap).length > 1) { | ||
console.debug('Using mock data for params', paramString); | ||
} | ||
let status = 200; | ||
if (typeof response === 'number') { | ||
status = response; | ||
response = undefined; | ||
} else if (/post/.test(method)) { | ||
status = 201; | ||
} else if (/patch|put|delete/.test(method)) { | ||
status = 204; | ||
} | ||
return HttpResponse.json(response || undefined, { status }); | ||
}; | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
const handler = (http as any)[method]; | ||
if (!handler) { | ||
console.error('Unsupported method:', method); | ||
} | ||
handlers.push(handler.call(http, url, resolver)); | ||
}); |
Oops, something went wrong.