|
- import {IncomingHttpHeaders, IncomingMessage, OutgoingHttpHeaders, request, RequestOptions} from 'http';
- import {Method} from '../src/backend/common';
- import {DataSource} from '../src/backend/data-source';
- import {FALLBACK_LANGUAGE, Language} from '../src/common';
-
- interface ClientParams {
- method: Method;
- path: string;
- headers?: IncomingHttpHeaders;
- body?: unknown;
- }
-
- type ResponseBody = Buffer | string | object;
-
- export interface TestClient {
- (params: ClientParams): Promise<[IncomingMessage, ResponseBody?]>;
- acceptMediaType(mediaType: string): this;
- acceptLanguage(language: string): this;
- acceptCharset(charset: string): this;
- contentType(mediaType: string): this;
- contentCharset(charset: string): this;
- }
-
- export const createTestClient = (options: Omit<RequestOptions, 'method' | 'path'>): TestClient => {
- const additionalHeaders: OutgoingHttpHeaders = {};
- const client = (params: ClientParams) => new Promise<[IncomingMessage, ResponseBody?]>((resolve, reject) => {
- const {
- ...etcAdditionalHeaders
- } = additionalHeaders;
-
- const headers: OutgoingHttpHeaders = {
- ...(options.headers ?? {}),
- ...etcAdditionalHeaders,
- };
-
- let contentTypeHeader: string | undefined;
- if (typeof params.body !== 'undefined') {
- contentTypeHeader = headers['content-type'] = params.headers?.['content-type'] ?? 'application/json';
- }
-
- const req = request({
- ...options,
- method: params.method,
- path: params.path,
- headers,
- });
-
- req.on('response', (res) => {
- res.on('error', (err) => {
- reject(err);
- });
-
- let resBuffer: Buffer | undefined;
- res.on('data', (c) => {
- resBuffer = (
- typeof resBuffer === 'undefined'
- ? Buffer.from(c)
- : Buffer.concat([resBuffer, c])
- );
- });
-
- res.on('close', () => {
- const acceptHeader = Array.isArray(headers['accept']) ? headers['accept'].join('; ') : headers['accept'];
- const contentTypeBase = acceptHeader ?? 'application/octet-stream';
- const [type, subtype] = contentTypeBase.split('/');
- const allSubtypes = subtype.split('+');
- if (typeof resBuffer !== 'undefined') {
- if (allSubtypes.includes('json')) {
- const acceptCharset = (
- Array.isArray(headers['accept-charset'])
- ? headers['accept-charset'].join('; ')
- : headers['accept-charset']
- ) as BufferEncoding | undefined;
- resolve([res, JSON.parse(resBuffer.toString(acceptCharset ?? 'utf-8'))]);
- return;
- }
-
- if (type === 'text') {
- const acceptCharset = (
- Array.isArray(headers['accept-charset'])
- ? headers['accept-charset'].join('; ')
- : headers['accept-charset']
- ) as BufferEncoding | undefined;
- resolve([res, resBuffer.toString(acceptCharset ?? 'utf-8')]);
- return;
- }
-
- resolve([res, resBuffer]);
- return;
- }
-
- resolve([res]);
- });
- });
-
- req.on('error', (err) => {
- reject(err);
- })
-
- if (typeof params.body !== 'undefined') {
- const theContentTypeHeader = Array.isArray(contentTypeHeader) ? contentTypeHeader.join('; ') : contentTypeHeader?.toString();
- const contentTypeAll = theContentTypeHeader ?? 'application/octet-stream';
- const [contentTypeBase, ...contentTypeParams] = contentTypeAll.split(';').map((s) => s.replace(/\s+/g, '').trim());
- const charsetParam = contentTypeParams.find((s) => s.startsWith('charset='));
- const charset = charsetParam?.split('=')?.[1] as BufferEncoding | undefined;
- const [, subtype] = contentTypeBase.split('/');
- const allSubtypes = subtype.split('+');
- req.write(
- allSubtypes.includes('json')
- ? JSON.stringify(params.body)
- : Buffer.from(params.body?.toString() ?? '', contentTypeBase === 'text' ? charset : undefined)
- );
- }
-
- req.end();
- });
-
- client.acceptMediaType = function acceptMediaType(mediaType: string) {
- additionalHeaders['accept'] = mediaType;
- return this;
- };
-
- client.acceptLanguage = function acceptLanguage(language: string) {
- additionalHeaders['accept-language'] = language;
- return this;
- };
-
- client.acceptCharset = function acceptCharset(charset: string) {
- additionalHeaders['accept-charset'] = charset;
- return this;
- };
-
- client.contentType = function contentType(mediaType: string) {
- additionalHeaders['content-type'] = mediaType;
- return this;
- };
-
- client.contentCharset = function contentCharset(charset: string) {
- additionalHeaders['content-type'] = `${additionalHeaders['content-type']}; charset="${charset}"`;
- return this;
- };
-
- return client;
- };
-
- export class DummyError extends Error {}
-
- export class DummyDataSource implements DataSource {
- private resource?: { dataSource?: unknown };
-
- async create(): Promise<object> {
- return {};
- }
-
- async delete(): Promise<void> {}
-
- async emplace(): Promise<[object, boolean]> {
- return [{}, false];
- }
-
- async getById(): Promise<object> {
- return {};
- }
-
- async newId(): Promise<string> {
- return '';
- }
-
- async getMultiple(): Promise<object[]> {
- return [];
- }
-
- async getSingle(): Promise<object> {
- return {};
- }
-
- async getTotalCount(): Promise<number> {
- return 0;
- }
-
- async initialize(): Promise<void> {}
-
- async patch(): Promise<object> {
- return {};
- }
-
- prepareResource(rr: unknown) {
- this.resource = rr as unknown as { dataSource: DummyDataSource };
- this.resource.dataSource = this;
- }
- }
-
- export const TEST_LANGUAGE: Language = {
- name: FALLBACK_LANGUAGE.name,
- statusMessages: {
- unableToInitializeResourceDataSource: 'unableToInitializeResourceDataSource',
- unableToFetchResourceCollection: 'unableToFetchResourceCollection',
- unableToFetchResource: 'unableToFetchResource',
- resourceIdNotGiven: 'resourceIdNotGiven',
- languageNotAcceptable: 'languageNotAcceptable',
- encodingNotAcceptable: 'encodingNotAcceptable',
- mediaTypeNotAcceptable: 'mediaTypeNotAcceptable',
- methodNotAllowed: 'methodNotAllowed',
- urlNotFound: 'urlNotFound',
- badRequest: 'badRequest',
- ok: 'ok',
- resourceCollectionFetched: 'resourceCollectionFetched',
- resourceFetched: 'resourceFetched',
- resourceNotFound: 'resourceNotFound',
- deleteNonExistingResource: 'deleteNonExistingResource',
- unableToCreateResource: 'unableToCreateResource',
- unableToBindResourceDataSource: 'unableToBindResourceDataSource',
- unableToGenerateIdFromResourceDataSource: 'unableToGenerateIdFromResourceDataSource',
- unableToAssignIdFromResourceDataSource: 'unableToAssignIdFromResourceDataSource',
- unableToEmplaceResource: 'unableToEmplaceResource',
- unableToSerializeResponse: 'unableToSerializeResponse',
- unableToEncodeResponse: 'unableToEncodeResponse',
- unableToDeleteResource: 'unableToDeleteResource',
- unableToDeserializeResource: 'unableToDeserializeResource',
- unableToDecodeResource: 'unableToDecodeResource',
- resourceDeleted: 'resourceDeleted',
- unableToDeserializeRequest: 'unableToDeserializeRequest',
- patchNonExistingResource: 'patchNonExistingResource',
- unableToPatchResource: 'unableToPatchResource',
- invalidResourcePatch: 'invalidResourcePatch',
- invalidResourcePatchType: 'invalidResourcePatchType',
- invalidResource: 'invalidResource',
- resourcePatched: 'resourcePatched',
- resourceCreated: 'resourceCreated',
- resourceReplaced: 'resourceReplaced',
- notImplemented: 'notImplemented',
- provideOptions: 'provideOptions',
- internalServerError: 'internalServerError',
- },
- bodies: {
- languageNotAcceptable: [],
- encodingNotAcceptable: [],
- mediaTypeNotAcceptable: [],
- },
- };
|