docs: improve API testing feature (#7311)

This commit is contained in:
Shahed Nasser
2024-05-14 10:12:53 +03:00
committed by GitHub
parent 5b26f5f2cf
commit 70c4ffff8b
10 changed files with 368 additions and 68 deletions

View File

@@ -1,168 +0,0 @@
"use client"
import React from "react"
import { useEffect, useMemo, useState } from "react"
import { useRequestRunner } from "../../../hooks"
import { CodeBlock } from ".."
import { Card } from "../../Card"
import { Button, InputText } from "../../.."
import { ApiMethod, ApiDataOptions, ApiTestingOptions } from "types"
type ApiRunnerProps = {
apiMethod: ApiMethod
apiUrl: string
pathData?: Record<string, unknown>
queryData?: Record<string, unknown>
bodyData?: Record<string, unknown>
}
export const ApiRunner = ({
apiMethod,
apiUrl,
pathData,
bodyData,
queryData,
}: ApiRunnerProps) => {
// assemble api testing options
const [apiTestingOptions, setApiTestingOptions] = useState<ApiTestingOptions>(
{
method: apiMethod,
url: apiUrl,
pathData,
bodyData,
queryData,
}
)
const [isRunning, setIsRunning] = useState(false)
const [ran, setRan] = useState(false)
const hasData = (data?: Record<string, unknown>): boolean =>
data !== undefined && Object.keys(data).length > 0
// TODO change to be based on whether auth/data needed
const manualTestTrigger = useMemo(
() =>
hasData(apiTestingOptions.pathData) ||
hasData(apiTestingOptions.queryData) ||
hasData(apiTestingOptions.bodyData),
[apiTestingOptions]
)
const [responseLogs, setResponseLogs] = useState<string[]>([])
const [responseCode, setResponseCode] = useState<string | undefined>()
const pushMessage = (...message: string[]) =>
setResponseLogs((prev) => [...prev, ...message])
const { runRequest } = useRequestRunner({
pushLog: pushMessage,
onFinish: (_message, statusCode) => {
setIsRunning(false)
setResponseCode(statusCode)
},
replaceLog: (message) => setResponseLogs([message]),
})
useEffect(() => {
if (!isRunning && !manualTestTrigger && !ran) {
setIsRunning(true)
}
}, [apiTestingOptions, manualTestTrigger, isRunning, ran])
useEffect(() => {
if (isRunning && !ran) {
setRan(true)
setResponseLogs(["Sending request..."])
runRequest(apiTestingOptions)
}
}, [isRunning, ran])
const getParamsElms = ({
data,
title,
nameInApiOptions,
}: {
data: ApiDataOptions
title: string
nameInApiOptions: "pathData" | "bodyData" | "queryData"
}) => (
<div className="flex flex-col gap-docs_0.5">
<span className="text-compact-medium-plus text-medusa-fg-base">
{title}
</span>
<div className="flex gap-docs_0.5">
{Object.keys(data).map((pathParam, index) => (
<InputText
name={pathParam}
onChange={(e) =>
setApiTestingOptions((prev) => ({
...prev,
[nameInApiOptions]: {
...prev[nameInApiOptions],
[pathParam]: e.target.value,
},
}))
}
key={index}
placeholder={pathParam}
value={
typeof data[pathParam] === "string"
? (data[pathParam] as string)
: typeof data[pathParam] === "number"
? (data[pathParam] as number)
: `${data[pathParam]}`
}
/>
))}
</div>
</div>
)
return (
<>
{manualTestTrigger && (
<Card className="font-base mb-docs_1" contentClassName="gap-docs_0.5">
{apiTestingOptions.pathData &&
getParamsElms({
data: apiTestingOptions.pathData,
title: "Path Parameters",
nameInApiOptions: "pathData",
})}
{apiTestingOptions.bodyData &&
getParamsElms({
data: apiTestingOptions.bodyData,
title: "Request Body Parameters",
nameInApiOptions: "bodyData",
})}
{apiTestingOptions.queryData &&
getParamsElms({
data: apiTestingOptions.queryData,
title: "Request Query Parameters",
nameInApiOptions: "queryData",
})}
<Button
onClick={() => {
setIsRunning(true)
setRan(false)
}}
>
Send Request
</Button>
</Card>
)}
{(isRunning || ran) && (
<CodeBlock
source={responseLogs.join("\n")}
lang="json"
title="Testing Result"
collapsed={true}
blockStyle="subtle"
noReport={true}
badgeLabel={responseCode}
badgeColor={
!responseCode
? undefined
: responseCode.startsWith("2")
? "green"
: "red"
}
/>
)}
</>
)
}

View File

@@ -3,14 +3,13 @@
import React, { useMemo, useState } from "react"
import clsx from "clsx"
import { HighlightProps, Highlight, themes } from "prism-react-renderer"
import { CopyButton, Tooltip, Link } from "@/components"
import { ApiRunner, CopyButton, Tooltip, Link } from "@/components"
import { useColorMode } from "@/providers"
import { ExclamationCircle, PlaySolid, SquareTwoStack } from "@medusajs/icons"
import { CodeBlockHeader, CodeBlockHeaderMeta } from "./Header"
import { CodeBlockLine } from "./Line"
import { ApiAuthType, ApiDataOptions, ApiMethod } from "types"
import { CSSTransition } from "react-transition-group"
import { ApiRunner } from "./ApiRunner"
import { GITHUB_ISSUES_PREFIX } from "../.."
export type Highlight = {
@@ -69,7 +68,10 @@ export const CodeBlock = ({
const { colorMode } = useColorMode()
const [showTesting, setShowTesting] = useState(false)
const canShowApiTesting = useMemo(
() => apiTesting && rest.testApiMethod && rest.testApiUrl,
() =>
apiTesting !== undefined &&
rest.testApiMethod !== undefined &&
rest.testApiUrl !== undefined,
[apiTesting, rest]
)