{"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","funding_links":["https://github.com/sponsors/karatelabs"],"categories":["Java","API Testing","测试","Automated API Testing \u0026 Load Testing Tools","Application Recommendation","API Testing with Doc Features","Don't forget to give a :star: to make the project popular","automation","Projects","Performance Testing","\u003ca name=\"Java\"\u003e\u003c/a\u003eJava"],"sub_categories":[".NET","42. [Karate](https://github.com/karatelabs/karate)","🛠️ DevOps","API Testing","API Testing \u0026 Contract Testing"],"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 `ORI","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"}