feat: v4.0.0 (#1016)
Co-authored-by: Denys Konovalov <kontakt@denyskon.de> Co-authored-by: Mathieu COSYNS <64072917+Mathieu-COSYNS@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
682576ffc4
commit
799c7e6936
@ -1,3 +1,5 @@
|
||||
import { isNotNullish } from '@staticcms/core/lib/util/null.util';
|
||||
|
||||
export const createMockRequest = <T>(
|
||||
status: number,
|
||||
data: {
|
||||
@ -35,44 +37,87 @@ export const createMockRequest = <T>(
|
||||
} as Response;
|
||||
};
|
||||
|
||||
export type FetchMethod = 'GET' | 'POST' | 'PUT' | 'HEAD';
|
||||
|
||||
export type QueryCheckFunc = (query: URLSearchParams) => boolean;
|
||||
|
||||
export interface RequestData {
|
||||
query: string | true | QueryCheckFunc;
|
||||
response: MockResponse<unknown> | MockResponseFunc<unknown>;
|
||||
limit?: number;
|
||||
used?: number;
|
||||
}
|
||||
|
||||
export type ReplyFunc = <T>(response: MockResponse<T> | MockResponseFunc<T>) => void;
|
||||
export type RepeatFunc = (limit: number) => { reply: ReplyFunc };
|
||||
|
||||
export interface MockFetch {
|
||||
baseUrl: string;
|
||||
mocks: Record<string, Response>;
|
||||
when: (url: string) => {
|
||||
reply: <T>(
|
||||
status: number,
|
||||
data: {
|
||||
json?: T;
|
||||
text?: string;
|
||||
},
|
||||
options?: {
|
||||
contentType?: string;
|
||||
headers?: Record<string, string>;
|
||||
},
|
||||
) => void;
|
||||
mocks: Record<string, Partial<Record<FetchMethod, RequestData[]>>>;
|
||||
when: (
|
||||
method: FetchMethod,
|
||||
url: string,
|
||||
) => {
|
||||
query: (query: string | true | QueryCheckFunc) => { reply: ReplyFunc; repeat: RepeatFunc };
|
||||
repeat: RepeatFunc;
|
||||
reply: ReplyFunc;
|
||||
};
|
||||
reset: () => void;
|
||||
}
|
||||
|
||||
export interface MockResponse<T> {
|
||||
status: number;
|
||||
json?: T;
|
||||
text?: string;
|
||||
contentType?: string;
|
||||
headers?: Record<string, string>;
|
||||
}
|
||||
|
||||
export type MockResponseFunc<T> = (url: string) => MockResponse<T> | Promise<MockResponse<T>>;
|
||||
|
||||
const mockFetch = (baseUrl: string): MockFetch => {
|
||||
const mockedFetch: MockFetch = {
|
||||
baseUrl,
|
||||
mocks: {},
|
||||
when(this: MockFetch, url: string) {
|
||||
// eslint-disable-next-line object-shorthand
|
||||
when: function (this: MockFetch, method: FetchMethod, url: string) {
|
||||
const reply =
|
||||
(query: string | true | QueryCheckFunc = '') =>
|
||||
(limit?: number) =>
|
||||
<T>(response: MockResponse<T> | MockResponseFunc<T>) => {
|
||||
const fullUrl = `${baseUrl}${url}`;
|
||||
if (!(fullUrl in this.mocks)) {
|
||||
this.mocks[fullUrl] = {};
|
||||
}
|
||||
|
||||
if (!(method in this.mocks[fullUrl])) {
|
||||
this.mocks[fullUrl][method] = [];
|
||||
}
|
||||
|
||||
this.mocks[fullUrl][method]?.push({
|
||||
query,
|
||||
response,
|
||||
limit,
|
||||
});
|
||||
};
|
||||
|
||||
const repeat =
|
||||
(query: string | true | QueryCheckFunc = '') =>
|
||||
(limit: number) => {
|
||||
return {
|
||||
reply: reply(query)(limit),
|
||||
};
|
||||
};
|
||||
|
||||
return {
|
||||
reply: <T>(
|
||||
status: number,
|
||||
data: {
|
||||
json?: T;
|
||||
text?: string;
|
||||
},
|
||||
options?: {
|
||||
contentType?: string;
|
||||
headers?: Record<string, string>;
|
||||
},
|
||||
) => {
|
||||
this.mocks[`${baseUrl}${url}`] = createMockRequest(status, data, options);
|
||||
query: (query: string | true | QueryCheckFunc) => {
|
||||
return {
|
||||
repeat: repeat(query),
|
||||
reply: reply(query)(),
|
||||
};
|
||||
},
|
||||
repeat: repeat(),
|
||||
reply: reply()(),
|
||||
};
|
||||
},
|
||||
reset(this: MockFetch) {
|
||||
@ -80,9 +125,66 @@ const mockFetch = (baseUrl: string): MockFetch => {
|
||||
},
|
||||
};
|
||||
|
||||
global.fetch = jest.fn().mockImplementation((url: string) => {
|
||||
return Promise.resolve(mockedFetch.mocks[url.split('?')[0]]);
|
||||
});
|
||||
global.fetch = jest
|
||||
.fn()
|
||||
.mockImplementation(async (fullUrl: string, { method = 'GET' }: { method: FetchMethod }) => {
|
||||
const [url, ...rest] = fullUrl.split('?');
|
||||
const query = rest.length > 0 ? rest[0] : '';
|
||||
|
||||
const mockResponses = [...(mockedFetch.mocks[url]?.[method] ?? [])];
|
||||
if (!mockResponses) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
for (let i = 0; i < mockResponses.length; i++) {
|
||||
const mockResponse = mockResponses[i];
|
||||
|
||||
const limit = mockResponse.limit;
|
||||
const used = mockResponse.used ?? 0;
|
||||
|
||||
if (isNotNullish(limit)) {
|
||||
if (used >= limit) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (isNotNullish(mockResponse.query) && mockResponse.query !== true) {
|
||||
if (typeof mockResponse.query === 'string') {
|
||||
if (mockResponse.query !== query) {
|
||||
continue;
|
||||
}
|
||||
} else if (!mockResponse.query(new URLSearchParams(query))) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let responseData = mockResponse.response;
|
||||
if (typeof responseData === 'function') {
|
||||
responseData = await responseData(fullUrl);
|
||||
}
|
||||
|
||||
const response = createMockRequest(
|
||||
responseData.status,
|
||||
{
|
||||
json: responseData.json,
|
||||
text: responseData.text,
|
||||
},
|
||||
{
|
||||
contentType: responseData.contentType,
|
||||
headers: responseData.headers,
|
||||
},
|
||||
);
|
||||
|
||||
mockedFetch.mocks[url][method]![i] = {
|
||||
...mockResponse,
|
||||
used: used + 1,
|
||||
};
|
||||
|
||||
return Promise.resolve(response);
|
||||
}
|
||||
|
||||
return Promise.resolve(undefined);
|
||||
});
|
||||
|
||||
return mockedFetch;
|
||||
};
|
||||
|
Reference in New Issue
Block a user