{"id":13458711,"url":"https://github.com/karatelabs/karate","last_synced_at":"2025-05-13T15:04:06.405Z","repository":{"id":37408377,"uuid":"81226206","full_name":"karatelabs/karate","owner":"karatelabs","description":"Test Automation Made Simple","archived":false,"fork":false,"pushed_at":"2025-05-08T04:40:24.000Z","size":26504,"stargazers_count":8542,"open_issues_count":70,"forks_count":1982,"subscribers_count":225,"default_branch":"master","last_synced_at":"2025-05-13T11:02:21.910Z","etag":null,"topics":["api-testing","assertions","automated-testing","automation","bdd","contract-testing","cucumber","developer-tools","load-testing","microservices","mock-server","test-automation","testing","testing-framework","testing-tools","webdriver"],"latest_commit_sha":null,"homepage":"https://karatelabs.github.io/karate","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/karatelabs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":["karatelabs"]}},"created_at":"2017-02-07T15:59:17.000Z","updated_at":"2025-05-13T01:37:03.000Z","dependencies_parsed_at":"2023-09-26T16:47:30.792Z","dependency_job_id":"5fcabe8c-2143-45c5-8363-40c4af466a98","html_url":"https://github.com/karatelabs/karate","commit_stats":null,"previous_names":["intuit/karate"],"tags_count":56,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/karatelabs%2Fkarate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/karatelabs%2Fkarate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/karatelabs%2Fkarate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/karatelabs%2Fkarate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/karatelabs","download_url":"https://codeload.github.com/karatelabs/karate/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253957994,"owners_count":21990542,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api-testing","assertions","automated-testing","automation","bdd","contract-testing","cucumber","developer-tools","load-testing","microservices","mock-server","test-automation","testing","testing-framework","testing-tools","webdriver"],"created_at":"2024-07-31T09:00:55.544Z","updated_at":"2025-05-13T15:04:01.396Z","avatar_url":"https://github.com/karatelabs.png","language":"Java","readme":"\u003ctable\u003e\n  \u003ctr\u003e \n    \u003cth\u003e\n      \u003ch3\u003e\n          \u003ca href=\"https://github.com/karatelabs/karate/wiki/Get-Started\"\u003e⏩ \u003cbr/\u003e Get Started\u003c/a\u003e\n      \u003c/h3\u003e\n   \u003c/th\u003e\n   \u003ctd\u003e\n     Get started using VS Code, IntelliJ, Maven, Gradle, NPM, \u003cbr/\u003e GitHub Codespaces, Docker or the command-line\n   \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e \n    \u003cth\u003e\n      \u003ch3\u003e\n          \u003ca href=\"https://github.com/karatelabs/karate-examples/blob/main/README.md\"\u003e💡 \u003cbr/\u003e Examples\u003c/a\u003e\n      \u003c/h3\u003e\n   \u003c/th\u003e\n   \u003ctd\u003e\n     Examples and demos of integrations with other frameworks\n   \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e \n    \u003cth\u003e\n      \u003ch3\u003e\n          \u003ca href=\"https://www.youtube.com/playlist?list=PLnONaB4tNFOkxwM3dOvXLXJstSg_wMJSs\"\u003e📺 \u003cbr/\u003e Kick Start Videos\u003c/a\u003e\n      \u003c/h3\u003e\n   \u003c/th\u003e\n   \u003ctd\u003e\n     Beginner-friendly step-by-step guides to starting from scratch\n   \u003c/td\u003e\n  \u003c/tr\u003e    \n\u003c/table\u003e\n\n# Karate\n\n## Test Automation Made `Simple.`\n\n\u003cdiv\u003e \n  \u003ca href=\"https://github.com/karatelabs/karate/wiki/Support\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/support-wiki-red.svg\"/\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://twitter.com/getkarate\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/@getkarate--lightgrey?logo=twitter\u0026amp;style=social\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/karatelabs/karate/stargazers\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/stars/karatelabs/karate?style=social\"/\u003e\n  \u003c/a\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  \u003ca href=\"https://central.sonatype.com/namespace/io.karatelabs\"\u003e\n    \u003cimg src=\"https://img.shields.io/maven-central/v/io.karatelabs/karate-core.svg\"/\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/karatelabs/karate/actions?query=workflow%3Amaven-build\"\u003e\n    \u003cimg src=\"https://github.com/karatelabs/karate/actions/workflows/maven-build.yml/badge.svg?branch=develop\"/\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/karatelabs/karate/releases\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/release/karatelabs/karate.svg\"/\u003e\n  \u003c/a\u003e\n\u003c/div\u003e\n\n\u003ca href=\"https://karatelabs.io\"\u003e\u003cimg src=\"karate-core/src/test/resources/karate-map.jpg\" height=\"650\" /\u003e\u003c/a\u003e\n\nKarate is the only open-source tool to combine API test-automation, [mocks](karate-netty), [performance-testing](karate-gatling) and even [UI automation](karate-core) into a **single**, *unified* framework. The syntax is language-neutral, and easy for even non-programmers. Assertions and HTML reports are built-in, and you can run tests in parallel for speed.\n\nThere's also a cross-platform [stand-alone executable](karate-netty#standalone-jar) for teams not comfortable with Java. You don't have to compile code. Just write tests in a **simple**, *readable* syntax - carefully designed for HTTP, JSON, GraphQL and XML. And you can mix API and [UI test-automation](karate-core) within the same test script.\n\nA [Java API](#java-api) also exists for those who prefer to programmatically integrate Karate's rich automation and data-assertion capabilities.\n\n## Hello World\n### For API Testing\n\u003ca href=\"https://gist.github.com/ptrthomas/d5a2d9e15d0b07e4f1b46f692a599f93\"\u003e\u003cimg src=\"karate-demo/src/test/resources/karate-hello-world.jpg\" height=\"400\" /\u003e\u003c/a\u003e\n\n\u003e If you are familiar with Cucumber / Gherkin, the [*big difference*](#cucumber-vs-karate) here is that you **don't** need to write extra \"glue\" code or Java \"step definitions\" !\n\nIt is worth pointing out that JSON is a 'first class citizen' of the syntax such that you can express payload and expected data without having to use double-quotes and without having to enclose JSON field names in quotes.  There is no need to 'escape' characters like you would have had to in Java or other programming languages.\n\nAnd you don't need to create additional Java classes for any of the payloads that you need to work with.\n\n# Index\n\n\u003ctable\u003e\n\u003ctr\u003e\n  \u003cth\u003eStart\u003c/th\u003e\n  \u003ctd\u003e\n      \u003ca href=\"#maven\"\u003eMaven\u003c/a\u003e \n    | \u003ca href=\"#gradle\"\u003eGradle\u003c/a\u003e\n    | \u003ca href=\"#quickstart\"\u003eQuickstart\u003c/a\u003e\n    | \u003ca href=\"https://github.com/karatelabs/karate/tree/master/karate-netty#standalone-jar\"\u003eStandalone Executable\u003c/a\u003e\n    | \u003ca href=\"#folder-structure\"\u003eNaming Conventions\u003c/a\u003e\n    | \u003ca href=\"#script-structure\"\u003eScript Structure\u003c/a\u003e\n  \u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n  \u003cth\u003eRun\u003c/th\u003e\n  \u003ctd\u003e\n      \u003ca href=\"#junit-5\"\u003eJUnit 5\u003c/a\u003e\n    | \u003ca href=\"#command-line\"\u003eCommand Line\u003c/a\u003e\n    | \u003ca href=\"#ide-support\"\u003eIDE Support\u003c/a\u003e    \n    | \u003ca href=\"#tags\"\u003eTags / Grouping\u003c/a\u003e\n    | \u003ca href=\"#parallel-execution\"\u003eParallel Execution\u003c/a\u003e\n    | \u003ca href=\"#java-api\"\u003eJava API\u003c/a\u003e \n    | \u003ca href=\"#jbang\"\u003ejbang\u003c/a\u003e    \n  \u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n  \u003cth\u003eReport\u003c/th\u003e\n  \u003ctd\u003e\n      \u003ca href=\"#configuration\"\u003eConfiguration\u003c/a\u003e \n    | \u003ca href=\"#switching-the-environment\"\u003eEnvironment Switching\u003c/a\u003e\n    | \u003ca href=\"#test-reports\"\u003eReports\u003c/a\u003e\n    | \u003ca href=\"#junit-html-report\"\u003eJUnit HTML Report\u003c/a\u003e\n    | \u003ca href=\"#dry-run\"\u003eDry Run\u003c/a\u003e\n    | \u003ca href=\"#report-verbosity\"\u003eReport Verbosity\u003c/a\u003e\n    | \u003ca href=\"#logging\"\u003eLogging\u003c/a\u003e\n    | \u003ca href=\"#log-masking\"\u003eLog Masking\u003c/a\u003e\n  \u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n  \u003cth\u003eTypes\u003c/th\u003e\n  \u003ctd\u003e\n      \u003ca href=\"#json\"\u003eJSON\u003c/a\u003e \n    | \u003ca href=\"#xml\"\u003eXML\u003c/a\u003e\n    | \u003ca href=\"#javascript-functions\"\u003eJavaScript Functions\u003c/a\u003e\n    | \u003ca href=\"#reading-files\"\u003eReading Files\u003c/a\u003e\n    | \u003ca href=\"#type-conversion\"\u003eType / String Conversion\u003c/a\u003e\n    | \u003ca href=\"#floats-and-integers\"\u003eFloats and Integers\u003c/a\u003e\n    | \u003ca href=\"#embedded-expressions\"\u003eEmbedded Expressions\u003c/a\u003e\n    | \u003ca href=\"#jsonpath-filters\"\u003eJsonPath\u003c/a\u003e\n    | \u003ca href=\"#xpath-functions\"\u003eXPath\u003c/a\u003e\n    | \u003ca href=\"#karate-expressions\"\u003eKarate Expressions\u003c/a\u003e\n  \u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n  \u003cth\u003eVariables\u003c/th\u003e\n  \u003ctd\u003e\n      \u003ca href=\"#def\"\u003e\u003ccode\u003edef\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#text\"\u003e\u003ccode\u003etext\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#table\"\u003e\u003ccode\u003etable\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#yaml\"\u003e\u003ccode\u003eyaml\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#csv\"\u003e\u003ccode\u003ecsv\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#type-string\"\u003e\u003ccode\u003estring\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#type-json\"\u003e\u003ccode\u003ejson\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#type-xml\"\u003e\u003ccode\u003exml\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#type-xmlstring\"\u003e\u003ccode\u003exmlstring\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#type-bytes\"\u003e\u003ccode\u003ebytes\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#type-copy\"\u003e\u003ccode\u003ecopy\u003c/code\u003e\u003c/a\u003e\n  \u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n  \u003cth\u003eActions\u003c/th\u003e\n  \u003ctd\u003e\n      \u003ca href=\"#assert\"\u003e\u003ccode\u003eassert\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#print\"\u003e\u003ccode\u003eprint\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#replace\"\u003e\u003ccode\u003ereplace\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#get\"\u003e\u003ccode\u003eget\u003c/code\u003e\u003c/a\u003e \n    | \u003ca href=\"#set\"\u003e\u003ccode\u003eset\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#remove\"\u003e\u003ccode\u003eremove\u003c/code\u003e\u003c/a\u003e    \n    | \u003ca href=\"#configure\"\u003e\u003ccode\u003econfigure\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#call\"\u003e\u003ccode\u003ecall\u003c/code\u003e\u003c/a\u003e \n    | \u003ca href=\"#callonce\"\u003e\u003ccode\u003ecallonce\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#eval\"\u003e\u003ccode\u003eeval\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#listen\"\u003e\u003ccode\u003elisten\u003c/code\u003e\u003c/a\u003e \n    | \u003ca href=\"#doc\"\u003e\u003ccode\u003edoc\u003c/code\u003e\u003c/a\u003e    \n    | \u003ca href=\"#reading-files\"\u003e\u003ccode\u003eread()\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#compare-image\"\u003e\u003ccode\u003ecompareImage\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#the-karate-object\"\u003e\u003ccode\u003ekarate\u003c/code\u003e JS API\u003c/a\u003e  \n  \u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n  \u003cth\u003eHTTP\u003c/th\u003e\n  \u003ctd\u003e\n      \u003ca href=\"#url\"\u003e\u003ccode\u003eurl\u003c/code\u003e\u003c/a\u003e \n    | \u003ca href=\"#path\"\u003e\u003ccode\u003epath\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#request\"\u003e\u003ccode\u003erequest\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#method\"\u003e\u003ccode\u003emethod\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#status\"\u003e\u003ccode\u003estatus\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#soap-action\"\u003e\u003ccode\u003esoap action\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#retry-until\"\u003e\u003ccode\u003eretry until\u003c/code\u003e\u003c/a\u003e\n  \u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n  \u003cth\u003eRequest\u003c/th\u003e\n  \u003ctd\u003e\n      \u003ca href=\"#param\"\u003e\u003ccode\u003eparam\u003c/code\u003e\u003c/a\u003e \n    | \u003ca href=\"#header\"\u003e\u003ccode\u003eheader\u003c/code\u003e\u003c/a\u003e    \n    | \u003ca href=\"#cookie\"\u003e\u003ccode\u003ecookie\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#form-field\"\u003e\u003ccode\u003eform field\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#multipart-file\"\u003e\u003ccode\u003emultipart file\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#multipart-field\"\u003e\u003ccode\u003emultipart field\u003c/code\u003e\u003c/a\u003e       \n    | \u003ca href=\"#multipart-entity\"\u003e\u003ccode\u003emultipart entity\u003c/code\u003e\u003c/a\u003e    \n    | \u003ca href=\"#params\"\u003e\u003ccode\u003eparams\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#headers\"\u003e\u003ccode\u003eheaders\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#cookies\"\u003e\u003ccode\u003ecookies\u003c/code\u003e\u003c/a\u003e        \n    | \u003ca href=\"#form-fields\"\u003e\u003ccode\u003eform fields\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#multipart-files\"\u003e\u003ccode\u003emultipart files\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#multipart-fields\"\u003e\u003ccode\u003emultipart fields\u003c/code\u003e\u003c/a\u003e\n  \u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n  \u003cth\u003eResponse\u003c/th\u003e\n  \u003ctd\u003e\n      \u003ca href=\"#response\"\u003e\u003ccode\u003eresponse\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#responsebytes\"\u003e\u003ccode\u003eresponseBytes\u003c/code\u003e\u003c/a\u003e \n    | \u003ca href=\"#responsestatus\"\u003e\u003ccode\u003eresponseStatus\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#responseheaders\"\u003e\u003ccode\u003eresponseHeaders\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#responsecookies\"\u003e\u003ccode\u003eresponseCookies\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#responsetime\"\u003e\u003ccode\u003eresponseTime\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#responsetype\"\u003e\u003ccode\u003eresponseType\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#requesttimestamp\"\u003e\u003ccode\u003erequestTimeStamp\u003c/code\u003e\u003c/a\u003e\n  \u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n  \u003cth\u003eAssert\u003c/th\u003e\n  \u003ctd\u003e\n      \u003ca href=\"#match\"\u003e\u003ccode\u003ematch ==\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#match--not-equals\"\u003e\u003ccode\u003ematch !=\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#match-contains\"\u003e\u003ccode\u003ematch contains\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#match-contains-only\"\u003e\u003ccode\u003ematch contains only\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#match-contains-any\"\u003e\u003ccode\u003ematch contains any\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#match-contains-deep\"\u003e\u003ccode\u003ematch contains deep\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#match-contains-only-deep\"\u003e\u003ccode\u003ematch contains only deep\u003c/code\u003e\u003c/a\u003e       \n    | \u003ca href=\"#not-contains\"\u003e\u003ccode\u003ematch !contains\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#match-each\"\u003e\u003ccode\u003ematch each\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#match-each-contains-deep\"\u003e\u003ccode\u003ematch each contains deep\u003c/code\u003e\u003c/a\u003e\n    | \u003ca href=\"#match-header\"\u003e\u003ccode\u003ematch header\u003c/code\u003e\u003c/a\u003e    \n    | \u003ca href=\"#fuzzy-matching\"\u003eFuzzy Matching\u003c/a\u003e\n    | \u003ca href=\"#schema-validation\"\u003eSchema Validation\u003c/a\u003e\n    | \u003ca href=\"#contains-short-cuts\"\u003e\u003ccode\u003econtains\u003c/code\u003e short-cuts\u003c/a\u003e\n  \u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n  \u003cth\u003eRe-Use\u003c/th\u003e\n  \u003ctd\u003e\n      \u003ca href=\"#calling-other-feature-files\"\u003eCalling Other \u003ccode\u003e*.feature\u003c/code\u003e Files\u003c/a\u003e\n    | \u003ca href=\"#data-driven-features\"\u003eData Driven Features\u003c/a\u003e       \n    | \u003ca href=\"#calling-javascript-functions\"\u003eCalling JavaScript Functions\u003c/a\u003e\n    | \u003ca href=\"#calling-java\"\u003eCalling Java Code\u003c/a\u003e\n    | \u003ca href=\"#commonly-needed-utilities\"\u003eCommonly Needed Utilities\u003c/a\u003e\n    | \u003ca href=\"#data-driven-tests\"\u003eData Driven Scenarios\u003c/a\u003e    \n  \u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n  \u003cth\u003eAdvanced\u003c/th\u003e\n  \u003ctd\u003e\n      \u003ca href=\"#polling\"\u003ePolling\u003c/a\u003e\n    | \u003ca href=\"#conditional-logic\"\u003eConditional Logic\u003c/a\u003e\n    | \u003ca href=\"#hooks\"\u003eBefore / After Hooks\u003c/a\u003e\n    | \u003ca href=\"#json-transforms\"\u003eJSON Transforms\u003c/a\u003e\n    | \u003ca href=\"#loops\"\u003eLoops\u003c/a\u003e\n    | \u003ca href=\"#http-basic-authentication-example\"\u003eHTTP Basic Auth\u003c/a\u003e \n    | \u003ca href=\"#http-header-manipulation\"\u003eHeader Manipulation\u003c/a\u003e \n    | \u003ca href=\"#text\"\u003eGraphQL\u003c/a\u003e\n    | \u003ca href=\"#async\"\u003eWebsockets / Async\u003c/a\u003e\n    | \u003ca href=\"#call-vs-read\"\u003e\u003ccode\u003ecall\u003c/code\u003e vs \u003ccode\u003eread()\u003c/code\u003e\u003c/a\u003e\n  \u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n  \u003cth\u003eMore\u003c/th\u003e\n  \u003ctd\u003e\n      \u003ca href=\"karate-netty\"\u003eTest Doubles\u003c/a\u003e\n    | \u003ca href=\"karate-gatling\"\u003ePerformance Testing\u003c/a\u003e\n    | \u003ca href=\"karate-core\"\u003eUI Testing\u003c/a\u003e\n    | \u003ca href=\"karate-robot\"\u003eDesktop Automation\u003c/a\u003e\n    | \u003ca href=\"https://github.com/karatelabs/karate/wiki/IDE-Support#vs-code-karate-plugin\"\u003eVS Code / Debug\u003c/a\u003e\n    | \u003ca href=\"#comparison-with-rest-assured\"\u003eKarate vs REST-assured\u003c/a\u003e\n    | \u003ca href=\"#cucumber-vs-karate\"\u003eKarate vs Cucumber\u003c/a\u003e\n    | \u003ca href=\"karate-demo\"\u003eExamples and Demos\u003c/a\u003e\n  \u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\n# Features\n* Java knowledge is not required and even non-programmers can write tests\n* Scripts are plain-text, require no compilation step or IDE, and teams can collaborate using Git / standard SCM\n* Based on the popular Cucumber / Gherkin standard - with [IDE support](https://github.com/karatelabs/karate/wiki/IDE-Support) and syntax-coloring options\n* Elegant [DSL](https://en.wikipedia.org/wiki/Domain-specific_language) syntax 'natively' supports JSON and XML - including [JsonPath](#set) and [XPath](#xpath-functions) expressions\n* Eliminate the need for 'Java Beans' or 'helper code' to represent payloads and HTTP end-points, and [dramatically reduce the lines of code](https://twitter.com/KarateDSL/status/873035687817117696) needed for a test\n* Ideal for testing the highly dynamic responses from [GraphQL](http://graphql.org) API-s because of Karate's built-in [text-manipulation](#text) and [JsonPath](https://github.com/json-path/JsonPath#path-examples) capabilities\n* Tests are super-readable - as scenario data can be expressed in-line, in human-friendly [JSON](#json), [XML](#xml), Cucumber [Scenario](#the-cucumber-way) Outline [tables](#table), or a [payload builder](#set-multiple) approach [unique to Karate](https://gist.github.com/ptrthomas/d6beb17e92a43220d254af942e3ed3d9)\n* Express expected results as readable, well-formed JSON or XML, and [assert in a single step](#match) that the entire response payload (no matter how complex or deeply nested) - is as expected\n* Comprehensive [assertion capabilities](#fuzzy-matching) - and failures clearly report which data element (and path) is not as expected, for easy troubleshooting of even large payloads\n* [Fully featured debugger](https://github.com/karatelabs/karate/wiki/IDE-Support#vs-code-karate-plugin) that can step *backwards* and even [re-play a step while editing it](https://twitter.com/KarateDSL/status/1167533484560142336) - a *huge* time-saver\n* Simpler and more [powerful alternative](https://twitter.com/KarateDSL/status/878984854012022784) to JSON-schema for [validating payload structure](#schema-validation) and format - that even supports [cross-field](#referring-to-the-json-root) / domain validation logic\n* Scripts can [call other scripts](#calling-other-feature-files) - which means that you can easily re-use and maintain authentication and 'set up' flows efficiently, across multiple tests\n* Embedded JavaScript engine that allows you to build a library of [re-usable functions](#calling-javascript-functions) that suit your specific environment or organization\n* Re-use of payload-data and user-defined functions across tests is [so easy](#reading-files) - that it becomes a natural habit for the test-developer\n* Built-in support for [switching configuration](#switching-the-environment) across different environments (e.g. dev, QA, pre-prod)\n* Support for [data-driven tests](#data-driven-tests) and being able to [tag or group](#tags) tests is built-in, no need to rely on an external framework\n* Native support for reading [YAML](#yaml) and even [CSV](#csv-files) files - and you can use them for data-driven tests\n* Standard Java / Maven project structure, and [seamless integration](#command-line) into CI / CD pipelines - and support for [JUnit 5](#junit-5)\n* Option to use as a light-weight [stand-alone executable](https://github.com/karatelabs/karate/tree/master/karate-netty#standalone-jar) - convenient for teams not comfortable with Java\n* Multi-threaded [parallel execution](#parallel-execution), which is a huge time-saver, especially for integration and end-to-end tests\n* Built-in [test-reports](#test-reports) compatible with Cucumber so that you have the option of using third-party (open-source) maven-plugins for even [better-looking reports](karate-demo#example-report)\n* Reports include HTTP request and response [logs *in-line*](#test-reports), which makes [troubleshooting](https://twitter.com/KarateDSL/status/899671441221623809) and [debugging](https://twitter.com/KarateDSL/status/935029435140489216) easier\n* Easily invoke JDK classes, Java libraries, or re-use custom Java code if needed, for [ultimate extensibility](#calling-java)\n* Simple plug-in system for [authentication](#http-basic-authentication-example) and HTTP [header management](#configure-headers) that will handle any complex, real-world scenario\n* [Cross-browser Web UI automation](karate-core) so that you can test *all* layers of your application with the same framework\n* [experimental] [Android and iOS mobile support](https://github.com/karatelabs/karate/issues/743) via [Appium](http://appium.io)\n* Visual Validation via the built-in [image comparison](#compare-image) capabilities\n* Cross platform [Desktop Automation](karate-robot) that can be [mixed into Web Automation flows](https://twitter.com/ptrthomas/status/1215534821234995200) if needed\n* Option to invoke via a [Java API](#java-api),  which means that you can easily [mix Karate into Java projects or legacy UI-automation suites](https://stackoverflow.com/q/47795762/143475)\n* [Save significant effort](https://twitter.com/ptrthomas/status/986463717465391104) by re-using Karate test-suites as [Gatling performance tests](karate-gatling) that *deeply* assert that server responses are accurate under load\n* Gatling integration can hook into [*any* custom Java code](https://github.com/karatelabs/karate/tree/master/karate-gatling#custom) - which means that you can perf-test even non-HTTP protocols such as [gRPC](https://github.com/karatelabs/karate-examples/blob/main/grpc/README.md)\n* [API mocks](karate-netty) or test-doubles that even [maintain CRUD 'state'](https://hackernoon.com/api-consumer-contract-tests-and-test-doubles-with-karate-72c30ea25c18) across multiple calls - enabling TDD for micro-services and [Consumer Driven Contracts](https://martinfowler.com/articles/consumerDrivenContracts.html)\n* [Async](#async) support that allows you to seamlessly integrate the handling of custom events or listening to message-queues\n* Built-in [HTML templating](https://twitter.com/KarateDSL/status/1338892932691070976) so that you can extend your test-reports into readable specifications\n* Comprehensive support for different flavors of HTTP calls:\n  * [SOAP](#soap-action) / XML requests\n  * HTTPS / [SSL](#configure) - without needing certificates, key-stores or trust-stores\n  * HTTP [proxy server](#configure) support\n  * URL-encoded [HTML-form](#form-field) data\n  * [Multi-part](#multipart-field) file-upload - including `multipart/mixed` and `multipart/related`\n  * Browser-like [cookie](#cookie) handling\n  * Full control over HTTP [headers](#header), [path](#path) and query [parameters](#param)\n  * [Re-try](#retry-until) until condition\n  * [Websocket](http://www.websocket.org) [support](#async)\n\n## Real World Examples\nA set of real-life examples can be found here: [Karate Demos](karate-demo)\n\n## Comparison with REST-assured\nFor teams familiar with or currently using [REST-assured](http://rest-assured.io), this detailed comparison of [Karate vs REST-assured](http://tinyurl.com/karatera) - can help you evaluate Karate. Do note that if you prefer a pure Java API - Karate has [that covered](#java-api), and with far more capabilities.\n\n## References\n* [API Testing with Karate](https://youtu.be/WT4gg7Jutzg) - video + demos by [Peter Thomas](https://twitter.com/ptrthomas) (creator / lead dev of Karate)\n* [Introducing Karate: The ULTIMATE Test Automation Tool](https://youtu.be/_kMxvd37auc?si=WOEkvEUH6eWeHZUC) - video by [James Willett](https://www.linkedin.com/in/willettjames/)\n* [Karate in the ThoughtWorks Tech Radar](https://twitter.com/KarateDSL/status/1120985060843249664) and featured [a second time](https://twitter.com/KarateDSL/status/1262719979104817152)\n* [マイクロサービスにおけるテスト自動化 with Karate](https://speakerdeck.com/takanorig/microservices-testing-automation-with-karate) - (*Microservices Test Automation with Karate*) presentation by [Takanori Suzuki](https://twitter.com/takanorig)\n* [Writing API Tests with Karate](https://www.softwaretester.blog/writing-api-tests-with-karate) - book by [Benjamin Bischoff](https://www.softwaretester.blog/about), Packt Publishing, 2023\n* [Karate Webinar](https://www.youtube.com/watch?v=cXDIYpT6zck\u0026t=4333s) - Simplificando automação de API com Karate Framework by [Luana Assis](https://www.linkedin.com/in/luanapassis/) from [Base2 Tecnologia](https://www.base2.com.br/)\n\nKarate also has a dedicated \"tag\", and a very active and supportive community at [Stack Overflow](https://stackoverflow.com/questions/tagged/karate) - where you can get support and ask questions.\n\nYou can find a lot more references, tutorials and blog-posts at [karatelabs.io](https://karatelabs.io).\n\n# Getting Started\nIf you are a Java developer - Karate requires at least [Java](http://www.oracle.com/technetwork/java/javase/downloads/index.html) 17 and then either [Maven](http://maven.apache.org), [Gradle](https://gradle.org), or a Java IDE that embeds either to be installed. Note that Karate works fine on OpenJDK.\n\nIf you are new to programming or test-automation, the [official IntelliJ plugin](https://plugins.jetbrains.com/plugin/19232-karate) is recommended.\n\nIf you *don't* want to use Java, the [Karate extension for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=karatelabs.karate) is recommended, and JavaScript, .NET, Ruby and Python programmers will feel right at home.\n\nBoth the official Visual Studio Code and IntelliJ plugins support step-through debugging of Karate tests.\n\n## Maven\nAll you need is available in the [`karate-core`](https://search.maven.org/artifact/com.intuit.karate/karate-core) artifact. You can run tests with this [directly](#parallel-execution), but teams can choose the JUnit variant (shown below) that pulls in JUnit 5 and [slightly improves the in-IDE experience](https://stackoverflow.com/a/65578167/143475).\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.karatelabs\u003c/groupId\u003e\n    \u003cartifactId\u003ekarate-junit5\u003c/artifactId\u003e\n    \u003cversion\u003e1.5.1\u003c/version\u003e\n    \u003cscope\u003etest\u003c/scope\u003e\n\u003c/dependency\u003e\n```\n\n## Gradle\nAlternatively for [Gradle](https://gradle.org):\n\n```yml\n    testImplementation 'io.karatelabs:karate-junit5:1.5.1'\n```\n\nAlso refer to the wiki for using [Karate with Gradle](https://github.com/karatelabs/karate/wiki/Gradle).\n\n### Karate Core \"Fat JAR\"\nIf you mix Karate into a Maven or Gradle project with many other dependendies, you may run into problems because of dependency conflicts. For example a lot of Java projects directly (or indirectly) depend on Netty or Thymeleaf or ANTLR, etc.\n\nIf you face issues such as \"class not found\", just pull in the `karate-core` dependency, and use the `all` [classifier](https://www.baeldung.com/maven-artifact-classifiers) in your `pom.xml` (or `build.gradle`).\n\nFor example when using Maven:\n\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003eio.karatelabs\u003c/groupId\u003e\n  \u003cartifactId\u003ekarate-core\u003c/artifactId\u003e\n  \u003cversion\u003e${karate.version}\u003c/version\u003e\n  \u003cclassifier\u003eall\u003c/classifier\u003e\n  \u003cscope\u003etest\u003c/scope\u003e\n\u003c/dependency\u003e\n```\n\nNote that for very complicated projects you can consider using a [Maven profile](https://maven.apache.org/guides/introduction/introduction-to-profiles.html) so that testing-related dependencies don't collide with your development-time dependencies. Of course it is an option to have Karate tests in a separate stand-alone maven project and folder, while still being in the same Git repository.\n\n### Quickstart\nIt may be easier for you to use the Karate Maven archetype to create a skeleton project with one command. You can then skip the next few sections, as the `pom.xml`, recommended directory structure, sample test and [JUnit 5](#junit-5) runners - will be created for you.\n\n\u003e If you are behind a corporate proxy, or especially if your local Maven installation has been configured to point to a repository within your local network, the command below may not work. One workaround is to temporarily disable or rename your Maven [`settings.xml`](https://maven.apache.org/settings.html) file, and try again.\n\nYou can replace the values of `com.mycompany` and `myproject` as per your needs.\n\n```\nmvn archetype:generate \\\n-DarchetypeGroupId=io.karatelabs \\\n-DarchetypeArtifactId=karate-archetype \\\n-DarchetypeVersion=1.5.1 \\\n-DgroupId=com.mycompany \\\n-DartifactId=myproject\n```\n\nThis will create a folder called `myproject` (or whatever you set the name to).\n\n## IDE Support\nRefer to the wiki - [IDE Support](https://github.com/karatelabs/karate/wiki/IDE-Support).\n\n## Folder Structure\nA Karate test script has the file extension `.feature` which is the standard followed by Cucumber.  You are free to organize your files using regular Java package conventions.\n\nThe Maven tradition is to have non-Java source files in a separate `src/test/resources` folder structure - but we recommend that you keep them side-by-side with your `*.java` files. When you have a large and complex project, you will end up with a few data files (e.g. `*.js`, `*.json`, `*.txt`) as well and it is much more convenient to see the `*.java` and `*.feature` files and all related artifacts in the same place.\n\nThis can be easily achieved with the following tweak to your maven `\u003cbuild\u003e` section.\n```xml\n\u003cbuild\u003e\n    \u003ctestResources\u003e\n        \u003ctestResource\u003e\n            \u003cdirectory\u003esrc/test/java\u003c/directory\u003e\n            \u003cexcludes\u003e\n                \u003cexclude\u003e**/*.java\u003c/exclude\u003e\n            \u003c/excludes\u003e\n        \u003c/testResource\u003e\n    \u003c/testResources\u003e        \n    \u003cplugins\u003e\n    ...\n    \u003c/plugins\u003e\n\u003c/build\u003e\n```\n\nThis is very common in the world of Maven users and keep in mind that these are tests and not production code.  \n\nAlternatively, if using Gradle then add the following `sourceSets` definition\n         \n```yml\nsourceSets {\n    test {\n        resources {\n            srcDir file('src/test/java')\n            exclude '**/*.java'\n        }\n    }\n}\n```\n\nWith the above in place, you don't have to keep switching between your `src/test/java` and `src/test/resources` folders, you can have all your test-code and artifacts under `src/test/java` and everything will work as expected.\n\nOnce you get used to this, you may even start wondering why projects need a `src/test/resources` folder at all !\n\n## Naming Conventions\nSince these are tests and not production Java code, you don't need to be bound by the `com.mycompany.foo.bar` convention and the un-necessary explosion of sub-folders that ensues. We suggest that you have a folder hierarchy only one or two levels deep - where the folder names clearly identify which 'resource', 'entity' or API is the web-service under test.\n\nFor example:\n\n```\nsrc/test/java\n    |\n    +-- karate-config.js\n    +-- logback-test.xml\n    +-- some-reusable.feature\n    +-- some-classpath-function.js\n    +-- some-classpath-payload.json\n    |\n    \\-- animals\n        |\n        +-- AnimalsTest.java\n        |\n        +-- cats\n        |   |\n        |   +-- cats-post.feature\n        |   +-- cats-get.feature\n        |   +-- cat.json\n        |   \\-- CatsRunner.java\n        |\n        \\-- dogs\n            |\n            +-- dog-crud.feature\n            +-- dog.json\n            +-- some-helper-function.js\n            \\-- DogsRunner.java\n```\n\nAssuming you use JUnit, there are some good reasons for the recommended (best practice) naming convention and choice of file-placement shown above:\n* Not using the `*Test.java` convention for the JUnit classes (e.g. `CatsRunner.java`) in the `cats` and `dogs` folder ensures that these tests will **not** be picked up when invoking `mvn test` (for the whole project) from the [command line](#command-line). But you can still invoke these tests from the IDE, which is convenient when in development mode.\n* `AnimalsTest.java` (the only file that follows the `*Test.java` naming convention) acts as the 'test suite' for the entire project. By default, Karate will load all `*.feature` files from sub-directories as well. But since `some-reusable.feature` is _above_ `AnimalsTest.java` in the folder hierarchy, it will **not** be picked-up. Which is exactly what we want, because `some-reusable.feature` is designed to be [called](#calling-other-feature-files) only from one of the other test scripts (perhaps with some parameters being passed). You can also use [tags](#tags) to skip files.\n* `some-classpath-function.js` and `some-classpath-payload.json` are in the 'root' of the Java ['classpath'](#classpath) which means they can be easily [read](#reading-files) (and re-used) from any test-script by using the `classpath:` prefix, for e.g: `read('classpath:some-classpath-function.js')`. Relative paths will also work.\n\nFor details on what actually goes into a script or `*.feature` file, refer to the [syntax guide](#syntax-guide).\n\n## JUnit 5\nKarate supports [JUnit 5](https://junit.org/junit5) and the advantage is that you can have multiple methods in a test-class. Only 1 `import` is needed, and instead of a class-level annotation, you use a nice [DRY](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself) and [fluent-api](https://en.wikipedia.org/wiki/Fluent_interface) to express which tests and tags you want to use.\n\nNote that the Java class does not need to be `public` and even the test methods do not need to be `public` - so tests end up being very concise.\n\n\u003e Karate will traverse sub-directories and look for `*.feature` files. For example if you have the JUnit class in the `com.mycompany` package, `*.feature` files in `com.mycompany.foo` and `com.mycompany.bar` will also be run. This is one reason why you may want to prefer a 'flat' directory structure as [explained above](#naming-conventions).\n\nHere is an [example](karate-junit5/src/test/java/karate/SampleTest.java):\n\n```java\npackage karate;\n\nimport com.intuit.karate.junit5.Karate;\n\nclass SampleTest {\n\n    @Karate.Test\n    Karate testSample() {\n        return Karate.run(\"sample\").relativeTo(getClass());\n    }\n    \n    @Karate.Test\n    Karate testTags() {\n        return Karate.run(\"tags\").tags(\"@second\").relativeTo(getClass());\n    }\n\n    @Karate.Test\n    Karate testSystemProperty() {\n        return Karate.run(\"classpath:karate/tags.feature\")\n                .tags(\"@second\")\n                .karateEnv(\"e2e\")\n                .systemProperty(\"foo\", \"bar\");\n    }\n\n}\n```\n\nNote that more \"builder\" methods are available from the [`Runner.Builder`](#parallel-execution) class such as `reportDir()` etc.\n\nYou should be able to right-click and run a single method using your IDE - which should be sufficient when you are in development mode. But to be able to run JUnit 5 tests from the command-line, you need to ensure that the latest version of the [maven-surefire-plugin](https://maven.apache.org/surefire/maven-surefire-plugin/examples/junit-platform.html) is present in your project `pom.xml` (within the `\u003cbuild\u003e/\u003cplugins\u003e` section):\n\n```xml\n\u003cplugin\u003e\n    \u003cgroupId\u003eorg.apache.maven.plugins\u003c/groupId\u003e\n    \u003cartifactId\u003emaven-surefire-plugin\u003c/artifactId\u003e\n    \u003cversion\u003e2.22.2\u003c/version\u003e\n\u003c/plugin\u003e\n```\n\nTo run a single test method, for example the `testTags()` in the example above, you can do this:\n\n```\nmvn test -Dtest=SampleTest#testTags\n```\n\nAlso look at how to run tests via the [command-line](#command-line) and the [parallel runner](#parallel-execution).\n\n### JUnit HTML report\nWhen you use the JUnit runner - after the execution of each feature, an HTML report is output to the `target/karate-reports` folder and the full path will be printed to the console (see [video](https://twitter.com/KarateDSL/status/935029435140489216)).\n\n```\nhtml report: (paste into browser to view)\n-----------------------------------------\nfile:///projects/myproject/target/karate-reports/mypackage.myfeature.html\n```\n\nYou can easily select (double-click), copy and paste this `file:` URL into your browser address bar. This report is useful for troubleshooting and debugging a test because all requests and responses are shown in-line with the steps, along with error messages and the output of [`print`](#print) statements. Just re-fresh your browser window if you re-run the test.\n\n### Dry Run\nThis will give you the usual HTML report showing what features will be run, including all steps shown (including comments) so that it can be reviewed. Of course the actual time-durations, and logs will be missing, and *everything* will pass.\n\nThe “dry run” report is useful to review the tag \"coverage\" of what will be run. For example you can get a nice feature “coverage” report, provided you have a rich set of [tags](#tags). e.g. `@smoke @module=one @module=two` etc.\n\nThe [`Runner.Builder`](#parallel-execution) API has a `dryRun()` method to switch this on. Note that this mode can be also triggered via the command-line by adding `-D` or `--dryrun` to the [`karate.options`](#karateoptions).\n\n## Command Line\n\nIf you are using Karate via the [VS Code Plugin](https://marketplace.visualstudio.com/items?itemName=karatelabs.karate) or the stand-alone JAR, refer to the [CLI usage guide](https://github.com/karatelabs/karate/wiki/Get-Started:-Other-Runtime-Options). \n\n### Command Line - Maven\nNormally in dev mode, you will use your IDE to run a `*.feature` file directly or via the companion 'runner' JUnit Java class. When you have a 'runner' class in place, it would be possible to run it from the command-line as well.\n\nNote that the `mvn test` command only runs test classes that follow the `*Test.java` [naming convention](#naming-conventions) by default. But you can choose a single test to run like this:\n\n```\nmvn test -Dtest=CatsRunner\n```\n### `karate.options`\nWhen your Java test \"runner\" is linked to multiple feature files, which will be the case when you use the recommended [parallel runner](#parallel-execution), you can narrow down your scope to a single feature, scenario or directory via the command-line, useful in dev-mode. Note how even [tags](#tags) to exclude (or include) can be specified:\n\n\u003e Note that any `Feature` or `Scenario` with the [special `@ignore` tag](#special-tags) will be skipped by default.\n\n```\nmvn test \"-Dkarate.options=--tags ~@skipme classpath:demo/cats/cats.feature\" -Dtest=DemoTestParallel\n```\n\nMultiple feature files (or paths) can be specified, de-limited by the space character. They should be at the end of the `karate.options`. To run only a single scenario, append the line number on which the scenario is defined, de-limited by `:`.\n```\nmvn test \"-Dkarate.options=PathToFeatureFiles/order.feature:12\" -Dtest=DemoTestParallel\n```\n\nSince paths are expected at the end of the command-line options - if you want to only over-ride tags, use the `=` sign to make argument values clear. For example:\n\n```\nmvn test -Dkarate.options='-t=@dev -t=@src' -Dtest=ExamplesTest\n```\n\n### Command Line - Gradle\nFor Gradle, you must extend the test task to allow the `karate.options` to be passed to the runtime (otherwise they get consumed by Gradle itself). To do that, add the following:\n\n```yml\ntest {\n    // pull karate options into the runtime\n    systemProperty \"karate.options\", System.properties.getProperty(\"karate.options\")\n    // pull karate env into the runtime\n    systemProperty \"karate.env\", System.properties.getProperty(\"karate.env\")\n    // ensure tests are always run\n    outputs.upToDateWhen { false }\n}\n```\n\nAnd then the above command in Gradle would look like:\n\n```\n./gradlew test --tests *CatsRunner\n```\nor\n```\n./gradlew test -Dtest.single=CatsRunner\n```\n\n### Test Suites\n\u003e The recommended way to define and run test-suites and reporting in Karate is to use the [parallel runner](#parallel-execution), described in the next section. The approach in this section is more suited for troubleshooting in dev-mode, using your IDE.\n\nOne way to define 'test-suites' in Karate is to have a JUnit class at a level 'above' (in terms of folder hierarchy) all the `*.feature` files in your project. So if you take the previous [folder structure example](#naming-conventions), you can do this on the command-line:\n\n```\nmvn test \"-Dkarate.options=--tags ~@skipme\" -Dtest=AnimalsTest\n```\n\nHere, `AnimalsTest` is the name of the Java class we designated to run the multiple `*.feature` files that make up your test-suite. There is a neat way to [tag your tests](#tags) and the above example demonstrates how to run all tests _except_ the ones tagged `@skipme`.\n\nNote that the special, built-in tag `@ignore` will *always* be skipped by default, and you don't need to specify `~@ignore` anywhere.\n\nYou can 'lock down' the fact that you only want to execute the single JUnit class that functions as a test-suite - by using the following [maven-surefire-plugin configuration](http://maven.apache.org/surefire/maven-surefire-plugin/examples/inclusion-exclusion.html):\n\n```xml\n\u003cplugin\u003e\n    \u003cgroupId\u003eorg.apache.maven.plugins\u003c/groupId\u003e\n    \u003cartifactId\u003emaven-surefire-plugin\u003c/artifactId\u003e\n    \u003cversion\u003e${maven.surefire.version}\u003c/version\u003e\n    \u003cconfiguration\u003e\n        \u003cincludes\u003e\n            \u003cinclude\u003eanimals/AnimalsTest.java\u003c/include\u003e\n        \u003c/includes\u003e\n        \u003csystemProperties\u003e\n            \u003ckarate.options\u003e--tags @smoke\u003c/karate.options\u003e\n        \u003c/systemProperties\u003e            \n    \u003c/configuration\u003e\n\u003c/plugin\u003e \n```\n\nNote how the [`karate.options`](#karateoptions) can be specified using the `\u003csystemProperties\u003e` configuration.\n\nFor Gradle, you simply specify the test which is to be `include`-d:\n\n```yml\ntest {\n    include 'animals/AnimalsTest.java'\n    // pull karate options into the runtime\n    systemProperty \"karate.options\", System.properties.getProperty(\"karate.options\")\n    // pull karate env into the runtime\n    systemProperty \"karate.env\", System.properties.getProperty(\"karate.env\")\n    // ensure tests are always run\n    outputs.upToDateWhen { false }\n}\n```\n\nThe big drawback of the approach above is that you cannot run tests in parallel. The recommended approach for Karate reporting in a Continuous Integration set-up is described in the next section which can generate the [JUnit XML](https://wiki.jenkins-ci.org/display/JENKINS/JUnit+Plugin) format that most CI tools can consume. The [Cucumber JSON format](https://cucumber.io/docs/cucumber/reporting) can be also emitted, which gives you plenty of options for generating pretty reports using third-party maven plugins.\n\nAnd most importantly - you can run tests in parallel without having to depend on third-party hacks that introduce code-generation and config 'bloat' into your `pom.xml` or `build.gradle`.\n\n## Parallel Execution\n\n\u003e Please note that some [user analytics is tracked](karate-core/src/test/resources/analytics.md) only when you view the built-in Karate HTML report.\n\nKarate can run tests in parallel, and dramatically cut down execution time. This is a 'core' feature and does not depend on JUnit, Maven or Gradle.\n\n\u003e For those running Karate in non-Java projects via the command-line, note that you can set the number of threads via `--threads` or `-T` as explained [here](https://karatelabs.github.io/karate/karate-netty/#parallel-execution).\n\n* You can easily \"choose\" features and tags to run and compose test-suites in a very flexible manner.\n* You can use the returned `Results` object to check if any scenarios failed, and to even summarize the errors\n* [JUnit XML](https://wiki.jenkins-ci.org/display/JENKINS/JUnit+Plugin) reports can be generated in the \"`reportDir`\" path you specify, and you can easily configure your CI to look for these files after a build (for e.g. in `**/*.xml` or `**/karate-reports/*.xml`). Note that you have to call the `outputJunitXml(true)` method on the `Runner` \"builder\".\n* [Cucumber JSON reports](https://cucumber.io/docs/cucumber/reporting) can be generated, except that the extension will be `.json` instead of `.xml`. Note that you have to call the `outputCucumberJson(true)` method on the `Runner` \"builder\".\n* HTML reports can be disabled by calling [`outputHtmlReport(false)`](https://github.com/karatelabs/karate/blob/v1.2.1.RC1/karate-core/src/main/java/com/karatelabs/karate/Runner.java#L515).\n* The `Runner.path()` \"builder\" method in `karate-core` is how you refer to the package you want to execute, and all feature files within sub-directories will be picked up\n* `Runner.path()` takes multiple string parameters, so you can refer to multiple packages or even individual `*.feature` files and easily \"compose\" a test-suite\n  * e.g. `Runner.path(\"classpath:animals\", \"classpath:some/other/package.feature\")`\n* To [choose tags](#tags), call the `tags()` API, note that by default, any `*.feature` file tagged with the special (built-in) tag: `@ignore` will be skipped. You can also specify tags on the [command-line](#test-suites). The `tags()` method also takes multiple arguments, for e.g.\n  * this is an \"AND\" operation: `tags(\"@customer\", \"@smoke\")`\n  * and this is an \"OR\" operation: `tags(\"@customer,@smoke\")`\n* There is an optional `reportDir()` method if you want to customize the directory to which the [HTML, XML and JSON](#parallel-execution) files will be output, it defaults to `target/karate-reports`\n* If you want to dynamically and programmatically determine the tags and features to be included - the API also accepts `List\u003cString\u003e` as the `path()` and `tags()` methods arguments \n* `parallel()` *has* to be the last method called, and you pass the number of parallel threads needed. It returns a `Results` object that has all the information you need - such as the number of passed or failed tests.\n\n### JUnit 5 Parallel Execution\n\nThe example below assumes that [JUnit 5](https://junit.org/junit5) is available on the classpath, and uses the `@Test` annotation and the `assertEquals()` method.\n\n\u003e But if you really want, you could use the `Runner` and `Results` API directly in *any* Java class, and even a \"main\" method.\n\nUse the [`karate-template`](https://github.com/karatelabs/karate-template) project if you want to get an [example](https://github.com/karatelabs/karate-template/blob/main/src/test/java/examples/ExamplesTest.java) as part of a working, \"skeleton\" project.\n\n```java\nimport com.intuit.karate.Results;\nimport com.intuit.karate.Runner;\nimport static org.junit.jupiter.api.Assertions.*;\nimport org.junit.jupiter.api.Test;\n\nclass TestParallel {\n\n    @Test\n    void testParallel() {\n        Results results = Runner.path(\"classpath:animals\").tags(\"~@skipme\").parallel(5);\n        assertEquals(0, results.getFailCount(), results.getErrorMessages());\n    }\n\n}\n```\n\n### Parallel Stats\nFor convenience, some stats are logged to the console when execution completes, which should look something like this:\n\n```\n======================================================\nelapsed:   2.35 | threads:    5 | thread time: 4.98 \nfeatures:    54 | ignored:   25 | efficiency: 0.42\nscenarios:  145 | passed:   145 | failed: 0\n======================================================\n```\n\nThe parallel runner will always run `Feature`-s in parallel. Karate will also run `Scenario`-s in parallel by default. So if you have a `Feature` with multiple `Scenario`-s in it - they will execute in parallel, and even each `Examples` row in a `Scenario Outline` will do so ! \n\nA `karate-timeline.html` file will also be saved to the report output directory mentioned above (`target/karate-reports` by default) - which is useful for visually verifying or troubleshooting the effectiveness of the test-run ([see video](https://twitter.com/KarateDSL/status/1049321708241317888)).\n\n### `@parallel=false`\nIn rare cases you may want to suppress the default of `Scenario`-s executing in parallel and the special [`tag`](#tags) `@parallel=false` can be used. If you place it above the [`Feature`](#script-structure) keyword, it will apply to all `Scenario`-s. And if you just want one or two `Scenario`-s to NOT run in parallel, you can place this tag above only *those* `Scenario`-s. See [example](karate-demo/src/test/java/demo/encoding/encoding.feature).\n\nNote that forcing `Scenario`-s to run in a particular sequence [is an anti-pattern](https://stackoverflow.com/a/46080568/143475), and should be avoided as far as possible.\n\n## Test Reports\nAs mentioned above, most CI tools would be able to process the JUnit XML output of the [parallel runner](#parallel-execution) and determine the status of the build as well as generate reports.\n\nThe [Karate Demo](karate-demo) has a working example of the recommended parallel-runner set up. It also [details how](karate-demo#example-report) a third-party library can be easily used to generate some very nice-looking reports, from the JSON output of the parallel runner.\n\nFor example, here below is an actual report generated by the [cucumber-reporting](https://github.com/damianszczepanik/cucumber-reporting) open-source library.  \n\n\u003cimg src=\"karate-demo/src/test/resources/karate-maven-report.jpg\" height=\"600px\"/\u003e\n\nAnother example for a popular Maven reporting plugin that is compatible with Karate JSON is [Cluecumber](https://github.com/trivago/cluecumber-report-plugin).\n\nThe demo also features [code-coverage using Jacoco](karate-demo#code-coverage-using-jacoco), and some tips for even non-Java back-ends. Some third-party report-server solutions integrate with Karate such as [ReportPortal.io](https://github.com/reportportal/agent-java-karate).\n\n## Logging\n\u003e This is optional, and Karate will work without the logging config in place, but the default console logging may be too verbose for your needs.\n\nKarate uses [LOGBack](http://logback.qos.ch) which looks for a file called `logback-test.xml` on the '[classpath](#classpath)'.\n\n\u003e In rare cases, e.g. if you are using Karate to create a Java application, [LOGBack will look for `logback.xml`](http://logback.qos.ch/manual/configuration.html)\n\nHere is a sample `logback-test.xml` for you to get started.\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n\u003cconfiguration\u003e\n \n    \u003cappender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\"\u003e\n        \u003cencoder\u003e\n            \u003cpattern\u003e%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n\u003c/pattern\u003e\n        \u003c/encoder\u003e\n    \u003c/appender\u003e\n  \n    \u003cappender name=\"FILE\" class=\"ch.qos.logback.core.FileAppender\"\u003e\n        \u003cfile\u003etarget/karate.log\u003c/file\u003e\n        \u003cencoder\u003e\n            \u003cpattern\u003e%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n\u003c/pattern\u003e\n        \u003c/encoder\u003e\n    \u003c/appender\u003e    \n   \n    \u003clogger name=\"com.intuit.karate\" level=\"DEBUG\"/\u003e\n   \n    \u003croot level=\"info\"\u003e\n        \u003cappender-ref ref=\"STDOUT\" /\u003e\n        \u003cappender-ref ref=\"FILE\" /\u003e\n    \u003c/root\u003e\n  \n\u003c/configuration\u003e\n```\nYou can change the `com.intuit.karate` logger level to `INFO` to reduce the amount of logging. When the level is `DEBUG` the entire request and response payloads are logged. If you use the above config, logs will be captured in `target/karate.log`.\n\nIf you want to keep the level as `DEBUG` ([for HTML reports](#test-reports)) but suppress logging to the console, you can comment out the `STDOUT` \"root\" `appender-ref`:\n\n```xml\n  \u003croot level=\"warn\"\u003e\n      \u003c!-- \u003cappender-ref ref=\"STDOUT\" /\u003e --\u003e\n      \u003cappender-ref ref=\"FILE\" /\u003e\n  \u003c/root\u003e\n```\n\nOr another option is to use a [`ThresholdFilter`](http://logback.qos.ch/manual/filters.html#thresholdFilter), so you still see critical logs on the console:\n\n```xml\n  \u003cappender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\"\u003e\n      \u003cfilter class=\"ch.qos.logback.classic.filter.ThresholdFilter\"\u003e\n          \u003clevel\u003eWARN\u003c/level\u003e\n      \u003c/filter\u003e\n      \u003cencoder\u003e\n          \u003cpattern\u003e%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n\u003c/pattern\u003e\n      \u003c/encoder\u003e\n  \u003c/appender\u003e\n```\n\nIf you want to exclude the logs from your CI/CD pipeline but keep them in the execution of your users in their locals you can configure your logback using [Janino](http://logback.qos.ch/manual/configuration.html#conditional). In such cases it might be desirable to have your tests using `karate.logger.debug('your additional info')` instead of the `print` keyword so you can keep logs in your pipeline in INFO.\n\nFor suppressing sensitive information such as secrets and passwords from the log and reports, see [Log Masking](#log-masking) and [Report Verbosity](#report-verbosity).\n\n# Configuration\n\u003e You can skip this section and jump straight to the [Syntax Guide](#syntax-guide) if you are in a hurry to get started with Karate. Things will work even if the `karate-config.js` file is not present.\n\n## Classpath\nThe 'classpath' is a Java concept and is where some configuration files such as the one for [logging](#logging) are expected to be by default. If you use the Maven `\u003ctest-resources\u003e` tweak [described earlier](#folder-structure) (recommended), the 'root' of the classpath will be in the `src/test/java` folder, or else would be `src/test/resources`.\n\n## `karate-config.js`\nThe only 'rule' is that on start-up Karate expects a file called `karate-config.js` to exist on the 'classpath' and contain a [JavaScript function](#javascript-functions). The function is expected to return a JSON object and all keys and values in that JSON object will be made available as script variables.\n\nAnd that's all there is to Karate configuration ! You can easily get the value of the [current 'environment' or 'profile'](#switching-the-environment), and then set up 'global' variables using some simple JavaScript. Here is an example:\n\n```javascript    \nfunction fn() {   \n  var env = karate.env; // get java system property 'karate.env'\n  karate.log('karate.env system property was:', env);\n  if (!env) {\n    env = 'dev'; // a custom 'intelligent' default\n  }\n  var config = { // base config JSON\n    appId: 'my.app.id',\n    appSecret: 'my.secret',\n    someUrlBase: 'https://some-host.com/v1/auth/',\n    anotherUrlBase: 'https://another-host.com/v1/'\n  };\n  if (env == 'stage') {\n    // over-ride only those that need to be\n    config.someUrlBase = 'https://stage-host/v1/auth';\n  } else if (env == 'e2e') {\n    config.someUrlBase = 'https://e2e-host/v1/auth';\n  }\n  // don't waste time waiting for a connection or if servers don't respond within 5 seconds\n  karate.configure('connectTimeout', 5000);\n  karate.configure('readTimeout', 5000);\n  return config;\n}\n```\n\n\u003e Here above, you see the [`karate.log()`](#karate-log), [`karate.env`](#karate-env) and [`karate.configure()`](#karate-configure) \"helpers\" being used. Note that the `karate-config.js` is re-processed for *every* `Scenario` and in rare cases, you may want to initialize (e.g. auth tokens) only once for all of your tests. This can be achieved using [`karate.callSingle()`](#karatecallsingle).\n\nA common requirement is to pass dynamic parameter values via the command line, and you can use the [`karate.properties['some.name']`](#karate-properties) syntax for getting a system property passed via JVM options in the form `-Dsome.name=foo`. Refer to the section on [dynamic port numbers](#dynamic-port-numbers) for an example.\n\n\u003e You can even retrieve operating-system environment variables via [Java interop](#calling-java) as follows: `var systemPath = java.lang.System.getenv('PATH');`\n\nThis decision to use JavaScript for config is influenced by years of experience with the set-up of complicated test-suites and fighting with [Maven profiles](http://maven.apache.org/guides/introduction/introduction-to-profiles.html), [Maven resource-filtering](https://maven.apache.org/plugins/maven-resources-plugin/examples/filter.html) and the XML-soup that somehow gets summoned by the [Maven AntRun plugin](http://maven.apache.org/plugins/maven-antrun-plugin/usage.html).\n\nKarate's approach frees you from Maven, is far more expressive, allows you to eyeball all environments in one place, and is still a plain-text file.  If you want, you could even create [nested chunks of JSON that 'name-space' your config variables](https://stackoverflow.com/a/49693808/143475).\n\n\u003e One way to appreciate Karate's approach is to think over what it takes to add a new environment-dependent variable (e.g. a password) into a test. In typical frameworks it could mean changing multiple properties files, maven profiles and placeholders, and maybe even threading the value via a dependency-injection framework - before you can even access the value within your test.\n\nThis approach is indeed slightly more complicated than traditional `*.properties` files - but you _need_ this complexity. Keep in mind that these are tests (not production code) and this config is going to be maintained more by the dev or QE team instead of the 'ops' or operations team.\n\nAnd there is no more worrying about Maven profiles and whether the 'right' `*.properties` file has been copied to the proper place.\n\n## Switching the Environment\nThere is only one thing you need to do to switch the environment - which is to set a Java system property.\n\n\u003e By default, the value of `karate.env` when you access it within [`karate-config.js`](#karate-configjs) - would be `null`.\n\nThe recipe for doing this when running Maven from the command line is:\n```\nmvn test -DargLine=\"-Dkarate.env=e2e\"\n```\n\nOr in Gradle:\n\n```\n./gradlew test -Dkarate.env=e2e\n```\n\nYou can refer to the documentation of the\n[Maven Surefire Plugin](http://maven.apache.org/plugins-archives/maven-surefire-plugin-2.12.4/examples/system-properties.html) for alternate ways of achieving this, but the `argLine` approach is the simplest and should be more than sufficient for your Continuous Integration or test-automation needs.\n\nHere's a reminder that running any [single JUnit test via Maven](https://maven.apache.org/surefire/maven-surefire-plugin/examples/single-test.html) can be done by:\n```\nmvn test -Dtest=CatsRunner\n```\nWhere `CatsRunner` is the JUnit class name (in any package) you wish to run.\n\nKarate is flexible, you can easily over-write config variables within the Java or JUnit \"runner\" - which is very convenient when in dev-mode or rapid-prototyping.\n\n```java\nSystem.setProperty(\"karate.env\", \"pre-prod\");\n```\n\nBut the recommended way is to use the `karateEnv(name, value)` or `systemProperty(name, value)` API on the [parallel-runner](#parallel-execution).\n\nFor advanced users, note that [tags](#tags) and the `karate.env` environment-switch can be \"linked\" using the special [environment tags](#environment-tags).\n\n## Environment Specific Config\nWhen your project gets complex, you can have separate `karate-config-\u003cenv\u003e.js` files that will be processed for that specific value of [`karate.env`](#switching-the-environment). This is especially useful when you want to maintain passwords, secrets or even URL-s specific for your local dev environment. \n\n\u003e Make sure you configure your source code management system (e.g. Git) to ignore `karate-config-*.js` if needed.\n\n\u003e There should always be `karate-config.js` in the \"root\" folder, even if you don't have any \"common\" config. In such cases, the function can do nothing or return an empty JSON. [Learn more](https://github.com/karatelabs/karate/issues/1588).\n\nHere are the rules Karate uses on bootstrap (before every `Scenario` or `Examples` row in a `Scenario Outline`):\n\n* if the system-property `karate.config.dir` was set, Karate will look in this folder for `karate-config.js` - and if found, will process it\n* else if `karate-config.js` was not found in the above location (or `karate.config.dir` was not set), [`classpath:karate-config.js`](#configuration) would be processed (this is the default / common case)\n* if the `karate.env` system property was set\n  * if `karate.config.dir` was set, Karate will also look for `file:\u003ckarate.config.dir\u003e/karate-config-\u003cenv\u003e.js`\n  * else (if the `karate.config.dir` was *not* set), Karate will look for `classpath:karate-config-\u003cenv\u003e.js`\n* if the over-ride `karate-config-\u003cenv\u003e.js` exists, it will be processed, and the configuration (JSON entries) returned by this function will over-ride any set by `karate-config.js`\n\nRefer to the [karate demo](karate-demo) for an [example](karate-demo/src/test/java/karate-config-contract.js).\n\n### `karate-base.js`\nAdvanced users who build frameworks on top of Karate have the option to supply a `karate-base.js` file that Karate will look for on the [`classpath:`](#classpath). This is useful when you ship a JAR file containing re-usable features and JavaScript / Java code and want to 'default' a few variables that teams can 'inherit' from. So an additional rule in the above flow of 'rules' (before the *first* step) is as follows:\n\n* if `classpath:karate-base.js` exists - Karate will process this as a [configuration source](#configuration) before anything else\n\n# Syntax Guide\n## Script Structure\nKarate scripts are technically in '[Gherkin](https://docs.cucumber.io/gherkin/reference/)' format - but all you need to grok as someone who needs to test web-services are the three sections: `Feature`, `Background` and `Scenario`. There can be multiple Scenario-s in a `*.feature` file, and at least one should be present. The `Background` is optional. \n\n\u003e Variables set using [`def`](#def) in the `Background` will be re-set before *every* `Scenario`. If you are looking for a way to do something only **once** per `Feature`, take a look at [`callonce`](#callonce). On the other hand, if you are expecting a variable in the `Background` to be modified by one `Scenario` so that later ones can see the updated value - that is *not* how you should think of them, and you should combine your 'flow' into one scenario. Keep in mind that you should be able to comment-out a `Scenario` or skip some via [`tags`](#tags) without impacting any others. Note that the [parallel runner](#parallel-execution) will run `Scenario`-s in parallel, which means they can run in *any* order. If you are looking for ways to do something only *once* per feature or across *all* your tests, see [Hooks](#hooks).\n\nLines that start with a `#` are comments.\n```cucumber\nFeature: brief description of what is being tested\n    more lines of description if needed.\n\nBackground:\n  # this section is optional !\n  # steps here are executed before each Scenario in this file\n  # variables defined here will be 'global' to all scenarios\n  # and will be re-initialized before every scenario\n\nScenario: brief description of this scenario\n  # steps for this scenario\n\nScenario: a different scenario\n  # steps for this other scenario\n```\n\n\u003e There is also a variant of `Scenario` called `Scenario Outline` along with `Examples`, useful for [data-driven tests](#data-driven-tests).\n\n### Given-When-Then\nThe business of web-services testing requires access to low-level aspects such as HTTP headers, URL-paths, query-parameters, complex JSON or XML payloads and response-codes. And Karate gives you control over these aspects with the small set of keywords focused on HTTP such as [`url`](#url), [`path`](#path), [`param`](#param), etc.\n\nKarate does not attempt to have tests be in \"natural language\" like how Cucumber tests are [traditionally expected to be](https://docs.cucumber.io/gherkin/reference/). That said, the syntax is very concise, and the convention of every step having to start with either `Given`, `And`, `When` or `Then`, makes things very readable. You end up with a decent approximation of BDD even though web-services by nature are \"headless\", without a UI, and not really human-friendly.\n\n#### Cucumber vs Karate\n\u003e Karate was based on Cucumber-JVM until version 0.8.0 but the parser and engine were [re-written from scratch](https://github.com/karatelabs/karate/issues/444) in 0.9.0 onwards. So we use the same [Gherkin](https://docs.cucumber.io/gherkin/) syntax - but the similarity ends there.\n\nIf you are familiar with Cucumber (JVM), you may be wondering if you need to write [step-definitions](https://docs.cucumber.io/gherkin/step-organization/). The answer is **no**.\n\nKarate's approach is that all the step-definitions you need in order to work with HTTP, JSON and XML have been already implemented. And since you can easily extend Karate [using JavaScript](#call), there is no need to compile Java code any more.\n\nThe following table summarizes some key differences between Cucumber and Karate.\n\n:white_small_square: | Cucumber | Karate\n-------------------- | -------- | ------\n**Step Definitions Built-In** | **No**. You need to keep implementing them as your functionality grows. [This can get very tedious](https://thepracticaldeveloper.com/2017/08/03/microservices-end-to-end-tests-with-cucumber-and-spring-boot/), especially since for [dependency-injection](https://docs.cucumber.io/cucumber/state/#dependency-injection), you are [on your own](http://angiejones.tech/rest-assured-with-cucumber-using-bdd-for-web-services-automation?refreshed=y#comment-40). | :white_check_mark: **Yes**. No extra Java code needed.\n**Single Layer of Code To Maintain** | **No**. There are 2 Layers. The [Gherkin](https://docs.cucumber.io/gherkin/reference/) spec or `*.feature` files make up one layer, and you will also have the corresponding Java step-definitions. | :white_check_mark: **Yes**. Only 1 layer of Karate-script (based on Gherkin).\n**Readable Specification** | **Yes**. Cucumber will read like natural language _if_ you implement the step-definitions right. | :x: **No**. Although Karate is simple, and a [true DSL](https://ayende.com/blog/2984/dsl-vs-fluent-interface-compare-contrast), it is ultimately a [mini-programming language](https://hackernoon.com/yes-karate-is-not-true-bdd-698bf4a9be39). But it is [perfect for testing web-services](https://stackoverflow.com/a/47799207/143475) at the level of HTTP requests and responses.\n**Re-Use Feature Files** | **No**. Cucumber does not support being able to call (and thus re-use) other `*.feature` files from a test-script. | :white_check_mark: [**Yes**](#calling-other-feature-files).\n**Dynamic Data-Driven Testing** | **No**. Cucumber's [`Scenario Outline`](#the-cucumber-way) expects the `Examples` to contain a fixed set of rows. | :white_check_mark: **Yes**. Karate's support for calling other `*.feature` files allows you to use a [JSON array as the data-source](#data-driven-features) and you can [use JSON](https://twitter.com/KarateDSL/status/1051433711814627329) or [even CSV](#csv-files) directly in a data-driven `Scenario Outline`.\n**Parallel Execution** | **No**. There are some challenges (especially with reporting) and you can find various discussions and third-party projects on the web that attempt to close this gap | :white_check_mark: [**Yes**](#parallel-execution). Karate runs even `Scenario`-s in parallel, not just `Feature`-s.\n**Run 'Set-Up' Routines Only Once** | **No**. Cucumber has a limitation where `Background` steps are re-run for every `Scenario` and worse - even for every `Examples` row within a `Scenario Outline`. This has been a [highly-requested open issue](https://github.com/cucumber/cucumber-jvm/issues/515) for a *long* time. | :white_check_mark: [**Yes**](#hooks).\n**Embedded JavaScript Engine** | **No**. And you have to roll your own approach to environment-specific configuration and worry about [dependency-injection](https://docs.cucumber.io/cucumber/state/#dependency-injection). | :white_check_mark: **Yes**. Easily define all environments in a [single file](#configuration) and share variables across all scenarios. Full script-ability via [JS](#calling-javascript-functions) or [Java interop](#java-interop).\n\nOne nice thing about the design of the Gherkin syntax is that script-steps are treated the same no matter whether they start with the keyword `Given`, `And`, `When` or `Then`.  What this means is that you are free to use whatever makes sense for you.  You could even have all the steps start with `When` and Karate won't care.\n\nIn fact Gherkin supports the [catch-all symbol '`*`'](https://www.relishapp.com/cucumber/cucumber/docs/gherkin/using-star-notation-instead-of-given-when-then) - instead of forcing you to use `Given`, `When` or `Then`. This is perfect for those cases where it really doesn't make sense - for example the [`Background`](#script-structure) section or when you use the [`def`](#def) or [`set`](#set) syntax. When eyeballing a test-script, think of the `*` as a 'bullet-point'.\n\nYou can read more about the Given-When-Then convention at the [Cucumber reference documentation](https://docs.cucumber.io/gherkin/reference/). Since Karate uses Gherkin, you can also employ [data-driven](#data-driven-tests) techniques such as expressing data-tables in test scripts. Another good thing that Karate inherits is the nice IDE support for Cucumber that [IntelliJ](https://www.jetbrains.com/idea/help/cucumber.html) and [Eclipse](https://cucumber.io/cucumber-eclipse/) have. So you can do things like right-click and run a `*.feature` file (or scenario) without needing to use a JUnit runner.\n\nFor a detailed discussion on BDD and how Karate relates to Cucumber, please refer to this blog-post: [Yes, Karate is not *true* BDD](https://medium.com/@ptrthomas/yes-karate-is-not-true-bdd-698bf4a9be39). It is the opinion of the author of Karate that *true* BDD is un-necessary over-kill for API testing, and this is explained more in [this answer](https://stackoverflow.com/a/47799207/143475) on [Stack Overflow](https://stackoverflow.com/questions/tagged/karate).\n\nWith the formalities out of the way, let's dive straight into the syntax.\n\n# Setting and Using Variables\n## `def`\n### Set a named variable\n```cucumber\n# assigning a string value:\nGiven def myVar = 'world'\n\n# using a variable\nThen print myVar\n\n# assigning a number (you can use '*' instead of Given / When / Then)\n* def myNum = 5\n```\nNote that `def` will over-write any variable that was using the same name earlier. Keep in mind that the start-up [configuration routine](#configuration) could have already initialized some variables before the script even started. For details of scope and visibility of variables, see [Script Structure](#script-structure).\n\n\u003e Note that `url` and `request` are not allowed as variable names. This is just to reduce confusion for users new to Karate who tend to do `* def request = {}` and expect the [`request`](#request) body or similarly, the [`url`](#url) to be set.\n\nThe examples above are simple, but a variety of expression 'shapes' are supported on the right hand side of the `=` symbol. The section on [Karate Expressions](#karate-expressions) goes into the details.\n\n## `assert`\n### Assert if an expression evaluates to `true`\nOnce defined, you can refer to a variable by name. Expressions are evaluated using the embedded JavaScript engine. The assert keyword can be used to assert that an expression returns a boolean value.\n\n```cucumber\nGiven def color = 'red '\nAnd def num = 5\nThen assert color + num == 'red 5'\n```\nEverything to the right of the `assert` keyword will be evaluated as a single expression.\n\nSomething worth mentioning here is that you would hardly need to use `assert` in your test scripts. Instead you would typically use the [`match`](#match) keyword, that is designed for performing powerful assertions against JSON and XML response payloads.\n\n## `print`\n### Log to the console\nYou can use `print` to log variables to the console in the middle of a script. For convenience, you can have multiple expressions separated by commas, so this is the recommended pattern:\n\n```cucumber\n* print 'the value of a is:', a\n```\n\nSimilar to [`assert`](#assert), the expressions on the right-hand-side of a `print` have to be valid JavaScript. JsonPath and [Karate expressions](#karate-expressions) are not supported.\n\nIf you use commas (instead of concatenating strings using `+`), Karate will 'pretty-print' variables, which is what you typically want when dealing with [JSON or XML](#native-data-types).\n\n```cucumber\n* def myJson = { foo: 'bar', baz: [1, 2, 3] }\n* print 'the value of myJson is:', myJson\n```\nWhich results in the following output:\n```\n20:29:11.290 [main] INFO  com.intuit.karate - [print] the value of myJson is: {\n  \"foo\": \"bar\",\n  \"baz\": [\n    1,\n    2,\n    3\n  ]\n}\n```\n\n\u003e Since XML is represented internally as a JSON-like or map-like object, if you perform string concatenation when printing, you will *not* see XML - which can be confusing at first. Use the comma-delimited form (see above) or the JS helper (see below).\n\nThe built-in [`karate` object](#the-karate-object) is explained in detail later, but for now, note that this is also injected into `print` (and even `assert`) statements, and it has a helpful [`pretty`](#karate-pretty) method, that takes a JSON argument and a [`prettyXml`](#karate-prettyxml) method that deals with XML. So you could have also done something like:\n\n```cucumber\n* print 'the value of myJson is:\\n' + karate.pretty(myJson)\n```\n\nAlso refer to the [`configure`](#configure) keyword on how to switch on pretty-printing of all HTTP requests and responses.\n\n# 'Native' data types\nNative data types mean that you can insert them into a script without having to worry about enclosing them in strings and then having to 'escape' double-quotes all over the place. They seamlessly fit 'in-line' within your test script.\n\n## JSON\nNote that the parser is 'lenient' so that you don't have to enclose all keys in double-quotes.\n```cucumber\n* def cat = { name: 'Billie', scores: [2, 5] }\n* assert cat.scores[1] == 5\n```\n\n\u003e Some characters such as the hyphen `-` are not permitted in 'lenient' JSON keys (because they are interpreted by the JS engine as a 'minus sign'). In such cases, you *have* to use string quotes: `{ 'Content-Type': 'application/json' }`\n\nWhen asserting for expected values in JSON or XML, always prefer using [`match`](#match) instead of [`assert`](#assert). Match failure messages are much more descriptive and useful, and you get the power of [embedded expressions](#embedded-expressions) and [fuzzy matching](#fuzzy-matching).\n```cucumber\n* def cats = [{ name: 'Billie' }, { name: 'Bob' }]\n* match cats[1] == { name: 'Bob' }\n```\n\nKarate's native support for JSON means that you can assign parts of a JSON instance into another variable, which is useful when dealing with complex [`response`](#response) payloads.\n```cucumber\n* def first = cats[0]\n* match first == { name: 'Billie' }\n```\n\nFor manipulating or updating JSON (or XML) using path expressions, refer to the [`set`](#set) keyword.\n\n## XML\n```cucumber\nGiven def cat = \u003ccat\u003e\u003cname\u003eBillie\u003c/name\u003e\u003cscores\u003e\u003cscore\u003e2\u003c/score\u003e\u003cscore\u003e5\u003c/score\u003e\u003c/scores\u003e\u003c/cat\u003e\n# sadly, xpath list indexes start from 1\nThen match cat/cat/scores/score[2] == '5'\n# but karate allows you to traverse xml like json !!\nThen match cat.cat.scores.score[1] == 5\n```\n\n### Embedded Expressions\nKarate has a very useful payload 'templating' approach. Variables can be referred to within JSON, for example:\n\n```cucumber\nGiven def user = { name: 'john', age: 21 }\nAnd def lang = 'en'\nWhen def session = { name: '#(user.name)', locale: '#(lang)', sessionUser: '#(user)'  }\n```\nSo the rule is - if a string value within a JSON (or XML) object declaration is enclosed between `#(` and `)` - it will be evaluated as a JavaScript expression. And any variables which are alive in the context can be used in this expression. Here's how it works for XML:\n\n```cucumber\nGiven def user = \u003cuser\u003e\u003cname\u003ejohn\u003c/name\u003e\u003c/user\u003e\nAnd def lang = 'en'\nWhen def session = \u003csession\u003e\u003clocale\u003e#(lang)\u003c/locale\u003e\u003csessionUser\u003e#(user)\u003c/sessionUser\u003e\u003c/session\u003e\n```\n\nThis comes in useful in some cases - and avoids needing to use the [`set`](#set) keyword or [JavaScript functions](#javascript-functions) to manipulate JSON. So you get the best of both worlds: the elegance of JSON to express complex nested data - while at the same time being able to dynamically plug values (that could even be other JSON or XML 'trees') into a 'template'.\n\nNote that embedded expressions will be evaluated even when you [`read()` from a JSON or XML file](#reading-files). This is super-useful for re-use and data-driven tests.\n\nA few special built-in variables such as `$` (which is a [reference to the JSON root](#referring-to-self)) - can be mixed into JSON embedded expressions.\n\nA [special case](#remove-if-null) of embedded expressions can remove a JSON key (or XML element / attribute) if the expression evaluates to `null`.\n\n#### Rules for Embedded Expressions\n* They work only within JSON or XML\n* and when on the Right Hand Side of a \n  * [`def`](#def)\n  * [`match`](#match)\n  * [`configure`](#configure)\n* and when you [`read()`](#reading-files) a JSON or XML file\n* the expression *has* to start with `#(` and end with `)`\n  \nBecause of the last rule above, note that string-concatenation may not work quite the way you expect:\n\n```cucumber\n# wrong !\n* def foo = { bar: 'hello #(name)' }\n# right !\n* def foo = { bar: '#(\"hello \" + name)' }\n```\n\nObserve how you can achieve string concatenation if you really want, because any valid JavaScript expression can be stuffed within an embedded expression. You could always do this in two steps:\n```cucumber        \n* def temp = 'hello ' + name\n* def foo = { bar: '#(temp)' }\n```\n\nAs a convenience, embedded expressions are supported on the Right Hand Side of a [`match`](#match) statement even for \"quoted string\" literals:\n```cucumber\n* def foo = 'a1'\n* match foo == '#(\"a\" + 1)'\n```\n\nAnd do note that in Karate 1.0 onwards, ES6 string-interpolation within \"backticks\" is supported:\n\n```cucumber\n* param filter = `ORDER_DATE:\"${todaysDate}\"`\n```\n\n### Enclosed JavaScript\nAn alternative to embedded expressions (for JSON only) is to enclose the entire payload within parentheses - which tells Karate to evaluate it as pure JavaScript. This can be a lot simpler than embedded expressions in many cases, and JavaScript programmers will feel right at home.\n\nThe example below shows the difference between embedded expressions and enclosed JavaScript:\n\n```cucumber\nWhen def user = { name: 'john', age: 21 }\nAnd def lang = 'en'\n\n* def embedded = { name: '#(user.name)', locale: '#(lang)', sessionUser: '#(user)' }\n* def enclosed = ({ name: user.name, locale: lang, sessionUser: user })\n* match embedded == enclosed\n```\n\n\u003e So how would you choose between the two approaches to create JSON ? [Embedded expressions](#embedded-expressions) are useful when you have complex JSON [`read`](#reading-files) from files, because you can auto-replace (or even [remove](#remove-if-null)) data-elements with values dynamically evaluated from variables. And the JSON will still be 'well-formed', and editable in your IDE or text-editor. Embedded expressions also make more sense in [validation](#ignore-or-validate) and [schema-like](#schema-validation) short-cut situations. It can also be argued that the `#` symbol is easy to spot when eyeballing your test scripts - which makes things more readable and clear.\n\n### Multi-Line Expressions\nThe keywords [`def`](#def), [`set`](#set), [`match`](#match), [`request`](#request) and [`eval`](#eval) take multi-line input as the last argument. This is useful when you want to express a one-off lengthy snippet of text in-line, without having to split it out into a separate [file](#reading-files). Note how triple-quotes (`\"\"\"`) are used to enclose content. Here are some examples:\n\n```cucumber\n# instead of:\n* def cat = \u003ccat\u003e\u003cname\u003eBillie\u003c/name\u003e\u003cscores\u003e\u003cscore\u003e2\u003c/score\u003e\u003cscore\u003e5\u003c/score\u003e\u003c/scores\u003e\u003c/cat\u003e\n\n# this is more readable:\n* def cat = \n  \"\"\"\n  \u003ccat\u003e\n      \u003cname\u003eBillie\u003c/name\u003e\n      \u003cscores\u003e\n          \u003cscore\u003e2\u003c/score\u003e\n          \u003cscore\u003e5\u003c/score\u003e\n      \u003c/scores\u003e\n  \u003c/cat\u003e\n  \"\"\"\n# example of a request payload in-line\nGiven request \n  \"\"\" \n  \u003c?xml version='1.0' encoding='UTF-8'?\u003e\n  \u003cS:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\"\u003e\n  \u003cS:Body\u003e\n  \u003cns2:QueryUsageBalance xmlns:ns2=\"http://www.mycompany.com/usage/V1\"\u003e\n      \u003cns2:UsageBalance\u003e\n          \u003cns2:LicenseId\u003e12341234\u003c/ns2:LicenseId\u003e\n      \u003c/ns2:UsageBalance\u003e\n  \u003c/ns2:QueryUsageBalance\u003e\n  \u003c/S:Body\u003e\n  \u003c/S:Envelope\u003e\n  \"\"\"\n\n# example of a payload assertion in-line\nThen match response ==\n  \"\"\"\n  { id: { domain: \"DOM\", type: \"entityId\", value: \"#ignore\" },\n    created: { on: \"#ignore\" }, \n    lastUpdated: { on: \"#ignore\" },\n    entityState: \"ACTIVE\"\n  }\n  \"\"\"\n```\n\n## `table`\n### A simple way to create JSON Arrays\nNow that we have seen how JSON is a 'native' data type that Karate understands, there is a very nice way to create JSON using the support for expressing [data-tables](http://www.thinkcode.se/blog/2014/06/30/cucumber-data-tables).\n\n```cucumber\n* table cats\n  | name   | age |\n  | 'Bob'  | 2   |\n  | 'Wild' | 4   |\n  | 'Nyan' | 3   |\n\n* match cats == [{name: 'Bob', age: 2}, {name: 'Wild', age: 4}, {name: 'Nyan', age: 3}]\n```\n\nThe [`match`](#match) keyword is explained later, but it should be clear right away how convenient the `table` keyword is. JSON can be combined with the ability to [call other `*.feature` files](#data-driven-features) to achieve dynamic data-driven testing in Karate.\n\nNotice that in the above example, string values within the table need to be enclosed in quotes. Otherwise they would be evaluated as expressions - which does come in useful for some dynamic data-driven situations:\n\n```cucumber\n* def one = 'hello'\n* def two = { baz: 'world' }\n* table json\n  | foo     | bar            |\n  | one     | { baz: 1 }     |\n  | two.baz | ['baz', 'ban'] |\n* match json == [{ foo: 'hello', bar: { baz: 1 } }, { foo: 'world', bar: ['baz', 'ban'] }]\n```\nYes, you can even nest chunks of JSON in tables, and things work as you would expect.\n\nEmpty cells or expressions that evaluate to `null` will result in the key being omitted from the JSON. To force a `null` value, wrap it in parentheses:\n```cucumber\n* def one = { baz: null }\n* table json\n  | foo     | bar    |\n  | 'hello' |        |\n  | one.baz | (null) |\n  | 'world' | null   |\n* match json == [{ foo: 'hello' }, { bar: null }, { foo: 'world' }]\n```\n\nAn alternate way to create data is using the [`set` multiple](#set-multiple) syntax. It is actually a 'transpose' of the `table` approach, and can be very convenient when there are a large number of keys per row or if the nesting is complex. Here is an example of what is possible:\n\n```cucumber\n* set search\n  | path       | 0        | 1      | 2       |\n  | name.first | 'John'   | 'Jane' |         |\n  | name.last  | 'Smith'  | 'Doe'  | 'Waldo' |\n  | age        | 20       |        |         |\n\n* match search[0] == { name: { first: 'John', last: 'Smith' }, age: 20 }\n* match search[1] == { name: { first: 'Jane', last: 'Doe' } }\n* match search[2] == { name: { last: 'Waldo' } }\n```\n\n## `text`\n### Don't parse, treat as raw text\nNot something you would commonly use, but in some cases you need to disable Karate's default behavior of attempting to parse anything that looks like JSON (or XML) when using [multi-line](#multi-line-expressions) / string [expressions](#karate-expressions). This is especially relevant when manipulating [GraphQL](http://graphql.org) queries - because although they look suspiciously like JSON, they are not, and tend to confuse Karate's internals. And as shown in the example below, having text 'in-line' is useful especially when you use the `Scenario Outline:` and `Examples:` for [data-driven tests](#data-driven-tests) involving place-holder substitutions in strings.\n\n```cucumber\nScenario Outline:\n  # note the 'text' keyword instead of 'def'\n  * text query =\n    \"\"\"\n    {\n      hero(name: \"\u003cname\u003e\") {\n        height\n        mass\n      }\n    }\n    \"\"\"\n  Given path 'graphql'\n  And request { query: '#(query)' }\n  And header Accept = 'application/json'\n  When method post\n  Then status 200\n\n  Examples:\n    | name  |\n    | John  |\n    | Smith | \n```\n\nNote that if you did not need to inject [`Examples:`](#data-driven-tests) into 'placeholders' enclosed within `\u003c` and `\u003e`, [reading from a file](#reading-files) with the extension `*.txt` may have been sufficient.\n\nFor placeholder-substitution, the [`replace`](#replace) keyword can be used instead, but with the advantage that the text can be read from a file or dynamically created.\n\nKarate is a great fit for testing GraphQL because of how easy it is to deal with dynamic and deeply nested JSON responses. Refer to this example for more details: [`graphql.feature`](karate-demo/src/test/java/demo/graphql/graphql.feature).\n\n## `replace`\n### Text Placeholder Replacement\n\u003e Modifying existing JSON and XML is __natively__ supported by Karate via the [`set`](#set) keyword, and `replace` is primarily intended for dealing with raw strings. But when you deal with complex, nested JSON (or XML) - it may be easier in some cases to use `replace`, especially when you want to substitute multiple placeholders with one value, and when you don't need array manipulation. Since `replace` auto-converts the result to a string, make sure you perform [type conversion](#type-conversion) back to JSON (or XML) if applicable.\n\nKarate provides an elegant 'native-like' experience for placeholder substitution within strings or text content. This is useful in any situation where you need to concatenate dynamic string fragments to form content such as GraphQL or SQL.\n\nThe placeholder format defaults to angle-brackets, for example: `\u003creplaceMe\u003e`. Here is how to replace one placeholder at a time:\n\n```cucumber\n* def text = 'hello \u003cfoo\u003e world'\n* replace text.foo = 'bar'\n* match text == 'hello bar world'\n```\n\nKarate makes it really easy to substitute multiple placeholders in a single, readable step as follows:\n\n```cucumber\n* def text = 'hello \u003cone\u003e world \u003ctwo\u003e bye'\n\n* replace text\n  | token | value   |\n  | one   | 'cruel' |\n  | two   | 'good'  |\n\n* match text == 'hello cruel world good bye'\n```\n\nNote how strings have to be enclosed in quotes. This is so that you can mix expressions into text replacements as shown below. This example also shows how you can use a custom placeholder format instead of the default:\n\n```cucumber\n* def text = 'hello \u003cone\u003e world ${two} bye'\n* def first = 'cruel'\n* def json = { second: 'good' }\n\n* replace text\n    | token  | value       |\n    | one    | first       |\n    | ${two} | json.second |\n\n* match text == 'hello cruel world good bye'\n```\nRefer to this file for a detailed example: [`replace.feature`](karate-core/src/test/java/com/intuit/karate/core/replace.feature)\n\n## YAML Files\nFor those who may prefer [YAML](http://yaml.org) as a simpler way to represent data, Karate allows you to read YAML content from a [file](#reading-files) - and it will be auto-converted into JSON.\n\n```cucumber\n# yaml from a file (the extension matters), and the data-type of 'bar' would be JSON\n* def bar = read('data.yaml')\n```\n\n### `yaml`\nA very rare need is to be able to convert a string which happens to be in YAML form into JSON, and this can be done via the `yaml` type cast keyword. For example - if a response data element or downloaded file is YAML and you need to use the data in subsequent steps. Also see [type conversion](#type-conversion).\n\n```cucumber\n* text foo =\n  \"\"\"\n  name: John\n  input:\n    id: 1\n    subType: \n      name: Smith\n      deleted: false\n  \"\"\"\n# yaml to json type conversion  \n* yaml foo = foo\n* match foo ==\n  \"\"\"\n  {\n    name: 'John',\n    input: { \n      id: 1,\n      subType: { name: 'Smith', deleted: false }    \n    }\n  }\n  \"\"\"\n```\n\n## CSV Files\nKarate can read `*.csv` files and will auto-convert them to JSON. A header row is always expected. See the section on [reading files](#reading-files) - and also this example [`dynamic-csv.feature`](karate-demo/src/test/java/demo/outline/dynamic-csv.feature), which shows off the convenience of [dynamic `Scenario Outline`-s](#dynamic-scenario-outline).\n\nIn rare cases you may want to use a csv-file as-is and *not* auto-convert it to JSON. A good example is when you want to use a CSV file as the [request-body](#request) for a file-upload. You could get by by renaming the file-extension to say `*.txt` but an alternative is to use the [`karate.readAsString()`](#read-file-as-string) API.\n\n### `csv`\nJust like [`yaml`](#yaml), you may occasionally need to [convert a string](#type-conversion) which happens to be in CSV form into JSON, and this can be done via the `csv` keyword.\n\n```cucumber\n* text foo =\n    \"\"\"\n    name,type\n    Billie,LOL\n    Bob,Wild\n    \"\"\"\n* csv bar = foo\n* match bar == [{ name: 'Billie', type: 'LOL' }, { name: 'Bob', type: 'Wild' }]\n```\n\n## JavaScript Functions\nJavaScript Functions are also 'native'. And yes, functions can take arguments.\n\n\u003e Standard JavaScript syntax rules apply, but the right-hand-side should begin with the `function` keyword if declared *in-line*. When using stand-alone `*.js` files, you can have a comment before the `function` keyword, and you can use `fn` as the function name, so that your IDE does not complain about JavaScript syntax errors, e.g. `function fn(x){ return x + 1 }`\n\n```cucumber\n* def greeter = function(title, name) { return 'hello ' + title + ' ' + name }\n* assert greeter('Mr.', 'Bob') == 'hello Mr. Bob'\n```\n\n\u003e When JavaScript executes in Karate, the built-in [`karate` object](#the-karate-object) provides some commonly used utility functions. And with [Karate expressions](#karate-expressions), you can \"dive into\" JavaScript without needing to define a function - and [conditional logic](#conditional-logic) is a good example.\n\n### Java Interop\nFor more complex functions you are better off using the [multi-line](#multi-line-expressions) 'doc-string' approach. This example actually calls into existing Java code, and being able to do this opens up a whole lot of possibilities. The JavaScript interpreter will try to convert types across Java and JavaScript as smartly as possible. For e.g. JSON objects become Java `Map`-s, JSON arrays become Java `List`-s, and Java Bean properties are accessible (and update-able) using 'dot notation' e.g. '`object.name`'\n\n```cucumber\n* def dateStringToLong =\n  \"\"\"\n  function(s) {\n    var SimpleDateFormat = Java.type('java.text.SimpleDateFormat');\n    var sdf = new SimpleDateFormat(\"yyyy-MM-dd'T'HH:mm:ss.SSSZ\");\n    return sdf.parse(s).time; // '.getTime()' would also have worked instead of '.time'\n  } \n  \"\"\"\n* assert dateStringToLong(\"2016-12-24T03:39:21.081+0000\") == 1482550761081\n```\n\n\u003e More examples of Java interop and how to invoke custom code can be found in the section on [Calling Java](#calling-java).\n\nThe `call` keyword provides an [alternate way of calling JavaScript functions](#calling-javascript-functions) that have only one argument. The argument can be provided after the function name, without parentheses, which makes things slightly more readable (and less cluttered) especially when the solitary argument is JSON.\n\n```cucumber\n* def timeLong = call dateStringToLong '2016-12-24T03:39:21.081+0000'\n* assert timeLong == 1482550761081\n\n# a better example, with a JSON argument\n* def greeter = function(name){ return 'Hello ' + name.first + ' ' + name.last + '!' }\n* def greeting = call greeter { first: 'John', last: 'Smith' }\n```\n\n## Reading Files\nKarate makes re-use of payload data, utility-functions and even other test-scripts as easy as possible. Teams typically define complicated JSON (or XML) payloads in a file and then re-use this in multiple scripts. Keywords such as [`set`](#set) and [`remove`](#remove) allow you to to 'tweak' payload-data to fit the scenario under test. You can imagine how this greatly simplifies setting up tests for boundary conditions. And such re-use makes it easier to re-factor tests when needed, which is great for maintainability.\n\n\u003e Note that the [`set` (multiple)](#set-multiple) keyword can build complex, nested JSON (or XML) from scratch in a data-driven manner, and you may not even need to read from files for many situations. Test data can be within the main flow itself, which makes scripts highly readable.\n\nReading files is achieved using the built-in JavaScript function called `read()`. By default, the file is expected to be in the same folder (package) and side-by-side with the `*.feature` file. But you can prefix the name with `classpath:` in which case the ['root' folder](#classpath) would be `src/test/java` (assuming you are using the [recommended folder structure](#folder-structure)).\n\nPrefer [`classpath:`](#classpath) when a file is expected to be heavily re-used all across your project.  And yes, relative paths will work.\n\n```cucumber\n# json\n* def someJson = read('some-json.json')\n* def moreJson = read('classpath:more-json.json')\n\n# xml\n* def someXml = read('../common/my-xml.xml')\n\n# import yaml (will be converted to json)\n* def jsonFromYaml = read('some-data.yaml')\n\n# csv (will be converted to json)\n* def jsonFromCsv = read('some-data.csv')\n\n# string\n* def someString = read('classpath:messages.txt')\n\n# javascript (will be evaluated)\n* def someValue = read('some-js-code.js')\n\n# if the js file evaluates to a function, it can be re-used later using the 'call' keyword (or invoked just like normal js)\n* def someFunction = read('classpath:some-reusable-code.js')\n* def someCallResult = call someFunction\n* def sameCallResult = someFunction()\n\n# the following short-cut is also allowed\n* def someCallResult = call read('some-js-code.js')\n```\n\nYou can also [re-use other `*.feature`](#calling-other-feature-files) files from test-scripts:\n\n```cucumber\n# perfect for all those common authentication or 'set up' flows\n* def result = call read('classpath:some-reusable-steps.feature')\n```\n\nWhen a *called* feature depends on some side-by-side resources such as JSON or JS files, you can use the `this:` prefix to ensure that relative paths work correctly - because by default Karate calculates relative paths from the \"root\" feature or the top-most \"caller\".\n\n```cucumber\n* def data = read('this:payload.json')\n```\n\nIf a file does not end in `.json`, `.xml`, `.yaml`, `.js`, `.csv` or `.txt`, it is treated as a stream - which is typically what you would need for [`multipart`](#multipart-field) file uploads.\n\n```cucumber\n* def someStream = read('some-pdf.pdf')\n```\n\n\u003e The `.graphql` and `.gql` extensions are also recognized (for GraphQL) but are handled the same way as `.txt` and treated as a string.\n\nFor JSON and XML files, Karate will evaluate any [embedded expressions](#embedded-expressions) on load. This enables more concise tests, and the file can be re-usable in multiple, data-driven tests.\n\nSince it is internally implemented as a JavaScript function, you can mix calls to `read()` freely wherever JavaScript expressions are allowed:\n\n```cucumber\n* def someBigString = read('first.txt') + read('second.txt')\n```\n\n\u003e Tip: you can even use JS expressions to dynamically choose a file based on some condition: `* def someConfig = read('my-config-' + someVariable + '.json')`. Refer to [conditional logic](#conditional-logic) for more ideas.\n\nAnd a very common need would be to use a file as the [`request`](#request) body:\n\n```cucumber\nGiven request read('some-big-payload.json')\n```\n\nOr in a [`match`](#match):\n\n```cucumber\nAnd match response == read('expected-response-payload.json')\n```\n\nThe rarely used `file:` prefix is also supported. You could use it for 'hard-coded' absolute paths in dev mode, but is obviously not recommended for CI test-suites. A good example of where you may need this is if you programmatically write a file to the `target` folder, and then you can read it like this:\n\n```cucumber\n* def payload = read('file:target/large.xml')\n```\n\n### Path Prefixes\nTo summarize the possible prefixes:\n\nPrefix | Description\n------ | -----------\n`classpath:` | relative to the [classpath](#classpath), recommended for re-usable features \n`file:` | do not use this unless you know what you are doing, see above\n`this:` | when in a *called* feature, ensure that files are resolved relative to the current feature file\n\nTake a look at the [Karate Demos](karate-demo) for real-life examples of how you can use files for validating HTTP responses, like this one: [`read-files.feature`](karate-demo/src/test/java/demo/read/read-files.feature).\n\n### Read File As String\nIn some rare cases where you don't want to auto-convert JSON, XML, YAML or CSV, and just get the raw string content (without having to re-name the file to end with `.txt`) - you can use the [`karate.readAsString()`](#karate-readasstring) API. Here is an example of using a CSV file as the request-body:\n\n```cucumber\nGiven path 'upload'\nAnd header Content-Type = 'text/csv'\nAnd request karate.readAsString('classpath:my.csv')\nWhen method post\nThen status 202\n```\n\n## Compare Image\nKarate provides a flexible way to compare two images to determine if they are the same or similar. This is especially useful when capturing screenshots during tests and comparing against baseline images that are known to be correct.\n\n\u003e A stand-alone example can be found here: [`examples/image-comparison`](examples/image-comparison) along with a [video explanation](https://youtu.be/wlvmNBraP60).\n\nBelow is a simple example that will compare a `baseline` image to a more recent `latest` image. An image comparison UI will also be embedded into the Karate HTML report with detailed information about any differences between the two images.\n\n```cucumber\n* compareImage { baseline: 'screenshots/login.png', latest: '/tmp/login.png' }\n```\n\nYou can also compare images using Karate [path prefixes](#path-prefixes) (e.g. `classpath:`, `this:`, `file:`) or byte arrays:\n\n```cucumber\n* def latestImgBytes = karate.readAsBytes('login.png')\n* compareImage { baseline: 'classpath:screenshots/login.png', latest: '#(latestImgBytes)' }\n```\n\nYou may configure the following image comparison options using the `configure` action:\n\n```cucumber\n* configure imageComparison = { /* image comparison options ... */ }\n```\n\nImage comparison configuration options:\n\n| Key                   | Type        | Default    | Description                                                                                                                                                                                                                                |\n|-----------------------|-------------|------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `allowScaling`        | boolean     | `false`    | When `true` we will scale latest images to match the dimensions of the baseline when they are not equal                                                                                                                                    |\n| `engine`              | string      | 'resemble' | Comparison engine(s) to use. Valid options are `resemble` and `ssim` separated by either `,` or \u003ccode\u003e\u0026#124\u003c/code\u003e                                                                                                                         |\n| `failureThreshold`    | number      | `0.0`      | Precentage of `latest` image pixels allowed to differ from `baseline` before we consider the comparison as failed                                                                                                                          |\n| `mismatchShouldPass`  | boolean     | `false`    | When `true` all image comparisons will pass (even when difference is \u003e= `failureThreshold`). Note: failures will result in image comparison UI *always* being embedded in Karate HTML reports regardless of `hideUiOnSuccess` setting. |\n| `onShowRebase`        | string (js) | `null`     | Function to be called when displaying image comparison rebase in Karate HTML reports (e.g. to customize rebase filename and/or output)                                                                                                     |\n| `onShowConfig`        | string (js) | `null`     | Function to be called when displaying image comparison configuration in Karate HTML reports (e.g. to customize configuration output)                                                                                                       |\n| `hideUiOnSuccess` | boolean     | `false`    | When `true` the comparison UI will *NOT* be embedded in Karate HTML reports for all non-failed image comparisons                                                                                                                           |\n\nExamples:\n\n```cucumber\n# use only 'ssim' (structural similarity) engine\n* configure imageComparison = { engine: 'ssim' }\n\n# always use both 'resemble' and 'ssim' engines but only evaluate the lowest mismatch percentage against our `failureThreshold`\n* configure imageComparison = { engine: 'resemble,ssim' }\n\n# prefer 'resemble' and fallback to 'ssim' engine only if the resemble mismatch percentage is \u003e= `failureThreshold`\n* configure imageComparison = { engine: 'resemble|ssim' }\n\n# only consider the comparison as failed when 2% or more pixels are different from the baseline\n* configure imageComparison = { failureThreshold: 2 }\n\n# consider image comparisons that fail due to too many mismatched pixels as passed (especially useful when you are first starting without any baseline images)\n* configure imageComparison = { mismatchShouldPass: true }\n\n# custom JS function called in Karate HTML image comparison UI when the user clicks the `Rebase` button\n* text onShowRebaseFn =\n\"\"\"\nfunction (config, downloadLatestFn) {\n  // trigger download of latest image with custom file name\n  downloadLatestFn('custom_latest.png')\n  return 'this text will be displayed to the user when they click the rebase button'\n}\n\"\"\"\n* configure imageComparison = { onShowRebase: '#(onShowRebaseFn)' }\n\n# custom JS function called in Karate HTML image comparison UI when the user clicks the `Show config` button\n* text onShowConfigFn =\n\"\"\"\nfunction (customConfigJson, config) {\n  return 'this text will be displayed above the image comparison config\\n' + customConfigJson\n}\n\"\"\"\n* configure imageComparison = { onShowConfig: '#(onShowConfigFn)' }\n\n# don't embed the image comparison UI when the latest image is the same / similar to the baseline (e.g. to save space and speed up report loading)\n* configure imageComparison = { hideUiOnSuccess: true }\n```\n\nImage comparison engines can also be customized:\n\n```cucumber\n* compareImage { baseline: 'baseline.png', latest: 'latest.png', options: { /* engine options ... */ } }\n```\n\nImage comparison configuration options:\n\n| Key                      | Engines        | Type            | Default   | Description                                                                                                                                                                                                                                            |\n|--------------------------|----------------|-----------------|-----------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `ignoredBoxes`           | resemble, ssim | array of object | `null`    | Array of rectangles that should be ignored during image comparison                                                                                                                                                                                     |\n| `ignore`                 | resemble       | string          | 'less'    | Resemble ignore preset. Valid options are `nothing`, `less`, `antialiasing`, `colors`, `alpha` (see [presets](https://github.com/t12y/resemble/blob/0c55a1849232b68aa4c16f1d7a949cc429a6af8e/src/main/java/io/github/t12y/resemble/Options.java#L20)). |\n| `ignoreAreasColoredWith` | resemble       | object          | `null`    | Resemble option to ignore a specific color                                                                                                                                                                                                             |\n| `ignoreColors`           | resemble       | boolean         | `false`   | When `true` only pixel brightness is compared                                                                                                                                                                                                          |\n| `ignoreAntialiasing`     | resemble       | boolean         | `false`   | When `true` only pixel brightness is compared for pixels determined to be antialiased                                                                                                                                                                  |\n| `tolerances`             | resemble       | object          | `null`    | Resemble option to override preset tolerances for color and brightness                                                                                                                                                                                 |\n| `ssim`                   | ssim           | string          | 'WEBER'   | SSIM algorithm. Valid options are `FAST` or `WEBER`                                                                                                                                                                                                    |\n| `rgb2grayVersion`        | ssim           | string          | 'INTEGER' | SSIM grayscale algorithm. Valid options are `ORIGINAL` or `INTEGER`                                                                                                                                                                                    |\n| `k1`                     | ssim           | number          | `0.01`    | SSIM first stability constant (see [ssim.pdf](https://github.com/obartra/ssim/blob/3f3af6118c78b3ed4f0ff6eb224700c071f29c99/assets/ssim.pdf))                                                                                                          |\n| `k2`                     | ssim           | number          | `0.03`    | SSIM second stability constant (see [ssim.pdf](https://github.com/obartra/ssim/blob/3f3af6118c78b3ed4f0ff6eb224700c071f29c99/assets/ssim.pdf))                                                                                                         |\n| `windowSize`             | ssim           | integer         | `11`      | Window size for the SSIM map (see [ssim.pdf](https://github.com/obartra/ssim/blob/3f3af6118c78b3ed4f0ff6eb224700c071f29c99/assets/ssim.pdf))                                                                                                           |\n| `bitDepth`               | ssim           | integer         | `8`       | The number of bits used to encode each pixel                                                                                                                                                                                                           |\n| `maxSize`                | ssim           | integer         | `256`     | The maximum size on the smallest dimension before downsampling                                                                                                                                                                                         |\n\nExamples:\n\n```cucumber\n# ignore areas of an image (e.g. to avoid constant failures due to loading animations)\n* def boxes =\n\"\"\"\n[{\n  top: 483,\n  left: 1085,\n  bottom: 893,\n  right: 1496\n}]\n\"\"\"\n* compareImage { baseline: 'baseline.png', latest: 'latest.png', options: { ignoredBoxes: #(boxes) } }\n\n#############################\n### Resemble-only options ###\n#############################\n\n# zero-tolerance for color shifts\n* compareImage { baseline: 'baseline.png', latest: 'latest.png', options: { ignore: 'nothing' } }\n\n# ignore all purple areas\n* def purple =\n\"\"\"\n{\n  r: 190,\n  g: 0,\n  b: 255\n}\n\"\"\"\n* compareImage { baseline: 'baseline.png', latest: 'latest.png', options: { ignoreAreasColoredWith: '#(purple)' } }\n\n# compare images as grayscale\n* compareImage { baseline: 'baseline.png', latest: 'latest.png', options: { ignoreColors: true } }\n\n# attempt to detect and ignore antialiasing\n* compareImage { baseline: 'baseline.png', latest: 'latest.png', options: { ignoreAntialiasing: true } }\n\n# customize color / brightness tolerances\n* def customTolerances =\n\"\"\"\n{\n  red: 4,\n  green: 4,\n  blue: 4,\n  alpha: 4,\n  minBrightness: 4,\n  maxBrightness: 250\n}\n* compareImage { baseline: 'baseline.png', latest: 'latest.png', options: { tolerances: '#(customTolerances)' } }\n\n#########################\n### SSIM-only options ###\n#########################\n\n# switch to `fast` SSIM algorithm\n* compareImage { baseline: 'baseline.png', latest: 'latest.png', options: { ssim: 'FAST' } }\n\n# switch to `original` grayscale SSIM algorithm\n* compareImage { baseline: 'baseline.png', latest: 'latest.png', options: { rgb2grayVersion: 'ORIGINAL' } }\n\n# update SSIM stability constants\n* compareImage { baseline: 'baseline.png', latest: 'latest.png', options: { k1: 0, k2: 0 } }\n\n# update SSIM window size\n* compareImage { baseline: 'baseline.png', latest: 'latest.png', options: { windowSize: 3 } }\n\n# update SSIM bit depth\n* compareImage { baseline: 'baseline.png', latest: 'latest.png', options: { bitDepth: 16 } }\n\n# update SSIM max size\n* compareImage { baseline: 'baseline.png', latest: 'latest.png', options: { maxSize: 512 } }\n```\n\n## Type Conversion\n\u003e Best practice is to stick to using only [`def`](#def) unless there is a very good reason to do otherwise.\n\nInternally, Karate will auto-convert JSON (and even XML) to Java `Map` objects. And JSON arrays would become Java `List`-s. But you will never need to worry about this internal data-representation most of the time.\n\nIn some rare cases, for e.g. if you acquired a string from some external source, or if you generated JSON (or XML) by concatenating text or using [`replace`](#replace), you may want to convert a string to JSON and vice-versa. You can even perform a conversion from XML to JSON if you want.\n\nOne example of when you may want to convert JSON (or XML) to a string is when you are passing a payload to custom code via [Java interop](#calling-java). Do note that when passing JSON, the default `Map` and `List` representations should suffice for most needs ([see example](karate-demo/src/test/java/demo/java/cats-java.feature)), and using them would avoid un-necessary string-conversion.\n\nSo you have the following type markers you can use instead of [`def`](#def) (or the rarely used [`text`](#text)). The first four below are best explained in this example file: [`type-conv.feature`](karate-core/src/test/java/com/intuit/karate/core/type-conv.feature).\n\n* \u003ca name=\"type-string\"\u003e\u003ccode\u003estring\u003c/code\u003e\u003c/a\u003e - convert JSON or any other data-type (except XML) to a string\n* \u003ca name=\"type-json\"\u003e\u003ccode\u003ejson\u003c/code\u003e\u003c/a\u003e - convert XML, a map-like or list-like object, a string, or even a Java object into JSON\n* \u003ca name=\"type-xml\"\u003e\u003ccode\u003exml\u003c/code\u003e\u003c/a\u003e - convert JSON, a map-like object, a string, or even a Java object into XML\n* \u003ca name=\"type-xmlstring\"\u003e\u003ccode\u003exmlstring\u003c/code\u003e\u003c/a\u003e - specifically for converting the map-like Karate internal representation of XML into a string\n* \u003ca name=\"type-csv\"\u003e\u003ccode\u003ecsv\u003c/code\u003e\u003c/a\u003e - convert a CSV string into JSON, see [`csv`](#csv)\n* \u003ca name=\"type-yaml\"\u003e\u003ccode\u003eyaml\u003c/code\u003e\u003c/a\u003e - convert a YAML string into JSON, see [`yaml`](#yaml)\n* \u003ca name=\"type-bytes\"\u003e\u003ccode\u003ebytes\u003c/code\u003e\u003c/a\u003e - convert to a byte-array, useful for binary payloads or comparisons, see [example](karate-demo/src/test/java/demo/websocket/echo.feature)\n* \u003ca name=\"type-copy\"\u003e\u003ccode\u003ecopy\u003c/code\u003e\u003c/a\u003e - to clone a given payload variable reference (JSON, XML, Map or List), refer: [`copy`](#copy)\n\nThe `csv` and `yaml` types can be initialized in-line using the \"triple quote\" or \"docstring\" multi-line approach as shown [here](karate-core/src/test/java/com/intuit/karate/core/type-conversion.feature).\n\nIf you want to 'pretty print' a JSON or XML value with indenting, refer to the documentation of the [`print`](#print) keyword.\n\n### Floats and Integers\nWhile converting a number to a string is easy (just concatenate an empty string e.g. `myInt + ''`), in some rare cases, you may need to convert a string to a number. You can do this by multiplying by `1` or using the built-in JavaScript `parseInt()` function:\n\n```cucumber\n* def foo = '10'\n* string json = { bar: '#(1 * foo)' }\n* match json == '{\"bar\":10.0}'\n\n* string json = { bar: '#(parseInt(foo))' }\n* match json == '{\"bar\":10.0}'\n```\n\nAs per the JSON spec, all numeric values are treated as doubles, so for integers - it really doesn't matter if there is a decimal point or not. In fact it may be a good idea to slip doubles instead of integers into some of your tests ! Anyway, there are times when you may want to force integers (perhaps for cosmetic reasons) and you can easily do so using the 'double-tilde' [short-cut: '`~~`'](http://rocha.la/JavaScript-bitwise-operators-in-practice).\n\n```cucumber\n* def foo = '10'\n* string json = { bar: '#(~~foo)' }\n* match json == '{\"bar\":10}'\n\n# JS math can introduce a decimal point in some cases\n* def foo = 100\n* string json = { bar: '#(foo * 0.1)' }\n* match json == '{\"bar\":10.0}'\n\n# but you can easily coerce to an integer if needed\n* string json = { bar: '#(~~(foo * 0.1))' }\n* match json == '{\"bar\":10}'\n```\n\n### Large Numbers\nSometimes when dealing with very large numbers, the JS engine may mangle the number into scientific notation:\n\n```cucumber\n* def big = 123123123123\n* string json = { num: '#(big)' }\n* match json == '{\"num\":1.23123123123E11}'\n```\n\nThis can be easily solved by using `java.math.BigDecimal`:\n\n```cucumber\n* def big = new java.math.BigDecimal(123123123123)\n* string json = { num: '#(big)' }\n* match json == '{\"num\":123123123123}'\n```\n\nFor more tips, refer [here](https://stackoverflow.com/a/77576066/143475).\n\n## `doc`\nKarate has a built-in HTML templating engine that can be used to insert additional custom HTML into the test-reports. Here is an [example](karate-core/src/test/java/com/intuit/karate/core/users-doc.feature):\n\n```cucumber\n* url 'https://jsonplaceholder.typicode.com/users'\n* method get\n* doc { read: 'users.html' }\n```\n\nAny Karate [variable](#def) will be available to the template, which is [`users.html`](karate-core/src/test/java/com/intuit/karate/core/users.html) in this example.\n\n```html\n\u003ctable class=\"table table-striped\"\u003e\n  \u003cthead\u003e\n    \u003ctr\u003e\n      \u003cth\u003eID\u003c/th\u003e\n      \u003cth\u003eName\u003c/th\u003e\n      \u003cth\u003eE-Mail\u003c/th\u003e\n    \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n    \u003ctr th:each=\"user: response\"\u003e\n      \u003ctd th:text=\"user.id\"\u003e\u003c/td\u003e\n      \u003ctd th:text=\"user.name\"\u003e\u003c/td\u003e\n      \u003ctd th:text=\"user.email\"\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n```\n\nYou can see what the result looks like [here](https://twitter.com/ptrthomas/status/1335478948365443072).\n\nSince templates can be loaded using the [`classpath:`](#classpath) prefix, you can even re-use templates across your projects via [Java JAR files](https://stackoverflow.com/a/58339662/143475).\n\n# Karate Expressions\nBefore we get to the HTTP keywords, it is worth doing a recap of the various 'shapes' that the right-hand-side of an assignment statement can take:\n\n Example | Shape | Description\n-------- | ----- | -----------\n`* def foo = 'bar'` | JS | simple strings, numbers or booleans\n`* def foo = 'bar' + baz[0]` | JS | any valid JavaScript expression, and variables can be mixed in, another example: `bar.length + 1`\n`* def foo = { bar: '#(baz)' }` | JSON | anything that starts with a `{` or a `[` is parsed as JSON, use [`text`](#text) instead of [`def`](#def) if you need to suppress the default behavior\n`* def foo = ({ bar: baz })` | JS | [enclosed JavaScript](#enclosed-javascript), the result of which is exactly equivalent to the above\n`* def foo = \u003cfoo\u003ebar\u003c/foo\u003e` | XML | anything that starts with a `\u003c` is parsed as XML, use [`text`](#text) instead of [`def`](#def) if you need to suppress the default behavior\n`* def foo = function(arg){ return arg + bar }` | JS Fn | anything that starts with `function(...){` is parsed as a JS function.\n`* def foo = read('bar.json')` | JS | using the built-in [`read()`](#reading-files) function\n`* def foo = $.bar[0]` | JsonPath | short-cut JsonPath on the [`response`](#response)\n`* def foo = /bar/baz` | XPath | short-cut XPath on the [`response`](#response)\n`* def foo = get bar $..baz[?(@.ban)]` | [`get`](#get) JsonPath | [JsonPath](https://github.com/json-path/JsonPath#path-examples) on the variable `bar`, you can also use [`get[0]`](#get-plus-index) to get the first item if the JsonPath evaluates to an array - especially useful when using wildcards such as `[*]` or [filter-criteria](#jsonpath-filters)\n`* def foo = $bar..baz[?(@.ban)]` | $var.JsonPath | [convenience short-cut](#get-short-cut) for the above\n`* def foo = get bar count(/baz//ban)` | [`get`](#get) XPath | XPath on the variable `bar`\n`* def foo = karate.pretty(bar)` | JS | using the [built-in `karate` object](#the-karate-object) in JS expressions\n`* def Foo = Java.type('com.mycompany.Foo')` | JS-Java | [Java Interop](#java-interop), and even package-name-spaced one-liners like `java.lang.System.currentTimeMillis()` are possible\n`* def foo = call bar { baz: '#(ban)' }` | [`call`](#call) | or [`callonce`](#callonce), where expressions like [`read('foo.js')`](#reading-files) are allowed as the object to be called or the argument\n`* def foo = bar({ baz: ban })` | JS | equivalent to the above, JavaScript function invocation\n\n# Core Keywords\nThey are `url`, `path`, `request`, `method` and `status`.\n\nThese are essential HTTP operations, they focus on setting one (un-named or 'key-less') value at a time and therefore don't need an `=` sign in the syntax.\n\n## `url`\n```cucumber\nGiven url 'https://myhost.com/v1/cats'\n```\nWithin a `Scenario`, a URL remains constant until you use the `url` keyword again, so this is a good place to set-up the 'non-changing' parts of your REST URL-s.\n\nA URL can take expressions, so the approach below is legal.  And yes, variables can come from global [config](#configuration).\n```cucumber\nGiven url 'https://' + e2eHostName + '/v1/api'\n```\n\nJavaScript enthusiasts may prefer variable interpolation using backticks:\n```cucumber\n* url `https://${e2eHostName}/v1/api`\n```\n\nIf you are trying to build dynamic URLs including query-string parameters in the form: `http://myhost/some/path?foo=bar\u0026search=true` - please refer to the [`param`](#param) keyword.\n\n\n### `configure url`\nWhen you [`call`](#call) other features, the `url` will be \"reset\". But if you want the `url` to persist, you can do this:\n\n```cucumber\nFeature:\n\nScenario:\n* configure url = 'https://httpbin.org'\n* path 'anything'\n* method get\n* call read('@called')\n\n@ignore @called\nScenario:\n* path 'anything'\n* method get\n```\n\nNote how in the \"called\" `Scenario` you could omit the `url`. It is easy to change the `url` anytime by using the keyword. Note that you can use variables to set up the `url` any time you need to.\n\n## `path`\nREST-style path parameters.  Can be expressions that will be evaluated.  Comma delimited values are supported which can be more convenient, and takes care of URL-encoding and appending '/' between path segments as needed.\n\n```cucumber\nGiven path 'documents', documentId, 'download'\n\n# or you can do the same on multiple lines if you wish\nGiven path 'documents'\nAnd path documentId\nAnd path 'download'\n```\n\nNote that the `path` 'resets' after any HTTP request is made but not the `url`. The [Hello World](#hello-world) is a great example of 'REST-ful' use of the `url` when the test focuses on a single REST 'resource'. Look at how the `path` did not need to be specified for the second HTTP `get` call since `/cats` is part of the `url`.\n\n\u003e Important: If you attempt to build a URL in the form `?myparam=value` by using `path` the `?` will get encoded into `%3F`. Use either the [`param`](#param) keyword, e.g.: `* param myparam = 'value'` or [`url`](#url): `* url 'http://example.com/v1?myparam'`\n\nBecause Karate strips trailing slashes if part of a `path` parameter, if you want to append a forward-slash to the end of the URL in the final HTTP request - make sure that the last `path` is a single '/'. For example, if your path has to be `documents/` (and not just `documents`), use:\n\n```cucumber\nGiven path 'documents', '/'\n```\n\n## `request`\nIn-line JSON:\n```cucumber\nGiven request { name: 'Billie', type: 'LOL' }\n```\nIn-line XML:\n```cucumber\nAnd request \u003ccat\u003e\u003cname\u003eBillie\u003c/name\u003e\u003ctype\u003eCeiling\u003c/type\u003e\u003c/cat\u003e\n```\nFrom a [file](#reading-files) in the same package.  Use the `classpath:` prefix to load from the [classpath](#classpath) instead.\n```cucumber\nGiven request read('my-json.json')\n```\nYou could always use a variable:\n```cucumber\nAnd request myVariable\n```\nIn most cases you won't need to set the `Content-Type` [`header`](#header) as Karate will automatically do the right thing depending on the data-type of the `request`.\n\nDefining the `request` is mandatory if you are using an HTTP `method` that expects a body such as `post`. If you really need to have an empty body, you can use an empty string as shown below, and you can force the right `Content-Type` header by using the [`header`](#header) keyword.\n\n```cucumber\nGiven request ''\nAnd header Content-Type = 'text/html'\n```\n\nSending a [file](#reading-files) as the entire binary request body is easy (note that [`multipart`](#multipart-file) is different):\n\n```cucumber\nGiven path 'upload'\nAnd request read('my-image.jpg')\nWhen method put\nThen status 200\n```\n\n## `method`\nThe HTTP verb - `get`, `post`, `put`, `delete`, `patch`, `options`, `head`, `connect`, `trace`.\n\nLower-case is fine.\n```cucumber\nWhen method post\n```\n\nIt is worth internalizing that during test-execution, it is upon the `method` keyword that the actual HTTP request is issued. Which suggests that the step should be in the `When` form, for example: `When method post`. And steps that follow should logically be in the `Then` form. Also make sure that you complete the set up of things like [`url`](#url), [`param`](#param), [`header`](#header), [`configure`](#configure) etc. *before* you fire the `method`.\n\n```cucumber\n# set headers or params (if any) BEFORE the method step\nGiven header Accept = 'application/json'\nWhen method get\n# the step that immediately follows the above would typically be:\nThen status 200\n```\n\nAlthough rarely needed, variable references or [expressions](#karate-expressions) are also supported:\n\n```cucumber\n* def putOrPost = (someVariable == 'dev' ? 'put' : 'post')\n* method putOrPost\n```\n\n## `status`\nThis is a shortcut to assert the HTTP response code.\n```cucumber\nThen status 200\n```\nAnd this assertion will cause the test to fail if the HTTP response code is something else.\n\nSee also [`responseStatus`](#responsestatus) if you want to do some complex assertions against the HTTP status code.\n\n# Keywords that set key-value pairs\nThey are `param`, `header`, `cookie`, `form field` and `multipart field`. \n\nThe syntax will include a '=' sign between the key and the value.  The key should not be within quotes.\n\n\u003e To make dynamic data-driven testing easier, the following keywords also exist: [`params`](#params), [`headers`](#headers), [`cookies`](#cookies-json) and [`form fields`](#form-fields). They use JSON to build the relevant parts of the HTTP request.\n\n## `param` \nSetting query-string parameters:\n```cucumber\nGiven param someKey = 'hello'\nAnd param anotherKey = someVariable\n```\n\nThe above would result in a URL like: `http://myhost/mypath?someKey=hello\u0026anotherKey=foo`. Note that the `?` and `\u0026` will be automatically inserted.\n\nMulti-value params are also supported:\n```cucumber\n* param myParam = ['foo', 'bar']\n```\n\nFor convenience, a `null` value will be ignored. You can also use JSON to set multiple query-parameters in one-line using [`params`](#params) and this is especially useful for dynamic data-driven testing.\n\n## `header`\nYou can use [functions](#calling-javascript-functions) or [expressions](#karate-expressions):\n```cucumber\nGiven header Authorization = myAuthFunction()\nAnd header transaction-id = 'test-' + myIdString\n```\n\nIt is worth repeating that in most cases you won't need to set the `Content-Type` header as Karate will automatically do the right thing depending on the data-type of the [`request`](#request).\n\nBecause of how easy it is to set HTTP headers, Karate does not provide any special keywords for things like \nthe [`Accept`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept) header. You simply do \nsomething like this:\n\n```cucumber\nGiven path 'some/path'\nAnd request { some: 'data' }\nAnd header Accept = 'application/json'\nWhen method post\nThen status 200\n```\n\nA common need is to send the same header(s) for _every_ request, and [`configure headers`](#configure-headers) (with JSON) is how you can set this up once for all subsequent requests. And if you do this within a `Background:` section, it would apply to all `Scenario:` sections within the `*.feature` file.\n\n```cucumber\n* configure headers = { 'Content-Type': 'application/xml' }\n```\n\nNote that `Content-Type` had to be enclosed in quotes in the JSON above because the \"`-`\" (hyphen character) would cause problems otherwise. Also note that \"`; charset=UTF-8`\" would be appended to the `Content-Type` header that Karate sends by default, and in some rare cases, you may need to suppress this behavior completely. You can do so by setting the `charset` to null via the [`configure`](#configure) keyword:\n\n```cucumber\n* configure charset = null\n```\n\nIf you need headers to be dynamically generated for each HTTP request, use a JavaScript function with [`configure headers`](#configure-headers) instead of JSON.\n\nMulti-value headers (though rarely used in the wild) are also supported:\n```cucumber\n* header myHeader = ['foo', 'bar']\n```\n\nAlso look at the [`headers`](#headers) keyword which uses JSON and makes some kinds of dynamic data-driven testing easier.\n\n## `cookie`\nSetting a cookie:\n```cucumber\nGiven cookie foo = 'bar'\n```\n\nYou also have the option of setting multiple cookies in one-step using the [`cookies`](#cookies) keyword.\n\nNote that any cookies returned in the HTTP response would be automatically set for any future requests. This mechanism works by calling [`configure cookies`](#configure) behind the scenes and if you need to stop auto-adding cookies for future requests, just do this:\n\n```cucumber\n* configure cookies = null\n```\n\nAlso refer to the built-in variable [`responseCookies`](#responsecookies) for how you can access and perform assertions on cookie data values.\n\n## `form field` \nHTML form fields would be URL-encoded when the HTTP request is submitted (by the [`method`](#method) step). You would typically use these to simulate a user sign-in and then grab a security token from the [`response`](#response).\n\nNote that the `Content-Type` header will be automatically set to: `application/x-www-form-urlencoded`. You just need to do a normal `POST` (or `GET`).\n\nFor example:\n\n```cucumber\nGiven path 'login'\nAnd form field username = 'john'\nAnd form field password = 'secret'\nWhen method post\nThen status 200\nAnd def authToken = response.token\n```\n\nA good example of the use of `form field` for a typical sign-in flow is this OAuth 2 demo: [`oauth2.feature`](karate-demo/src/test/java/demo/oauth/oauth2.feature).\n\nMulti-values are supported the way you would expect (e.g. for simulating check-boxes and multi-selects):\n```cucumber\n* form field selected = ['apple', 'orange']\n```\n\nYou can also dynamically set multiple fields in one step using the [`form fields`](#form-fields) keyword.\n\n## `multipart field`\nUse this for building multipart named (form) field requests. This is typically combined with `multipart file` as shown below.  \n\n\u003e Multiple fields can be set in one step using [`multipart fields`](#multipart-fields).\n\n## `multipart file`\n```cucumber\nGiven multipart file myFile = { read: 'test.pdf', filename: 'upload-name.pdf', contentType: 'application/pdf' }\nAnd multipart field message = 'hello world'\nWhen method post\nThen status 200\n```\n\nIt is important to note that `myFile` above is the \"field name\" within the `multipart/form-data` request payload. This roughly corresponds to a [`cURL`](https://curl.haxx.se/docs/manpage.html#-F) argument of `-F @myFile=test.pdf`.\n\n\u003e `multipart` file uploads can be tricky, and hard to get right. If you get stuck and ask a question on [Stack Overflow](https://stackoverflow.com/questions/tagged/karate), make sure you provide a `cURL` command that works - or else it would be very difficult for anyone to troubleshoot what you could be doing wrong. Also see [this thread](https://github.com/karatelabs/karate/issues/1645#issuecomment-862502881).\n\nAlso note that `multipart file` takes a JSON argument so that you can easily set the `filename` and the `contentType` (mime-type) in one step.\n\n* `read`: the name of a file, and the [`classpath:`](#reading-files) prefix also is allowed. mandatory unless `value` is used, see below.\n* `value`: alternative to `read` in rare cases where something like a JSON or XML file is being uploaded and you want to create it dynamically.\n* `filename`: optional, if not specified there will be no `filename` attribute in `Content-Disposition` \n* `contentType`: optional, will default to `application/octet-stream`\n\nWhen 'multipart' content is involved, the `Content-Type` header of the HTTP request defaults to `multipart/form-data`.\nYou can over-ride it by using the [`header`](#header) keyword before the `method` step.  Look at\n[`multipart entity`](#multipart-entity) for an example.\n\nAlso refer to this [demo example](karate-demo) for a working example of multipart file uploads: [`upload.feature`](karate-demo/src/test/java/demo/upload/upload.feature).\n\nYou can also dynamically set multiple files in one step using [`multipart files`](#multipart-files).\n\n## `multipart entity`\n\u003e This is technically not in the key-value form: `multipart field name = 'foo'`, but logically\nbelongs here in the documentation.\n\nUse this for multipart content items that don't have field-names.  Here below is an example that \nalso demonstrates using the [`multipart/related`](https://tools.ietf.org/html/rfc2387) content-type.\n\n```cucumber\nGiven path 'v2', 'documents'\nAnd multipart entity read('foo.json')\nAnd multipart field image = read('bar.jpg')\nAnd header Content-Type = 'multipart/related'\nWhen method post \nThen status 201\n```\n\n# Multi-Param Keywords\n## Keywords that set multiple key-value pairs in one step\n`params`, `headers`, `cookies`, `form fields`, `multipart fields` and `multipart files` take a single JSON argument (which can be in-line or a variable reference), and this enables certain types of dynamic data-driven testing, especially because any JSON key with a `null` value will be ignored. Here is a good example in the demos: [`dynamic-params.feature`](karate-demo/src/test/java/demo/search/dynamic-params.feature)\n\n## `params`\n```cucumber\n* params { searchBy: 'client', active: true, someList: [1, 2, 3] }\n```\n\nSee also [`param`](#param).\n\n## `headers`\n```cucumber\n* def someData = { Authorization: 'sometoken', tx_id: '1234', extraTokens: ['abc', 'def'] }\n* headers someData\n```\n\nSee also [`header`](#header).\n\n## `cookies`\n```cucumber\n* cookies { someKey: 'someValue', foo: 'bar' }\n```\n\nSee also [`cookie`](#cookie).\n\n## `form fields`\n```cucumber\n* def credentials = { username: '#(user.name)', password: 'secret', projects: ['one', 'two'] }\n* form fields credentials\n```\n\nSee also [`form field`](#form-field).\n\n## `multipart fields`\n```cucumber\nAnd multipart fields { message: 'hello world', json: { foo: 'bar' } }\n```\n\nSee also [`multipart field`](#multipart-field).\n\n## `multipart files`\nThe single JSON argument needs to be in the form `{ field1: { read: 'file1.ext' }, field2: { read: 'file2.ext' } }` where each nested JSON is in the form expected by [`multipart file`](#multipart-file)\n\n```cucumber\n* def json = {}\n* set json.myFile1 = { read: 'test1.pdf', filename: 'upload-name1.pdf', contentType: 'application/pdf' }\n# if you have dynamic keys you can do this\n* def key = 'myFile2'\n* json[key] = { read: 'test2.pdf', filename: 'upload-name2.pdf', contentType: 'application/pdf' }\nAnd multipart files json\n```\n\nFor an example, refer: [`upload-multiple-files.feature`](karate-demo/src/test/java/demo/upload/upload-multiple-files.feature).\n\n# SOAP\nSince a SOAP request needs special handling, this is the only case where the\n[`method`](#method) step is not used to actually fire the request to the server.\n\n## `soap action`\nThe name of the SOAP action specified is used as the 'SOAPAction' header.  Here is an example\nwhich also demonstrates how you could assert for expected values in the response XML.\n```cucumber\nGiven request read('soap-request.xml')\nWhen soap action 'QueryUsageBalance'\nThen status 200\nAnd match response /Envelope/Body/QueryUsageBalanceResponse/Result/Error/Code == 'DAT_USAGE_1003'\nAnd match response /Envelope/Body/QueryUsageBalanceResponse == read('expected-response.xml')\n```\n\nRefer to the [demos](karate-demo) for an example: [`soap.feature`](karate-demo/src/test/java/demo/soap/soap.feature).\n\nMore examples are available that showcase various ways of parameter-izing and dynamically manipulating SOAP requests in a data-driven fashion. Karate is quite flexible, and provides multiple options for you to evolve patterns that fit your environment, as you can see here: [`xml.feature`](karate-core/src/test/java/com/intuit/karate/core/xml/xml.feature).\n\n## `retry until`\nKarate has built-in support for re-trying an HTTP request until a certain condition has been met. The default setting for the max retry-attempts is 3 with a poll interval of 3000 milliseconds (3 seconds). If needed, this can be changed by using [`configure`](#configure) - any time during a test, or set globally via [`karate-config.js`](#configuration)\n\n```cucumber\n* configure retry = { count: 10, interval: 5000 }\n```\n\nThe `retry` keyword is designed to extend the existing [`method`](#method) syntax (and should appear **before** a `method` step) like so:\n\n```cucumber\nGiven url demoBaseUrl\nAnd path 'greeting'\nAnd retry until response.id \u003e 3\nWhen method get\nThen status 200\n```\n\nAny JavaScript expression that uses any variable in scope can be placed after the \"`retry until`\" part. So you can refer to the [`response`](#response), [`responseStatus`](#responsestatus) or even [`responseHeaders`](#responseheaders) if needed. For example:\n\n```cucumber\nGiven url demoBaseUrl\nAnd path 'greeting'\nAnd retry until responseStatus == 200 \u0026\u0026 response.id \u003e 3\nWhen method get\n```\n\n\u003e Note that it has to be a pure JavaScript expression - which means that `match` syntax such as `contains` will *not* work. But you can easily achieve any complex logic by [using the JS API](https://stackoverflow.com/a/55823180/143475).\n\nRefer to [`polling.feature`](karate-demo/src/test/java/demo/polling/polling.feature) for an example, and also see the alternative way to achieve [polling](#polling).\n\n# `configure`\n## Managing Headers, SSL, Timeouts and HTTP Proxy\nYou can adjust configuration settings for the HTTP client used by Karate using this keyword. The syntax is similar to [`def`](#def) but instead of a named variable, you update configuration. Here are the configuration keys supported:\n\n Key | Type | Description\n------ | ---- | ---------\n`url` | string | See [`configure url`](#configure-url)\n`headers` | JSON / JS function | See [`configure headers`](#configure-headers)\n`cookies` | JSON / JS function | Just like `configure headers`, but for cookies. You will typically never use this, as response cookies are auto-added to all future requests. If you need to clear cookies at any time, just do `configure cookies = null`\n`logPrettyRequest` | boolean | Pretty print the request payload JSON or XML with indenting (default `false`)\n`logPrettyResponse` | boolean | Pretty print the response payload JSON or XML with indenting (default `false`)\n`printEnabled` | boolean | Can be used to suppress the [`print`](#print) output when not in 'dev mode' by setting as `false` (default `true`)\n`report` | JSON / boolean | see [report verbosity](#report-verbosity)\n`afterScenario` | JS function | Will be called [after every `Scenario`](#hooks) (or `Example` within a `Scenario Outline`), refer to this example: [`hooks.feature`](karate-demo/src/test/java/demo/hooks/hooks.feature)\n`afterScenarioOutline` | JS function | Will be called [after every `Scenario Outline`](#hooks). Is called after the last `afterScenario` for the last scenario in the outline. Refer to this example: [`hooks.feature`](karate-demo/src/test/java/demo/hooks/hooks.feature)\n`afterFeature` | JS function | Will be called [after every `Feature`](#hooks), refer to this example: [`hooks.feature`](karate-demo/src/test/java/demo/hooks/hooks.feature)\n`ssl` | boolean | Enable HTTPS calls without needing to configure a trusted certificate or key-store.\n`ssl` | string | Like above, but force the SSL algorithm to one of [these values](http://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SSLContext). (The above form internally defaults to `TLS` if simply set to `true`).\n`ssl` | JSON | see [X509 certificate authentication](#x509-certificate-authentication)\n`followRedirects` | boolean | Whether the HTTP client automatically follows redirects - (default `true`), refer to this [example](karate-demo/src/test/java/demo/redirect/redirect.feature).\n`connectTimeout` | integer | Set the connect timeout (milliseconds). The default is 30000 (30 seconds). Note that for `karate-apache`, this sets the [socket timeout](https://stackoverflow.com/a/22722260/143475) to the same value as well.\n`readTimeout` | integer | Set the read timeout (milliseconds). The default is 30000 (30 seconds).\n`proxy` | string | Set the URI of the HTTP proxy to use.\n`proxy` | JSON | For a proxy that requires authentication, set the `uri`, `username` and `password`, see example below. Also a `nonProxyHosts` key is supported which can take a list for e.g. `{ uri: 'http://my.proxy.host:8080',  nonProxyHosts: ['host1', 'host2']}`\n`localAddress` | string | see [`karate-gatling`](karate-gatling#configure-localaddress)\n`charset` | string | The charset that will be sent in the request `Content-Type` which defaults to `utf-8`. You typically never need to change this, and you can over-ride (or disable) this per-request if needed via the [`header`](#header) keyword ([example](karate-demo/src/test/java/demo/headers/content-type.feature)).\n`retry` | JSON | defaults to `{ count: 3, interval: 3000 }` - see [`retry until`](#retry-until)\n`callSingleCache` | JSON | defaults to `{ minutes: 0, dir: 'target' }` - see [`configure callSingleCache`](#configure-callsinglecache)\n`lowerCaseResponseHeaders` | boolean | Converts every key in the [`responseHeaders`](#responseheaders) to lower-case which makes it easier to validate or re-use\n`abortedStepsShouldPass` | boolean | defaults to `false`, whether steps after a [`karate.abort()`](#karate-abort) should be marked as `PASSED` instead of `SKIPPED` - this can impact the behavior of 3rd-party reports, see [this issue](https://github.com/karatelabs/karate/issues/755) for details\n`logModifier` | Java Object | See [Log Masking](#log-masking)\n`responseHeaders` | JSON / JS function | See [`karate-netty`](karate-netty#configure-responseheaders)\n`cors` | boolean | See [`karate-netty`](karate-netty#configure-cors)\n`driver` | JSON | See [UI Automation](karate-core)\n`driverTarget` | JSON / Java Object | See [`configure driverTarget`](karate-core#configure-drivertarget)\n`pauseIfNotPerf` | boolean | defaults to `false`, relevant only for performance-testing, see [`karate.pause()`](#karate-pause) and [`karate-gatling`](karate-gatling#think-time)\n`xmlNamespaceAware` | boolean | defaults to `false`, to handle XML namespaces in [some special circumstances](https://github.com/karatelabs/karate/issues/1587)\n`abortSuiteOnFailure` | boolean | defaults to `false`, to not attempt to run any more tests upon a failure\n`ntlmAuth` | JSON | See [NTLM Authentication](#ntlm-authentication)\n`matchEachEmptyAllowed` | boolean | defaults to `false`, [`match each`](#match-each) by default expects the array to be non-empty, refer to [this issue](https://github.com/karatelabs/karate/issues/2364) to understand why you may want to over-ride this.\n`httpRetryEnabled` | boolean | defaults to `false`, retry when the http requests fails with an exception `org.apache.httpNoHttpResponseException`.  For details see [this issue](https://github.com/karatelabs/karate/issues/2408)\n\nExamples:\n```cucumber\n# pretty print the response payload\n* configure logPrettyResponse = true\n\n# enable ssl (and no certificate is required)\n* configure ssl = true\n\n# enable ssl and force the algorithm to TLSv1.2\n* configure ssl = 'TLSv1.2'\n\n# time-out if the response is not received within 10 seconds (after the connection is established)\n* configure readTimeout = 10000\n\n# set the uri of the http proxy server to use\n* configure proxy = 'http://my.proxy.host:8080'\n\n# proxy which needs authentication\n* configure proxy = { uri: 'http://my.proxy.host:8080', username: 'john', password: 'secret' }\n```\n\n## `configure` globally \nIf you need to set any of these \"globally\" you can easily do so using [the `karate` object](#the-karate-object) in [`karate-config.js`](#configuration) - for e.g:\n\n```js\n  karate.configure('ssl', true);\n  karate.configure('readTimeout', 5000);\n```\n\nIn rare cases where you need to add nested non-JSON data to the `configure` value, you have to play by the [rules](#restrictions-on-global-variables) that apply within [`karate-config.js`](#karate-configjs). Here is an example of performing a [`configure driver`](karate-core#configure-driver) step in JavaScript:\n\n```js\n  var LM = Java.type('com.mycompany.MyHttpLogModifier');\n  var driverConfig = { type:'chromedriver', start: false, webDriverUrl:'https://user:password@zalenium.net/wd/hub' };\n  driverConfig.httpConfig = karate.toMap({ logModifier: LM.INSTANCE });\n  karate.configure('driver', driverConfig);\n```\n\n### Report Verbosity\nBy default, Karate will add logs to the report output so that HTTP requests and responses appear in-line in the HTML reports. There may be cases where you want to suppress this to make the reports \"lighter\" and easier to read.\n\nThe configure key here is `report` and it takes a JSON value. For example:\n\n```cucumber\n* configure report = { showLog: true, showAllSteps: false }\n```\n\n `report` | Type | Description\n------ | ---- | ---------\n`showLog` | boolean | HTTP requests and responses (including headers) will appear in the HTML report, default `true`\n`showAllSteps` | boolean | If `false`, any step that starts with `*` instead of `Given`, `When`, `Then` etc. will *not* appear in the HTML report. The [`print`](#print) step is an exception. Default `true`.\n\nYou can 'reset' default settings by using the following short-cut:\n\n```cucumber\n# reset to defaults\n* configure report = true\n```\n\nSince you can use `configure` any time within a test, you have control over which requests or steps you want to show / hide. This can be convenient if a particular call results in a huge response payload.\n\nThe following short-cut is also supported which will disable all logs:\n\n```cucumber\n* configure report = false\n```\n#### `@report=false`\nWhen you use a re-usable feature that has [commonly used utilities](multiple-functions-in-one-file), you may want to hide this completely from the HTML reports. The special [tag](#tags) `@report=false` can be used, and it can even be used only for a single `Scenario`:\n\n```cucumber\n@ignore @report=false\nFeature:\n\nScenario:\n# some re-usable steps\n```\n\n### Log Masking\nIn cases where you want to \"mask\" values which are sensitive from a security point of view from the output files, logs and HTML reports, you can implement the [`HttpLogModifier`](karate-core/src/main/java/com/intuit/karate/http/HttpLogModifier.java) and tell Karate to use it via the [`configure`](#configure) keyword. Here is an [example](karate-demo/src/test/java/demo/headers/DemoLogModifier.java) of an implementation. For performance reasons, you can implement  `enableForUri()` so that this \"activates\" only for some URL patterns.\n\nInstantiating a Java class and using this in a test is easy (see [example](karate-demo/src/test/java/demo/headers/headers-masking.feature)):\n\n```cucumber\n# if this was in karate-config.js, it would apply \"globally\"\n* def LM = Java.type('demo.headers.DemoLogModifier')\n* configure logModifier = new LM()\n```\n\nOr globally in [`karate-config.js`](#karate-configjs)\n\n```js\nvar LM = Java.type('demo.headers.DemoLogModifier');\nkarate.configure('logModifier', new LM());\n```\n\nSince `karate-config.js` is processed for every `Scenario`, you can use a singleton instead of calling `new` every time. Something like this:\n\n```js\nvar LM = Java.type('demo.headers.DemoLogModifier');\nkarate.configure('logModifier', LM.INSTANCE);\n```\n\n### System Properties for SSL and HTTP proxy\nFor HTTPS / SSL, you can also specify a custom certificate or trust store by [setting Java system properties](https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#InstallationAndCustomization). And similarly - for [specifying the HTTP proxy](https://docs.oracle.com/javase/8/docs/technotes/guides/net/proxies.html).\n\n### X509 Certificate Authentication\nAlso referred to as \"mutual auth\" - if your API requires that clients present an X509 certificate for authentication, Karate supports this via JSON as the `configure ssl` value.  The following parameters are supported:\n\nKey | Type | Required? | Description\n---- | ----- | ------ | ----------\n`keyStore` | string | optional | path to file containing public and private keys for your client certificate.\n`keyStorePassword` | string | optional | password for keyStore file.\n`keyStoreType` | string | optional | Format of the keyStore file.  Allowed keystore types are as described in the [Java `KeyStore` docs](https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#KeyStore).\n`trustStore` | string | optional | path to file containing the trust chain for your server certificate.\n`trustStorePassword` | string | optional | password for trustStore file.\n`trustStoreType` | string | optional | Format of the trustStore file.  Allowed keystore types are as described in the [Java `KeyStore` docs](https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#KeyStore).\n`trustAll` | boolean | optional | if all server certificates should be considered trusted. Default value is `false`. If `true` will allow self-signed certificates. If `false`, will expect the whole chain in the `trustStore` or use what is available in the environment.\n`algorithm` | string | optional | force the SSL algorithm to one of [these values](http://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SSLContext). Default is `TLS`.  \n\nExample:  \n```cucumber\n# enable X509 certificate authentication with PKCS12 file 'certstore.pfx' and password 'certpassword'\n* configure ssl = { keyStore: 'classpath:certstore.pfx', keyStorePassword: 'certpassword', keyStoreType: 'pkcs12' }\n```\n\n```cucumber\n# trust all server certificates, in the feature file\n* configure ssl = { trustAll: true }\n```\n\n```js\n// trust all server certificates, global configuration in 'karate-config.js'\nkarate.configure('ssl', { trustAll: true });\n```\n\nFor end-to-end examples in the Karate demos, look at the files in [this folder](karate-demo/src/test/java/ssl).\n\n### NTLM Authentication\nKarate provides support for NTLM authentication using the Apache NTLMEngine implementation.\n\n| Key           | Type   | Required? | Description                                                    |\n|---------------|--------|-----------|----------------------------------------------------------------|\n| `username`    | string | required  | NTLM username                                                  |\n| `password`    | string | required  | NTLM password                                                  |\n| `workstation` | string | optional  | The workstation the authentication request is originating from |\n| `domain`      | string | optional  | The domain to authenticate within                              |\n\nExample:\n```cucumber\n# enable NTLM authentication for the remaining scenario requests\n* configure ntlmAuth = { username: 'admin', password: 'secret', domain: 'my.domain', workstation: 'my-pc' }\n\n# enable NTLM authentication with only credentials\n* configure ntlmAuth = { username: 'admin', password: 'secret' }\n\n# disable NTLM authentication\n* configure ntlmAuth = null\n```\n\n```js\n// enable NTLM authentication within js\nkarate.confgure('ntlmAuth', { username: 'admin', password: 'secret', domain: 'my.domain', workstation: 'my-pc' })\n```\n\n# Payload Assertions\n## Prepare, Mutate, Assert.\nNow it should be clear how Karate makes it easy to express JSON or XML. If you [read from a file](#reading-files), the advantage is that multiple scripts can re-use the same data.\n\nOnce you have a [JSON or XML object](#native-data-types), Karate provides multiple ways to manipulate, extract or transform data. And you can easily assert that the data is as expected by comparing it with another JSON or XML object.\n\n## `match`\n### Payload Assertions / Smart Comparison\nThe `match` operation is smart because white-space does not matter, and the order of keys (or data elements) does not matter. Karate is even able to [ignore fields you choose](#ignore-or-validate) - which is very useful when you want to handle server-side dynamically generated fields such as UUID-s, time-stamps, security-tokens and the like.\n\nThe match syntax involves a double-equals sign '==' to represent a comparison (and not an assignment '=').\n\nSince `match` and `set` go well together, they are both introduced in the examples in the section below.\n\n## `set`\nGame, `set` and `match` - Karate !\n\n### JS for JSON\nBefore you consider the `set` keyword - note that for simple JSON update operations, you can use [`eval`](#eval) - especially useful when the path you are trying to mutate is dynamic. Since the `eval` keyword can be omitted when operating on variables using JavaScript, this leads to very concise code:\n\n```cucumber\n* def myJson = { a: '1' }\n* myJson.b = 2\n* match myJson == { a: '1', b: 2 }\n```\n\nRefer to [`eval`](#eval) for more / advanced examples.\n\n### Manipulating Data\nSetting values on JSON documents is simple using the `set` keyword.\n\n```cucumber\n* def myJson = { foo: 'bar' }\n* set myJson.foo = 'world'\n* match myJson == { foo: 'world' }\n\n# add new keys.  you can use pure JsonPath expressions (notice how this is different from the above)\n* set myJson $.hey = 'ho'\n* match myJson == { foo: 'world', hey: 'ho' }\n\n# and even append to json arrays (or create them automatically)\n* set myJson.zee[0] = 5\n* match myJson == { foo: 'world', hey: 'ho', zee: [5] }\n\n# omit the array index to append\n* set myJson.zee[] = 6\n* match myJson == { foo: 'world', hey: 'ho', zee: [5, 6] }\n\n# nested json ? no problem\n* set myJson.cat = { name: 'Billie' }\n* match myJson == { foo: 'world', hey: 'ho', zee: [5, 6], cat: { name: 'Billie' } }\n\n# and for match - the order of keys does not matter\n* match myJson == { cat: { name: 'Billie' }, hey: 'ho', foo: 'world', zee: [5, 6] }\n\n# you can ignore fields marked with '#ignore'\n* match myJson == { cat: '#ignore', hey: 'ho', foo: 'world', zee: [5, 6] }\n```\n\nXML and XPath works just like you'd expect.\n```cucumber\n* def cat = \u003ccat\u003e\u003cname\u003eBillie\u003c/name\u003e\u003c/cat\u003e\n* set cat /cat/name = 'Jean'\n* match cat / == \u003ccat\u003e\u003cname\u003eJean\u003c/name\u003e\u003c/cat\u003e\n\n# you can even set whole fragments of xml\n* def xml = \u003cfoo\u003e\u003cbar\u003ebaz\u003c/bar\u003e\u003c/foo\u003e\n* set xml/foo/bar = \u003chello\u003eworld\u003c/hello\u003e\n* match xml == \u003cfoo\u003e\u003cbar\u003e\u003chello\u003eworld\u003c/hello\u003e\u003c/bar\u003e\u003c/foo\u003e\n```\nRefer to the section on [XPath Functions](#xpath-functions) for examples of advanced XPath usage.\n\n### `match` and variables\nIn case you were wondering, variables (and even expressions) are supported on the right-hand-side. So you can compare 2 JSON (or XML) payloads if you wanted to:\n```cucumber\n* def foo = { hello: 'world', baz: 'ban' }\n* def bar = { baz: 'ban', hello: 'world' }\n* match foo == bar\n```\n\nIf you are wondering about the finer details of the `match` syntax, the Left-Hand-Side has to be either a \n* variable name - e.g. `foo`\n* a 'named' JsonPath or XPath expression - e.g. `foo[0].bar` or `foo[*].bar`\n    * note that this cannot be \"dynamic\" (with in-line variables) so [use an extra step](#get) if needed\n* any valid function or method call - e.g. `foo.bar()` or `foo.bar('hello').baz`\n* or anything wrapped in parentheses which will be evaluated as JavaScript - e.g. `(foo + bar)` or `(42)` - and in *this* case, variables can be used\n\nAnd the right-hand-side can be any valid [Karate expression](#karate-expressions). Refer to the section on [JsonPath short-cuts](#jsonpath-short-cuts) for a deeper understanding of 'named' JsonPath expressions in Karate.\n\n### `match !=` (not equals)\nThe 'not equals' operator `!=` works as you would expect:\n\n```cucumber\n* def test = { foo: 'bar' }\n* match test != { foo: 'baz' }\n```\n\n\u003e You typically will *never* need to use the `!=` (not-equals) operator ! Use it sparingly, and only for string, number or simple payload comparisons.\n\n### `set` multiple\nKarate has an elegant way to set multiple keys (via path expressions) in one step. For convenience, non-existent keys (or array elements) will be created automatically. You can find more JSON examples here: [`js-arrays.feature`](karate-core/src/test/java/com/intuit/karate/core/js-arrays.feature).\n\n```cucumber\n* def cat = { name: '' }\n\n* set cat\n  | path   | value |\n  | name   | 'Bob' |\n  | age    | 5     |\n\n* match cat == { name: 'Bob', age: 5 }\n```\n\nOne extra convenience for JSON is that if the variable itself (which was `cat` in the above example) does not exist, it will be created automatically. You can even create (or modify existing) JSON arrays by using multiple columns.\n\n```cucumber\n* set foo\n  | path | 0     | 1     |\n  | bar  | 'baz' | 'ban' |\n\n* match foo == [{ bar: 'baz' }, { bar: 'ban' }]\n```\n\nIf you have to set a bunch of deeply nested keys, you can move the parent path to the top, next to the `set` keyword and save a lot of typing ! Note that this is not supported for \"arrays\" like above, and you can have only one `value` column.\n\n```cucumber\n* set foo.bar\n  | path   | value |\n  | one    | 1     |\n  | two[0] | 2     |\n  | two[1] | 3     |\n\n* match foo == { bar: { one: 1, two: [2, 3] } }\n```\n\nThe same concept applies to XML and you can build complicated payloads from scratch in just a few, extremely readable lines. The `value` column can take expressions, *even* XML chunks. You can find more examples here: [`xml.feature`](karate-core/src/test/java/com/intuit/karate/core/xml/xml.feature).\n\n```cucumber\n* set search /acc:getAccountByPhoneNumber\n  | path                        | value |\n  | acc:phone/@foo              | 'bar' |\n  | acc:phone/acc:number[1]     | 1234  |\n  | acc:phone/acc:number[2]     | 5678  |     \n  | acc:phoneNumberSearchOption | 'all' |\n\n* match search ==\n  \"\"\"\n  \u003cacc:getAccountByPhoneNumber\u003e\n      \u003cacc:phone foo=\"bar\"\u003e\n          \u003cacc:number\u003e1234\u003c/acc:number\u003e\n          \u003cacc:number\u003e5678\u003c/acc:number\u003e\n      \u003c/acc:phone\u003e\n      \u003cacc:phoneNumberSearchOption\u003eall\u003c/acc:phoneNumberSearchOption\u003e        \n  \u003c/acc:getAccountByPhoneNumber\u003e\n  \"\"\"\n```\n\n## `remove`\nThis is like the opposite of [`set`](#set) if you need to remove keys or data elements from JSON or XML instances. You can even remove JSON array elements by index.\n```cucumber\n* def json = { foo: 'world', hey: 'ho', zee: [1, 2, 3] }\n* remove json.hey\n* match json == { foo: 'world', zee: [1, 2, 3] }\n* remove json $.zee[1]\n* match json == { foo: 'world', zee: [1, 3] }\n```\n\n`remove` works for XML elements as well:\n```cucumber\n* def xml = \u003cfoo\u003e\u003cbar\u003e\u003chello\u003eworld\u003c/hello\u003e\u003c/bar\u003e\u003c/foo\u003e\n* remove xml/foo/bar/hello\n* match xml == \u003cfoo\u003e\u003cbar/\u003e\u003c/foo\u003e\n* remove xml /foo/bar\n* match xml == \u003cfoo/\u003e\n```\n\nAlso take a look at how a special case of [embedded-expressions](#embedded-expressions) can remove key-value pairs from a JSON (or XML) payload: [Remove if Null](#remove-if-null).\n\nSee also `delete`, below.\n\n### `delete`\nFor JSON, you can also use the JS [`delete`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete) operator via [`eval`](#eval), useful when the path you are trying to mutate is dynamic.\n\n```cucumber\n* def key = 'a'\n* def foo = { a: 1 }\n* eval delete foo[key]\n```\nAs a convenience, you can omit the `eval`:\n\n```cucumber\n* delete foo[key]\n```\n\n## Fuzzy Matching\n### Ignore or Validate\nWhen expressing expected results (in JSON or [XML](#match-and-xml)) you can mark some fields to be ignored when the match (comparison) is performed.  You can even use a regular-expression so that instead of checking for equality, Karate will just validate that the actual value conforms to the expected pattern.\n\nThis means that even when you have dynamic server-side generated values such as UUID-s and time-stamps appearing in the response, you can still assert that the full-payload matched in one step.\n\n```cucumber\n* def cat = { name: 'Billie', type: 'LOL', id: 'a9f7a56b-8d5c-455c-9d13-808461d17b91' }\n* match cat == { name: '#ignore', type: '#regex [A-Z]{3}', id: '#uuid' }\n# this will fail\n# * match cat == { name: '#ignore', type: '#regex .{2}', id: '#uuid' }\t\n```\n\n\u003e Note that regex escaping has to be done with a *double* back-slash - for e.g: `'#regex a\\\\.dot'` will match `'a.dot'`\n\nThe supported markers are the following:\n\nMarker | Description\n------ | -----------\n`#ignore` | Skip comparison for this field even if the data element or JSON key is present\n`#null` | Expects actual value to be `null`, and the data element or JSON key *must* be present\n`#notnull` | Expects actual value to be not-`null`\n`#present` | Actual value can be any type or *even* `null`, but the key *must* be present (only for JSON / XML, see below)\n`#notpresent` | Expects the key to be **not** present at all (only for JSON / XML, see below)\n`#array` | Expects actual value to be a JSON array\n`#object` | Expects actual value to be a JSON object\n`#boolean` | Expects actual value to be a boolean `true` or `false`\n`#number` | Expects actual value to be a number\n`#string` | Expects actual value to be a string\n`#uuid` | Expects actual (string) value to conform to the UUID format\n`#regex STR` | Expects actual (string) value to match the regular-expression 'STR' (see examples above)\n`#? EXPR` | Expects the JavaScript expression 'EXPR' to evaluate to true, see [self-validation expressions](#self-validation-expressions) below\n`#[NUM] EXPR` | Advanced array validation, see [schema validation](#schema-validation)\n`#(EXPR)` | For completeness, [embedded expressions](#embedded-expressions) belong in this list as well\n\nNote that `#present` and `#notpresent` only make sense when you are matching within a JSON or XML context or using a JsonPath or XPath on the left-hand-side.\n```cucumber\n* def json = { foo: 'bar' }\n* match json == { foo: '#present' }\n* match json.nope == '#notpresent'\n```\n\nThe rest can also be used even in 'primitive' data matches like so:\n```cucumber\n* match foo == '#string'\n# convenient (and recommended) way to check for array length\n* match bar == '#[2]'\n```\n\n### Optional Fields\nIf two cross-hatch `#` symbols are used as the prefix (for example: `##number`), it means that the key is optional or that the value can be null.\n```cucumber\n* def foo = { bar: 'baz' }\n* match foo == { bar: '#string', ban: '##string' }\n```\n\n### Remove If Null\nA very useful behavior when you combine the optional marker with an [embedded expression](#embedded-expressions) is as follows: if the embedded expression evaluates to `null` - the JSON key (or XML element or attribute) will be deleted from the payload (the equivalent of [`remove`](#remove)).\n\n```cucumber\n* def data = { a: 'hello', b: null, c: null }\n* def json = { foo: '#(data.a)', bar: '#(data.b)', baz: '##(data.c)' }\n* match json == { foo: 'hello', bar: null }\n```\n\nIf you are just trying to pre-define schema snippets to use in a [fuzzy-match](#fuzzy-matching), you can use [enclosed Javascript](#enclosed-javascript) to suppress the default behavior of replacing placeholders. For example:\n\n```cucumber\n* def dogSchema = { id: '#string', color: '#string' }\n# here we enclose in round-brackets to preserve the optional embedded expression\n# so that it can be used later in a \"match\"\n* def schema = ({ id: '#string', name: '#string', dog: '##(dogSchema)' })\n\n* def response1 = { id: '123', name: 'foo' }\n* match response1 == schema\n```\n\nAnd if you need to suppress placeholder substitution for [`read()`](#reading-files), but still need a JSON snippet, you can do this. Note how we read as a string, but [\"cast\" to JSON](#type-conversion):\n\n```cucumber\n* json schema = karate.readAsString('schema.json')\n```\n\nIf you want to use the triple-quote / multi-line way of defining JSON or if you have to use XML - you can use [`text`](#text) and \"cast\" to JSON or XML as a second step -  before using in a [`match`](#match):\n\n```cucumber\n* text schema =\n\"\"\"\n\u003croot\u003e\n  \u003ca\u003e#string\u003c/a\u003e\n  \u003cb\u003e##(subSchema)\u003c/b\u003e\n\u003c/root\u003e\n\"\"\"\n* xml schema = schema\n```\n\n### `#null` and `#notpresent`\nKarate's [`match`](#match) is strict, and the case where a JSON key exists but has a `null` value (`#null`) is considered different from the case where the key is not present at all (`#notpresent`) in the payload.\n\nBut note that `##null` can be used to represent a convention that many teams adopt, which is that keys with `null` values are stripped from the JSON payload. In other words, `{ a: 1, b: null }` is considered 'equal' to `{ a: 1 }` and `{ a: 1, b: '##null' }` will `match` both cases.\n\nThese examples (all exact matches) can make things more clear:\n\n```cucumber\n* def foo = { }\n* match foo == { a: '##null' }\n* match foo == { a: '##notnull' }\n* match foo == { a: '#notpresent' }\n* match foo == { a: '#ignore' }\n\n* def foo = { a: null }\n* match foo == { a: '#null' }    \n* match foo == { a: '##null' }\n* match foo == { a: '#present' }\n* match foo == { a: '#ignore' }\n\n* def foo = { a: 1 }\n* match foo == { a: '#notnull' }\n* match foo == { a: '##notnull' }\n* match foo == { a: '#present' }\n* match foo == { a: '#ignore' }\n```\n\nNote that you can alternatively use JsonPath on the left-hand-side:\n\n```cucumber\n* def foo = { a: 1 }\n* match foo.a == '#present'\n* match foo.nope == '#notpresent'\n```\n\nBut of course it is preferable to match whole objects in one step as far as possible.\n\n### 'Self' Validation Expressions\nThe special 'predicate' marker `#? EXPR` in the table above is an interesting one.  It is best explained via examples. Any valid JavaScript expression that evaluates to a [Truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy) or [Falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy) value is expected after the `#?`.\n\nObserve how the value of the field being validated (or 'self') is injected into the 'underscore' expression variable: '`_`'\n```cucumber\n* def date = { month: 3 }\n* match date == { month: '#? _ \u003e 0 \u0026\u0026 _ \u003c 13' }\n```\n\nWhat is even more interesting is that expressions can refer to variables:\n```cucumber\n* def date = { month: 3 }\n* def min = 1\n* def max = 12\n* match date == { month: '#? _ \u003e= min \u0026\u0026 _ \u003c= max' }\n```\n\nAnd functions work as well ! You can imagine how you could evolve a nice set of utilities that validate all your domain objects.\n```cucumber\n* def date = { month: 3 }\n* def isValidMonth = function(m) { return m \u003e= 1 \u0026\u0026 m \u003c= 12 }\n* match date == { month: '#? isValidMonth(_)' }\n```\n\nEspecially since strings can be easily coerced to numbers (and vice-versa) in Javascript, you can combine built-in validators with the self-validation 'predicate' form like this: `'#number? _ \u003e 0'`\n\n```cucumber\n# given this invalid input (string instead of number)\n* def date = { month: '3' }\n# this will pass\n* match date == { month: '#? _ \u003e 0' }\n# but this 'combined form' will fail, which is what we want\n# * match date == { month: '#number? _ \u003e 0' }\n```\n\n#### Referring to the JSON root\nYou can actually refer to any JsonPath on the document via `$` and perform cross-field or conditional validations ! This example uses [`contains`](#match-contains) and the [`#?`](#self-validation-expressions) 'predicate' syntax, and situations where this comes in useful will be apparent when we discuss [`match each`](#match-each).\n\n```cucumber\nGiven def temperature = { celsius: 100, fahrenheit: 212 }\nThen match temperature == { celsius: '#number', fahrenheit: '#? _ == $.celsius * 1.8 + 32' }\n# when validation logic is an 'equality' check, an embedded expression works better\nThen match temperature contains { fahrenheit: '#($.celsius * 1.8 + 32)' }\n```\n\n### `match` text or binary\n```cucumber\n# when the response is plain-text\nThen match response == 'Health Check OK'\nAnd match response != 'Error'\n\n# when the response is binary (byte-array)\nThen match responseBytes == read('test.pdf')\n\n# incidentally, match and assert behave exactly the same way for strings\n* def hello = 'Hello World!'\n* match hello == 'Hello World!'\n* assert hello == 'Hello World!'\n```\n\nChecking if a string is contained within another string is a very common need and [`match` (name) `contains`](#match-contains) works just like you'd expect:\n```cucumber\n* def hello = 'Hello World!'\n* match hello contains 'World'\n* match hello !contains 'blah'\n```\n\nFor case-insensitive string comparisons, see how to create [custom utilities](#commonly-needed-utilities) or [`karate.lowerCase()`](#karate-lowercase). And for dealing with binary content - see [`bytes`](#type-bytes).\n\n### `match header`\nSince asserting against header values in the response is a common task - `match header` has a special meaning.  It short-cuts to the pre-defined variable [`responseHeaders`](#responseheaders) and reduces some complexity - because strictly, HTTP headers are a 'multi-valued map' or a 'map of lists' - the Java-speak equivalent being `Map\u003cString, List\u003cString\u003e\u003e`. And since header names are case-insensitive - it ignores the case when finding the header to match.\n\n```cucumber\n# so after a http request\nThen match header Content-Type == 'application/json'\n# 'contains' works as well\nThen match header Content-Type contains 'application'\n```  \nNote the extra convenience where you don't have to enclose the LHS key in quotes.\n\nYou can always directly access the variable called [`responseHeaders`](#responseheaders) if you wanted to do more checks, but you typically won't need to.\n\n### `match` and XML\nAll the [fuzzy matching](#fuzzy-matching) markers will work in XML as well. Here are some examples:\n\n```cucumber\n  * def xml = \u003croot\u003e\u003chello\u003eworld\u003c/hello\u003e\u003cfoo\u003ebar\u003c/foo\u003e\u003c/root\u003e\n  * match xml == \u003croot\u003e\u003chello\u003eworld\u003c/hello\u003e\u003cfoo\u003e#ignore\u003c/foo\u003e\u003c/root\u003e\n  * def xml = \u003croot\u003e\u003chello foo=\"bar\"\u003eworld\u003c/hello\u003e\u003c/root\u003e\n  * match xml == \u003croot\u003e\u003chello foo=\"#ignore\"\u003eworld\u003c/hello\u003e\u003c/root\u003e\n```\n\nRefer to this file for a comprehensive set of XML examples: [`xml.feature`](karate-core/src/test/java/com/intuit/karate/core/xml/xml.feature).\n\n## Matching Sub-Sets of JSON Keys and Arrays\n### `match contains`\n#### JSON Keys\nIn some cases where the response JSON is wildly dynamic, you may want to only check for the existence of some keys. And `match` (name) `contains` is how you can do so:\n\n```cucumber\n* def foo = { bar: 1, baz: 'hello', ban: 'world' }\n\n* match foo contains { bar: 1 }\n* match foo contains { baz: 'hello' }\n* match foo contains { bar:1, baz: 'hello' }\n# this will fail\n# * match foo == { bar:1, baz: 'hello' }\n```\n\nNote that `match contains` will *not* \"recurse\" any nested JSON chunks so use [`match contains deep`](#match-contains-deep) instead.\n\nAlso note that [`match contains any`](#match-contains-any) is possible for JSON objects as well as [JSON arrays](#json-arrays).\n\n### (not) `!contains`\nIt is sometimes useful to be able to check if a key-value-pair does **not** exist. This is possible by prefixing `contains` with a `!` (with no space in between).\n\n```cucumber\n* def foo = { bar: 1, baz: 'hello', ban: 'world' }\n* match foo !contains { bar: 2 }\n* match foo !contains { huh: '#notnull' }\n```\n\nHere's a reminder that the [`#notpresent`](#null-and-notpresent) marker can be mixed into an equality `match` (`==`) to assert that some keys exist and at the same time ensure that some keys do **not** exist:\n\n```cucumber\n* def foo = { a: 1 }\n* match foo == { a: '#number', b: '#notpresent' }\n\n# if b can be present (optional) but should always be null\n* match foo == { a: '#number', b: '##null' }\n```\n\nThe `!` (not) operator is especially useful for `contains` and JSON arrays.\n\n```cucumber\n* def foo = [1, 2, 3]\n* match foo !contains 4\n* match foo !contains [5, 6]\n```\n\n#### JSON Arrays\nThis is a good time to deep-dive into JsonPath, which is perfect for slicing and dicing JSON into manageable chunks. It is worth taking a few minutes to go through the documentation and examples here: [JsonPath Examples](https://github.com/jayway/JsonPath#path-examples).\n\nHere are some example assertions performed while scraping a list of child elements out of the JSON below. Observe how you can `match` the result of a JsonPath expression with your expected data.\n\n```cucumber\nGiven def cat = \n  \"\"\"\n  {\n    name: 'Billie',\n    kittens: [\n      { id: 23, name: 'Bob' },\n      { id: 42, name: 'Wild' }\n    ]\n  }\n  \"\"\"\n# normal 'equality' match. note the wildcard '*' in the JsonPath (returns an array)\nThen match cat.kittens[*].id == [23, 42]\n\n# when inspecting a json array, 'contains' just checks if the expected items exist\n# and the size and order of the actual array does not matter\nThen match cat.kittens[*].id contains 23\nThen match cat.kittens[*].id contains [42]\nThen match cat.kittens[*].id contains [23, 42]\nThen match cat.kittens[*].id contains [42, 23]\n\n# the .. operator is great because it matches nodes at any depth in the JSON \"tree\"\nThen match cat..name == ['Billie', 'Bob', 'Wild']\n\n# and yes, you can assert against nested objects within JSON arrays !\nThen match cat.kittens contains [{ id: 42, name: 'Wild' }, { id: 23, name: 'Bob' }]\n\n# ... and even ignore fields at the same time !\nThen match cat.kittens contains { id: 42, name: '#string' }\n```\n\nIt is worth mentioning that to do the equivalent of the last line in Java, you would typically have to traverse 2 Java Objects, one of which is within a list, and you would have to check for nulls as well.\n\nWhen you use Karate, all your data assertions can be done in pure JSON and without needing a thick forest of companion Java objects. And when you [`read`](#read) your JSON objects from (re-usable) files, even complex response payload assertions can be accomplished in just a single line of Karate-script.\n\nRefer to this [case study](https://twitter.com/KarateDSL/status/873035687817117696) for how dramatic the reduction of lines of code can be.\n\n#### `match contains only`\nFor those cases where you need to assert that **all** array elements are present but in **any order**\nyou can do this:\n\n```cucumber\n* def data = { foo: [1, 2, 3] }\n* match data.foo contains 1\n* match data.foo contains [2]\n* match data.foo contains [3, 2]\n* match data.foo contains only [3, 2, 1]\n* match data.foo contains only [2, 3, 1]\n# this will fail\n# * match data.foo contains only [2, 3]\n```\n\n#### `match contains any`\nTo assert that **any** of the given array elements are present.\n\n```cucumber\n* def data = { foo: [1, 2, 3] }\n* match data.foo contains any [9, 2, 8]\n```\n\nAnd this happens to work as expected for JSON object keys as well:\n\n```cucumber\n* def data = { a: 1, b: 'x' }\n* match data contains any { b: 'x', c: true }\n```\n\n#### `match contains deep`\nThis modifies the behavior of [`match contains`](#match-contains) so that nested lists or objects are processed for a \"deep contains\" match instead of a \"deep equals\" one which is the default. This is convenient for complex nested payloads where you are sure that you only want to check for *some* values in the various \"trees\" of data.\n\nHere is an example:\n\n```cucumber\nScenario: recurse nested json\n  * def original = { a: 1, b: 2, c: 3, d: { a: 1, b: 2 } }\n  * def expected = { a: 1, c: 3, d: { b: 2 } }\n  * match original contains deep expected\n\nScenario: recurse nested array\n  * def original = { a: 1, arr: [ { b: 2, c: 3 }, { b: 3, c: 4 } ] }\n  * def expected = { a: 1, arr: [ { b: 2 }, { c: 4 } ] }\n  * match original contains deep expected\n```\n\n\u003e the NOT operator e.g. `!contains deep` is not yet supported, please contribute code if you can.\n\n#### `match contains only deep`\nThis is exactly like [`match ==`](#match) but the order of arrays does not matter. All arrays no matter the \"depth\" will be checked in this way.\n\n```cucumber\n* def response = { foo: [ 'a', 'b' ] }\n* match response contains only deep { foo: [ 'b', 'a' ] }\n```\n\n## Validate every element in a JSON array\n### `match each`\nThe `match` keyword can be made to iterate over all elements in a JSON array using the `each` modifier. Here's how it works:\n```cucumber\n* def data = { foo: [{ bar: 1, baz: 'a' }, { bar: 2, baz: 'b' }, { bar: 3, baz: 'c' }]}\n\n* match each data.foo == { bar: '#number', baz: '#string' }\n\n# and you can use 'contains' the way you'd expect\n* match each data.foo contains { bar: '#number' }\n* match each data.foo contains { bar: '#? _ != 4' }\n\n# some more examples of validation macros\n* match each data.foo contains { baz: \"#? _ != 'z'\" }\n* def isAbc = function(x) { return x == 'a' || x == 'b' || x == 'c' }\n* match each data.foo contains { baz: '#? isAbc(_)' }\n\n# this is also possible, see the subtle difference from the above\n* def isXabc = function(x) { return x.baz == 'a' || x.baz == 'b' || x.baz == 'c' }\n* match each data.foo == '#? isXabc(_)'\n``` \n\nHere is a contrived example that uses `match each`, [`contains`](#match-contains) and the [`#?`](#self-validation-expressions) 'predicate' marker to validate that the value of `totalPrice` is always equal to the `roomPrice` of the first item in the `roomInformation` array.\n\n```cucumber\nGiven def json =\n  \"\"\"\n  {\n    \"hotels\": [\n      { \"roomInformation\": [{ \"roomPrice\": 618.4 }], \"totalPrice\": 618.4  },\n      { \"roomInformation\": [{ \"roomPrice\": 679.79}], \"totalPrice\": 679.79 }\n    ]\n  }\n  \"\"\"\nThen match each json.hotels contains { totalPrice: '#? _ == _$.roomInformation[0].roomPrice' }\n# when validation logic is an 'equality' check, an embedded expression works better\nThen match each json.hotels contains { totalPrice: '#(_$.roomInformation[0].roomPrice)' }\n```\n\n#### Referring to self\nWhile [`$`](#referring-to-the-json-root) always refers to the [JSON 'root'](#referring-to-the-json-root), note the use of `_$` above to represent the 'current' node of a `match each` iteration. Here is a recap of symbols that can be used in JSON [embedded expressions](#embedded-expressions):\n\nSymbol  | Evaluates To\n------- | ------                               \n| `$`   | The ['root'](#referring-to-the-json-root) of the JSON document in scope          \n| `_`   | The value of ['self'](#self-validation-expressions)\n| `_$`  | The 'parent' of 'self' or 'current' item in the list, relevant when using [`match each`](#match-each)\n\nThere is a shortcut for `match each` explained in the next section that can be quite useful, especially for 'in-line' schema-like validations.\n\n#### `match each contains deep`\n`match each` can be combined with `contains deep` so that for each JSON object  a “deep contains” match is performed within nested lists or objects. \n\nThis is useful for testing payloads with JSON arrays whose members have a few essential keys that you wish to validate. \n\n```cucumber\n  Given def response = \n  \"\"\"\n  [\n    {\n      \"a\": 1,\n      \"arr\": [\n          {\n              \"b\": 2,\n              \"c\": 3\n          }\n      ]\n    },\n    {\n      \"a\": 1,\n      \"arr\": [\n          {\n              \"b\": 2,\n              \"c\": 3\n          },\n          {\n              \"b\": 4,\n              \"c\": 5\n          }\n      ]\n    }\n  ]\n  \"\"\"\n  Then match each response contains deep { a: 1, arr: [ { b: 2 } ] }\n```\n\n## Schema Validation\nKarate provides a far more simpler and more powerful way than [JSON-schema](http://json-schema.org) to validate the structure of a given payload. You can even mix domain and conditional validations and perform all assertions in a single step.\n\nBut first, a special short-cut for array validation needs to be introduced:\n\n```cucumber\n* def foo = ['bar', 'baz']\n\n# should be an array\n* match foo == '#[]'\n\n# should be an array of size 2\n* match foo == '#[2]'\n\n# should be an array of strings with size 2\n* match foo == '#[2] #string'\n\n# each array element should have a 'length' property with value 3\n* match foo == '#[]? _.length == 3'\n\n# should be an array of strings each of length 3\n* match foo == '#[] #string? _.length == 3'\n\n# should be null or an array of strings\n* match foo == '##[] #string'\n```\n\nThis 'in-line' short-cut for validating JSON arrays is similar to how [`match each`](#match-each) works. So now, complex payloads (that include arrays) can easily be validated in one step by combining [validation markers](#ignore-or-validate) like so:\n\n```cucumber\n* def oddSchema = { price: '#string', status: '#? _ \u003c 3', ck: '##number', name: '#regex[0-9X]' }\n* def isValidTime = read('time-validator.js')\nWhen method get\nThen match response ==\n  \"\"\"\n  { \n    id: '#regex[0-9]+',\n    count: '#number',\n    odd: '#(oddSchema)',\n    data: { \n      countryId: '#number', \n      countryName: '#string', \n      leagueName: '##string', \n      status: '#number? _ \u003e= 0', \n      sportName: '#string',\n      time: '#? isValidTime(_)'\n    },\n    odds: '#[] oddSchema'  \n  }\n  \"\"\"\n```\n\nEspecially note the re-use of the `oddSchema` both as an [embedded-expression](#embedded-expressions) and as an array validation (on the last line).\n\nAnd you can perform conditional / [cross-field validations](#referring-to-the-json-root) and even business-logic validations at the same time.\n\n```cucumber\n# optional (can be null) and if present should be an array of size greater than zero\n* match $.odds == '##[_ \u003e 0]'\n\n# should be an array of size equal to $.count\n* match $.odds == '#[$.count]'\n\n# use a predicate function to validate each array element\n* def isValidOdd = function(o){ return o.name.length == 1 }\n* match $.odds == '#[]? isValidOdd(_)'\n```\n\nRefer to this for the complete example: [`schema-like.feature`](karate-core/src/test/java/com/intuit/karate/core/schema-like.feature)\n\nAnd there is another example in the [karate-demos](karate-demo): [`schema.feature`](karate-demo/src/test/java/demo/schema/schema.feature) where you can compare Karate's approach with an actual JSON-schema example. You can also find a nice visual comparison and explanation [here](https://twitter.com/KarateDSL/status/878984854012022784).\n\n### `contains` short-cuts\nEspecially when payloads are complex (or highly dynamic), it may be more practical to use [`contains`](#match-contains) semantics. Karate has the following short-cut symbols designed to be mixed into [`embedded expressions`](#embedded-expressions):\n\nSymbol  | Means\n------- | ------                               \n| `^`   | [`contains`](#match-contains)           \n| `^^`  | [`contains only`](#match-contains-only) \n| `^*`  | [`contains any`](#match-contains-any) \n| `^+`  | [`contains deep`](#match-contains-deep)\n| `!^`  | [`not contains`](#not-contains)\n\n\u003e For completeness, [`==`](#match) and [`!=`](#match--not-equals) also belong in the above list.\n\nHere'a table of the alternative 'in-line' forms compared with the 'standard' form. Note that *all* the short-cut forms on the right-side of the table resolve to 'equality' (`==`) matches, which enables them to be 'in-lined' into a _full_ (single-step) payload `match`, using [embedded expressions](#embedded-expressions).\n\n\u003ca href=\"https://gist.github.com/ptrthomas/2a1e30bcb4d782279019b3d5c10b3ed1\"\u003e\u003cimg src=\"karate-demo/src/test/resources/karate-json-assertions.jpg\" height=\"690px\"/\u003e\u003c/a\u003e\n\nA very useful capability is to be able to check that an array `contains` an object that `contains` the provided *sub-set* of keys instead of having to specify the *complete* JSON - which can get really cumbersome for large objects. This turns out to be very useful in practice, and this particular `match` *jsonArray* `contains '#(^`*partialObject*`)'` form has no 'in-line' equivalent (see the third-from-last row above).\n\n\u003e The last row in the table is a little different from the rest, and this short-cut form is the recommended way to validate the length of a JSON array. As a rule of thumb, prefer [`match`](#match) over [`assert`](#assert), because `match` failure messages are more detailed and descriptive.\n\nIn real-life tests, these are very useful when the order of items in arrays returned from the server are not guaranteed. You can easily assert that all expected elements are present, _even_ in nested parts of your JSON - while doing a [`match`](#match) on the _full_ payload.\n\n```cucumber\n* def cat = \n  \"\"\"\n  {\n    name: 'Billie',\n    kittens: [\n      { id: 23, name: 'Bob' },\n      { id: 42, name: 'Wild' }\n    ]\n  }\n  \"\"\"\n* def expected = [{ id: 42, name: 'Wild' }, { id: 23, name: 'Bob' }]\n* match cat == { name: 'Billie', kittens: '#(^^expected)' }\n```\n\nThere's a lot going on in the last line above ! It validates the entire payload in one step and checks if the `kittens` array [_**contains all**_](#contains-short-cuts)  the `expected` items but in _**any order**_.\n\n## `get`\nBy now, it should be clear that [JsonPath]((https://github.com/jayway/JsonPath#path-examples)) can be very useful for extracting JSON 'trees' out of a given object. The `get` keyword allows you to save the results of a JsonPath expression for later use - which is especially useful for dynamic [data-driven testing](#data-driven-features).\n\n```cucumber\n* def cat = \n  \"\"\"\n  {\n    name: 'Billie',\n    kittens: [\n      { id: 23, name: 'Bob' },\n      { id: 42, name: 'Wild' }\n    ]\n  }\n  \"\"\"\n* def kitnums = get cat.kittens[*].id\n* match kitnums == [23, 42]\n* def kitnames = get cat $.kittens[*].name\n* match kitnames == ['Bob', 'Wild']\n```\n\n### `get` short-cut\nThe 'short cut' `$variableName` form is also supported. Refer to [JsonPath short-cuts](#jsonpath-short-cuts) for a detailed explanation. So the above could be re-written as follows:\n\n```cucumber\n* def kitnums = $cat.kittens[*].id\n* match kitnums == [23, 42]\n* def kitnames = $cat.kittens[*].name\n* match kitnames == ['Bob', 'Wild']\n```\n\nIt is worth repeating that the above can be condensed into 2 lines. Note that since [only JsonPath is expected](#match-and-variables) on the left-hand-side of the `==` sign of a [`match`](#match) statement, you don't need to prefix the variable reference with `$`:\n\n```cucumber\n* match cat.kittens[*].id == [23, 42]\n* match cat.kittens[*].name == ['Bob', 'Wild']\n\n# if you prefer using 'pure' JsonPath, you can do this\n* match cat $.kittens[*].id == [23, 42]\n* match cat $.kittens[*].name == ['Bob', 'Wild']\n```\n\n### `get` plus index\nA convenience that the `get` syntax supports (but not the `$` short-cut form) is to return a single element if the right-hand-side evaluates to a list-like result (e.g. a JSON array). This is useful because the moment you use a wildcard `[*]` or search filter in JsonPath (see the next section), you get an *array* back - even though typically you would only be interested in the *first* item.\n\n```cucumber\n* def actual = 23\n\n# so instead of this\n* def kitnums = get cat.kittens[*].id\n* match actual == kitnums[0]\n\n# you can do this in one line\n* match actual == get[0] cat.kittens[*].id\n```\n\n### JsonPath filters\nJsonPath [filter expressions](https://github.com/json-path/JsonPath#filter-operators) are very useful for extracting elements that meet some filter criteria out of arrays.\n\n```cucumber\n* def cat = \n  \"\"\"\n  {\n    name: 'Billie',\n    kittens: [\n      { id: 23, name: 'Bob' },\n      { id: 42, name: 'Wild' }\n    ]\n  }\n  \"\"\"\n# find single kitten where id == 23\n* def bob = get[0] cat.kittens[?(@.id==23)]\n* match bob.name == 'Bob'\n\n# using the karate object if the expression is dynamic\n* def temp = karate.jsonPath(cat, \"$.kittens[?(@.name=='\" + bob.name + \"')]\")\n* match temp[0] == bob\n\n# or alternatively\n* def temp = karate.jsonPath(cat, \"$.kittens[?(@.name=='\" + bob.name + \"')]\")[0]\n* match temp == bob\n```\n\nYou usually won't need this, but the second-last line above shows how the `karate` object can be used to [evaluate JsonPath](#karate-jsonpath) if the filter expression depends on a variable. If you find yourself struggling to write [dynamic JsonPath filters](https://stackoverflow.com/a/52741196/143475), look at [`karate.filter()`](#karate-filter) as an alternative, described just below.\n\n## JSON Transforms\nKarate supports the following [functional-style](https://en.wikipedia.org/wiki/Functional_programming) operations via the JS API -  [`karate.map()`](#karate-map), [`karate.filter()`](#karate-filter) and [`karate.forEach()`](#karate-foreach). They can be very useful in some situations. A [good example](https://stackoverflow.com/a/53120851/143475) is when you have the *expected* data available as ready-made JSON but it is in a different \"shape\" from the *actual* data or HTTP `response`. There is also a [`karate.mapWithKey()`](#karate-mapwithkey) for a common need - which is to convert an array of primitives into an array of objects, which is the form that [data driven features](#data-driven-features) expect.\n\nThe Graal JS engine that Karate uses supports the full ES6 spec, which means that JSON variables are first-class JS objects, and arrays can be *directly* looped over or manipulated using [`map()`, `filter()` and `forEach()`](https://stackoverflow.com/a/76091034/143475). And JS \"arrow functions\" are supported, which makes code much more concise.\n\nA few more useful \"transforms\" are to select a sub-set of key-value pairs using [`karate.filterKeys()`](#karate-filterkeys), merging 2 or more JSON-s using [`karate.merge()`](#karate-merge) and combining 2 or more arrays (or objects) into a single array using [`karate.append()`](#karate-append). And [`karate.appendTo()`](#karate-appendto) is for updating an existing variable (the equivalent of `array.push()` in JavaScript), which is especially useful in the body of a `karate.forEach()`.\n\nYou can also sort arrays of arbitrary JSON using [`karate.sort()`](#karate-sort). Simple arrays of strings or numbers can be stripped of duplicates using [`karate.distinct()`](#karate-distinct). All JS \"native\" array operations can be used, such as `someName.reverse()`.\n\n\u003e Note that a single JS function is sufficient to transform a given JSON object into a completely new one, and you can use complex conditional logic if needed.\n\n```cucumber\nScenario: karate map operation\n    * def fun = function(x){ return x * x }\n    * def list = [1, 2, 3]\n    * def res = karate.map(list, fun)\n    * match res == [1, 4, 9]\n\nScenario: js style map operation\n    * def list = [1, 2, 3]\n    * def res = list.map(list, x =\u003e x * x)\n    * match res == [1, 4, 9]\n\nScenario: convert an array into a different shape\n    * def before = [{ foo: 1 }, { foo: 2 }, { foo: 3 }]\n    * def fun = function(x){ return { bar: x.foo } }\n    * def after = karate.map(before, fun)\n    * match after == [{ bar: 1 }, { bar: 2 }, { bar: 3 }]\n\nScenario: convert array of primitives into array of objects\n    * def list = [ 'Bob', 'Wild', 'Nyan' ]\n    * def data = karate.mapWithKey(list, 'name')\n    * match data == [{ name: 'Bob' }, { name: 'Wild' }, { name: 'Nyan' }]\n\nScenario: karate filter operation\n    * def fun = function(x){ return x % 2 == 0 }\n    * def list = [1, 2, 3, 4]\n    * def res = karate.filter(list, fun)\n    * match res == [2, 4]\n\nScenario: js style filter operation\n    * def list = [1, 2, 3, 4]\n    * def res = list.filter(list, x =\u003e x % 2 == 0)\n    * match res == [2, 4]    \n\nScenario: karate.forEach() works even on object key-values, not just arrays\n    * def keys = []\n    * def vals = []\n    * def idxs = []\n    * def fun = \n    \"\"\"\n    function(x, y, i) { \n      karate.appendTo(keys, x); \n      karate.appendTo(vals, y); \n      karate.appendTo(idxs, i); \n    }\n    \"\"\"\n    * def map = { a: 2, b: 4, c: 6 }\n    * karate.forEach(map, fun)\n    * match keys == ['a', 'b', 'c']\n    * match vals == [2, 4, 6]\n    * match idxs == [0, 1, 2]\n\nScenario: filterKeys\n    * def schema = { a: '#string', b: '#number', c: '#boolean' }\n    * def response = { a: 'x', c: true }\n    # very useful for validating a response against a schema \"super-set\"\n    * match response == karate.filterKeys(schema, response)\n    * match karate.filterKeys(response, 'b', 'c') == { c: true }\n    * match karate.filterKeys(response, ['a', 'b']) == { a: 'x' }\n\nScenario: merge\n    * def foo = { a: 1 }\n    * def bar = karate.merge(foo, { b: 2 })\n    * match bar == { a: 1, b: 2 }\n\nScenario: append\n    * def foo = [{ a: 1 }]\n    * def bar = karate.append(foo, { b: 2 })\n    * match bar == [{ a: 1 }, { b: 2 }]\n\nScenario: sort\n    * def foo = [{a: { b: 3 }}, {a: { b: 1 }}, {a: { b: 2 }}]\n    * def fun = function(x){ return x.a.b }\n    * def bar = karate.sort(foo, fun)\n    * match bar == [{a: { b: 1 }}, {a: { b: 2 }}, {a: { b: 3 }}]\n    * match bar.reverse() == [{a: { b: 3 }}, {a: { b: 2 }}, {a: { b: 1 }}]\n```\n\n### Loops\nGiven the examples above, it has to be said that a best practice with Karate is to avoid JavaScript `for` loops as far as possible. A common requirement is to build an array with `n` elements or do something `n` times where `n` is an integer (that could even be a variable reference). This is easily achieved with the [`karate.repeat()`](#karate-repeat) API:\n\n```cucumber\n* def fun = function(i){ return i * 2 }\n* def foo = karate.repeat(5, fun)\n* match foo == [0, 2, 4, 6, 8]\n\n* def foo = []\n* def fun = function(i){ karate.appendTo(foo, i) }\n* karate.repeat(5, fun)\n* match foo == [0, 1, 2, 3, 4]\n\n# generate test data easily\n* def fun = function(i){ return { name: 'User ' + (i + 1) } }\n* def foo = karate.repeat(3, fun)\n* match foo == [{ name: 'User 1' }, { name: 'User 2' }, { name: 'User 3' }]\n\n# generate a range of numbers as a json array\n* def foo = karate.range(4, 9)\n* match foo == [4, 5, 6, 7, 8, 9]\n```\n\nAnd there's also [`karate.range()`](#karate-range) which can be useful to generate test-data.\n\nDon't forget that Karate's [data-driven testing capabilities](#data-driven-tests) can loop over arrays of JSON objects automatically.\n\n## XPath Functions\nWhen handling XML, you sometimes need to call [XPath functions](https://docs.oracle.com/javase/tutorial/jaxp/xslt/xpath.html), for example to get the count of a node-set. Any valid XPath expression is allowed on the left-hand-side of a [`match`](#match) statement.\n\n```cucumber\n* def foo =\n  \"\"\"\n  \u003crecords\u003e\n    \u003crecord index=\"1\"\u003ea\u003c/record\u003e\n    \u003crecord index=\"2\"\u003eb\u003c/record\u003e\n    \u003crecord index=\"3\" foo=\"bar\"\u003ec\u003c/record\u003e\n  \u003c/records\u003e\n  \"\"\"\n\n* match foo count(/records//record) == 3\n* match foo //record[@index=2] == 'b'\n* match foo //record[@foo='bar'] == 'c'\n```\n\n### Advanced XPath\nSome XPath expressions return a list of nodes (instead of a single node). But since you can express a list of data-elements as a JSON array - even these XPath expressions can be used in `match` statements.\n\n```cucumber\n* def teachers = \n  \"\"\"\n  \u003cteachers\u003e\n    \u003cteacher department=\"science\"\u003e\n      \u003csubject\u003emath\u003c/subject\u003e\n      \u003csubject\u003ephysics\u003c/subject\u003e\n    \u003c/teacher\u003e\n    \u003cteacher department=\"arts\"\u003e\n      \u003csubject\u003epolitical education\u003c/subject\u003e\n      \u003csubject\u003eenglish\u003c/subject\u003e\n    \u003c/teacher\u003e\n  \u003c/teachers\u003e\n  \"\"\"\n* match teachers //teacher[@department='science']/subject == ['math', 'physics']\n```\n\nIf your XPath is dynamic and has to be formed 'on the fly' perhaps by using some variable derived from previous steps, you can use the [`karate.xmlPath()`](#karate-xmlpath) helper:\n\n```cucumber\n* def xml = \u003cquery\u003e\u003cname\u003e\u003cfoo\u003ebar\u003c/foo\u003e\u003c/name\u003e\u003c/query\u003e\n* def elementName = 'name'\n* def name = karate.xmlPath(xml, '/query/' + elementName + '/foo')\n* match name == 'bar'\n* def queryName = karate.xmlPath(xml, '/query/' + elementName)\n* match queryName == \u003cname\u003e\u003cfoo\u003ebar\u003c/foo\u003e\u003c/name\u003e\n```\n\nYou can refer to this file (which is part of the Karate test-suite) for more XML examples: [`xml-and-xpath.feature`](karate-core/src/test/java/com/intuit/karate/core/xml/xml-and-xpath.feature)\n\n\n# Special Variables\nThese are 'built-in' variables, there are only a few and all of them give you access to the HTTP response.\n\n## `response`\nAfter every HTTP call this variable is set with the response body, and is available until the next HTTP request over-writes it. You can easily assign the whole `response` (or just parts of it using Json-Path or XPath) to a variable, and use it in later steps.\n\nThe response is automatically available as a JSON, XML or String object depending on what the response contents are.\n\nAs a short-cut, when running JsonPath expressions - `$` represents the `response`.  This has the advantage that you can use pure [JsonPath](https://github.com/jayway/JsonPath#path-examples) and be more concise.  For example:\n\n```cucumber\n# the three lines below are equivalent\nThen match response $ == { name: 'Billie' }\nThen match response == { name: 'Billie' }\nThen match $ == { name: 'Billie' }\n\n# the three lines below are equivalent\nThen match response.name == 'Billie'\nThen match response $.name == 'Billie'\nThen match $.name == 'Billie'\n\n```\nAnd similarly for XML and XPath, '/' represents the `response`\n```cucumber\n# the four lines below are equivalent\nThen match response / == \u003ccat\u003e\u003cname\u003eBillie\u003c/name\u003e\u003c/cat\u003e\nThen match response/ == \u003ccat\u003e\u003cname\u003eBillie\u003c/name\u003e\u003c/cat\u003e\nThen match response == \u003ccat\u003e\u003cname\u003eBillie\u003c/name\u003e\u003c/cat\u003e\nThen match / == \u003ccat\u003e\u003cname\u003eBillie\u003c/name\u003e\u003c/cat\u003e \n\n# the three lines below are equivalent\nThen match response /cat/name == 'Billie'\nThen match response/cat/name == 'Billie'\nThen match /cat/name == 'Billie'\n```\n\n#### JsonPath short-cuts\nThe [`$varName` form](#get-short-cut) is used on the right-hand-side of [Karate expressions](#karate-expressions) and is *slightly* different from pure [JsonPath expressions](https://github.com/json-path/JsonPath#path-examples) which always begin with `$.` or `$[`. Here is a summary of what the different 'shapes' mean in Karate:\n\n| Shape | Description |\n| ----- | ----------- |\n`$.bar` | Pure JsonPath equivalent of `$response.bar` where `response` is a JSON object\n`$[0]`  | Pure JsonPath equivalent of `$response[0]` where `response` is a JSON array\n`$foo.bar` | Evaluates the JsonPath `$.bar` on the variable `foo` which is a JSON object or map-like\n`$foo[0]` | Evaluates the JsonPath `$[0]` on the variable `foo` which is a JSON array or list-like\n\n\u003e There is no need to prefix variable names with `$` on the left-hand-side of [`match`](#match) statements because it is implied. You *can* if you want to, but since [*only* JsonPath (on variables)](#match-and-variables) is allowed here, Karate ignores the `$` and looks only at the variable name. None of the examples in the documentation use the `$varName` form on the LHS, and this is the recommended best-practice.\n\n## `responseBytes`\nThis will always hold the contents of the response as a byte-array. This is rarely used, unless you are expecting binary content returned by the server. The `match` keyword will [work as you expect](#match-text-or-binary). Here is an example: [`binary.feature`](karate-core/src/test/java/com/intuit/karate/core/mock/binary.feature).\n\n## `responseCookies`\nThe `responseCookies` variable is set upon any HTTP response and is a map-like (or JSON-like) object. It can be easily inspected or used in expressions.\n\n```cucumber\n* assert responseCookies['my.key'].value == 'someValue'\n\n# karate's unified data handling means that even 'match' works\n* match responseCookies contains { time: '#notnull' }\n\n# ... which means that checking if a cookie does NOT exist is a piece of cake\n* match responseCookies !contains { blah: '#notnull' }\n\n# save a response cookie for later use\n* def time = responseCookies.time.value\n```\n\nAs a convenience, cookies from the previous response are collected and passed as-is as part of the next HTTP request. This is what is normally expected and simulates a web-browser - which makes it easy to script things like HTML-form based authentication into test-flows. Refer to the documentation for [`cookie`](#cookie) for details and how you can disable this if need be.\n\nEach item within `responseCookies` is itself a 'map-like' object. Typically you would examine the `value` property as in the example above, but `domain` and `path` are also available.\n\n## `responseHeaders`\nSee also [`match header`](#match-header) which is what you would normally need.\n\nBut if you need to use values in the response headers - they will be in a variable named `responseHeaders`. Note that it is a 'map of lists' so you will need to do things like this:\n```cucumber\n* def contentType = responseHeaders['Content-Type'][0]\n```\nAnd just as in the [`responseCookies`](#responsecookies) example above, you can use [`match`](#match) to run complex validations on the `responseHeaders`.\n\nFinally, using [`karate.response.header(name)`](#karate-response) can be simpler to just get a header value string by name, and it will ignore-case for the name passed as the argument:\n\n```cucumber\n* match karate.response.header('content-type') == 'application/json'\n```\n\n## `responseStatus`\nYou would normally only need to use the [`status`](#status) keyword.  But if you really need to use the HTTP response code in an expression or save it for later, you can get it as an integer:\n\n```cucumber\n* def uploadStatusCode = responseStatus\n\n# check if the response status is either of two values\nThen assert responseStatus == 200 || responseStatus == 204\n```\n\nNote that [`match`](#match) can give you some extra readable options:\n\n```cucumber\n* match [200, 201, 204] contains responseStatus\n\n# this may be sufficient to check a range of values\n* assert responseStatus \u003e= 200\n* assert responseStatus \u003c 300\n\n# but using karate.range() you can even do this !\n* match karate.range(200, 299) contains responseStatus\n```\n\n## `responseTime`\nThe response time (in milliseconds) for the current [`response`](#response) would be available in a variable called `responseTime`. You can use this to assert that it was returned within the expected time like so:\n```cucumber\nWhen method post\nThen status 201\nAnd assert responseTime \u003c 1000\n```\n\n## `responseType`\nKarate will attempt to parse the raw HTTP response body as JSON or XML and make it available as the [`response`](#response) value. If parsing fails, Karate will log a warning and the value of `response` will then be a plain string. You can still perform string comparisons such as a [`match contains`](#match-text-or-binary) and look for error messages etc. In rare cases, you may want to check what the \"type\" of the `response` is and it can be one of 3 different values: `json`, `xml` and `string`.\n\nSo if you really wanted to assert that the HTTP response body is well-formed JSON or XML you can do this:\n\n```cucumber\nWhen method post\nThen status 201\nAnd match responseType == 'json'\n```\n\n## `requestTimeStamp`\nVery rarely used - but you can get the Java system-time (for the current [`response`](#response)) at the point when the HTTP request was initiated (the value of `System.currentTimeMillis()`) which can be used for detailed logging or custom framework / stats calculations.\n\n# HTTP Header Manipulation\n## `configure headers`\nCustom header manipulation for every HTTP request is something that Karate makes very easy and pluggable. For every HTTP request made from Karate, the internal flow is as follows:\n* did we [`configure`](#configure) the value of `headers` ?\n* if so, is the configured value a JavaScript function ?\n  * if so, a [`call`](#call) is made to that function.\n  * did the function invocation return a map-like (or JSON) object ?\n    * all the key-value pairs are added to the HTTP headers.\n* or is the configured value a JSON object ?\n  * all the key-value pairs are added to the HTTP headers.\n\nThis makes setting up of complex authentication schemes for your test-flows really easy. It typically ends up being a one-liner that appears in the `Background` section at the start of your test-scripts.  You can re-use the function you create across your whole project.\n \nHere is an example JavaScript function that uses some variables in the context (which have been possibly set as the result of a sign-in) to build the `Authorization` header. Note how even [calls to Java code](#calling-java) can be made if needed.\n\n\u003e In the example below, note the use of the [`karate.get()`](#karate-get) helper for getting the value of a dynamic variable (which was *not set* at the time this JS `function` was *declared*). This is preferred because it takes care of situations such as if the value is `undefined` in JavaScript. In rare cases you may need to *set* a variable from this routine, and a good example is to make the generated UUID \"visible\" to the currently executing script or feature. You can easily do this via [`karate.set('someVarName', value)`](#karate-set).\n\n```javascript\nfunction fn() {\n  var uuid = '' + java.util.UUID.randomUUID(); // convert to string\n  var out = { // so now the txid_header would be a unique uuid for each request\n    txid_header: uuid,\n    ip_header: '123.45.67.89', // hard coded here, but also can be as dynamic as you want   \n  };\n  var authString = '';\n  var authToken = karate.get('authToken'); // use the 'karate' helper to do a 'safe' get of a 'dynamic' variable\n  if (authToken) { // and if 'authToken' is not null ... \n    authString = ',auth_type=MyAuthScheme'\n        + ',auth_key=' + authToken.key\n        + ',auth_user=' + authToken.userId\n        + ',auth_project=' + authToken.projectId;\n  }\n  // the 'appId' variable here is expected to have been set via karate-config.js (bootstrap init) and will never change\n  out['Authorization'] = 'My_Auth app_id=' + appId + authString;\n  return out;\n}\n```\nAssuming the above code is in a file called `my-headers.js`, the next section on [calling other feature files](#calling-other-feature-files) shows how it looks like in action at the beginning of a test script.\n\nNotice how once the `authToken` variable is initialized, it is used by the above function to generate headers for every HTTP call made as part of the test flow.\n\nIf a few steps in your flow need to temporarily change (or completely bypass) the currently-set header-manipulation scheme, just update `configure headers` to a new value (or set it to `null`) in the middle of a script. Then use the [`header`](#header) keyword to do a custom 'over-ride' if needed.\n\nThe [karate-demo](karate-demo) has an example showing various ways to `configure` or set headers: [`headers.feature`](karate-demo/src/test/java/demo/headers/headers.feature)\n\n# The `karate` object\nA JavaScript function or [Karate expression](#karate-expressions) at runtime has access to a utility object in a variable named: `karate`.  This provides the following methods:\n\nOperation | Description\n--------- | -----------\n\u003ca name=\"karate-abort\"\u003e\u003ccode\u003ekarate.abort()\u003c/code\u003e\u003c/a\u003e | you can prematurely exit a `Scenario` by combining this with [conditional logic](#conditional-logic) like so: `* if (condition) karate.abort()` - please use [sparingly](https://martinfowler.com/articles/nonDeterminism.html) ! and also see [`configure abortedStepsShouldPass`](#configure)\n\u003ca name=\"karate-append\"\u003e\u003ccode\u003ekarate.append(... items)\u003c/code\u003e\u003c/a\u003e | useful to create lists out of items (which can be lists as well), see [JSON transforms](#json-transforms)\n\u003ca name=\"karate-appendto\"\u003e\u003ccode\u003ekarate.appendTo(name, ... items)\u003c/code\u003e\u003c/a\u003e | useful to append to a list-like variable (that has to exist) in scope, see [JSON transforms](#json-transforms) - the first argument can be a reference to an array-like variable or even the name (string) of an existing variable which is list-like\n\u003ca name=\"karate-compareimage\"\u003e\u003ccode\u003ekarate.compareImage(baseline, latest, [options])\u003c/code\u003e\u003c/a\u003e | compare two images the same way that [`compareImage`](#compare-image) works (with an optional `options` argument), returns an object with the following keys: `baseline`, `latest`, `mismatchPercentage`, `engine`, `failureThreshold` and optionally: `error`, `isBaselineMissing`, `isScaleMismatch`, `isMismatch`, `resembleMismatchPercentage`, `ssimMismatchPercentage`\n\u003ca name=\"karate-call\"\u003e\u003ccode\u003ekarate.call(fileName, [arg])\u003c/code\u003e\u003c/a\u003e | invoke a [`*.feature` file](#calling-other-feature-files) or a [JavaScript function](#calling-javascript-functions) the same way that [`call`](#call) works (with an optional solitary argument), see [`call()` vs `read()`](#call-vs-read) for details\n\u003ca name=\"karate-callsingle\"\u003e\u003ccode\u003ekarate.callSingle(fileName, [arg])\u003c/code\u003e\u003c/a\u003e | like the above, but guaranteed to run **only once** even across multiple features - see [`karate.callSingle()`](#karatecallsingle)\n\u003ca name=\"karate-configure\"\u003e\u003ccode\u003ekarate.configure(key, value)\u003c/code\u003e\u003c/a\u003e | does the same thing as the [`configure`](#configure) keyword, and a very useful example is to do `karate.configure('connectTimeout', 5000);` in [`karate-config.js`](#configuration) - which has the 'global' effect of not wasting time if a connection cannot be established within 5 seconds\n\u003ca name=\"karate-distinct\"\u003e\u003ccode\u003ekarate.distinct(list)\u003c/code\u003e\u003c/a\u003e | returns only unique items out of an array of strings or numbers\n\u003ca name=\"karate-doc\"\u003e\u003ccode\u003ekarate.doc(arg)\u003c/code\u003e\u003c/a\u003e | just like [`karate.render()`](#karate-render) but will insert the HTML into the report\n\u003ca name=\"karate-embed\"\u003e\u003ccode\u003ekarate.embed(object, mimeType)\u003c/code\u003e\u003c/a\u003e | embeds the object (can be raw bytes or an image) into the JSON report output, see this [example](karate-demo/src/test/java/demo/embed/embed.feature)\n\u003ca name=\"karate-env\"\u003e\u003ccode\u003ekarate.env\u003c/code\u003e\u003c/a\u003e | gets the value (read-only) of the environment property 'karate.env', and this is typically used for bootstrapping [configuration](#configuration)\n\u003ca name=\"karate-eval\"\u003e\u003ccode\u003ekarate.eval(expression)\u003c/code\u003e\u003c/a\u003e | for really advanced needs, you can programmatically generate a snippet of JavaScript which can be evaluated at run-time, you can find an example [here](karate-core/src/test/java/com/intuit/karate/core/js-arrays.feature)\n\u003ca name=\"karate-exec\"\u003e\u003ccode\u003ekarate.exec(command)\u003c/code\u003e\u003c/a\u003e | convenient way to execute an OS specific command and return the console output e.g. `karate.exec('some.exe -h')` (or `karate.exec(['some.exe', '-h'])`) useful for calling non-Java code (that can even return data) or for starting user-interfaces to be automated, this command will block until the process terminates, also see [`karate.fork()`](#karate-fork)\n\u003ca name=\"karate-extract\"\u003e\u003ccode\u003ekarate.extract(text, regex, group)\u003c/code\u003e\u003c/a\u003e | useful to \"scrape\" text out of non-JSON or non-XML text sources such as HTML, `group` follows the Java [regex rules](https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html), see [this example](karate-core/src/test/java/com/intuit/karate/core/extract.feature)\n\u003ca name=\"karate-extractall\"\u003e\u003ccode\u003ekarate.extractAll(text, regex, group)\u003c/code\u003e\u003c/a\u003e | like the above, but returns a list of text-matches\n\u003ca name=\"karate-fail\"\u003e\u003ccode\u003ekarate.fail(message)\u003c/code\u003e\u003c/a\u003e | if you want to conditionally stop a test with a descriptive error message, e.g. `* if (condition) karate.fail('we expected something else')`\n\u003ca name=\"karate-feature\"\u003e\u003ccode\u003ekarate.feature\u003c/code\u003e\u003c/a\u003e | get metadata about the currently executing feature within a test \n\u003ca name=\"karate-filter\"\u003e\u003ccode\u003ekarate.filter(list, predicate)\u003c/code\u003e\u003c/a\u003e | functional-style 'filter' operation useful to filter list-like objects (e.g. JSON arrays), see [example](karate-core/src/test/java/com/intuit/karate/core/js-arrays.feature), the second argument has to be a JS function (item, [index]) that returns a `boolean`\n\u003ca name=\"karate-filterkeys\"\u003e\u003ccode\u003ekarate.filterKeys(map, keys)\u003c/code\u003e\u003c/a\u003e | extracts a sub-set of key-value pairs from the first argument, the second argument can be a list (or varargs) of keys - or even another JSON where only the keys would be used for extraction, [example](karate-core/src/test/java/com/intuit/karate/core/js-arrays.feature)\n`karate.forEach(list, function)` | functional-style 'loop' operation useful to traverse list-like (or even map-like) objects (e.g. JSON / arrays), see [example](karate-core/src/test/java/com/intuit/karate/core/js-arrays.feature), the second argument has to be a JS function (item, [index]) for lists and (key, [value], [index]) for JSON / maps\n\u003ca name=\"karate-fork\"\u003e\u003ccode\u003ekarate.fork(map)\u003c/code\u003e\u003c/a\u003e | executes an OS command, but forks a process in parallel and will not block the test like [`karate.exec()`](#karate-exec) e.g. `karate.fork({ args: ['some.exe', '-h'] })` or `karate.fork(['some.exe', '-h'])` - you can use a composite string as `line` (or the solitary argument e.g. `karate.fork('some.exe -h')`) instead of `args`, and an optional `workingDir` string property and `env` JSON / map is also supported - this returns a [`Command`](karate-core/src/main/java/com/intuit/karate/shell/Command.java) object which has operations such as `waitSync()` and `close()` if you need more control, more details [here](https://stackoverflow.com/a/62911366/143475)\n\u003ca name=\"karate-fromstring\"\u003e\u003ccode\u003ekarate.fromString(string)\u003c/code\u003e\u003c/a\u003e | for advanced conditional logic for e.g. when a string coming from an external process is dynamic - and whether it is JSON or XML is not known in advance, see [example](karate-core/src/test/java/com/intuit/karate/core/type-conv.feature)\n\u003ca name=\"karate-get\"\u003e\u003ccode\u003ekarate.get(name, [default])\u003c/code\u003e\u003c/a\u003e | get the value of a variable by name (or JsonPath expression), if not found - this returns `null` which is easier to handle in JavaScript (than `undefined`), and an optional (literal / constant) second argument can be used to return a \"default\" value, very useful to set variables in called features that have not been pre-defined\n\u003ca name=\"karate-http\"\u003e\u003ccode\u003ekarate.http(url)\u003c/code\u003e\u003c/a\u003e | returns a convenience [`Http`](karate-core/src/main/java/com/intuit/karate/Http.java) request builder class, only recommended for [advanced use](https://github.com/karatelabs/karate/tree/develop/examples/ui-test#webdriver-tips)\n\u003ca name=\"karate-jsonpath\"\u003e\u003ccode\u003ekarate.jsonPath(json, expression)\u003c/code\u003e\u003c/a\u003e | brings the power of [JsonPath](https://github.com/json-path/JsonPath) into JavaScript, and you can find an example [here](karate-core/src/test/java/com/intuit/karate/core/js-arrays.feature).\n\u003ca name=\"karate-keysof\"\u003e\u003ccode\u003ekarate.keysOf(object)\u003c/code\u003e\u003c/a\u003e | returns only the keys of a map-like object\n\u003ca name=\"karate-log\"\u003e\u003ccode\u003ekarate.log(... args)\u003c/code\u003e\u003c/a\u003e | log to the same logger (and log file) being used by the parent process, logging can be suppressed with [`configure printEnabled`](#configure) set to `false`, and just like [`print`](#print) - use comma-separated values to \"pretty print\" JSON or XML\n\u003ca name=\"karate-logger-debug\"\u003e\u003ccode\u003ekarate.logger.debug(... args)\u003c/code\u003e\u003c/a\u003e | access to the Karate logger directly and log in debug. Might be desirable instead of `karate.log` or `print` when looking to reduce the logs in console in your CI/CD pipeline but still retain the information for reports. See [Logging](#logging) for additional details. \n\u003ca name=\"karate-lowercase\"\u003e\u003ccode\u003ekarate.lowerCase(object)\u003c/code\u003e\u003c/a\u003e | useful to brute-force all keys and values in a JSON or XML payload to lower-case, useful in some cases, see [example](karate-core/src/test/java/com/intuit/karate/core/lower-case.feature)\n\u003ca name=\"karate-map\"\u003e\u003ccode\u003ekarate.map(list, function)\u003c/code\u003e\u003c/a\u003e | functional-style 'map' operation useful to transform list-like objects (e.g. JSON arrays), see [example](karate-core/src/test/java/com/intuit/karate/core/js-arrays.feature), the second argument has to be a JS function (item, [index])\n\u003ca name=\"karate-mapwithkey\"\u003e\u003ccode\u003ekarate.mapWithKey(list, string)\u003c/code\u003e\u003c/a\u003e | convenient for the common case of transforming an array of primitives into an array of objects, see [JSON transforms](#json-transforms)\n\u003ca name=\"karate-match\"\u003e\u003ccode\u003ekarate.match(actual, expected)\u003c/code\u003e\u003c/a\u003e | brings the power of the *fuzzy* [`match`](#match) syntax into Karate-JS, returns a JSON in the form `{ pass: '#boolean', message: '#string' }` and you can find an example [here](karate-core/src/test/java/com/intuit/karate/core/js-arrays.feature) - you can even place a *full* match expression like this: `karate.match(\"each foo contains { a: '#number' }\")`\n\u003ca name=\"karate-merge\"\u003e\u003ccode\u003ekarate.merge(... maps)\u003c/code\u003e\u003c/a\u003e | useful to merge the key-values of two (or more) JSON (or map-like) objects, see [JSON transforms](#json-transforms)\n\u003ca name=\"karate-os\"\u003e\u003ccode\u003ekarate.os\u003c/code\u003e\u003c/a\u003e | returns the operating system details as JSON, for e.g. `{ type: 'macosx', name: 'Mac OS X' }` - useful for writing conditional logic, the possible `type`-s being: `macosx`, `windows`, `linux` and `unknown`\n\u003ca name=\"karate-pause\"\u003e\u003ccode\u003ekarate.pause(number)\u003c/code\u003e\u003c/a\u003e | sleep time in milliseconds, relevant only for [performance-testing](karate-gatling#think-time) - and will be a no-op otherwise unless [`configure pauseIfNotPerf`](#configure) is `true`\n\u003ca name=\"karate-pretty\"\u003e\u003ccode\u003ekarate.pretty(value)\u003c/code\u003e\u003c/a\u003e | return a 'pretty-printed', nicely indented string representation of the JSON value, also see: [`print`](#print)\n\u003ca name=\"karate-prettyxml\"\u003e\u003ccode\u003ekarate.prettyXml(value)\u003c/code\u003e\u003c/a\u003e | return a 'pretty-printed', nicely indented string representation of the XML value, also see: [`print`](#print)\n\u003ca name=\"karate-prevrequest\"\u003e\u003ccode\u003ekarate.prevRequest\u003c/code\u003e\u003c/a\u003e | for advanced users, you can inspect the *actual* HTTP request after it happens, useful if you are writing a framework over Karate, refer to this example: [`request.feature`](karate-demo/src/test/java/demo/request/request.feature)\n\u003ca name=\"karate-properties\"\u003e\u003ccode\u003ekarate.properties[key]\u003c/code\u003e\u003c/a\u003e | get the value of any Java system-property by name, useful for [advanced custom configuration](#dynamic-port-numbers)\n\u003ca name=\"karate-range\"\u003e\u003ccode\u003ekarate.range(start, end, [interval])\u003c/code\u003e\u003c/a\u003e | returns a JSON array of integers (inclusive), the optional third argument must be a positive integer and defaults to 1, and if start \u003c end the order of values is reversed\n\u003ca name=\"karate-read\"\u003e\u003ccode\u003ekarate.read(filename)\u003c/code\u003e\u003c/a\u003e | the same [`read()`](#reading-files) function - which is pre-defined even within JS blocks, so there is no need to ever do `karate.read()`, and just `read()` is sufficient\n\u003ca name=\"karate-readasbytes\"\u003e\u003ccode\u003ekarate.readAsBytes(filename)\u003c/code\u003e\u003c/a\u003e | rarely used, like [`karate.readAsString`](#karate-readasstring) - but returns a byte array\n\u003ca name=\"karate-readasstream\"\u003e\u003ccode\u003ekarate.readAsStream(filename)\u003c/code\u003e\u003c/a\u003e | rarely used, like [`karate.readAsString`](#karate-readasstring) - but returns a Java `InputStream`\n\u003ca name=\"karate-readasstring\"\u003e\u003ccode\u003ekarate.readAsString(filename)\u003c/code\u003e\u003c/a\u003e | [rarely used](#read-file-as-string), behaves exactly like [`read`](#reading-files) - but does *not* auto convert to JSON or XML\n\u003ca name=\"karate-remove\"\u003e\u003ccode\u003ekarate.remove(name, path)\u003c/code\u003e\u003c/a\u003e | very rarely used - when needing to perform conditional removal of JSON keys or XML nodes. Behaves the same way as the [`remove`](#remove) keyword.\n\u003ca name=\"karate-render\"\u003e\u003ccode\u003ekarate.render(arg)\u003c/code\u003e\u003c/a\u003e | renders an HTML template, the `arg` can be a string (prefixable path to the HTML) or a JSON that takes either a `path` or `html` property, see [`doc`](#doc)\n\u003ca name=\"karate-repeat\"\u003e\u003ccode\u003ekarate.repeat(count, function)\u003c/code\u003e\u003c/a\u003e | useful for building an array with `count` items or doing something `count` times, see [loops](#loops).\n\u003ca name=\"karate-response\"\u003e\u003ccode\u003ekarate.response\u003c/code\u003e\u003c/a\u003e | returns the last HTTP response as a JS object that enables advanced use-cases such as getting a header ignoring case: `karate.response.header('some-header')`\n\u003ca name=\"karate-request\"\u003e\u003ccode\u003ekarate.request\u003c/code\u003e\u003c/a\u003e | returns the last HTTP request as a JS object that enables advanced use-cases such as getting a header ignoring case: `karate.request.header('some-header')`, which works [even in mocks](https://github.com/karatelabs/karate/tree/master/karate-netty#requestheaders)\n\u003ca name=\"karate-scenario\"\u003e\u003ccode\u003ekarate.scenario\u003c/code\u003e\u003c/a\u003e | get metadata about the currently executing `Scenario` (or `Outline` - `Example`) within a test \n\u003ca name=\"karate-scenarioOutline\"\u003e\u003ccode\u003ekarate.scenarioOutline\u003c/code\u003e\u003c/a\u003e | get metadata about the currently executing scenario outline within a test\n\u003ca name=\"karate-set\"\u003e\u003ccode\u003ekarate.set(name, value)\u003c/code\u003e\u003c/a\u003e | sets the value of a variable (immediately), which may be needed in case any other routines (such as the [configured headers](#configure-headers)) depend on that variable\n\u003ca name=\"karate-setall\"\u003e\u003ccode\u003ekarate.set(object)\u003c/code\u003e\u003c/a\u003e | where the single argument is expected to be a `Map` or JSON-like, and will perform the above `karate.set()` operation for all key-value pairs in one-shot\n\u003ca name=\"karate-setpath\"\u003e\u003ccode\u003ekarate.set(name, path, value)\u003c/code\u003e\u003c/a\u003e | only needed when you need to conditionally build payload elements, especially XML. This is best explained via [an example](karate-core/src/test/java/com/intuit/karate/core/xml/xml.feature#L211), and it behaves the same way as the [`set`](#set) keyword. Also see [`eval`](#eval).\n\u003ca name=\"karate-setxml\"\u003e\u003ccode\u003ekarate.setXml(name, xmlString)\u003c/code\u003e\u003c/a\u003e | rarely used, refer to the example above\n\u003ca name=\"karate-setup\"\u003e\u003ccode\u003ekarate.setup([name])\u003c/code\u003e\u003c/a\u003e | call a `Scenario` tagged with the built-in [`@setup`](#setup) annotation\n\u003ca name=\"karate-setuponce\"\u003e\u003ccode\u003ekarate.setupOnce([name])\u003c/code\u003e\u003c/a\u003e | like [`karate.setup()`](#karate-setup) above, but cache the result so that the \"setup\" runs only once\n\u003ca name=\"karate-signal\"\u003e\u003ccode\u003ekarate.signal(result)\u003c/code\u003e\u003c/a\u003e | trigger an event that [`karate.listen(timeout)`](#karate-listen) is waiting for, and pass the data, see [async](#async)\n\u003ca name=\"karate-sizeof\"\u003e\u003ccode\u003ekarate.sizeOf(object)\u003c/code\u003e\u003c/a\u003e | returns the size of the map-like or list-like object\n\u003ca name=\"karate-sort\"\u003e\u003ccode\u003ekarate.sort(list, function)\u003c/code\u003e\u003c/a\u003e | sorts the list using the provided custom function called for each item in the list (and the optional second argument is the item index) e.g. `karate.sort(myList, x =\u003e x.val)`, and the second / function argument is not needed if the list is of plain strings or numbers\n\u003ca name=\"karate-start\"\u003e\u003ccode\u003ekarate.start()\u003c/code\u003e\u003c/a\u003e | only for starting a mock from [within a test / feature file see mocks](karate-netty#within-a-karate-test)\n\u003ca name=\"karate-stop\"\u003e\u003ccode\u003ekarate.stop(port)\u003c/code\u003e\u003c/a\u003e | will pause the test execution until a socket connection (even HTTP `GET`) is made to the port logged to the console, useful for troubleshooting UI tests without using a [de-bugger](https://twitter.com/KarateDSL/status/1167533484560142336), of course - *NEVER* forget to remove this after use ! \n\u003ca name=\"karate-target\"\u003e\u003ccode\u003ekarate.target(object)\u003c/code\u003e\u003c/a\u003e | currently for web-ui automation only, see [target lifecycle](karate-core#target-lifecycle)\n\u003ca name=\"karate-tags\"\u003e\u003ccode\u003ekarate.tags\u003c/code\u003e\u003c/a\u003e | for advanced users - scripts can introspect the tags that apply to the current scope, refer to this example: [`tags.feature`](karate-core/src/test/java/com/intuit/karate/core/tags.feature)\n\u003ca name=\"karate-tagvalues\"\u003e\u003ccode\u003ekarate.tagValues\u003c/code\u003e\u003c/a\u003e | for even more advanced users - Karate natively supports tags in a `@name=val1,val2` format, and there is an inheritance mechanism where `Scenario` level tags can over-ride `Feature` level tags, refer to this example: [`tags.feature`](karate-core/src/test/java/com/intuit/karate/core/tags.feature)\n\u003ca name=\"karate-toabsolutepath\"\u003e\u003ccode\u003ekarate.toAbsolutePath(relativePath)\u003c/code\u003e\u003c/a\u003e | when you want to get the absolute OS path to the argument which could even have a prefix such as `classpath:`, e.g. `karate.toAbsolutePath('some.json')`\n\u003ca name=\"karate-tobean\"\u003e\u003ccode\u003ekarate.toBean(json, className)\u003c/code\u003e\u003c/a\u003e | converts a JSON string or map-like object into a Java object, given the Java class name as the second argument, refer to this [file](karate-core/src/test/java/com/intuit/karate/core/type-conv.feature) for an example\n\u003ca name=\"karate-tocsv\"\u003e\u003ccode\u003ekarate.toCsv(list)\u003c/code\u003e\u003c/a\u003e | converts a JSON array (of objects) or a list-like object into a CSV string, writing this to a file is your responsibility or you could use [`karate.write()`](#karate-write)\n\u003ca name=\"karate-tojava\"\u003e\u003ccode\u003ekarate.toJava(function)\u003c/code\u003e\u003c/a\u003e | rarely used, when you need to pass a JS function to custom Java code, typically for [Async](#async), and another edge case is to convert a JSON array or object to a Java `List` or `Map`, see [example](karate-core/src/test/java/com/intuit/karate/core/to-bean.feature)\n\u003ca name=\"karate-tojavafile\"\u003e\u003ccode\u003ekarate.toJavaFile(path)\u003c/code\u003e\u003c/a\u003e | in case you need a `java.io.File` instance to pass to Java interop, takes the [Karate prefixes](#reading-files) such as `classpath:` for convenience\n\u003ca name=\"karate-tojson\"\u003e\u003ccode\u003ekarate.toJson(object)\u003c/code\u003e\u003c/a\u003e | converts a Java object into JSON, and `karate.toJson(object, true)` will strip all keys that have `null` values from the resulting JSON, convenient for unit-testing Java code, see [example](karate-demo/src/test/java/demo/unit/cat.feature)\n\u003ca name=\"karate-typeof\"\u003e\u003ccode\u003ekarate.typeOf(any)\u003c/code\u003e\u003c/a\u003e | for advanced conditional logic when object types are dynamic and not known in advance, see [example](karate-core/src/test/java/com/intuit/karate/core/type-conv.feature)\n\u003ca name=\"karate-urldecode\"\u003e\u003ccode\u003ekarate.urlDecode(string)\u003c/code\u003e\u003c/a\u003e | URL decode\n\u003ca name=\"karate-urlencode\"\u003e\u003ccode\u003ekarate.urlEncode(string)\u003c/code\u003e\u003c/a\u003e | URL encode\n\u003ca name=\"karate-valuesof\"\u003e\u003ccode\u003ekarate.valuesOf(object)\u003c/code\u003e\u003c/a\u003e | returns only the values of a map-like object (or itself if a list-like object)\n\u003ca name=\"karate-waitforhttp\"\u003e\u003ccode\u003ekarate.waitForHttp(url)\u003c/code\u003e\u003c/a\u003e | will wait until the URL is ready to accept HTTP connections\n\u003ca name=\"karate-waitforport\"\u003e\u003ccode\u003ekarate.waitForPort(host, port)\u003c/code\u003e\u003c/a\u003e | will wait until the host:port is ready to accept socket connections\n\u003ca name=\"karate-websocket\"\u003e\u003ccode\u003ekarate.webSocket(url, handler)\u003c/code\u003e\u003c/a\u003e | see [websocket](#websocket)\n\u003ca name=\"karate-write\"\u003e\u003ccode\u003ekarate.write(object, path)\u003c/code\u003e\u003c/a\u003e | *normally not recommended, please [read this first](https://stackoverflow.com/a/54593057/143475)* - writes the bytes of `object` to a path which will *always* be relative to the \"build\" directory (typically `target`), see this example: [`embed-pdf.js`](karate-demo/src/test/java/demo/embed/embed-pdf.js) - and this method returns a `java.io.File` reference to the file created / written to\n\u003ca name=\"karate-xmlpath\"\u003e\u003ccode\u003ekarate.xmlPath(xml, expression)\u003c/code\u003e\u003c/a\u003e | Just like [`karate.jsonPath()`](#karate-jsonpath) - but for XML, and allows you to use dynamic XPath if needed, see [example](karate-core/src/test/java/com/intuit/karate/core/xml/xml.feature).\n\n# Code Reuse / Common Routines\n## `call`\nIn any complex testing endeavor, you would find yourself needing 'common' code that needs to be re-used across multiple test scripts. A typical need would be to perform a 'sign in', or create a fresh user as a pre-requisite for the scenarios being tested.\n\nThere are two types of code that can be `call`-ed. `*.feature` files and [JavaScript functions](#calling-javascript-functions).\n\n## Calling other `*.feature` files\nWhen you have a sequence of HTTP calls that need to be repeated for multiple test scripts, Karate allows you to treat a `*.feature` file as a re-usable unit. You can also pass parameters into the `*.feature` file being called, and extract variables out of the invocation result.\n\nHere is an example of using the `call` keyword to invoke another feature file, loaded using the [`read`](#reading-files) function:\n\n\u003e If you find this hard to understand at first, try looking at this [set of examples](karate-demo/src/test/java/demo/callfeature/call-feature.feature).\n\n```cucumber\nFeature: which makes a 'call' to another re-usable feature\n\nBackground:\n  * configure headers = read('classpath:my-headers.js')\n  * def signIn = call read('classpath:my-signin.feature') { username: 'john', password: 'secret' }\n  * def authToken = signIn.authToken\n\nScenario: some scenario\n  # main test steps\n```\n\n\u003e Note that [`def`](#def) can be used to *assign* a __feature__ to a variable. For example look at how \"`creator`\" has been defined in the `Background` in [this example](karate-demo/src/test/java/demo/calldynamic/call-dynamic-json.feature), and used later in a `call` statement. This is very close to how \"custom keywords\" work in other frameworks. See this other example for more ideas: [`dsl.feature`](karate-demo/src/test/java/demo/dsl/dsl.feature).\n\nThe contents of `my-signin.feature` are shown below. A few points to note:\n* Karate creates a new 'context' for the feature file being invoked but passes along all variables and configuration. This means that all your [config variables](#configuration) and [`configure` settings](#configure) would be available to use, for example `loginUrlBase` in the example below. \n* When you use [`def`](#def) in the 'called' feature, it will **not** over-write variables in the 'calling' feature (unless you explicitly choose to use [shared scope](#shared-scope)). But note that JSON, XML, Map-like or List-like variables are 'passed by reference' which means that 'called' feature steps can *update* or 'mutate' them using the [`set`](#set) keyword. Use the [`copy`](#copy) keyword to 'clone' a JSON or XML payload if needed, and refer to this example for more details: [`copy.feature`](karate-core/src/test/java/com/intuit/karate/core/copy.feature).\n* You can add (or over-ride) variables by passing a call 'argument' as shown above. Only one JSON argument is allowed, but this does not limit you in any way as you can use any complex JSON structure. You can even initialize the JSON in a separate step and pass it by name, especially if it is complex. Observe how using JSON for parameter-passing makes things super-readable. In the 'called' feature, the argument can also be accessed using the built-in variable: [`__arg`](#built-in-variables-for-call).\n* **All** variables that were defined (using [`def`](#def)) in the 'called' script would be returned as 'keys' within a JSON-like object. Note that this includes ['built-in' variables](#special-variables), which means that things like the last value of [`response`](#response) would also be present. In the example above you can see that the JSON 'envelope' returned - is assigned to the variable named `signIn`. And then getting hold of any data that was generated by the 'called' script is as simple as accessing it by name, for example `signIn.authToken` as shown above. This design has the following advantages:\n  * 'called' Karate scripts don't need to use any special keywords to 'return' data and can behave like 'normal' Karate tests in 'stand-alone' mode if needed\n  * the data 'return' mechanism is 'safe', there is no danger of the 'called' script over-writing any variables in the 'calling' (or parent) script (unless you use [shared scope](#shared-scope))\n  * the need to explicitly 'unpack' variables by name from the returned 'envelope' keeps things readable and maintainable in the 'caller' script\n\n\u003e Note that only [variables](#def) and [configuration settings](#configure) will be passed. You can't do things such as `* url 'http://foo.bar'` and expect the URL to be set in the \"called\" feature. Use a variable in the \"called\" feature instead, for e.g. `* url myUrl` or take a look at [`configure url`](#configure-url).\n\n```cucumber\nFeature: here are the contents of 'my-signin.feature'\n\nScenario:\n  Given url loginUrlBase\n  And request { userId: '#(username)', userPass: '#(password)' }\n  When method post\n  Then status 200\n  And def authToken = response\n\n  # second HTTP call, to get a list of 'projects'\n  Given path 'users', authToken.userId, 'projects'\n  When method get\n  Then status 200\n  # logic to 'choose' first project\n  And set authToken.projectId = response.projects[0].projectId;\n```\n\nThe above example actually makes two HTTP requests - the first is a standard 'sign-in' POST and then (for illustrative purposes) another HTTP call (a GET) is made for retrieving a list of projects for the signed-in user, and the first one is 'selected' and added to the returned 'auth token' JSON object.\n\nSo you get the picture, any kind of complicated 'sign-in' flow can be scripted and re-used.\n\n\u003e If the second HTTP call above expects headers to be set by `my-headers.js` - which in turn depends on the `authToken` variable being updated, you will need to duplicate the line `* configure headers = read('classpath:my-headers.js')` from the 'caller' feature here as well. The above example does **not** use [shared scope](#shared-scope), which means that the variables in the 'calling' (parent) feature are *not* shared by the 'called' `my-signin.feature`. The above example can be made more simpler with the use of `call` (or [`callonce`](#callonce)) *without* a [`def`](#def)-assignment to a variable, and is the [recommended pattern](#shared-scope) for implementing re-usable authentication setup flows.\n\nDo look at the documentation and example for [`configure headers`](#configure-headers) also as it goes hand-in-hand with `call`. In the above example, the end-result of the `call` to `my-signin.feature` resulted in the `authToken` variable being initialized. Take a look at how the [`configure headers`](#configure-headers) example uses the `authToken` variable.\n\n### Call Tag Selector\nYou can \"select\" a single `Scenario` (or `Scenario`-s or `Scenario Outline`-s or even specific `Examples` rows) by appending a \"tag selector\" at the end of the feature-file you are calling. For example:\n\n```cucumber\ncall read('classpath:my-signin.feature@name=someScenarioName')\n```\n\nWhile the tag does not need to be in the `@key=value` form, it is recommended for readability when you start getting into the business of giving meaningful names to your `Scenario`-s.\n\nThis \"tag selection\" capability is designed for you to be able to \"compose\" flows out of existing test-suites when using the [Karate Gatling integration](karate-gatling). Normally we recommend that you keep your \"re-usable\" features lightweight - by limiting them to just one `Scenario`.\n\n\n#### Call Same Feature\nAs a convenience, you can call a tag directly, which is a short-cut to call another `Scenario` within the same feature file. Note that you would typically want to use the [`@ignore`](#special-tags) tag for such cases.\n\n```cucumber\nScenario: one\n* call read('@two')\n\n@ignore @two\nScenario: two\n* print 'called'\n```\n\n### Data-Driven Features\nIf the argument passed to the [call of a `*.feature` file](#calling-other-feature-files) is a JSON array, something interesting happens. The feature is invoked for each item in the array. Each array element is expected to be a JSON object, and for each object - the behavior will be as described above.\n\nBut this time, the return value from the `call` step will be a JSON array of the same size as the input array. And each element of the returned array will be the 'envelope' of variables that resulted from each iteration where the `*.feature` got invoked.\n\nHere is an example that combines the [`table`](#table) keyword with calling a `*.feature`. Observe how the [`get`](#get) [shortcut](#get-short-cut) is used to 'distill' the result array of variable 'envelopes' into an array consisting only of [`response`](#response) payloads.\n\n```cucumber\n* table kittens \n  | name   | age |\n  | 'Bob'  |   2 |\n  | 'Wild' |   1 |\n  | 'Nyan' |   3 |\n\n* def result = call read('cat-create.feature') kittens\n* def created = $result[*].response\n* match each created == { id: '#number', name: '#string', age: '#number' }\n* match created[*].name contains only ['Bob', 'Wild', 'Nyan']\n```\n\nAnd here is how `cat-create.feature` could look like:\n\n```cucumber\n@ignore\nFeature:\n\nScenario:\n  Given url someUrlFromConfig\n  And path 'cats'\n  And request { name: '#(name)', age: '#(age)' }\n  When method post\n  Then status 200\n```\n\nIf you replace the `table` with perhaps a JavaScript function call that gets some JSON data from some data-source, you can imagine how you could go about dynamic data-driven testing.\n\nAlthough it is just a few lines of code, take time to study the above example carefully. It is a great example of how to effectively use the unique combination of syntax and JsonPath that Karate provides.\n\nAlso look at the [demo examples](karate-demo), especially [`dynamic-params.feature`](karate-demo/src/test/java/demo/search/dynamic-params.feature) - to compare the above approach with how the Gherkin [`Scenario Outline:`](#the-cucumber-way) can be alternatively used for data-driven tests.\n\n### Built-in variables for `call`\nAlthough all properties in the passed JSON-like argument are 'unpacked' into the current scope as separate 'named' variables, it sometimes makes sense to access the whole argument and this can be done via `__arg`. And if being called in a loop, a built-in variable called `__loop` will also be available that will hold the value of the current loop index. So you can do things like this: `* def name = name + __loop` - or you can use the loop index value for looking up other values that may be in scope - in a data-driven style.\n\nVariable  | Refers To\n--------- | ------                               \n| `__arg`   | the single `call` (or [`callonce`](#callonce)) argument, will be `null` if there was none         \n| `__loop`  | the current iteration index (starts from 0) if being called in a loop, will be `-1` if not\n\nRefer to this [demo feature](karate-demo) for an example: [`kitten-create.feature`](karate-demo/src/test/java/demo/calltable/kitten-create.feature)\n\n### Default Values\nSome users need \"callable\" features that are re-usable even when variables have not been defined by the calling feature. Normally an undefined variable results in nasty JavaScript errors. But there is an elegant way you can specify a default value using the [`karate.get()`](#karate-get) API:\n\n```cucumber\n# if foo is not defined, it will default to 42\n* def foo = karate.get('foo', 42)\n```\n\n\u003e A word of caution: we recommend that you should not over-use Karate's capability of being able to re-use features. Re-use can sometimes result in negative benefits - especially when applied to test-automation. Prefer readability over re-use. See this for an [example](https://stackoverflow.com/a/54126724/143475).\n\n### `copy`\nFor a [`call`](#call) (or [`callonce`](#callonce)) - payload / data structures (JSON, XML, Map-like or List-like) variables are 'passed by reference' which means that steps within the 'called' feature can update or 'mutate' them, for e.g. using the [`set`](#set) keyword. This is actually the intent most of the time and is convenient. If you want to pass a 'clone' to a 'called' feature, you can do so using the rarely used `copy` keyword that works very similar to [type conversion](#type-conversion). This is best explained in this example: [`copy.feature`](karate-core/src/test/java/com/intuit/karate/core/copy.feature).\n\n## Calling JavaScript Functions\nExamples of [defining and using JavaScript functions](#javascript-functions) appear in earlier sections of this document. Being able to define and re-use JavaScript functions is a powerful capability of Karate. For example, you can:\n* call re-usable functions that take complex data as an argument and return complex data that can be stored in a variable\n* [call and interoperate with Java code](#calling-java) if needed\n* share and re-use test [utilities](#commonly-needed-utilities) or 'helper' functionality across your organization\n\n\u003e For an advanced example of how you can build and re-use a common set of JS functions, refer to [this answer on Stack Overflow](https://stackoverflow.com/a/49384760/143475).\n\nIn real-life scripts, you would typically also use this capability of Karate to [`configure headers`](#configure-headers) where the specified JavaScript function uses the variables that result from a [sign in](#calling-other-feature-files) to manipulate headers for all subsequent HTTP requests. And it is worth mentioning that the Karate [configuration 'bootstrap'](#configuration) routine is itself a JavaScript function.\n\n\u003e Also refer to the [`eval`](#eval) keyword for a simpler way to execute arbitrary JavaScript that can be useful in some situations.\n\n### JS function argument rules for `call`\nWhen using `call` (or [`callonce`](#callonce)), only one argument is allowed. But this does not limit you in any way, because similar to how you can [call `*.feature files`](#calling-other-feature-files), you can pass a whole JSON object as the argument. In the case of the `call` of a JavaScript function, you can also pass a JSON array or a primitive (string, number, boolean) as the solitary argument, and the function implementation is expected to handle whatever is passed.\n\nInstead of using `call` (or `callonce`) you are always free to call JavaScript functions 'normally' and then you can use more than one argument.\n\n```cucumber\n* def adder = function(a, b){ return a + b }\n* assert adder(1, 2) == 3\n```\n\n### Return types\nNaturally, only one value can be returned.  But again, you can return a JSON object. There are two things that can happen to the returned value.\n\nEither - it can be assigned to a variable like so.\n```cucumber\n* def returnValue = call myFunction\n```\n\nOr - if a `call` is made without an assignment, and if the function returns a map-like object, it will add each key-value pair returned as a new variable into the execution context.\n```cucumber\n# while this looks innocent ...\n# ... behind the scenes, it could be creating (or over-writing) a bunch of variables !\n* call someFunction\n```\n\nWhile this sounds dangerous and should be used with care (and limits readability), the reason this feature exists is to quickly set (or over-write) a bunch of config variables when needed. In fact, this is the mechanism used when [`karate-config.js`](#configuration) is processed on start-up.\n\n#### Shared Scope\nThis behavior where all key-value pairs in the returned map-like object get automatically added as variables - applies to the [calling of `*.feature` files](#calling-other-feature-files) as well. In other words, when [`call`](#call) or [`callonce`](#callonce) is used without a [`def`](#def), the 'called' script not only shares all variables (and [`configure`](#configure) settings) but can update the shared execution context. This is very useful to boil-down those 'common' steps that you may have to perform at the start of multiple test-scripts - into one-liners. But use wisely, because called scripts will now over-write variables that may have been already defined.\n\n```cucumber\n* def config = { user: 'john', password: 'secret' }\n# this next line may perform many steps and result in multiple variables set for the rest of the script\n* call read('classpath:common-setup.feature') config\n```\n\nYou can use [`callonce`](#callonce) instead of `call` within the [`Background`](#script-structure) in case you have multiple `Scenario` sections or [`Examples`](#data-driven-tests). Note the 'inline' use of the [read](#reading-files) function as a short-cut above. This applies to JS functions as well:\n\n```cucumber\n* call read('my-function.js')\n```\n\nThese heavily commented [demo examples](karate-demo) can help you understand 'shared scope' better, and are designed to get you started with creating re-usable 'sign-in' or authentication flows:\n\n| Scope | Caller Feature | Called Feature |\n| ----- | -------------- | -------------- |\nIsolated | [`call-isolated-headers.feature`](karate-demo/src/test/java/demo/headers/call-isolated-headers.feature) | [`common-multiple.feature`](karate-demo/src/test/java/demo/headers/common-multiple.feature)\nShared | [`call-updates-config.feature`](karate-demo/src/test/java/demo/headers/call-updates-config.feature) | [`common.feature`](karate-demo/src/test/java/demo/headers/common.feature)\n\n\u003e Once you get comfortable with Karate, you can consider moving your authentication flow into a 'global' one-time flow using [`karate.callSingle()`](#karate-callsingle), think of it as '[`callonce`](#callonce) on steroids'.\n\n#### `call` vs `read()`\nSince this is a frequently asked question, the different ways of being able to re-use code (or data) are summarized below.\n\nCode | Description\n---- | -----------\n`* def login = read('login.feature')`\u003cbr/\u003e`* call login` | [Shared Scope](#shared-scope), and the \u003cbr/\u003e`login` variable can be re-used\n`* call read('login.feature')` | short-cut for the above \u003cbr/\u003ewithout needing a variable\n`* def credentials = read('credentials.json')`\u003cbr/\u003e`* def login = read('login.feature')`\u003cbr/\u003e`* call login credentials` | Note how using [`read()`](#reading-files) \u003cbr/\u003efor a JSON file returns *data* - \u003cbr/\u003enot \"callable\" code, and here it is \u003cbr/\u003eused as the [`call`](#call) argument\n`* call read('login.feature') read('credentials.json')` | You *can* do this in theory, \u003cbr/\u003ebut it is not as readable as the above\n`* karate.call('login.feature')` | The [JS API](#karate-call) allows you to do this, \u003cbr/\u003ebut this will *not* be [Shared Scope](#shared-scope)\n`* def result = call read('login.feature')` | [`call`](#call) result assigned to a variable \u003cbr/\u003eand *not* [Shared Scope](#shared-scope)\n`* def result = karate.call('login.feature')` | exactly equivalent to the above !\n`* if (cond) karate.call(true, 'login.feature')` | if you need [conditional logic](#conditional-logic) \u003cbr/\u003e*and* [Shared Scope](#shared-scope), add a \u003cbr/\u003eboolean `true` first argument\n`* def credentials = read('credentials.json')`\u003cbr/\u003e`* def result = call read('login.feature') credentials` | like the above, \u003cbr/\u003ebut with a [`call`](#call) argument\n`* def credentials = read('credentials.json')`\u003cbr/\u003e`* def result = karate.call('login.feature', credentials)` | like the above, but in [JS API](#karate-call) form, \u003cbr/\u003ethe advantage of the above form is \u003cbr/\u003ethat using an in-line argument is less \u003cbr/\u003e\"cluttered\" (see next row)\n`* def login = read('login.feature')`\u003cbr/\u003e`* def result = call login { user: 'john', password: 'secret' }` | using the `call` keyword makes \u003cbr/\u003epassing an in-line JSON argument \u003cbr/\u003emore \"readable\"\n`* call read 'credentials.json'` | Since \"`read`\" happens to be a \u003cbr/\u003e[*function*](#calling-javascript-functions) (that takes a single \u003cbr/\u003estring argument), this has the effect \u003cbr/\u003eof loading *all* keys in the JSON file\u003cbr/\u003einto [Shared Scope](#shared-scope) as [variables](#def) ! \u003cbr/\u003eThis *can* be [sometimes handy](karate-core#locator-lookup).\n`* call read ('credentials.json')` | A common mistake. First, there \u003cbr/\u003eis no meaning in `call` for JSON. \u003cbr/\u003eSecond, the space after the \"`read`\" \u003cbr/\u003emakes this equal to the above.\n`* karate.set(read('credentials.json'))` | For completeness - this has *exactly* the [same effect](#karate-setall) as the above two rows !\n\n### Calling Java\nThere are examples of calling JVM classes in the section on [Java Interop](#java-interop) and in the [file-upload demo](karate-demo). Also look at the section on [commonly needed utilities](#commonly-needed-utilities) for more ideas.\n\nCalling any Java code is that easy.  Given this custom, user-defined Java class:\n```java\npackage com.mycompany;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class JavaDemo {    \n    \n    public Map\u003cString, Object\u003e doWork(String fromJs) {\n        Map\u003cString, Object\u003e map = new HashMap\u003c\u003e();\n        map.put(\"someKey\", \"hello \" + fromJs);\n        return map;\n    }\n\n    public static String doWorkStatic(String fromJs) {\n        return \"hello \" + fromJs;\n    }   \n\n}\n```\nThis is how it can be called from a test-script via [JavaScript](#javascript-functions), and yes, even static methods can be invoked:\n```cucumber\n* def doWork =\n  \"\"\"\n  function(arg) {\n    var JavaDemo = Java.type('com.mycompany.JavaDemo');\n    var jd = new JavaDemo();\n    return jd.doWork(arg);  \n  }\n  \"\"\"\n# in this case the solitary 'call' argument is of type string\n* def result = call doWork 'world'\n* match result == { someKey: 'hello world' }\n\n# using a static method - observe how java interop is truly seamless !\n* def JavaDemo = Java.type('com.mycompany.JavaDemo')\n* def result = JavaDemo.doWorkStatic('world')\n* assert result == 'hello world'\n```\n\nNote that JSON gets auto-converted to `Map` (or `List`) when making the cross-over to Java. Refer to the [`cats-java.feature`](karate-demo/src/test/java/demo/java/cats-java.feature) demo for an example.\n\n\u003e An additional-level of auto-conversion happens when objects cross the boundary between JS and Java. In the rare case that you need to mutate a `Map` or `List` returned from Java but while still within a JS block, use [`karate.toJson()`](#karate-tojson) to convert.\n\nAnother example is [`dogs.feature`](karate-demo/src/test/java/demo/dogs/dogs.feature) -  which actually makes JDBC (database) calls, and since the data returned from the Java code is JSON, the last section of the test is able to use [`match`](#match) *very* effectively for data assertions.\n\nGood examples of how you can extend Karate, even bypass the HTTP client - but still use Karate's test-automation effectively, are the following:\n* [AWS DynamoDB](https://github.com/karatelabs/karate-examples/blob/main/aws-dynamodb/README.md)\n* [SSH](https://github.com/karatelabs/karate-examples/blob/main/ssh/README.md)\n* [Active MQ + Async](https://x.com/getkarate/status/1417023536082812935)\n* [Spring Boot + Database](https://github.com/karatelabs/karate-examples/blob/main/database/README.md)\n* [RabbitMQ](https://github.com/karatelabs/karate-examples/blob/main/rabbitmq/README.md).\n\n#### HTTP Basic Authentication Example\nThis should make it clear why Karate does not provide 'out of the box' support for any particular HTTP authentication scheme. Things are designed so that you can plug-in what you need, without needing to compile Java code. You get to choose how to manage your environment-specific configuration values such as user-names and passwords.\n\nFirst the JavaScript file, `basic-auth.js`:\n```javascript\nfunction fn(creds) {\n  var temp = creds.username + ':' + creds.password;\n  var Base64 = Java.type('java.util.Base64');\n  var encoded = Base64.getEncoder().encodeToString(temp.toString().getBytes());\n  return 'Basic ' + encoded;\n}\n```\nAnd here's how it works in a test-script using the [`header`](#header) keyword.\n\n```cucumber\n* header Authorization = call read('basic-auth.js') { username: 'john', password: 'secret' }\n```\n\nYou can set this up for all subsequent requests or dynamically generate headers for each HTTP request if you [`configure headers`](#configure-headers).\n\n## `callonce`\nCucumber has a limitation where [`Background`](#script-structure) steps are re-run for every `Scenario`. And if you have a `Scenario Outline`, this happens for *every* row in the `Examples`. This is a problem especially for expensive, time-consuming HTTP calls, and this has been an [open issue for a long time](https://github.com/cucumber/cucumber-jvm/issues/515). \n\nKarate's `callonce` keyword behaves exactly like [`call`](#call) but is guaranteed to execute only once. The results of the first call are cached, and any future calls will simply return the cached result instead of executing the JavaScript function (or feature) again and again. \n\nThis does require you to move 'set-up' into a separate `*.feature` (or JavaScript) file. But this totally makes sense for things not part of the 'main' test flow and which typically need to be re-usable anyway.\n\nSo when you use the combination of `callonce` in a `Background`, you can indeed get the same effect as using a [`@BeforeAll`](https://junit.org/junit5/docs/5.0.0/api/org/junit/jupiter/api/BeforeAll.html) annotation, and you can find examples in the [karate-demo](karate-demo), such as this one: [`callonce.feature`](karate-demo/src/test/java/demo/callonce/call-once.feature).\n\nA `callonce` is ideally used for only \"pure\" JSON. You may face issues if you attempt to mix in JS functions or Java code. See [`karate.callSingle()`](#karatecallsingle).\n\n## `eval`\n\u003e This is for evaluating arbitrary JavaScript and you are advised to use this only as a last resort ! Conditional logic is not recommended especially within test scripts because [tests should be deterministic](https://martinfowler.com/articles/nonDeterminism.html).\n\nThere are a few situations where this comes in handy:\n* you *really* don't need to assign a result to a variable\n* statements in the `if` form (also see [conditional logic](#conditional-logic))\n* 'one-off' logic (or [Java interop](#java-interop)) where you don't need the 'ceremony' of a [re-usable function](#calling-javascript-functions)\n* JavaScript / JSON-style mutation of existing [variables](#def) as a dynamic alternative to [`set`](#set) and [`remove`](#remove) - by using [`karate.set()`](#karate-setpath) and [`karate.remove()`](#karate-remove).\n\n```cucumber\n# just perform an action, we don't care about saving the result\n* eval myJavaScriptFunction()\n\n# do something only if a condition is true\n* eval if (zone == 'zone1') karate.set('temp', 'after')\n```\n\nAs a convenience, you can omit the `eval` keyword and so you can shorten the above to:\n\n```cucumber\n* myJavaScriptFunction()\n* if (zone == 'zone1') karate.set('temp', 'after')\n```\n\nThis is __very__ convenient especially if you are calling a method on a variable that has been [defined](#def) such as the [`karate`](#the-karate-object) object, and for general-purpose scripting needs such as [UI automation](karate-core). Note how `karate.set()` and `karate.remove()` below are used directly as a script \"statement\".\n\n```cucumber\n# you can use multiple lines of JavaScript if needed\n* eval\n  \"\"\"\n  var foo = function(v){ return v * v };\n  var nums = [0, 1, 2, 3, 4];\n  var squares = [];\n  for (var n in nums) {\n    squares.push(foo(n));\n  }\n  karate.set('temp', squares);\n  \"\"\"\n* match temp == [0, 1, 4, 9, 16]\n\n* def json = { a: 1 }\n* def key = 'b'\n# use dynamic path expressions to mutate json\n* json[key] = 2\n* match json == { a: 1, b: 2 }\n* karate.remove('json', key)\n* match json == { a: 1 }\n* karate.set('json', '$.c[]', { d: 'e' })\n* match json == { a: 1, c: [{ d: 'e' }] }\n```\n\n# Advanced / Tricks\n## Polling\nThe built-in [`retry until`](#retry-until) syntax should suffice for most needs, but if you have some specific needs, this demo example (using JavaScript) should get you up and running: [`polling.feature`](karate-demo/src/test/java/demo/polling/polling.feature).\n\n## Conditional Logic\nThe keywords [`Given` `When` `Then`](#given-when-then) are only for decoration and should not be thought of as similar to an `if - then - else` statement. And as a testing framework, Karate [discourages tests](https://martinfowler.com/articles/nonDeterminism.html) that give different results on every run.\n\nThat said, if you really need to implement 'conditional' checks, this can be one pattern:\n\n```cucumber\n* def filename = zone == 'zone1' ? 'test1.feature' : 'test2.feature'\n* def result = call read(filename)\n```\n\nAnd this is another, using [`karate.call()`](#karate-call). Here we want to [`call`](#call) a file only if a condition is satisfied:\n\n```cucumber\n* def result = responseStatus == 404 ? {} : karate.call('delete-user.feature')\n```\n\nOr if we don't care about the result, we can [`eval`](#eval) an `if` statement:\n\n```cucumber\n* if (responseStatus == 200) karate.call('delete-user.feature')\n```\n\nAnd this may give you more ideas. You can always use a [JavaScript function](#javascript-functions) or [call Java](#calling-java) for more complex logic.\n\n```cucumber\n* def expected = zone == 'zone1' ? { foo: '#string' } : { bar: '#number' }\n* match response == expected\n```\n\n### JSON Lookup\nYou can always use a JavaScript [`switch case`](https://www.w3schools.com/js/js_switch.asp) within an [`eval`](#eval) or [function](#javascript-functions) block. But one pattern that you should be aware of is that JSON is actually a great data-structure for looking up data.\n\n```cucumber\n* def data =\n\"\"\"\n{\n   foo: 'hello',\n   bar: 'world'  \n}\n\"\"\"\n# in real-life key can be dynamic\n* def key = 'bar'\n# and used to lookup data\n* match (data[key]) == 'world'\n```\n\nYou can find more details [here](https://stackoverflow.com/a/59162760/143475). Also note how you can wrap the LHS of the [`match`](#match) in parentheses in the rare cases where the parser expects JsonPath by default.\n\n### Abort and Fail\nIn some rare cases you need to exit a `Scenario` based on some condition. You can use [`karate.abort()`](#karate-abort) like so:\n\n```cucumber\n* if (responseStatus == 404) karate.abort()\n```\n\nUsing `karate.abort()` will *not* fail the test. Conditionally making a test fail is easy with [`karate.fail()`](#karate-fail)\n\n```cucumber\n* if (condition) karate.fail('a custom message')\n```\n\nBut normally a [`match`](#match) statement is preferred unless you want a really descriptive error message.\n\nAlso refer to [polling](#polling) for more ideas.\n\n## Commonly Needed Utilities\nSince it is so easy to dive into [Java-interop](#calling-java), Karate does not include any random-number functions, uuid generator or date / time utilities out of the box. You simply roll your own. \n\nHere is an example of how to get the current date, and formatted the way you want:\n\n```cucumber\n* def getDate =\n  \"\"\"\n  function() {\n    var SimpleDateFormat = Java.type('java.text.SimpleDateFormat');\n    var sdf = new SimpleDateFormat('yyyy/MM/dd');\n    var date = new java.util.Date();\n    return sdf.format(date);\n  } \n  \"\"\"\n\n* def temp = getDate()\n* print temp\n```\n\nAnd the above will result in something like this being logged: `[print] 2017/10/16`. \n\nHere below are a few more common examples:\n\nUtility | Recipe\n------- | ------                               \n| System Time (as a string) | `function(){ return java.lang.System.currentTimeMillis() + '' }`\n| UUID  | `function(){ return java.util.UUID.randomUUID() + '' }`\n| Random Number (`0` to `max-1`) | `function(max){ return Math.floor(Math.random() * max) }`\n| Case Insensitive Comparison | `function(a, b){ return a.equalsIgnoreCase(b) }`\n| Sleep or Wait for `pause` milliseconds | `function(pause){ java.lang.Thread.sleep(pause) }`\n\nThe first three are good enough for random string generation for most situations. Note that if you need to do a lot of case-insensitive string checks, [`karate.lowerCase()`](#karate-lowercase) is what you are looking for.\n\n### Multiple Functions in One File\nIf you find yourself needing a complex helper or utility function, we strongly recommend that you [use Java](#calling-java) because it is much easier to maintain and even debug if needed. And if you need multiple functions, you can easily organize them into a single Java class with multiple static methods.\n\nThat said, if you want to stick to JavaScript, but find yourself accumulating a lot of helper functions that you need to use in multiple feature files, the following pattern is recommended.\n\nYou can organize multiple \"common\" utilities into a single re-usable feature file as follows e.g. `common.feature`\n\n```cucumber\n@ignore\nFeature:\n\nScenario:\n  * def hello = function(){ return 'hello' }\n  * def world = function(){ return 'world' }\n```\n\nAnd then you have two options. The first option using [shared scope](#shared-scope) should be fine for most projects, but if you want to \"name space\" your functions, use \"isolated scope\":\n\n```cucumber\nScenario: function re-use, global / shared scope\n    * call read('common.feature')\n    * assert hello() == 'hello'\n    * assert world() == 'world'\n\nScenario: function re-use, isolated / name-spaced scope\n    * def utils = call read('common.feature')\n    * assert utils.hello() == 'hello'\n    * assert utils.world() == 'world'\n```\n\nYou can even move commonly used routines into [`karate-config.js`](#restrictions-on-global-variables) which means that they become \"global\". But we recommend that you do this only if you are sure that these routines are needed in almost *all* `*.feature` files. Bloating your configuration can lead to loss of performance, and maintainability may suffer.\n\n## Async\nThe JS API has a [`karate.signal(result)`](#karate-signal) method that is useful for involving asynchronous flows into a test.\n\n### `listen`\nYou use the `listen` keyword (with a timeout) to wait until that event occurs. The `listenResult` magic variable will hold the value passed to the call to `karate.signal()`.\n\nThis is best [explained](https://github.com/karatelabs/karate/tree/master/karate-netty#consumer-provider-example) in this [example](karate-demo/src/test/java/mock/contract/payment-service.feature) that involves listening to an ActiveMQ / JMS queue.\n\nNote how [JS functions](#javascript-functions) defined at run-time can be mixed with custom [Java code](#java-interop) to get things done. You need to use [`karate.toJava()`](#karate-tojava) to \"wrap\" JS functions passed to custom Java code.\n\n```cucumber\nBackground:\n* def QueueConsumer = Java.type('mock.contract.QueueConsumer')\n* def queue = new QueueConsumer(queueName)\n* def handler = function(msg){ karate.signal(msg) }\n* queue.listen(karate.toJava(handler))\n* url paymentServiceUrl + '/payments'\n\nScenario: create, get, update, list and delete payments\n    Given request { amount: 5.67, description: 'test one' }\n    When method post\n    Then status 200\n    And match response == { id: '#number', amount: 5.67, description: 'test one' }\n    And def id = response.id\n    * listen 5000\n    * json shipment = listenResult\n    * print '### received:', shipment\n    * match shipment == { paymentId: '#(id)', status: 'shipped' }\n```\n\n## WebSocket\nKarate also has built-in support for [websocket](http://www.websocket.org) that is based on the [async](#async) capability and the [`listen`](#listen) keyword. The following method signatures are available on the [`karate` JS object](#the-karate-object) to obtain a websocket client:\n\n* `karate.webSocket(url)`\n* `karate.webSocket(url, handler)`\n* `karate.webSocket(url, handler, options)` - where `options` is an optional JSON (or map-like) object that takes the following optional keys:\n  * `subProtocol` - in case the server expects it\n  * `headers` - another JSON of key-value pairs\n  * `maxPayloadSize` - this defaults to 4194304 (bytes, around 4 MB)\n\nThese will init a websocket client for the given `url` and optional `subProtocol`. You can call `send()` on the returned object to send a message.\n\nIf a `handler` [function](#javascript-functions) (returning a boolean) is provided - it will be used to complete the [`listen`](#listen) \"wait\" if `true` is returned. A handler function is needed only if you have to ignore some incoming traffic and stop the \"wait\" when a certain payload arrives. If you don't pass a `handler` (or it is `null`), the first message is returned.\n\nNote that `karate.signal()` (described as part of the [`listen`](#listen) keyword) will be called internally and the `listenResult` will be the payload contents of the \"selected\" message.\n\nHere is an example, where the same websocket connection is used to send as well as receive a message.\n\n```cucumber\n* def handler = function(msg){ return msg.startsWith('hello') }\n* def socket = karate.webSocket(demoBaseUrl + '/websocket', handler)\n* socket.send('Billie')\n* listen 5000\n* match listenResult == 'hello Billie !'\n```\n\nFor handling binary messages, the same `karate.webSocket()` method signatures exist for `karate.webSocketBinary()`. Refer to these examples for more: [`echo.feature`](karate-demo/src/test/java/demo/websocket/echo.feature) | [`websocket.feature`](karate-demo/src/test/java/demo/websocket/websocket.feature). Note that any websocket instances created will be auto-closed at the end of the `Scenario`.\n\n### Java Function References\nJavaScript functions have some limitations when combined with multi-threaded Java code. So it is recommended that you directly use a Java `Function` when possible instead of using the `karate.toJava()` \"wrapper\" as shown above.\n\nOne pattern you can adopt is to create a \"factory\" method that returns a Java function - where you can easily delegate to the logic you want. For example, see the `sayHelloFactory()` method below:\n\n```java\npublic class Hello {\n\n    public static String sayHello(String message) {\n        return \"hello \" + message;\n    }\n\n    public static Function\u003cString, String\u003e sayHelloFactory() {\n        return s -\u003e sayHello(s);\n    }\n\n}\n```\n\nAnd now, to get a reference to that \"function\" you can do this:\n\n```cucumber\n* def sayHello = Java.type('com.myco.Hello').sayHelloFactory()\n```\n\nThis can be convenient when using [shared scope](#shared-scope) because you can just call `sayHello('myname')` where needed.\n\n## Tags\nGherkin has a great way to sprinkle meta-data into test-scripts - which gives you some interesting options when running tests in bulk.  The most common use-case would be to partition your tests into 'smoke', 'regression' and the like - which enables being able to selectively execute a sub-set of tests.\n\nThe documentation on how to run tests via the [command line](#test-suites) has an example of how to use tags to decide which tests to *not* run (or ignore). Also see [`first.feature`](karate-demo/src/test/java/demo/tags/first.feature) and [`second.feature`](karate-demo/src/test/java/demo/tags/second.feature) in the [demos](karate-demo). If you find yourself juggling multiple tags with logical `AND` and `OR` complexity, refer to this [Stack Overflow answer](https://stackoverflow.com/a/50693388/143475).\n\n\u003e For advanced users, Karate supports being able to query for tags within a test, and even tags in a `@name=value` form. Refer to [`karate.tags`](#karate-tags) and [`karate.tagValues`](#karate-tagvalues).\n\n### Special Tags\nFor completeness, the \"built-in\" tags are the following:\n\nTag | Description\n--- | -----------\n`@ignore` | Any `Scenario` with (or that has inherited) this tag will be skipped at run-time. This does not apply to anything that is \"called\" though\n`@parallel` | See [`@parallel=false`](#parallelfalse)\n`@report` | See [`@report=false`](#reportfalse)\n`@setup` | See [`@setup`](#setup)\n`@env` | See below\n`@envnot` | See below\n\n### Environment Tags\nThere are two special tags that allow you to \"select\" or \"un-select\" a `Scenario` depending on the value of [`karate.env`](#switching-the-environment). This can be really convenient, for example to *never* run some tests in a certain \"production like\" or sensitive environment.\n\n* `@env=foo,bar` - will run only when the value of `karate.env` is not-null *and* equal to `foo` *or* `bar`\n* `@envnot=foo` - will run when the value of `karate.env` is `null` or anything *other than* `foo`\n\nHere is an example:\n\n```cucumber\n@env=dev  \nScenario: runs only when karate.env is 'dev'\n* print 'karate.env is:', karate.env\n```\n\nSince multiple values are supported, you can also do this:\n\n```cucumber\n@envnot=perf,prod  \nScenario: never runs in perf or prod\n* print 'karate.env is:', karate.env\n```\n\n### Tags And Examples\nA little-known capability of the Gherkin syntax is to be able to tag even specific rows in a bunch of examples ! You have to repeat the `Examples` section for each tag. The example below combines this with the advanced features described above.\n\n```cucumber\nScenario Outline: examples partitioned by tag\n* def vals = karate.tagValues\n* match vals.region[0] == expected\n\n  @region=US\n  Examples:\n    | expected |\n    | US       |\n\n  @region=GB\n  Examples:\n    | expected |\n    | GB       |\n```\n\nNote that if you tag `Examples` like this, and if a tag selector is used when running a given `Feature` - only the `Examples` that match the tag selector will be executed. There is no concept of a \"default\" where for e.g. if there is no matching tag - that the `Examples` without a tag will be executed. But note that you can use the negative form of a tag selector: `~@region=GB`.\n\n## Dynamic Port Numbers\nIn situations where you start an (embedded) application server as part of the test set-up phase, a typical challenge is that the HTTP port may be determined at run-time. So how can you get this value injected into the Karate configuration ?\n\nIt so happens that the [`karate`](#the-karate-object) object has a field called `properties` which can read a Java system-property by name like this: [`karate.properties['myName']`](#karate-properties). Since the `karate` object is injected within [`karate-config.js`](#configuration) on start-up, it is a simple and effective way for other processes within the same JVM to pass configuration values to Karate at run-time. Refer to the 'demo' [`karate-config.js`](karate-demo/src/test/java/karate-config.js) for an example and how the `demo.server.port` system-property is set-up in the test runner: [`TestBase.java`](karate-demo/src/test/java/demo/TestBase.java).\n\n## Java API\nKarate has a [set of Java API-s](https://twitter.com/KarateDSL/status/1353969718730788865) that expose the HTTP, JSON, data-assertion and UI automation capabilities. The primary classes are described below.\n\n* [`Http`](karate-core/src/main/java/com/intuit/karate/Http.java) - build and execute any HTTP request and retrieve responses\n* [`Json`](karate-core/src/main/java/com/intuit/karate/Json.java) - build and manipulate JSON data using JsonPath expressions, convert to and from Java `Map`-s and `List`-s, parse strings into JSON and convert Java objects into JSON\n* [`Match`](karate-core/src/main/java/com/intuit/karate/Match.java) - exposes all of Karate's [`match`](#match) capabilities, and this works for Java `Map` and `List` objects\n* [`Driver`](karate-core/src/main/java/com/intuit/karate/driver/Driver.java) - perform [web-browser automation](https://github.com/karatelabs/karate/tree/master/karate-core)\n\nDo note that if you choose the Java API, you will naturally lose some of the test-automation framework benefits such as HTML reports, parallel execution and [JavaScript](#the-karate-object) / [configuration](#configuration). You may have to rely on unit-testing frameworks or integrate additional dependencies.\n\n### jbang\n[jbang](https://www.jbang.dev) is a great way for you to install and execute scripts that use Karate's Java API on any machine with minimal setup. Note that jbang itself is [super-easy to install](https://www.jbang.dev/documentation/guide/latest/installation.html) and there is even a \"[Zero Install](https://www.jbang.dev/documentation/guide/latest/installation.html#zero-install)\" option.\n\nHere below is an example jbang script that uses the Karate [Java API](#java-api) to do some useful work. Name the file as `javadsl.java` and run using the command: `jbang javadsl.java`.\n\n\u003e please replace `RELEASE` with the exact version of Karate you intend to use if applicable\n\n```java\n///usr/bin/env jbang \"$0\" \"$@\" ; exit $?\n//DEPS com.intuit.karate:karate-core:RELEASE:all\n\nimport com.intuit.karate.*;\nimport java.util.List;\n\npublic class javadsl {\n\n    public static void main(String[] args) {\n        List users = Http.to(\"https://jsonplaceholder.typicode.com/users\")\n                .get().json().asList();\n        Match.that(users.get(0)).contains(\"{ name: 'Leanne Graham' }\");\n        String city = Json.of(users).get(\"$[0].address.city\");\n        Match.that(\"Gwenborough\").isEqualTo(city);\n        System.out.println(\"\\n*** second user: \" + Json.of(users.get(1)).toString());\n    }\n\n}\n```\n\nRead the documentation of the [stand-alone JAR](karate-netty#jbang) for more - such as how you can even install custom command-line applications using jbang !\n\n### Invoking feature files using the Java API\nIt is also possible to invoke a feature file via a Java API which can be useful in some test-automation situations.\n\nA common use case is to mix API-calls into a larger test-suite, for example a Selenium or WebDriver UI test. So you can use Karate to set-up data via API calls, then run the UI test-automation, and finally again use Karate to assert that the system-state is as expected. Note that you can even include calls to a database from Karate using [Java interop](#calling-java). And [this example](karate-demo/src/test/java/demo/dogs/dogs.feature) may make it clear why using Karate itself to drive even your UI-tests may be a good idea.\n\nThe static method `com.intuit.karate.Runner.runFeature()` is best explained in this demo unit-test: [`JavaApiTest.java`](karate-demo/src/test/java/demo/java/JavaApiTest.java).\n\nYou can optionally pass in variable values or over-ride config via a `HashMap` or leave the second-last argument as `null`. The variable state after feature execution would be returned as a `Map\u003cString, Object\u003e`. The last `boolean` argument is whether the [`karate-config.js`](#configuration) should be processed or not. Refer to the documentation on [type-conversion](#type-conversion) to make sure you can 'unpack' data returned from Karate correctly, especially when dealing with XML.\n\n## Hooks\nIf you are looking for [Cucumber 'hooks'](http://toolsqa.com/cucumber/cucumber-hooks/) Karate does not support them, mainly because they depend on Java code, which goes against the Karate Way™. \n\nInstead, Karate gives you all you need as part of the syntax. Here is a summary:\n\nTo Run Some Code | How\n---------------- | ---\nBefore *everything* (or 'globally' once) | See [`karate.callSingle()`](#karatecallsingle)\nBefore every `Scenario` | Use the [`Background`](#script-structure). Note that [`karate-config.js`](#karate-configjs) is processed before *every* `Scenario` - so you can choose to put \"global\" config here, for example using [`karate.configure()`](#karate-configure).\nOnce (or at the start of) every `Feature` | Use a [`callonce`](#callonce) in the [`Background`](#script-structure). The advantage is that you can set up variables (using [`def`](#def) if needed) which can be used in all `Scenario`-s within that `Feature`.\nAfter every `Scenario` | [`configure afterScenario`](#configure) (see [example](karate-demo/src/test/java/demo/hooks/hooks.feature))\nAfter every `Scenario Outline` | [`configure afterScenarioOutline`](#configure) (see [example](karate-demo/src/test/java/demo/hooks/hooks.feature))\nAt the end of the `Feature` | [`configure afterFeature`](#configure) (see [example](karate-demo/src/test/java/demo/hooks/hooks.feature))\n\n\u003e Note that for the `afterFeature` hook to work, you should be using the [`Runner` API](#parallel-execution) and not the JUnit runner.\n\n### `karate.callSingle()`\nOnly recommended for advanced users, but this guarantees a routine is run only once, *even* when [running tests in parallel](#parallel-execution). You can use [`karate.callSingle()`](#karate-callsingle) in [`karate-config.js`](#karate-configjs) like this:\n\n```js\nvar result = karate.callSingle('classpath:some/package/my.feature');\n```\n\nIt can take a second JSON argument following the same rules as [`call`](#call). Once you get a result, you typically use it to set global variables.\n\nRefer to this example:\n* [`karate-config.js`](karate-demo/src/test/java/karate-config.js)\n* [`headers-single.feature`](karate-demo/src/test/java/demo/headers/headers-single.feature)\n\nYou *can* use `karate.callSingle()` directly in a `*.feature` file, but it logically fits better in the global \"bootstrap\". Ideally it should return \"pure JSON\" and note that you always get a \"deep clone\" of the cached result object.\n\nIMPORTANT: There are some restrictions when using [`callonce`](#callonce) or `karate.callSingle()` especially within [`karate-config.js`](#karate-configjs). Ideally you should return only *pure* JSON data (or a primitive string, number etc.). Keep in mind that the reason this exists is to \"cache\" data, and *not* behavior. So if you return complex objects such as a custom Java instance or a JS function that depends on complex objects, this [*may* cause issues when you run in parallel](https://github.com/karatelabs/karate/issues/1558). If you really need to re-use a Java function, see [Java Function References](#java-function-references).\n\n#### Multiple calls using `karate.callSingle()`\nThe first argument to `karate.callSingle()` is used as the \"cache key\". So if you tried to re-use the same feature but with multiple arguments, things will not work as you expect. But you can suffix a `?name` to the feature to de-dupe it, like so:\n\n```js\nvar adminResponse = karate.callSingle('classpath:get-token.feature?admin', {'username': 'admin', 'password': 'password123' });\nvar userResponse = karate.callSingle('classpath:get-token.feature?user', {'username': 'user', 'password': 'password456' });\n```\n\nNow `adminResponse` and `userResponse` will be different, even though the same feature file is being used for a `callSingle()`.\n\n#### `configure callSingleCache`\nWhen re-running tests in development mode and when your test suite depends on say an `Authorization` header set by [`karate.callSingle()`](#karatecallsingle), you can cache the results locally to a file, which is very convenient when your \"auth token\" is valid for a period of a few minutes - which typically is the case. This means that as long as the token \"on file\" is valid, you can save time by not having to make the one or two HTTP calls needed to \"sign-in\" or create \"throw-away\" users in your SSO store.\n\nSo in \"dev mode\" you can easily set this behavior like this. Just ensure that this is \"configured\" *before* you use `karate.callSingle()`:\n\n```js\nif (karate.env == 'local') {\n  karate.configure('callSingleCache', { minutes: 15 });\n}\n```\n\nBy default Karate will use `target` (or `build`) as the \"cache\" folder, which you can over-ride by adding a `dir` key:\n\n```js\n  karate.configure('callSingleCache', { minutes: 15, dir: 'some/other/folder' });\n```\n\n\u003e This caching behavior will work only if the result of `karate.callSingle()` is a JSON-like object, and any JS functions or Java objects mixed in will be lost.\n\n## Data Driven Tests\n### The Cucumber Way\nCucumber has a concept of [Scenario Outlines](https://docs.cucumber.io/gherkin/reference/#scenario-outline) where you can re-use a set of data-driven steps and assertions, and the data can be declared in a very user-friendly fashion. Observe the usage of `Scenario Outline:` instead of `Scenario:`, and the new `Examples:` section.\n\nYou should take a minute to compare this with the [exact same example implemented in REST-assured and TestNG](https://github.com/basdijkstra/rest-assured-workshop/blob/d9734da98bfcd8087055bdcd78545581dd23cb77/src/test/java/answers/RestAssuredAnswers2Test.java). Note that this example only does a \"string equals\" check on *parts* of the JSON, but with Karate you are always encouraged to match the *entire* payload in one step.\n\n```cucumber\nFeature: karate answers 2\n\nBackground:\n  * url 'http://localhost:8080'\n\nScenario Outline: given circuit name, validate country\n  Given path 'api/f1/circuits/\u003cname\u003e.json'\n  When method get\n  Then match $.MRData.CircuitTable.Circuits[0].Location.country == '\u003ccountry\u003e'\n\n  Examples:\n    | name   | country  |\n    | monza  | Italy    |\n    | spa    | Belgium  |\n    | sepang | Malaysia |\n\nScenario Outline: given race number, validate number of pitstops for Max Verstappen in 2015\n  Given path 'api/f1/2015/\u003crace\u003e/drivers/max_verstappen/pitstops.json'\n  When method get\n  Then assert response.MRData.RaceTable.Races[0].PitStops.length == \u003cstops\u003e\n\n  Examples:\n    | race | stops |\n    | 1    | 1     |\n    | 2    | 3     |\n    | 3    | 2     |\n    | 4    | 2     |\n```\nThis is great for testing boundary conditions against a single end-point, with the added bonus that your test becomes even more readable. This approach can certainly enable product-owners or domain-experts who are not programmer-folk, to review, and even collaborate on test-scenarios and scripts.\n\n### Scenario Outline Enhancements\nKarate has enhanced the Cucumber `Scenario Outline` as follows:\n* __Type Hints__: if the `Examples` column header has a `!` appended, each value will be evaluated as a JavaScript data-type (number, boolean, or *even* in-line JSON) - else it defaults to string.\n* __Magic Variables__: `__row` gives you the entire row as a JSON object, and `__num` gives you the row index (the first row is `0`).\n* __Auto Variables__: in addition to `__row`, each column key-value will be available as a separate [variable](#def), which greatly simplifies JSON manipulation - especially when you want to re-use JSON [files](#reading-files) containing [embedded expressions](#embedded-expressions).\n* Any empty cells will result in a `null` value for that column-key, and this can be useful to [remove nodes](#remove-if-null) from JSON or XML documents\n\nThese are best explained with [examples](karate-core/src/test/java/com/intuit/karate/core/outline.feature). You can choose between the string-placeholder style `\u003cfoo\u003e` or *directly* refer to the [variable](#def) `foo` (or even the *whole row* JSON as `__row`) in JSON-friendly [expressions](#karate-expressions).\n\nNote that even the scenario name can accept placeholders - which is very useful in reports. \n\n```cucumber\nScenario Outline: name is \u003cname\u003e and age is \u003cage\u003e\n  * def temp = '\u003cname\u003e'\n  * match temp == name\n  * match temp == __row.name\n  * def expected = __num == 0 ? 'name is Bob and age is 5' : 'name is Nyan and age is 6'\n  * match expected == karate.scenario.name\n\n  Examples:\n    | name | age |\n    | Bob  | 5   |\n    | Nyan | 6   |\n\nScenario Outline: magic variables with type hints\n  * def expected = [{ name: 'Bob', age: 5 }, { name: 'Nyan', age: 6 }]\n  * match __row == expected[__num]\n\n  Examples:\n    | name | age! |\n    | Bob  | 5    |\n    | Nyan | 6    |\n\nScenario Outline: embedded expressions and type hints\n  * match __row == { name: '#(name)', alive: '#boolean' }\n\n  Examples:\n    | name | alive! |\n    | Bob  | false  |\n    | Nyan | true   |\n\nScenario Outline: inline json\n  * match __row == { first: 'hello', second: { a: 1 } }\n  * match first == 'hello'\n  * match second == { a: 1 }\n\n  Examples:\n    | first  | second!  |\n    | hello  | { a: 1 } |\n```\n\nFor another example, see: [`examples.feature`](karate-demo/src/test/java/demo/outline/examples.feature).\n\nIf you're looking for more complex ways of dynamically naming your scenarios you can use JS string interpolation by including placeholders in your scenario name.\n\n```cucumber\nScenario Outline: name is ${name.first} ${name.last} and age is ${age}\n  * match name.first == \"#? _ == 'Bob' || _ == 'Nyan'\"\n  * match name.last == \"#? _ == 'Dylan' || _ == 'Cat'\"\n  * match title == karate.scenario.name\n\nExamples:\n  | name!                               | age | title                           |\n  | { \"first\": \"Bob\", \"last\": \"Dylan\" } | 10  | name is Bob Dylan and age is 10 |\n  | { \"first\": \"Nyan\", \"last\": \"Cat\" }  | 5   | name is Nyan Cat and age is 5   |\n```\n\nString interpolation will support variables in scope and / or the `Examples` (including functions defined globally, but not functions defined in the background). Even Java interop and access to the [`karate` JS API](#the-karate-object) would work.\n\nFor some more examples check [`test-outline-name-js.feature`](karate-core/src/test/java/com/intuit/karate/core/parser/test-outline-name-js.feature).\n\n### The Karate Way\nThe limitation of the Cucumber `Scenario Outline:` (seen above) is that the number of rows in the `Examples:` is fixed. But take a look at how Karate can [loop over a `*.feature` file](#data-driven-features) for each object in a JSON array - which gives you dynamic data-driven testing, if you need it. For advanced examples, refer to some of the scenarios within this [demo](karate-demo): [`dynamic-params.feature`](karate-demo/src/test/java/demo/search/dynamic-params.feature#L70).\n\nAlso see the option below, where you can data-drive an `Examples:` table using JSON.\n\n### Dynamic Scenario Outline\nYou can feed an `Examples` table from a custom data-source, which is great for those situations where the table-content is dynamically resolved at run-time. This capability is triggered when the table consists of a single \"cell\", i.e. there is exactly one row and one column in the table.\n\n#### JSON Array Data Source\nThe \"scenario expression\" result is expected to be an array of JSON objects. Here is an example:\n\n```cucumber\nFeature: scenario outline using a JSON array as the data-source\n\nScenario Outline: cat name: ${name}\n    Given url demoBaseUrl\n    And path 'cats'\n    And request { name: '#(name)' }\n    When method post\n    Then status 200\n    And match response == { id: '#number', name: '#(name)' }\n\n    # the single cell can be any valid karate expression\n    Examples:\n    | read('../callarray/kittens.json') |\n```\n\nYou can see the structure of the data here: [`kittens.json`](karate-demo/src/test/java/demo/callarray/kittens.json)\n\nAny [Karate expression](#karate-expressions) can be used in the \"cell expression\", and you can even use [Java-interop](#calling-java) to use external data-sources such as a database.\n\nNote that Karate has built-in support for [CSV files](#csv-files) and here is an example: [`dynamic-csv.feature`](karate-demo/src/test/java/demo/outline/dynamic-csv.feature).\n\n#### `@setup`\nIn cases where the data-source needs multiple steps, for e.g. if an API needs to be called to get a JSON array, you can call a separate `Scenario` to \"set up\" this data. The `@setup` tag is built-in for this purpose and any `Scenario` tagged with this will behave like [`@ignore`](#special-tags). So the only way to call this `Scenario` is by using the `karate.setup()` JS API.\n\nHere is the above example re-written to do so:\n\n```cucumber\nFeature: scenario outline using a JSON array as the data-source\n\n@setup\nScenario:\n* def kittens = read('../callarray/kittens.json')\n\nScenario Outline: cat name: ${name}\n    Given url demoBaseUrl\n    And path 'cats'\n    And request { name: '#(name)' }\n    When method post\n    Then status 200\n    And match response == { id: '#number', name: '#(name)' }\n\n    Examples:\n    | karate.setup().kittens |\n```\n\nThe result of `karate.setup()` will be a JSON of all the variables created within the `Scenario` tagged with `@setup`. Note how we \"unpack\" the `kittens` and use it to \"data drive\" the `Scenario Outline`. You can get really creative and use [JS functions to filter data](https://github.com/karatelabs/karate/issues/1905#issuecomment-1207342290) for different needs.\n\nNote that `@setup` is designed specifically to create data for a [dynamic `Scenario Outline`](#dynamic-scenario-outline) and it is the first thing to execute within a `Feature`. In other words, it *cannot* depend on the `Background`. The `Background` will be used for each `Scenario` that is spawned from a `Scenario Outline`.\n\nThough not really recommended, you can have multiple `Scenario`-s within a `Feature` tagged with `@setup`. But in that case you should de-dupe them using a name:\n\n```cucumber\nFeature:\n\n@setup=myname\nScenario:\n* def data = [{ a: 1 }, { a: 2}]\n\nScenario Outline:\n* print __row\n\nExamples:\n| karate.setup('myname').data |\n```\n\nAnd since it is common to run a `@setup` `Scenario` only once per-feature you can call `karate.setupOnce()`. In the feature below, the `* print 'in setup'` step will run only once. Also note how the `Background` will run 4 times (twice per `Scenario`).\n\n```cucumber\nFeature:\n\nBackground:\n* print 'in background', __num\n\n@setup\nScenario:\n* print 'in setup'\n* def data = [{a:1}, {a:2}]\n\nScenario Outline: first\n* print __row\n\nExamples:\n| karate.setupOnce().data |\n\nScenario Outline: second\n* print __row\n\nExamples:\n| karate.setupOnce().data |\n```\n\n#### JSON Function Data Source\nAn advanced option is where the \"scenario expression\" returns a JavaScript \"generator\" function. This is a very powerful way to generate test-data without having to load a large number of data rows into memory. The function has to return a JSON object. To signal the end of the data, just return `null`. The function argument is the row-index, so you can easily determine *when* to stop the generation of data. Here is an example:\n\n```cucumber\nFeature: scenario outline using a dynamic generator function\n\n@setup\nScenario:\n    * def generator = function(i){ if (i == 20) return null; return { name: 'cat' + i, age: i } }\n\nScenario Outline: cat name: ${name}\n    Given url demoBaseUrl\n    And path 'cats'\n    And request { name: '#(name)', age: '#(age)' }\n    When method post\n    Then status 200\n    And match response == { id: '#number', name: '#(name)' }\n\n    Examples:\n    | karate.setup().generator |\n```\n","funding_links":["https://github.com/sponsors/karatelabs"],"categories":["Java","API Testing","测试","Automated API Testing \u0026 Load Testing Tools","Application Recommendation","Projects","API Testing with Doc Features","Don't forget to give a :star: to make the project popular","\u003ca name=\"Java\"\u003e\u003c/a\u003eJava"],"sub_categories":[".NET","42. [Karate](https://github.com/karatelabs/karate)","🛠️ DevOps","API Testing"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkaratelabs%2Fkarate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkaratelabs%2Fkarate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkaratelabs%2Fkarate/lists"}