[{"data":1,"prerenderedAt":577},["ShallowReactive",2],{"docs-/docs/guides/api-testing":3},{"id":4,"title":5,"body":6,"description":569,"extension":570,"meta":571,"navigation":572,"path":573,"seo":574,"stem":575,"__hash__":576},"docs/docs/guides/api-testing.md","API Testing",{"type":7,"value":8,"toc":560},"minimark",[9,13,26,31,216,223,227,230,275,282,286,362,366,443,482,490,494,505,514,518,528,532,556],[10,11,5],"h1",{"id":12},"api-testing",[14,15,16,17,21,22,25],"p",{},"Define APIs in ",[18,19,20],"code",{},"testflowkit.yml",", then call them with ",[18,23,24],{},"I prepare a request to \"api_name.endpoint_name\"",". Same syntax for REST and GraphQL.",[27,28,30],"h2",{"id":29},"rest-configuration","REST configuration",[32,33,38],"pre",{"className":34,"code":35,"language":36,"meta":37,"style":37},"language-yaml shiki shiki-themes github-light github-dark","apis:\n  default_timeout: 10000\n  definitions:\n    jsonplaceholder:\n      type: rest\n      base_url: \"https://jsonplaceholder.typicode.com\"\n      default_headers:\n        Content-Type: \"application/json\"\n      endpoints:\n        get_posts:\n          method: GET\n          path: \"/posts\"\n        create_post:\n          method: POST\n          path: \"/posts\"\n        get_post_by_id:\n          method: GET\n          path: \"/posts/{id}\"\n","yaml","",[18,39,40,53,66,74,82,94,105,113,124,132,140,151,162,170,180,189,197,206],{"__ignoreMap":37},[41,42,45,49],"span",{"class":43,"line":44},"line",1,[41,46,48],{"class":47},"s9eBZ","apis",[41,50,52],{"class":51},"sVt8B",":\n",[41,54,56,59,62],{"class":43,"line":55},2,[41,57,58],{"class":47},"  default_timeout",[41,60,61],{"class":51},": ",[41,63,65],{"class":64},"sj4cs","10000\n",[41,67,69,72],{"class":43,"line":68},3,[41,70,71],{"class":47},"  definitions",[41,73,52],{"class":51},[41,75,77,80],{"class":43,"line":76},4,[41,78,79],{"class":47},"    jsonplaceholder",[41,81,52],{"class":51},[41,83,85,88,90],{"class":43,"line":84},5,[41,86,87],{"class":47},"      type",[41,89,61],{"class":51},[41,91,93],{"class":92},"sZZnC","rest\n",[41,95,97,100,102],{"class":43,"line":96},6,[41,98,99],{"class":47},"      base_url",[41,101,61],{"class":51},[41,103,104],{"class":92},"\"https://jsonplaceholder.typicode.com\"\n",[41,106,108,111],{"class":43,"line":107},7,[41,109,110],{"class":47},"      default_headers",[41,112,52],{"class":51},[41,114,116,119,121],{"class":43,"line":115},8,[41,117,118],{"class":47},"        Content-Type",[41,120,61],{"class":51},[41,122,123],{"class":92},"\"application/json\"\n",[41,125,127,130],{"class":43,"line":126},9,[41,128,129],{"class":47},"      endpoints",[41,131,52],{"class":51},[41,133,135,138],{"class":43,"line":134},10,[41,136,137],{"class":47},"        get_posts",[41,139,52],{"class":51},[41,141,143,146,148],{"class":43,"line":142},11,[41,144,145],{"class":47},"          method",[41,147,61],{"class":51},[41,149,150],{"class":92},"GET\n",[41,152,154,157,159],{"class":43,"line":153},12,[41,155,156],{"class":47},"          path",[41,158,61],{"class":51},[41,160,161],{"class":92},"\"/posts\"\n",[41,163,165,168],{"class":43,"line":164},13,[41,166,167],{"class":47},"        create_post",[41,169,52],{"class":51},[41,171,173,175,177],{"class":43,"line":172},14,[41,174,145],{"class":47},[41,176,61],{"class":51},[41,178,179],{"class":92},"POST\n",[41,181,183,185,187],{"class":43,"line":182},15,[41,184,156],{"class":47},[41,186,61],{"class":51},[41,188,161],{"class":92},[41,190,192,195],{"class":43,"line":191},16,[41,193,194],{"class":47},"        get_post_by_id",[41,196,52],{"class":51},[41,198,200,202,204],{"class":43,"line":199},17,[41,201,145],{"class":47},[41,203,61],{"class":51},[41,205,150],{"class":92},[41,207,209,211,213],{"class":43,"line":208},18,[41,210,156],{"class":47},[41,212,61],{"class":51},[41,214,215],{"class":92},"\"/posts/{id}\"\n",[14,217,218,219,222],{},"Timeout precedence: endpoint → API → ",[18,220,221],{},"apis.default_timeout"," → 30s fallback.",[27,224,226],{"id":225},"typical-flow","Typical flow",[14,228,229],{},"Most API scenarios follow the same pattern:",[231,232,233,243,253,261,267],"ol",{},[234,235,236,240,241],"li",{},[237,238,239],"strong",{},"Prepare"," — ",[18,242,24],{},[234,244,245,248,249,252],{},[237,246,247],{},"Configure"," — set body, path/query params, headers (merged with ",[18,250,251],{},"default_headers",")",[234,254,255,240,258],{},[237,256,257],{},"Send",[18,259,260],{},"I send the request",[234,262,263,266],{},[237,264,265],{},"Assert"," — status code, response fields (GJSON for JSON, XPath for XML), headers",[234,268,269,240,272],{},[237,270,271],{},"Extract",[18,273,274],{},"I store the response path \"data.id\" from the response into \"id\" variable",[14,276,277,278,281],{},"Use ",[18,279,280],{},"{{variable}}"," anywhere in step values.",[27,283,285],{"id":284},"rest-example","REST example",[32,287,291],{"className":288,"code":289,"language":290,"meta":37,"style":37},"language-gherkin shiki shiki-themes github-light github-dark","Scenario: Create and verify a post\n  Given I prepare a request to \"jsonplaceholder.create_post\"\n  And I set the request body to:\n    \"\"\"\n    {\n      \"title\": \"Test Post\",\n      \"body\": \"Test body\",\n      \"userId\": 1\n    }\n    \"\"\"\n  When I send the request\n  Then the response status code should be 201\n  And the response should have field \"id\"\n  And the response field \"title\" should be \"Test Post\"\n","gherkin",[18,292,293,298,303,308,313,318,323,328,333,338,342,347,352,357],{"__ignoreMap":37},[41,294,295],{"class":43,"line":44},[41,296,297],{},"Scenario: Create and verify a post\n",[41,299,300],{"class":43,"line":55},[41,301,302],{},"  Given I prepare a request to \"jsonplaceholder.create_post\"\n",[41,304,305],{"class":43,"line":68},[41,306,307],{},"  And I set the request body to:\n",[41,309,310],{"class":43,"line":76},[41,311,312],{},"    \"\"\"\n",[41,314,315],{"class":43,"line":84},[41,316,317],{},"    {\n",[41,319,320],{"class":43,"line":96},[41,321,322],{},"      \"title\": \"Test Post\",\n",[41,324,325],{"class":43,"line":107},[41,326,327],{},"      \"body\": \"Test body\",\n",[41,329,330],{"class":43,"line":115},[41,331,332],{},"      \"userId\": 1\n",[41,334,335],{"class":43,"line":126},[41,336,337],{},"    }\n",[41,339,340],{"class":43,"line":134},[41,341,312],{},[41,343,344],{"class":43,"line":142},[41,345,346],{},"  When I send the request\n",[41,348,349],{"class":43,"line":153},[41,350,351],{},"  Then the response status code should be 201\n",[41,353,354],{"class":43,"line":164},[41,355,356],{},"  And the response should have field \"id\"\n",[41,358,359],{"class":43,"line":172},[41,360,361],{},"  And the response field \"title\" should be \"Test Post\"\n",[27,363,365],{"id":364},"graphql","GraphQL",[32,367,369],{"className":34,"code":368,"language":36,"meta":37,"style":37},"apis:\n  definitions:\n    my_graphql:\n      type: graphql\n      endpoint: \"{{ env.graphql_endpoint }}\"\n      operations:\n        get_user:\n          type: query\n          operation: \"graphql/queries/get_user.graphql\"\n",[18,370,371,377,383,390,399,409,416,423,433],{"__ignoreMap":37},[41,372,373,375],{"class":43,"line":44},[41,374,48],{"class":47},[41,376,52],{"class":51},[41,378,379,381],{"class":43,"line":55},[41,380,71],{"class":47},[41,382,52],{"class":51},[41,384,385,388],{"class":43,"line":68},[41,386,387],{"class":47},"    my_graphql",[41,389,52],{"class":51},[41,391,392,394,396],{"class":43,"line":76},[41,393,87],{"class":47},[41,395,61],{"class":51},[41,397,398],{"class":92},"graphql\n",[41,400,401,404,406],{"class":43,"line":84},[41,402,403],{"class":47},"      endpoint",[41,405,61],{"class":51},[41,407,408],{"class":92},"\"{{ env.graphql_endpoint }}\"\n",[41,410,411,414],{"class":43,"line":96},[41,412,413],{"class":47},"      operations",[41,415,52],{"class":51},[41,417,418,421],{"class":43,"line":107},[41,419,420],{"class":47},"        get_user",[41,422,52],{"class":51},[41,424,425,428,430],{"class":43,"line":115},[41,426,427],{"class":47},"          type",[41,429,61],{"class":51},[41,431,432],{"class":92},"query\n",[41,434,435,438,440],{"class":43,"line":126},[41,436,437],{"class":47},"          operation",[41,439,61],{"class":51},[41,441,442],{"class":92},"\"graphql/queries/get_user.graphql\"\n",[32,444,446],{"className":288,"code":445,"language":290,"meta":37,"style":37},"Scenario: Fetch a user\n  Given I prepare a request to \"my_graphql.get_user\"\n  And I set the following GraphQL variables:\n    | id | 1 |\n  When I send the request\n  Then the GraphQL response should not have errors\n  And the response should have field \"user.username\"\n",[18,447,448,453,458,463,468,472,477],{"__ignoreMap":37},[41,449,450],{"class":43,"line":44},[41,451,452],{},"Scenario: Fetch a user\n",[41,454,455],{"class":43,"line":55},[41,456,457],{},"  Given I prepare a request to \"my_graphql.get_user\"\n",[41,459,460],{"class":43,"line":68},[41,461,462],{},"  And I set the following GraphQL variables:\n",[41,464,465],{"class":43,"line":76},[41,466,467],{},"    | id | 1 |\n",[41,469,470],{"class":43,"line":84},[41,471,346],{},[41,473,474],{"class":43,"line":96},[41,475,476],{},"  Then the GraphQL response should not have errors\n",[41,478,479],{"class":43,"line":107},[41,480,481],{},"  And the response should have field \"user.username\"\n",[14,483,484,485,489],{},"Operations can also be defined inline in config — see ",[486,487,20],"a",{"href":488},"/docs/config/overview",".",[27,491,493],{"id":492},"authentication","Authentication",[14,495,496,497,500,501,504],{},"Configure reusable auth with ",[18,498,499],{},"security_schemes"," and ",[18,502,503],{},"security_ref"," (bearer, basic, apikey, oauth2), or set a header per request:",[32,506,508],{"className":288,"code":507,"language":290,"meta":37,"style":37},"And I set the header \"Authorization\" to \"Bearer {{auth_token}}\"\n",[18,509,510],{"__ignoreMap":37},[41,511,512],{"class":43,"line":44},[41,513,507],{},[27,515,517],{"id":516},"step-catalog","Step catalog",[14,519,520,521,527],{},"For the full list of API sentences, browse the ",[237,522,523],{},[486,524,526],{"href":525},"/sentences","Step Definitions catalog"," — searchable by keyword and category.",[27,529,531],{"id":530},"next-steps","Next Steps",[533,534,535,542,549],"ul",{},[234,536,537,541],{},[486,538,540],{"href":539},"/docs/patterns/variables","Variables"," — Store and reuse response data",[234,543,544,548],{},[486,545,547],{"href":546},"/docs/patterns/random-data","Random Data"," — Dynamic request payloads",[234,550,551,555],{},[486,552,554],{"href":553},"/docs/patterns/global-hooks","Global Hooks"," — Auth and data setup before tests",[557,558,559],"style",{},"html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":37,"searchDepth":55,"depth":55,"links":561},[562,563,564,565,566,567,568],{"id":29,"depth":55,"text":30},{"id":225,"depth":55,"text":226},{"id":284,"depth":55,"text":285},{"id":364,"depth":55,"text":365},{"id":492,"depth":55,"text":493},{"id":516,"depth":55,"text":517},{"id":530,"depth":55,"text":531},"REST API and GraphQL testing capabilities","md",{},{"title":5},"/docs/guides/api-testing",{"title":5,"description":569},"docs/guides/api-testing","gZdB3ccSMOG8RtVYMcXw1El6Ot0yWm5XAPY40pgOTWo",1781768344581]