-
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.
FI-1534 feat: add
mockWebSocketRoute
/unmockWebSocketRoute
actions
- Loading branch information
Showing
28 changed files
with
470 additions
and
53 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import {Route} from './Route'; | ||
|
||
/** | ||
* Abstract route for WebSocket "requests". | ||
*/ | ||
export abstract class WebSocketRoute< | ||
Params = undefined, | ||
SomeRequest = unknown, | ||
SomeResponse = unknown, | ||
> extends Route<Params> { | ||
/** | ||
* Request type of WebSocket route. | ||
*/ | ||
// eslint-disable-next-line @typescript-eslint/naming-convention | ||
declare readonly __REQUEST_KEY: SomeRequest; | ||
|
||
/** | ||
* Response type of WebSocket route. | ||
*/ | ||
// eslint-disable-next-line @typescript-eslint/naming-convention | ||
declare readonly __RESPONSE_KEY: SomeResponse; | ||
|
||
/** | ||
* Returns `true`, if the request body is in JSON format. | ||
*/ | ||
getIsRequestBodyInJsonFormat(): boolean { | ||
return true; | ||
} | ||
|
||
/** | ||
* Returns `true`, if the response body is in JSON format. | ||
*/ | ||
getIsResponseBodyInJsonFormat(): boolean { | ||
return true; | ||
} | ||
} |
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,2 +1,4 @@ | ||
export {mockApiRoute} from './mockApiRoute'; | ||
export {mockWebSocketRoute} from './mockWebSocketRoute'; | ||
export {unmockApiRoute} from './unmockApiRoute'; | ||
export {unmockWebSocketRoute} from './unmockWebSocketRoute'; |
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 |
---|---|---|
@@ -0,0 +1,80 @@ | ||
import {LogEventType} from '../../constants/internal'; | ||
import {getFullMocksState} from '../../context/fullMocks'; | ||
import {getWebSocketMockState} from '../../context/webSocketMockState'; | ||
import {getPlaywrightPage} from '../../useContext'; | ||
import {assertValueIsDefined} from '../../utils/asserts'; | ||
import {setCustomInspectOnFunction} from '../../utils/fn'; | ||
import {log} from '../../utils/log'; | ||
import {getRequestsFilter, getSetResponse} from '../../utils/mockWebSocketRoute'; | ||
import {setReadonlyProperty} from '../../utils/setReadonlyProperty'; | ||
|
||
import type { | ||
WebSocketMockFunction, | ||
WebSocketRouteClassTypeWithGetParamsFromUrl, | ||
} from '../../types/internal'; | ||
|
||
/** | ||
* Mock WebSocket for some API route. | ||
* Applicable only for routes with the `getParamsFromUrlOrThrow` method. | ||
* The mock is applied to a WebSocket that matches the route by url | ||
* (by methods `getParamsFromUrlOrThrow` and `isMatchUrl`). | ||
*/ | ||
export const mockWebSocketRoute = async <RouteParams, SomeRequest, SomeResponse>( | ||
Route: WebSocketRouteClassTypeWithGetParamsFromUrl<RouteParams>, | ||
webSocketMockFunction: WebSocketMockFunction<RouteParams, SomeRequest, SomeResponse>, | ||
{skipLogs = false}: {skipLogs?: boolean} = {}, | ||
): Promise<void> => { | ||
setCustomInspectOnFunction(webSocketMockFunction); | ||
|
||
const webSocketMockState = getWebSocketMockState(); | ||
|
||
if (!webSocketMockState.isMocksEnabled) { | ||
return; | ||
} | ||
|
||
const fullMocksState = getFullMocksState(); | ||
|
||
if (fullMocksState?.appliedMocks !== undefined) { | ||
setReadonlyProperty(webSocketMockState, 'isMocksEnabled', false); | ||
} | ||
|
||
let {optionsByRoute} = webSocketMockState; | ||
|
||
if (optionsByRoute === undefined) { | ||
optionsByRoute = new Map(); | ||
|
||
setReadonlyProperty(webSocketMockState, 'optionsByRoute', optionsByRoute); | ||
|
||
const requestsFilter = getRequestsFilter(webSocketMockState); | ||
|
||
setReadonlyProperty(webSocketMockState, 'requestsFilter', requestsFilter); | ||
} | ||
|
||
if (optionsByRoute.size === 0) { | ||
const {requestsFilter} = webSocketMockState; | ||
|
||
assertValueIsDefined(requestsFilter, 'requestsFilter is defined', { | ||
routeName: Route.name, | ||
webSocketMockState, | ||
}); | ||
|
||
const page = getPlaywrightPage(); | ||
|
||
const setResponse = getSetResponse(webSocketMockState); | ||
|
||
await page.routeWebSocket(requestsFilter, setResponse); | ||
} | ||
|
||
optionsByRoute.set(Route, { | ||
skipLogs, | ||
webSocketMockFunction: webSocketMockFunction as WebSocketMockFunction, | ||
}); | ||
|
||
if (skipLogs !== true) { | ||
log( | ||
`Mock WebSocket for route "${Route.name}"`, | ||
{webSocketMockFunction}, | ||
LogEventType.InternalAction, | ||
); | ||
} | ||
}; |
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,57 @@ | ||
import {LogEventType} from '../../constants/internal'; | ||
import {getWebSocketMockState} from '../../context/webSocketMockState'; | ||
import {getPlaywrightPage} from '../../useContext'; | ||
import {assertValueIsDefined} from '../../utils/asserts'; | ||
import {setCustomInspectOnFunction} from '../../utils/fn'; | ||
import {log} from '../../utils/log'; | ||
|
||
import type { | ||
WebSocketMockFunction, | ||
WebSocketRouteClassTypeWithGetParamsFromUrl, | ||
} from '../../types/internal'; | ||
|
||
/** | ||
* Unmock WebSocket (remove mock, if any) for some WebSocket route. | ||
*/ | ||
export const unmockWebSocketRoute = async <RouteParams, SomeRequest, SomeResponse>( | ||
Route: WebSocketRouteClassTypeWithGetParamsFromUrl<RouteParams, SomeRequest, SomeResponse>, | ||
): Promise<void> => { | ||
const webSocketMockState = getWebSocketMockState(); | ||
const {optionsByRoute, requestsFilter} = webSocketMockState; | ||
let webSocketMockFunction: WebSocketMockFunction | undefined; | ||
let routeWasMocked = false; | ||
let skipLogs: boolean | undefined; | ||
|
||
if (optionsByRoute?.has(Route)) { | ||
const options = optionsByRoute.get(Route); | ||
|
||
webSocketMockFunction = options?.webSocketMockFunction; | ||
skipLogs = options?.skipLogs; | ||
|
||
routeWasMocked = true; | ||
optionsByRoute.delete(Route); | ||
} | ||
|
||
if (optionsByRoute?.size === 0) { | ||
assertValueIsDefined(requestsFilter, 'requestsFilter is defined', { | ||
routeName: Route.name, | ||
routeWasMocked, | ||
}); | ||
|
||
const page = getPlaywrightPage(); | ||
|
||
await page.unroute(requestsFilter); | ||
} | ||
|
||
if (webSocketMockFunction) { | ||
setCustomInspectOnFunction(webSocketMockFunction); | ||
} | ||
|
||
if (skipLogs !== true) { | ||
log( | ||
`Unmock WebSocket for route "${Route.name}"`, | ||
{routeWasMocked, webSocketMockFunction}, | ||
LogEventType.InternalAction, | ||
); | ||
} | ||
}; |
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,32 @@ | ||
import {useContext} from '../useContext'; | ||
|
||
import type {WebSocketMockState} from '../types/internal'; | ||
|
||
/** | ||
* Raw get and set internal (maybe `undefined`) WebSocket mock state. | ||
* @internal | ||
*/ | ||
const [getRawWebSocketMockState, setRawWebSocketMockState] = useContext<WebSocketMockState>(); | ||
|
||
/** | ||
* Get internal always defined WebSocket mock state (for `mockWebSocketRoute`). | ||
* @internal | ||
*/ | ||
export const getWebSocketMockState = (): WebSocketMockState => { | ||
const maybeWebSocketMockState = getRawWebSocketMockState(); | ||
|
||
if (maybeWebSocketMockState !== undefined) { | ||
return maybeWebSocketMockState; | ||
} | ||
|
||
const webSocketMockState: WebSocketMockState = { | ||
isMocksEnabled: true, | ||
optionsByRoute: undefined, | ||
optionsWithRouteByUrl: Object.create(null) as {}, | ||
requestsFilter: undefined, | ||
}; | ||
|
||
setRawWebSocketMockState(webSocketMockState); | ||
|
||
return webSocketMockState; | ||
}; |
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
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 |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import type {URL} from 'node:url'; | ||
|
||
import type {WebSocketRoute} from '../WebSocketRoute'; | ||
|
||
import type {Url} from './http'; | ||
import type {MaybePromise} from './promise'; | ||
import type {WebSocketRouteClassTypeWithGetParamsFromUrl} from './routes'; | ||
|
||
/** | ||
* Mock option with mocked route. | ||
* @internal | ||
*/ | ||
type MockOptionsWithRoute = MockOptions & Readonly<{route: WebSocketRoute<unknown>}>; | ||
|
||
/** | ||
* Mock option (`skipLogs` and `webSocketMockFunction`). | ||
*/ | ||
type MockOptions = Readonly<{skipLogs: boolean; webSocketMockFunction: WebSocketMockFunction}>; | ||
|
||
/** | ||
* WebSocket mock function, that map request to mocked response. | ||
*/ | ||
export type WebSocketMockFunction< | ||
RouteParams = unknown, | ||
SomeRequest = unknown, | ||
SomeResponse = unknown, | ||
> = (routeParams: RouteParams, request: SomeRequest) => MaybePromise<SomeResponse>; | ||
|
||
/** | ||
* Internal state of `mockWebSocketRoute`/`unmockWebSocketRoute`. | ||
* @internal | ||
*/ | ||
export type WebSocketMockState = Readonly<{ | ||
isMocksEnabled: boolean; | ||
optionsByRoute: Map<WebSocketRouteClassTypeWithGetParamsFromUrl, MockOptions> | undefined; | ||
optionsWithRouteByUrl: Record<Url, MockOptionsWithRoute | undefined>; | ||
requestsFilter: ((urlObject: URL) => boolean) | undefined; | ||
}>; |
Oops, something went wrong.